[
  {
    "path": ".gitignore",
    "content": "__pycache__/*\nscripts/__pycache__/*\nfirebase.json\n.env\nPipfile.lock"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"fundamentalAnalysisHistoricalDataClient\"]\n\tpath = fundamentalAnalysisHistoricalDataClient\n\turl = https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataClient.git\n\tbranch = master\n[submodule \"fundamentalAnalysisHistoricalDataServer\"]\n\tpath = fundamentalAnalysisHistoricalDataServer\n\turl = https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataServer.git\n\tbranch = master\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at danilo_aleixo@hotmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail, or any other method with the owners of this repository before making a change. \n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n\n## Pull Request Process\n\n1. Ensure any install or build dependencies are removed before the end of the layer when doing a \n   build.\n2. Update the README.md with details of changes to the interface, this includes new environment \n   variables, exposed ports, useful file locations and container parameters.\n3. Increase the version numbers in any examples files and the README.md to the new version that this\n   Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).\n4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you \n   do not have permission to do that, you may request the second reviewer to merge it for you.\n\n## Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at [INSERT EMAIL ADDRESS]. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python\n\n\nCOPY fundamentus.py /data/fundamentus.py\nCOPY waitingbar.py /data/waitingbar.py\nWORKDIR /data\n\n# RUN pip install -r requirements.txt\nRUN pip install --upgrade lxml && \\\n    pip install --upgrade python_jwt && \\\n    pip install --upgrade gcloud && \\\n    pip install --upgrade sseclient && \\\n    pip install --upgrade Crypto && \\\n    pip install --upgrade pycryptodome==3.4.3 && \\\n    pip install --upgrade requests_toolbelt && \\\n    pip install --upgrade pymongo && \\\n    pip install sendgrid && \\\n    python -m pip install pymongo[srv]\n\nCMD python3 fundamentus.py"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 phoemur\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Pipfile",
    "content": "[[source]]\n\nurl = \"https://pypi.python.org/simple\"\nverify_ssl = true\n\n\n[packages]\n\ndjango = \"*\"\ngunicorn = \"*\"\ndjango-heroku = \"*\"\n\n\n[requires]\n\npython_version = \"3.6\"\n"
  },
  {
    "path": "Procfile",
    "content": "web: gunicorn gettingstarted.wsgi\n"
  },
  {
    "path": "Procfile.windows",
    "content": "web: python manage.py runserver 0.0.0.0:5000\n"
  },
  {
    "path": "README.md",
    "content": "# Bovespa Stock Ratings\n\nProjeto de análise de dados fundamentalistas da Bovespa\n\n**If you like this project you can support me.**  \n<div>\n<a href=\"https://apoia.se/daniloaleixo-bovespa\" target=\"_blank\"><img src=\"https://i.imgur.com/mFoBjIN.png\" alt=\"Apoia.se\" style=\"height: 51px !important;width: 217px !important;\" ></a>\n</div>\n\n\n## Sobre \nO projeto consiste na primeira fonte de informaçôes open-source sobre análise fundamentalista das ações da Bovespa.\nO objetivo é juntar informaçôes para tomadas de decisões.\n\n## Estrutura do projeto\n\nO projeto consiste de 4 projetos em repositórios separados:\n* [Crawler](https://github.com/daniloaleixo/bovespaStockRatings): script em python que faz um scrapping em algumas páginas para colher as informações para salvar em um banco de dados Mongo.\n* [Backend](https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataServer): Backend que faz a interface, usando GraphQL entre o banco e o front-end.\n* [Front-end](https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataClient): Visualização de dados da aplicação feita, totalmente em Angular.\n* [Agente de trading](https://github.com/daniloaleixo/NeuroEvolutionMarketTrader): Agente usando neuro evolução para comprar e vender ações automaticamente\n\n\n## Configurando o projeto\n\n  \nClonar o repositório principal\n```\ngit clone --recursive git@github.com:daniloaleixo/bovespaStockRatings.git\n```\n\n[Opcional] Se quiser clonar o subrepositórios\n```\ngit submodule update --init --recursive\n```\n  \n## Rodando o crawler\n\n### Rodando da imagem docker oficial\n```\ndocker run -e MONGO_URI=$MONGO_URI daniloaleixo/bovespa-stock-ratings-crawler\n```\n### Fazendo o build da imagem docker\n```\ndocker build -t bovespa_stock_ratings .\ndocker run -e MONGO_URI=$MONGO_URI -t bovespa_stock_ratings\n```\n\n\n\n## Análise \nEstou fazendo uma análise baseada nos princípios fundamentalistas do livro [Investidor Inteligente](https://en.wikipedia.org/wiki/The_Intelligent_Investor) do Benjamin Graham:\n\n* Tamanho Adequado \n  * Patrimônio Líquido maior que R$2bi\n* Posição Financeira Forte\n  * Liquidez Corrente maior que 1,5\n  * Dívida Bruta / Patrimônio Líquido < 50%\n* Histórico de Dividendos contínuos por, pelo menos, os últimos 20 anos.\n  * Ainda não consegui pegar essa informação, estou colocando só o último DY\n  * Ultimo DY maior que 2.5%\n* Estabilidade nos Ganhos, Nenhum prejuízo nos últimos 10 anos.\n  * Ainda não consegui verificar se teve algum prejuízo\n* Crescimento nos Ganhos: 10 anos de crescimento nos lucros-por-ação de, pelo menos,\num terço.\n  * Ainda não consegui colocar essa informação, mas tenho só \n  * Crescimento no últimos 5 anos maior que 5%\n  * ROE > 20%\n* Preço sobre Valor de Mercado: O preço da ação inferior a 1,5 x o valor dos ativos\nlíquidos.\n  * P/VPA < 1.5\n* P/L Moderado: O preço da ação inferior a 15x o lucro dos últimos 3 anos\n  * P/L < 15\n* Teste alternativo: Graham multiplicava o P/L pelo preço sobre o valor de mercado e\nverifica se o resultado está abaixo de 22.5\n  * P/L x P/VPA < 22.5\n\n## Credits\nThe project was inicially a contribution to this repostory: https://github.com/phoemur/fundamentus\n"
  },
  {
    "path": "app.json",
    "content": "{\n  \"name\": \"Start on Heroku: Python\",\n  \"description\": \"A barebones Python app, which can easily be deployed to Heroku.\",\n  \"image\": \"heroku/python\",\n  \"repository\": \"https://github.com/heroku/python-getting-started\",\n  \"keywords\": [\"python\", \"django\" ],\n  \"addons\": [ \"heroku-postgresql\" ],\n  \"env\": {\n    \"SECRET_KEY\": {\n      \"description\": \"The secret key for the Django application.\",\n      \"generator\": \"secret\"\n    }\n  },\n  \"environments\": {\n    \"test\": {\n      \"scripts\": {\n        \"test-setup\": \"python manage.py collectstatic --noinput\",\n        \"test\": \"python manage.py test\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "client/getFromFirebase.js",
    "content": "// \n// Get info from frebase and show it on the datatable\n// \n\n\n\nvar database = firebase.database();\nvar arrayStocksHistory = [];\n\nvar resultadoClone;\n\nvar lastUpdate;\n\nvar comparadores = {\n\tpatrLiq: { value: 2000000000, checked: 1 },\n\tliqCorr: { value: 1.5, checked: 1 },\n\troe: { value: 20, checked: 1 },\n\tdivPat: { value: 50, checked: 1 },\n\tcresc: { value: 5, checked: 1 },\n\tpvp: { value: 1.5, checked: 1 },\n\tpl: { value: 15, checked: 1 },\n\tdy: { value: 2.5, checked: 1 },\n\tplxpvp: { value: 22.5, checked: 1 },\n}\n\ninitInputs();\n\n\n// *******************************\n// \t\t\tLogic functions\n// *******************************\ndatabase.ref().child('stocks').once('value').then(function(snapshot){\n\t// console.log(snapshot.val())\n\n\tObject.keys(snapshot.val()).forEach(function(key){\n\t\t// console.log(snapshot.val()[key])\n\t\tvar object = JSON.parse(snapshot.val()[key]);\n\t\tarrayStocksHistory.push(object)\n\t\t// console.log(object);\n\t})\n\n\t// Sort by date, the first one will be the newest\n\tarrayStocksHistory.sort(function(a,b){\n\t\tvar date1 = new Date(a.date);\n\t\tvar date2 = new Date(b.date);\n\t\treturn date2 - date1;\n\t})\n\n\t// console.log(arrayStocksHistory);\n\tbuildTable(arrayStocksHistory[0]);\n\thideLoading();\n\n}, function(error){\n\tconsole.log(\"deu erro\");\n})\n\n// Get last update\ndatabase.ref().child('last_date').once('value').then(function(snapshot){\n\n\tlastUpdate = Object.keys(snapshot.val())\n\t.map(function(key){\n\t\treturn new Date(snapshot.val()[key]);\n\t})\n\t.sort(function(a, b) {\n\t\tconsole.log(new Date(a), new Date(b), new Date(a) > new Date(b));\n\t\treturn new Date(b) > new Date(a) ? 1 : -1;\n\t})[0];\n\n\t$(\"#lastUpdate\").append(lastUpdate);\n\n}, function(error){\n\tconsole.log(\"deu erro\");\n})\n\n\n\nvar buildTable = function(data){\n\t// console.log('vamos montar a tabela', data);\n\n\t// Put the objects in an array\n\tarrayObjects = [];\n\tObject.keys(data).forEach(function(key){\n\t\tarrayObjects.push(data[key])\n\t});\n\n\tarrayObjects = calculateScores(arrayObjects);\n\n\tvar resultArray = []; \n\tarrayObjects\n\t.forEach(function(element) {\n\t\tvar innerObject = {};\n\n\t\tif(Object.keys(element).pop().length > 3) {\n\t\t\tObject.keys(element).map(function(innerKey) {\n\t\t\t\tinnerObject = element[innerKey];\n\t\t\t\tinnerObject['papel'] = innerKey;\n\t\t\t});\n\n\t\t\tvar myArray = [];\n\n\t\t\tmyArray.push(innerObject[\"papel\"]);\n\t\t\tmyArray.push(innerObject[\"nota\"]);\n\t\t\tmyArray.push(innerObject[\"cotacao\"]);\n\t\t\tmyArray.push(innerObject[\"Pat.Liq\"]);\n\t\t\tmyArray.push(innerObject[\"Liq.Corr.\"]);\n\t\t\tmyArray.push(innerObject[\"ROE\"]);\n\t\t\tmyArray.push(innerObject[\"Div.Brut/Pat.\"]);\n\t\t\tmyArray.push(innerObject[\"Cresc.5a\"]);\n\t\t\tmyArray.push(innerObject[\"P/VP\"]);\n\t\t\tmyArray.push(innerObject[\"P/L\"]);\n\t\t\tmyArray.push(innerObject[\"DY\"]);\n\t\t\tmyArray.push(innerObject[\"PSR\"]);\n\t\t\tmyArray.push(innerObject[\"P/Ativo\"]);\n\t\t\tmyArray.push(innerObject[\"P/Cap.Giro\"]);\n\t\t\tmyArray.push(innerObject[\"P/EBIT\"]);\n\t\t\tmyArray.push(innerObject[\"P/Ativ.Circ.Liq.\"]);\n\t\t\tmyArray.push(innerObject[\"EV/EBIT\"]);\n\t\t\tmyArray.push(innerObject[\"EBITDA\"]);\n\t\t\tmyArray.push(innerObject[\"Mrg.Liq.\"]);\n\t\t\tmyArray.push(innerObject[\"ROIC\"]);\n\t\t\tmyArray.push(innerObject[\"Liq.2m.\"]);\n\t\t\tresultArray.push(myArray);\n\t\t\t\n\t\t}\n\n\t});\n\t$('#resultado').DataTable({ \n\t\t'data': resultArray,\n\t\t'order'\t: [[ 1, \"desc\" ]], // Order by score\n \t\t\"pageLength\": 500, // All stocks in the page\n \t\t\"createdRow\": function( row, data, dataIndex ) {\n \t\t\tif(data[1] >= 7.5) {\n \t\t\t\t$(row).css('background-color', '#cde0cd')\n \t\t\t}\n \t\t}\n\t});\n\n\t// var txt = \"\";\n\t// for(var i = 0; i < arrayObjects.length; i++) {\n\t// \tif(typeof(arrayObjects[i]) == \"object\"){\n\n\t// \t\tObject.keys(arrayObjects[i]).forEach(function(stock){\n\n\t// \t\t\tvar greenLine = \" class='green-line'\";\n\t// \t\t\t// If we see a stock with score below 7.5 we turnoff green\n\t// \t\t\tif(parseFloat(arrayObjects[i][stock][\"nota\"]) < 7.5)\n\t// \t\t\t\tgreenLine = '';\n\n\t// \t\t\tvar stockLine = \"<tr\" + greenLine + \">\" + \n\t// \t\t\t\t\t\t\t\"<td class='stock'>\" + stock + \"</td>\" + \n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"nota\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"cotacao\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Pat.Liq\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Liq.Corr.\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"ROE\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Div.Brut/Pat.\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Cresc.5a\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/VP\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/L\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"DY\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"PSR\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/Ativo\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/Cap.Giro\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/EBIT\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"P/Ativ.Circ.Liq.\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"EV/EBIT\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"EBITDA\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Mrg.Liq.\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"ROIC\"] + \"</td>\" +\n\t// \t\t\t            \t\"<td>\" + arrayObjects[i][stock][\"Liq.2m.\"] + \"</td>\" +\n\t// \t\t\t        \t\t\"</tr>\";\n\n\t// \t\t\t\t\t\t\ttxt += stockLine;\n\t// \t\t})\n\t// \t}\n\t// }\n\t// $(function(){\n\t// \t$(\".table-body\").append(txt);\n\t// \tconsole.log('estou aqui');\n\t// \t// $(\"#resultado\").append('dsajdhayasyusadd');\n\t// })\n}\n\nvar calculateScores = function(stockArray){\n\tconsole.log('calculando socres');\n\tlet dividePor = 0;\n\tObject.keys(comparadores).forEach(function(elem){\n\t\tif(comparadores[elem].checked) dividePor += 1;\n\t})\n\tconsole.log('dividePor', dividePor);\n\n\tfor(var i = 0; i < stockArray.length; i++) {\n\t\tif(typeof(stockArray[i]) == \"object\"){\n\t\t\tObject.keys(stockArray[i]).forEach(function(stock){\n\t\t\t\tvar nota = 0.0;\n\n\t\t\t\tvar patrLiq = parseFloat(stockArray[i][stock][\"Pat.Liq\"].replace(/\\./g, '').replace(/\\,/g, '.'));\n\t\t\t\tif(comparadores.patrLiq.checked &&  patrLiq > parseFloat(comparadores.patrLiq.value))\n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar liqCorr = parseFloat(stockArray[i][stock][\"Liq.Corr.\"].replace(/\\./g, '').replace(/,/g, '.'));\n\t\t\t\tif(comparadores.liqCorr.checked &&  liqCorr > parseFloat(comparadores.liqCorr.value))\n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar roe = parseFloat(stockArray[i][stock][\"ROE\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.roe.checked &&  roe > parseFloat(comparadores.roe.value)) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar divPat = parseFloat(stockArray[i][stock][\"Div.Brut/Pat.\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.divPat.checked &&  divPat * 100 < parseFloat(comparadores.divPat.value) && divPat > 0) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar cresc = parseFloat(stockArray[i][stock][\"Cresc.5a\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.cresc.checked &&  cresc > parseFloat(comparadores.cresc.value)) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar pvp = parseFloat(stockArray[i][stock][\"P/VP\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.pvp.checked &&  pvp < parseFloat(comparadores.pvp.value) && pvp > 0) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar pl = parseFloat(stockArray[i][stock][\"P/L\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.pl.checked &&  pl < parseFloat(comparadores.pl.value) && pl > 0) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tvar dy = parseFloat(stockArray[i][stock][\"DY\"].replace(/\\./g, '').replace(/\\,/g, '.').replace(/%/g, ''));\n\t\t\t\tif(comparadores.dy.checked &&  dy > parseFloat(comparadores.dy.value)) \n\t\t\t\t    nota = nota + 1\n\t\t\t\tif(comparadores.plxpvp.checked &&  pl * pvp < parseFloat(comparadores.plxpvp.value))\n\t\t\t\t\tnota = nota + 1;\n\n\t\t\t\tstockArray[i][stock][\"nota\"] = (parseFloat(nota) / dividePor * 10.0).toFixed(2);\n\n\t\t\t\t// console.log([stock, stockArray[i][stock][\"nota\"], patrLiq, liqCorr, roe, divPat, cresc, pvp, pl, dy])\n\n\t\t\t});\n\t\t}\n\t}\n\n\treturn stockArray;\n}\n\n\n\n// Clears the table\nvar resetTable = function() {\n\tif ( $.fn.DataTable.isDataTable('#resultado') ) {\n\t  $('#resultado').DataTable().destroy();\n\t}\n\tconsole.log(\"reseta tabela\", $(\".table-body\").html())\n}\n\n\n// *******************************\n// \t\t\tView state functions\n// *******************************\nvar hideLoading = function(){\n\t$('#loading-whell').addClass(\"hidden\");\n\t$('#info').removeClass(\"hidden\");\n}\n\n\nfunction initInputs(){\n\tconsole.log(\"chamei\");\n\t$(function() {\n\t\t$('#patrLiqInput').val(comparadores.patrLiq.value);\n\t\t$('#liqCorrInput').val(comparadores.liqCorr.value);\n\t\t$('#divPatInput').val(comparadores.divPat.value);\n\t\t$('#dyInput').val(comparadores.dy.value);\n\t\t$('#crescInput').val(comparadores.cresc.value);\n\t\t$('#roeInput').val(comparadores.roe.value);\n\t\t$('#pvpInput').val(comparadores.pvp.value);\n\t\t$('#plInput').val(comparadores.pl.value);\n\t\t$('#plxpvpInput').val(comparadores.plxpvp.value);\n\n\t\tresultadoClone = $(\".table-body\").clone();\n\t})\n}\n\n// Save rules\n$(document).on('click', '#saveRules', function(){\n\n\t// Get if checkbox is checked\n\tcomparadores.patrLiq.checked = $('#patrLiqCheckbox:checked').length;\n\tcomparadores.liqCorr.checked = $('#liqCorrCheckbox:checked').length;\n\tcomparadores.roe.checked = $('#roeCheckbox:checked').length;\n\tcomparadores.divPat.checked = $('#divPatCheckbox:checked').length;\n\tcomparadores.cresc.checked = $('#crescCheckbox:checked').length;\n\tcomparadores.pvp.checked = $('#pvpCheckbox:checked').length;\n\tcomparadores.pl.checked = $('#plCheckbox:checked').length;\n\tcomparadores.dy.checked = $('#dyCheckbox:checked').length;\n\tcomparadores.plxpvp.checked = $('#plxpvpCheckbox:checked').length;\n\n\t// get new values\n\tcomparadores.patrLiq.value = $('#patrLiqInput').val();\n\tcomparadores.liqCorr.value = $('#liqCorrInput').val();\n\tcomparadores.roe.value = $('#roeInput').val();\n\tcomparadores.divPat.value = $('#divPatInput').val();\n\tcomparadores.cresc.value = $('#crescInput').val();\n\tcomparadores.pvp.value = $('#pvpInput').val();\n\tcomparadores.pl.value = $('#plInput').val();\n\tcomparadores.dy.value = $('#dyInput').val();\n\tcomparadores.plxpvp.value = $('#plxpvpInput').val();\n\n\tresetTable();\n\tbuildTable(arrayStocksHistory[0]);\n\n})"
  },
  {
    "path": "client/styles.css",
    "content": "@keyframes App-logo-spin {\n  from { transform: rotate(0deg); }\n  to { transform: rotate(360deg); }\n}\n\nth {\n  background: white;\n  position: sticky;\n  top: 0;\n  z-index: 10;\n  background: #dddddd;\n  cursor: pointer;\n}\n\n.hidden{display:none;}\n\n.screen {\n  position: relative;\n  width: 100%;\n  height: 200px;\n}\n\n\n.loading-wrapper {\n  position: relative;\n}\n\n.loading-wrapper .loading-screen {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 10;\n    background-color: rgba(250,250,250,0.7);\n}\n\n.loading-wheel {\n    z-index: 11;\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    margin-top: -50px;\n    margin-left: -50px;\n    border: 8px solid #e3e3e3;\n    border-radius: 50%;\n    border-top: 8px solid #4e8df9;\n    width: 100px;\n    height: 100px;\n    transform: translateY(-50%);\n    -webkit-animation: App-logo-spin 1.5s linear infinite;\n    animation: App-logo-spin 1.5s linear infinite;\n}\n\n.stock {\n  color: #0062ff;\n}\n\n.green-line {\n  background-color: #cde0cd;\n}"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: \"3.4\"\nservices:\n  mongo:\n    network_mode: host\n    image: willguitaradmfar/mongo-auth\n    environment:\n      CREATE_DATABASES: \"myapp\"\n      MONGODB_USER: \"mongo_user\"\n      MONGODB_PASS: \"admin123\"\n    volumes:\n      - /var/lib/mongodb:/data/db\n    restart: always\n    ports:\n      - 27017:27017"
  },
  {
    "path": "functions/.gitignore",
    "content": "## Compiled JavaScript files\n**/*.js\n**/*.js.map\n\n# Typescript v1 declaration files\ntypings/\n\nnode_modules/"
  },
  {
    "path": "functions/package.json",
    "content": "{\n  \"name\": \"functions\",\n  \"scripts\": {\n    \"lint\": \"tslint --project tsconfig.json\",\n    \"build\": \"tsc\",\n    \"serve\": \"npm run build && firebase serve --only functions\",\n    \"shell\": \"npm run build && firebase functions:shell\",\n    \"start\": \"npm run shell\",\n    \"deploy\": \"firebase deploy --only functions\",\n    \"logs\": \"firebase functions:log\"\n  },\n  \"engines\": {\n    \"node\": \"8\"\n  },\n  \"main\": \"lib/index.js\",\n  \"dependencies\": {\n    \"firebase-admin\": \"^8.0.0\",\n    \"firebase-functions\": \"^3.0.0\",\n    \"mysql\": \"^2.17.1\"\n  },\n  \"devDependencies\": {\n    \"@types/mysql\": \"2.15.6\",\n    \"tslint\": \"^5.12.0\",\n    \"typescript\": \"^3.2.2\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "functions/src/index.ts",
    "content": "import { Change } from 'firebase-functions';\nimport { DataSnapshot } from 'firebase-functions/lib/providers/database';\nimport * as Mysql from 'mysql';\n\n// // Start writing Firebase Functions\n// // https://firebase.google.com/docs/functions/typescript\n//\n// export const helloWorld = functions.https.onRequest((request, response) => {\n//  response.send(\"Hello from Firebase!\");\n// });\n\nexport const saveStockHistory = (change: Change<DataSnapshot>, context = null) => {\n  // export const saveStockHistory = functions.database.ref('/stocks')\n  //   .onWrite((change: Change<DataSnapshot>, context) => {\n\n  const arrayStocksHistory = [];\n\n  const val = change.after.val;\n\n\n  \tObject.keys(val).forEach((key) => {\n      // console.log(snapshot.val()[key])\n      var object = JSON.parse(val[key]);\n      arrayStocksHistory.push(object)\n      // console.log(object);\n    })\n  \n    // Sort by date, the first one will be the newest\n    arrayStocksHistory.sort((a,b) => {\n      var date1: any = new Date(a.date);\n      var date2 : any= new Date(b.date);\n      return date2 - date1;\n    })\n\n\n\n  const conn: Mysql.Connection = Mysql.createConnection({\n    host: process.env.DB_ENDPOINT,\n    user: process.env.DB_USER,\n    password: process.env.DB_PASSWORD,\n    database: process.env.DATABASE_NAME,\n  });\n\n\n  query(conn, \"show tables\", {}).then((res) => {\n    console.log(res);\n\n    conn.destroy();\n  })\n    .catch(err => conn.destroy());\n\n\n  // Grab the current value of what was written to the Realtime Database.\n  console.log('Payload:', change, \"Context\", context);\n  return ['Uppercasing', context, change];\n  // const uppercase = original.toUpperCase();\n  // You must return a Promise when performing asynchronous tasks inside a Functions such as\n  // writing to the Firebase Realtime Database.\n  // Setting an \"uppercase\" sibling in the Realtime Database returns a Promise.\n  // return snapshot.ref.parent.child('uppercase').set(uppercase);\n  // });\n};\n\n\nasync function query<T>(conn: Mysql.Connection, queryString: string, substituionValues: Object): Promise<T> {\n  const queryOptions: Mysql.QueryOptions = transformIntoMySQLString(queryString, substituionValues);\n\n  return new Promise<T>((resolve, reject) => {\n    conn.query(\n      queryOptions,\n      (err: Mysql.MysqlError | null, results?: any, fields?: Mysql.FieldInfo[]) => {\n        if (err) reject(err);\n        else {\n          console.info('Salvo objeto com sucesso no DB');\n          resolve(results);\n        }\n      }\n    );\n  });\n}\n\nfunction transformIntoMySQLString(queryString: string, substituionValues: any): Mysql.QueryOptions {\n\n  // Get all keys (they have a ':' in front of the name)\n  const allKeys: string[] = queryString.split(' ')\n    .filter((word: string) => word.indexOf(':') == 0);\n\n  const allValuesInOrder: Array<string> = allKeys\n    .map((key: string) => substituionValues[key]);\n\n  // In case of error \n  if (allKeys.length != allValuesInOrder.length)\n    throw (\n      { 'queryString': queryString, subsValues: substituionValues }\n    );\n\n\n  // Overwrite the keys with '?'\n  let MysqlQueryString: string = queryString;\n  for (const key of allKeys) {\n    MysqlQueryString = MysqlQueryString.replace(key, '?');\n  }\n\n  return {\n    sql: MysqlQueryString,\n    values: allValuesInOrder\n  };\n}\n\n\nconst change: any = null;\n// {\n//   before:\n//     DataSnapshot: {\n//       app:\n//       FirebaseApp: {\n//         firebaseInternals_: [],\n//         services_: { },\n//         isDeleted_: false,\n//         name_: '__admin__',\n//         options_: [],\n//         INTERNAL: [] },\n//   instance: 'https://bovespastockratings.firebaseio.com',\n//   _path: '/stocks',\n//   _data:\n//     {\n//       '-LiAHa0uatNefaIDZ250': ' {\\n    \"0\": {\\n        \"GBIO33\": {\\n            \"Cresc.5a\": \"0,00%\",\\n            \"DY\": \"0,00%\",\\n            \"Div.Brut/Pat.\": \"0,30\",\\n            \"EBITDA\": \"23,44%\",\\n            \"EV/EBIT\": \"0,00\",\\n            \"Liq.2m.\": \"1.360.630,00\",\\n            \"Liq.Corr.\": \"2,03\",\\n            \"Mrg.Liq.\": \"7,73%\",\\n            \"P/Ativ.Circ.Liq.\": \"0,00\",\\n            \"P/Ativo\": \"0,000\",\\n            \"P/Cap.Giro\": \"0,00\",\\n            \"P/EBIT\": \"0,00\",\\n            \"P/L\": \"0,00\",\\n            \"P/VP\": \"0,00\",\\n            \"PSR\": \"0,000\",\\n            \"Pat.Liq\": \"729.236.000,00\",\\n            \"ROE\": \"8,70%\",\\n            \"ROIC\": \"19,69%\",\\n            \"cotacao\": \"7,25\"\\n        }\\n    },\\n    \"1\": {\\n        \"STBP3\": {\\n            \"Cresc.5a\": \"-2,25%\",\\n            \"DY\": \"0,10%\",\\n            \"Div.Brut/Pat.\": \"0,16\",\\n            \"EBITDA\": \"5,32%\",\\n            \"EV/EBIT\": \"58,74\",\\n            \"Liq.2m.\": \"6.607.860,00\",\\n            \"Liq.Corr.\": \"1,23\",\\n            \"Mrg.Liq.\": \"-0,01%\",\\n            \"P/Ativ.Circ.Liq.\": \"-2,58\",\\n            \"P/Ativo\": \"1,024\",\\n            \"P/Cap.Giro\": \"39,43\",\\n            \"P/EBIT\": \"59,37\",\\n            \"P/L\": \"-26.388,80\",\\n            \"P/VP\": \"2,21\",\\n            \"PSR\": \"3,161\",\\n            \"Pat.Liq\": \"1.337.190.000,00\",\\n            \"ROE\": \"-0,01%\",\\n            \"ROIC\": \"1,93%\",\\n            \"cotacao\": \"4,43\"\\n        }\\n    }'\n//     }\n//   }\n// }\n\nsaveStockHistory(change);"
  },
  {
    "path": "functions/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"outDir\": \"lib\",\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"target\": \"es2017\"\n  },\n  \"compileOnSave\": true,\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "functions/tslint.json",
    "content": "{\n  \"rules\": {\n    // -- Strict errors --\n    // These lint rules are likely always a good idea.\n\n    // Force function overloads to be declared together. This ensures readers understand APIs.\n    \"adjacent-overload-signatures\": true,\n\n    // Do not allow the subtle/obscure comma operator.\n    \"ban-comma-operator\": true,\n\n    // Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.\n    \"no-namespace\": true,\n\n    // Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.\n    \"no-parameter-reassignment\": true,\n\n    // Force the use of ES6-style imports instead of /// <reference path=> imports.\n    \"no-reference\": true,\n\n    // Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the\n    // code currently being edited (they may be incorrectly handling a different type case that does not exist).\n    \"no-unnecessary-type-assertion\": true,\n\n    // Disallow nonsensical label usage.\n    \"label-position\": true,\n\n    // Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.\n    \"no-conditional-assignment\": true,\n\n    // Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).\n    \"no-construct\": true,\n\n    // Do not allow super() to be called twice in a constructor.\n    \"no-duplicate-super\": true,\n\n    // Do not allow the same case to appear more than once in a switch block.\n    \"no-duplicate-switch-case\": true,\n\n    // Do not allow a variable to be declared more than once in the same block. Consider function parameters in this\n    // rule.\n    \"no-duplicate-variable\": [true, \"check-parameters\"],\n\n    // Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should\n    // instead use a separate variable name.\n    \"no-shadowed-variable\": true,\n\n    // Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.\n    \"no-empty\": [true, \"allow-empty-catch\"],\n\n    // Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.\n    // This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.\n    \"no-floating-promises\": true,\n\n    // Do not allow any imports for modules that are not in package.json. These will almost certainly fail when\n    // deployed.\n    \"no-implicit-dependencies\": true,\n\n    // The 'this' keyword can only be used inside of classes.\n    \"no-invalid-this\": true,\n\n    // Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.\n    \"no-string-throw\": true,\n\n    // Disallow control flow statements, such as return, continue, break, and throw in finally blocks.\n    \"no-unsafe-finally\": true,\n\n    // Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();\n    \"no-void-expression\": [true, \"ignore-arrow-function-shorthand\"],\n\n    // Disallow duplicate imports in the same file.\n    \"no-duplicate-imports\": true,\n\n\n    // -- Strong Warnings --\n    // These rules should almost never be needed, but may be included due to legacy code.\n    // They are left as a warning to avoid frustration with blocked deploys when the developer\n    // understand the warning and wants to deploy anyway.\n\n    // Warn when an empty interface is defined. These are generally not useful.\n    \"no-empty-interface\": {\"severity\": \"warning\"},\n\n    // Warn when an import will have side effects.\n    \"no-import-side-effect\": {\"severity\": \"warning\"},\n\n    // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for\n    // most values and let for values that will change.\n    \"no-var-keyword\": {\"severity\": \"warning\"},\n\n    // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.\n    \"triple-equals\": {\"severity\": \"warning\"},\n\n    // Warn when using deprecated APIs.\n    \"deprecation\": {\"severity\": \"warning\"},\n\n    // -- Light Warnings --\n    // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be \"info\"\n    // if TSLint supported such a level.\n\n    // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.\n    // (Even better: check out utils like .map if transforming an array!)\n    \"prefer-for-of\": {\"severity\": \"warning\"},\n\n    // Warns if function overloads could be unified into a single function with optional or rest parameters.\n    \"unified-signatures\": {\"severity\": \"warning\"},\n\n    // Prefer const for values that will not change. This better documents code.\n    \"prefer-const\": {\"severity\": \"warning\"},\n\n    // Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts.\n    \"trailing-comma\": {\"severity\": \"warning\"}\n  },\n\n  \"defaultSeverity\": \"error\"\n}\n"
  },
  {
    "path": "fundamentus.py",
    "content": "#!/usr/bin/env python3\n\nimport re\nimport urllib.request\nimport urllib.parse\nimport http.cookiejar\nimport time\nimport lxml\n\nfrom lxml.html import fragment_fromstring\nfrom collections import OrderedDict\nimport json\nimport ast\nimport datetime\nimport os\nfrom pymongo import MongoClient\nfrom sendgrid import SendGridAPIClient\nfrom sendgrid.helpers.mail import Mail\n\n\ndef get_data(*args, **kwargs):\n    url = 'http://www.fundamentus.com.br/resultado.php'\n    cj = http.cookiejar.CookieJar()\n    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))\n    opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201'),\n                         ('Accept', 'text/html, text/plain, text/css, text/sgml, */*;q=0.01')]\n\n    # Aqui estão os parâmetros de busca das ações\n    # Estão em branco para que retorne todas as disponíveis\n    data = {'pl_min':'',\n            'pl_max':'',\n            'pvp_min':'',\n            'pvp_max' :'',\n            'psr_min':'',\n            'psr_max':'',\n            'divy_min':'',\n            'divy_max':'',\n            'pativos_min':'',\n            'pativos_max':'',\n            'pcapgiro_min':'',\n            'pcapgiro_max':'',\n            'pebit_min':'',\n            'pebit_max':'',\n            'fgrah_min':'',\n            'fgrah_max':'',\n            'firma_ebit_min':'',\n            'firma_ebit_max':'',\n            'margemebit_min':'',\n            'margemebit_max':'',\n            'margemliq_min':'',\n            'margemliq_max':'',\n            'liqcorr_min':'',\n            'liqcorr_max':'',\n            'roic_min':'',\n            'roic_max':'',\n            'roe_min':'',\n            'roe_max':'',\n            'liq_min':'',\n            'liq_max':'',\n            'patrim_min':'',\n            'patrim_max':'',\n            'divbruta_min':'',\n            'divbruta_max':'',\n            'tx_cresc_rec_min':'',\n            'tx_cresc_rec_max':'',\n            'setor':'',\n            'negociada':'ON',\n            'ordem':'1',\n            'x':'28',\n            'y':'16'}\n\n    with opener.open(url, urllib.parse.urlencode(data).encode('UTF-8')) as link:\n        content = link.read().decode('ISO-8859-1')\n\n    pattern = re.compile('<table id=\"resultado\".*</table>', re.DOTALL)\n    reg = re.findall(pattern, content)[0]\n    page = fragment_fromstring(reg)\n    lista = OrderedDict()\n\n    stocks = page.xpath('tbody')[0].findall(\"tr\")\n\n    for i in range(0, len(stocks)):\n        lista[i] = {\n            stocks[i].getchildren()[0][0].getchildren()[0].text: {\n                'cotacao': stocks[i].getchildren()[1].text,\n               'P/L': stocks[i].getchildren()[2].text,\n               'P/VP': stocks[i].getchildren()[3].text,\n               'PSR': stocks[i].getchildren()[4].text,\n               'DY': stocks[i].getchildren()[5].text,\n               'P/Ativo': stocks[i].getchildren()[6].text,\n               'P/Cap.Giro': stocks[i].getchildren()[7].text,\n               'P/EBIT': stocks[i].getchildren()[8].text,\n               'P/Ativ.Circ.Liq.': stocks[i].getchildren()[9].text,\n               'EV/EBIT': stocks[i].getchildren()[10].text,\n               'EBITDA': stocks[i].getchildren()[11].text,\n               'Mrg. Ebit': stocks[i].getchildren()[12].text,\n               'Mrg.Liq.': stocks[i].getchildren()[13].text,\n               'Liq.Corr.': stocks[i].getchildren()[14].text,\n               'ROIC': stocks[i].getchildren()[15].text,\n               'ROE': stocks[i].getchildren()[16].text,\n               'Liq.2m.': stocks[i].getchildren()[17].text,\n               'Pat.Liq': stocks[i].getchildren()[18].text,\n               'Div.Brut/Pat.': stocks[i].getchildren()[19].text,\n               'Cresc.5a': stocks[i].getchildren()[20].text\n               }\n            }\n\n\n    return lista\n\n\ndef get_specific_data(stock):\n    url = \"http://www.fundamentus.com.br/detalhes.php?papel=\" + stock\n    cj = http.cookiejar.CookieJar()\n    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))\n    opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201'),\n                         ('Accept', 'text/html, text/plain, text/css, text/sgml, */*;q=0.01')]\n    \n    # Get data from site\n    link = opener.open(url, urllib.parse.urlencode({}).encode('UTF-8'))\n    content = link.read().decode('ISO-8859-1')\n\n    # Get all table instances\n    pattern = re.compile('<table class=\"w728\">.*</table>', re.DOTALL)\n    reg = re.findall(pattern, content)[0]\n    reg = \"<div>\" + reg + \"</div>\"\n    page = fragment_fromstring(reg)\n    all_data = {}\n\n    # There is 5 tables with tr, I will get all trs\n    all_trs = []\n    all_tables = page.xpath(\"table\")\n\n    for i in range(0, len(all_tables)):\n        all_trs = all_trs + all_tables[i].findall(\"tr\")\n\n    # Run through all the trs and get the label and the\n    # data for each line\n    for tr_index in range(0, len(all_trs)):\n        tr = all_trs[tr_index]\n        # Get into td\n        all_tds = tr.getchildren()\n        for td_index in range(0, len(all_tds)):\n            td = all_tds[td_index]\n\n\n            label = \"\"\n            data = \"\"\n\n            # The page has tds with contents and some \n            # other with not\n            if (td.get(\"class\").find(\"label\") != -1):\n                # We have a label\n                for span in td.getchildren():\n                    if (span.get(\"class\").find(\"txt\") != -1):\n                        label = span.text\n\n                # If we did find a label we have to look \n                # for a value \n                if (label and len(label) > 0):\n                    next_td = all_tds[td_index + 1]\n\n                    if (next_td.get(\"class\").find(\"data\") != -1):\n                        # We have a data\n                        for span in next_td.getchildren():\n                            if (span.get(\"class\").find(\"txt\") != -1):\n                                if (span.text):\n                                    data = span.text\n                                else:\n                                    # If it is a link\n                                    span_children = span.getchildren()\n                                    if (span_children and len(span_children) > 0):\n                                        data = span_children[0].text\n\n                                # Include into dict\n                                all_data[label] = data\n\n                                # Erase it\n                                label = \"\"\n                                data = \"\"\n\n    return all_data\n\n\n\ndef send_email(message):\n    try:\n        sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))\n        response = sg.send(message)\n        print(response.status_code)\n    except Exception as e:\n        print(\"Deu erro na hora de enviar o email\", str(e))\n    \n\n\ntry: \n    if __name__ == '__main__':\n        from waitingbar import WaitingBar\n        \n        THE_BAR = WaitingBar('[*] Downloading...')\n\n        lista = get_data()\n        THE_BAR.stop()\n        # print(\"Get all stocks data\")\n\n\n        #Transform em uma lista, agora preciso passar para formato JSON\n        array_format = list(lista.items())\n\n        # print(array_format, len(array_format))\n\n        hashes_list = []\n        # First include the list of all hashes\n        for i in range(0, len(array_format)):\n            hashes_list.append(array_format[i][1])\n\n        stocks = []\n        # Then from a list of hashes we will transform to a list of stocks\n        for i in range(0, len(hashes_list)):\n            for key in hashes_list[i]:\n                # Adds stockCode\n                hashes_list[i][key][\"stockCode\"] = key\n                stocks.append(hashes_list[i][key])\n        \n\n\n    #     json_format = {\n    #     \"0\": {\n    #         \"DAGB33\": {\n    #             \"Cresc.5a\": \"46,43%\",\n    #             \"DY\": \"0,00%\",\n    #             \"Div.Brut/Pat.\": \"1,37\",\n    #             \"EBITDA\": \"4,75%\",\n    #             \"EV/EBIT\": \"0,00\",\n    #             \"Liq.2m.\": \"916.730,00\",\n    #             \"Liq.Corr.\": \"1,16\",\n    #             \"Mrg.Liq.\": \"0,38%\",\n    #             \"P/Ativ.Circ.Liq.\": \"0,00\",\n    #             \"P/Ativo\": \"0,000\",\n    #             \"P/Cap.Giro\": \"0,00\",\n    #             \"P/EBIT\": \"0,00\",\n    #             \"P/L\": \"0,00\",\n    #             \"P/VP\": \"0,00\",\n    #             \"PSR\": \"0,000\",\n    #             \"Pat.Liq\": \"9.803.230.000,00\",\n    #             \"ROE\": \"-0,47%\",\n    #             \"ROIC\": \"4,59%\",\n    #             \"cotacao\": \"480,00\",\n    #             \"nota\": 0.5\n    #         }\n    #     }\n    # }\n\n        # Calculate the score of the stock\n        final_stocks = []\n        for stock in stocks:\n            nota = 0\n            patrLiq = float(stock[\"Pat.Liq\"].replace('.', '').replace(',', '.'))\n            if patrLiq > 2000000000:\n                nota = nota + 1\n            liqCorr = float(stock[\"Liq.Corr.\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if liqCorr > 1.5:\n                nota = nota + 1\n            roe = float(stock[\"ROE\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if roe > 20: \n                nota = nota + 1\n            divPat = float(stock[\"Div.Brut/Pat.\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if divPat < 0.5 and divPat > 0: \n                nota = nota + 1\n            cresc = float(stock[\"Cresc.5a\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if cresc > 5: \n                nota = nota + 1\n            pvp = float(stock[\"P/VP\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if pvp < 2 and pvp > 0: \n                nota = nota + 1\n            pl = float(stock[\"P/L\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if pl < 15 and pl > 0: \n                nota = nota + 1\n            dy = float(stock[\"DY\"].replace('.', '').replace(',', '.').replace('%', ''))\n            if dy > 2.5: \n                nota = nota + 1\n            stock[\"nota\"] = float(nota) / 8.0 * 10.0\n\n            newStock = {}\n            newStock[\"stockCode\"] = stock[\"stockCode\"]\n            newStock[\"patrimonioLiquido\"] = patrLiq\n            newStock[\"liquidezCorrente\"] = liqCorr\n            newStock[\"ROE\"] = roe\n            newStock[\"divSobrePatrimonio\"] = divPat\n            newStock[\"crescimentoCincoAnos\"] = cresc\n            newStock[\"precoSobreVP\"] = pvp\n            newStock[\"precoSobreLucro\"] = pl\n            newStock[\"dividendos\"] = dy\n            newStock[\"score\"] = stock[\"nota\"]\n            newStock[\"stockPrice\"] = float(stock[\"cotacao\"].replace('.', '').replace(',', '.'))\n            newStock[\"PSR\"] = float(stock[\"PSR\"].replace('.', '').replace(',', '.'))\n            newStock[\"precoSobreAtivo\"] = float(stock['P/Ativo'].replace('.', '').replace(',', '.'))\n            newStock[\"precoSobreCapitalGiro\"] = float(stock['P/Cap.Giro'].replace('.', '').replace(',', '.'))\n            newStock[\"precoSobreEBIT\"] = float(stock['P/EBIT'].replace('.', '').replace(',', '.'))\n            newStock[\"precoSobreAtivoCirculante\"] = float(stock['P/Ativ.Circ.Liq.'].replace('.', '').replace(',', '.'))\n            newStock[\"EVSobreEBIT\"] = float(stock['EV/EBIT'].replace('.', '').replace(',', '.'))\n            newStock[\"margemEBIT\"] = float(stock[\"EBITDA\"].replace('.', '').replace(',', '.').replace('%', ''))\n            newStock[\"margemLiquida\"] = float(stock['Mrg.Liq.'].replace('.', '').replace(',', '.').replace('%', ''))\n            newStock[\"ROIC\"] = float(stock[\"ROIC\"].replace('.', '').replace(',', '.').replace('%', ''))\n            newStock[\"liquidezDoisMeses\"] = float(stock['Liq.2m.'].replace('.', '').replace(',', '.').replace('%', ''))\n            newStock[\"timestamp\"] = datetime.datetime.now()\n\n            # Get more information\n            print(\"Getting more information from stock \", newStock[\"stockCode\"])\n            specific_data = get_specific_data(newStock[\"stockCode\"])\n\n\n            # Add everything to the object\n            newStock[\"tipo\"] = specific_data['Tipo']\n            newStock[\"name\"] = specific_data['Empresa']\n            newStock[\"setor\"] = specific_data['Setor']\n            newStock[\"subsetor\"] = specific_data['Subsetor']\n            newStock[\"max52sem\"] = float(specific_data['Max 52 sem'].replace('.', '').replace(',', '.')) if 'Max 52 sem' in specific_data and not \"-\" in specific_data['Max 52 sem'] else 0\n            newStock[\"volMed2M\"] = float(specific_data['Vol $ méd (2m)'].replace('.', '').replace(',', '.')) if 'Vol $ méd (2m)' in specific_data and not \"-\" in specific_data['Vol $ méd (2m)'] else 0\n            newStock[\"valorMercado\"] = float(specific_data['Valor de mercado'].replace('.', '').replace(',', '.')) if 'Valor de mercado' in specific_data and not \"-\" in specific_data['Valor de mercado'] else 0\n            newStock[\"valorFirma\"] = float(specific_data['Valor da firma'].replace('.', '').replace(',', '.')) if 'Valor da firma' in specific_data and not \"-\" in specific_data['Valor da firma'] else 0\n            newStock[\"nAcoes\"] = float(specific_data['Nro. Ações'].replace('.', '').replace(',', '.')) if 'Nro. Ações' in specific_data and not \"-\" in specific_data['Nro. Ações'] else 0\n            newStock[\"lucroPorAcao\"] = float(specific_data['LPA'].replace('.', '').replace(',', '.')) if 'LPA' in specific_data and not \"-\" in specific_data['LPA'] else 0\n            newStock[\"margemBruta\"] = float(specific_data['Marg. Bruta'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Marg. Bruta' in specific_data and not \"-\" in specific_data['Marg. Bruta'] else 0\n            newStock[\"EBITsobreAtivo\"] = float(specific_data['EBIT / Ativo'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'EBIT / Ativo' in specific_data and not \"-\" in specific_data['EBIT / Ativo'] else 0\n            newStock[\"giroAtivos\"] = float(specific_data['Giro Ativos'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Giro Ativos' in specific_data and not \"-\" in specific_data['Giro Ativos'] else 0\n            newStock[\"ativo\"] = float(specific_data['Ativo'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Ativo' in specific_data and not \"-\" in specific_data['Ativo'] else 0\n            newStock[\"divBruta\"] = float(specific_data['Dív. Bruta'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Dív. Bruta' in specific_data and not \"-\" in specific_data['Dív. Bruta'] else 0\n            newStock[\"divLiquida\"] = float(specific_data['Dív. Líquida'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Dív. Líquida' in specific_data and not \"-\" in specific_data['Dív. Líquida'] else 0\n            newStock[\"disponibilidades\"] = float(specific_data['Disponibilidades'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Disponibilidades' in specific_data and not \"-\" in specific_data['Disponibilidades'] else 0\n            newStock[\"receitaLiquida\"] = float(specific_data['Receita Líquida'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Receita Líquida' in specific_data and not \"-\" in specific_data['Receita Líquida'] else 0\n            newStock[\"lucroLiquido\"] = float(specific_data['Lucro Líquido'].replace('.', '').replace(',', '.').replace('%', '').replace(\"\\n\", \"\")) if 'Lucro Líquido' in specific_data and not \"-\" in specific_data['Lucro Líquido'] else 0\n\n            \n            final_stocks.append(newStock)\n\n\n\n        # Saves in mongoDB\n        client = MongoClient(os.environ['MONGO_URI'])\n\n        print(\"Peguei todos os stocks, agora preciso salvar\")\n\n\n        recent_stocks_db = client.recentStocks\n        all_stocks_coll = recent_stocks_db.stocks\n\n        # First drop the collection\n        recent_stocks_db.stocks.drop()\n\n        for i in range(0, len(final_stocks)):\n            stock = final_stocks[i]\n            # Insert in mongo\n            stock_id = all_stocks_coll.insert_one(stock).inserted_id\n            print(\"Inserted object on recent Objects \", i + 1, \" of \", len(final_stocks), \" :\",   stock_id)\n\n\n        # Send email of success\n        message = Mail(from_email='danilo_aleixo@hotmail.com', to_emails=os.environ.get('EMAIL_TO'), subject='Cron de analise diária, rodou certinho', html_content='Deu certo')\n        send_email(message)\n\nexcept Exception as e:\n    print(\"Deu erro\", str(e))\n    # Send email of error\n    message = Mail(from_email='danilo_aleixo@hotmail.com', to_emails=os.environ.get('EMAIL_TO'), subject='ERROR: Cron de analise diária, deu merda', html_content='Deu errado em ' + str(e))\n    send_email(message)\n\n\n\n"
  },
  {
    "path": "gettingstarted/__init__.py",
    "content": ""
  },
  {
    "path": "gettingstarted/settings.py",
    "content": "\"\"\"\nDjango settings for gettingstarted project.\n\nGenerated by 'django-admin startproject' using Django 2.0.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/2.0/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/2.0/ref/settings/\n\"\"\"\n\nimport os\nimport django_heroku\n\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = 'CHANGE_ME!!!! (P.S. the SECRET_KEY environment variable will be used, if set, instead).'\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = True\n\nALLOWED_HOSTS = []\n\n\n# Application definition\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'hello'\n]\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nROOT_URLCONF = 'gettingstarted.urls'\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = 'gettingstarted.wsgi.application'\n\n\n# Database\n# https://docs.djangoproject.com/en/2.0/ref/settings/#databases\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n    }\n}\n\n\n# Password validation\n# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/2.0/topics/i18n/\n\nLANGUAGE_CODE = 'en-us'\n\nTIME_ZONE = 'UTC'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/2.0/howto/static-files/\n\nSTATIC_URL = '/static/'\n\ndjango_heroku.settings(locals())"
  },
  {
    "path": "gettingstarted/static/humans.txt",
    "content": ""
  },
  {
    "path": "gettingstarted/urls.py",
    "content": "from django.conf.urls import include, url\nfrom django.urls import path\n\nfrom django.contrib import admin\nadmin.autodiscover()\n\nimport hello.views\n\n# Examples:\n# url(r'^$', 'gettingstarted.views.home', name='home'),\n# url(r'^blog/', include('blog.urls')),\n\nurlpatterns = [\n    url(r'^$', hello.views.index, name='index'),\n    url(r'^db', hello.views.db, name='db'),\n    path('admin/', admin.site.urls),\n]\n"
  },
  {
    "path": "gettingstarted/wsgi.py",
    "content": "\"\"\"\nWSGI config for gettingstarted project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/\n\"\"\"\n\nimport os\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"gettingstarted.settings\")\n\nfrom django.core.wsgi import get_wsgi_application\n\napplication = get_wsgi_application()\n"
  },
  {
    "path": "hello/__init__.py",
    "content": ""
  },
  {
    "path": "hello/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "hello/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.1 on 2016-01-27 21:54\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = [\n    ]\n\n    operations = [\n        migrations.CreateModel(\n            name='Greeting',\n            fields=[\n                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n                ('when', models.DateTimeField(auto_now_add=True, verbose_name=b'date created')),\n            ],\n        ),\n    ]\n"
  },
  {
    "path": "hello/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "hello/models.py",
    "content": "from django.db import models\n\n# Create your models here.\nclass Greeting(models.Model):\n    when = models.DateTimeField('date created', auto_now_add=True)\n"
  },
  {
    "path": "hello/templates/base.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<title>Python Getting Started on Heroku</title>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css\" />\n  <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n  <script type=\"text/javascript\" src=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js\"></script>\n  <style type=\"text/css\">\n    .jumbotron {\n        background: #532f8c;\n        color: white;\n        padding-bottom: 80px\n    }\n    .jumbotron .btn-primary {\n        background: #845ac7;\n        border-color: #845ac7\n    }\n    .jumbotron .btn-primary:hover {\n        background: #7646c1\n    }\n    .jumbotron p {\n        color: #d9ccee;\n        max-width: 75%;\n        margin: 1em auto 2em\n    }\n    .navbar+.jumbotron {\n        margin-top: -20px\n    }\n    .jumbotron .lang-logo {\n        display: block;\n        background: #b01302;\n        border-radius: 50%;\n        overflow: hidden;\n        width: 100px;\n        height: 100px;\n        margin: auto;\n        border: 2px solid white\n    }\n    .jumbotron .lang-logo img {\n        max-width: 100%\n    }\n\n\n  </style>\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-static-top navbar-inverse\">\n  <div class=\"container\">\n    <ul class=\"nav navbar-nav\">\n      <li class=\"active\">\n        <a href=\"/\"><span class=\"glyphicon glyphicon-home\"></span> Home</a>\n      </li>\n      <li>\n        <a href=\"https://devcenter.heroku.com/articles/how-heroku-works\"><span class=\"glyphicon glyphicon-user\"></span> How Heroku Works</a>\n      </li>\n      <li class=\"dropdown\">\n        <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\" role=\"button\" aria-expanded=\"false\"><span class=\"glyphicon glyphicon-info-sign\"></span> Getting Started Guides <span class=\"caret\"></span></a>\n          <ul class=\"dropdown-menu\" role=\"menu\">\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-ruby\">Getting Started with Ruby on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-nodejs\">Getting Started with Node on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-php\">Getting Started with PHP on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-python\">Getting Started with Python on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-java\">Getting Started with Java on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-clojure\">Getting Started with Clojure on Heroku</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-scala\">Getting Started with Scala on Heroku</a></li>\n            <li class=\"divider\"></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-heroku-and-connect-without-local-dev\">Getting Started on Heroku with Heroku Connect</a></li>\n            <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-jruby\">Getting Started with Ruby on Heroku (Microsoft Windows)</a></li>\n          </ul>\n      </li>\n    </ul>\n    <ul class=\"nav navbar-nav navbar-right\">\n      <li class=\"navbar-right\">\n        <a href=\"https://devcenter.heroku.com\"><span class=\"glyphicon glyphicon-book\"></span> Heroku Dev Center</a>\n      </li>\n    </ul>\n  </div>\n</nav>\n\n{% block content %}{% endblock %}\n\n</body>\n</html>\n"
  },
  {
    "path": "hello/templates/db.html",
    "content": "{% extends \"base.html\" %}\n{% load staticfiles %}\n\n{% block content %}\n  <div class=\"container\">\n\n\n<h2>Page View Report</h2>\n\n\n<ul>\n\n{% for greeting in greetings %}\n    <li>{{ greeting.when }}</li>\n{% endfor %}\n\n</ul>\n\n</div>\n\n{% endblock %}"
  },
  {
    "path": "hello/templates/index.html",
    "content": "{% extends \"base.html\" %}\n{% load staticfiles %}\n\n{% block content %}\n\n<div class=\"jumbotron text-center\">\n  <div class=\"container\">\n    <a href=\"/\" class=\"lang-logo\">\n      <img src=\"{% static 'lang-logo.png'%}\">\n    </a>\n    <h1>Getting Started with Python on Heroku</h1>\n    <p>This is a sample Python application deployed to Heroku. It's a reasonably simple app - but a good foundation for understanding how to get the most out of the Heroku platform.</p>\n    <a type=\"button\" class=\"btn btn-lg btn-default\" href=\"https://devcenter.heroku.com/articles/getting-started-with-python\"><span class=\"glyphicon glyphicon-flash\"></span> Getting Started with Python</a>\n    <a type=\"button\" class=\"btn btn-lg btn-primary\" href=\"https://github.com/heroku/python-getting-started\"><span class=\"glyphicon glyphicon-download\"></span> Source on GitHub</a>\n  </div>\n</div>\n<div class=\"container\">\n  <div class=\"alert alert-info text-center\" role=\"alert\">\n    To deploy your own copy, and learn the fundamentals of the Heroku platform, head over to the <a href=\"https://devcenter.heroku.com/articles/getting-started-with-python\" class=\"alert-link\">Getting Started with Python on Heroku</a> tutorial.\n  </div>\n  <hr>\n  <div class=\"row\">\n    <div class=\"col-md-6\">\n      <h3><span class=\"glyphicon glyphicon-info-sign\"></span> How this sample app works</h3>\n      <ul>\n        <li>This app was deployed to Heroku, either using Git or by using <a href=\"https://github.com/heroku/python-getting-started\">Heroku Button</a> on the repository.</li>\n\n        <li>When Heroku received the source code, it fetched all the dependencies in the <a href=\"https://github.com/heroku/python-getting-started/blob/master/Pipfile\">Pipfile</a>, creating a deployable slug.</li>\n        <li>The platform then spins up a dyno, a lightweight container that provides an isolated environment in which the slug can be mounted and executed.</li>\n        <li>You can scale your app, manage it, and deploy over <a href=\"https://addons.heroku.com/\">150 add-on services</a>, from the Dashboard or CLI.</li>\n      </ul>\n    </div>\n    <div class=\"col-md-6\">\n      <h3><span class=\"glyphicon glyphicon-link\"></span> Next Steps</h3>\n      <ul>\n        <li>If you are following the <a href=\"https://devcenter.heroku.com/articles/getting-started-with-python\">Getting Started</a> guide, then please head back to the tutorial and follow the next steps!</li>\n        <li>If you deployed this app by deploying the Heroku Button, then in a command line shell, run:</li>\n        <ul>\n          <li><code>git clone https://github.com/heroku/python-getting-started.git</code> - this will create a local copy of the source code for the app</li>\n          <li><code>cd python-getting-started</code> - change directory into the local source code repository</li>\n          <li><code>heroku git:remote -a &lt;your-app-name></code> - associate the Heroku app with the repository</li>\n          <li>You'll now be set up to run the app locally, or <a href=\"https://devcenter.heroku.com/articles/getting-started-with-python#push-local-changes\">deploy changes</a> to Heroku</li>\n        </ul>\n      </ul>\n      <h3><span class=\"glyphicon glyphicon-link\"></span> Helpful Links</h3>\n      <ul>\n        <li><a href=\"https://www.heroku.com/home\">Heroku</a></li>\n        <li><a href=\"https://devcenter.heroku.com/\">Heroku Dev Center</a></li>\n        <li><a href=\"https://devcenter.heroku.com/articles/getting-started-with-python\">Getting Started with Python on Heroku</a></li>\n        <li><a href=\"https://devcenter.heroku.com/articles/django-app-configuration\">Configuring Django Apps for Heroku</a></li>\n      </ul>\n    </div>\n  </div> <!-- row -->\n   <div class=\"alert alert-info text-center\" role=\"alert\">\n    Please do work through the Getting Started guide, even if you do know how to build such an application.  The guide covers the basics of working with Heroku, and will familiarize you with all the concepts you need in order to build and deploy your own apps.\n  </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "hello/tests.py",
    "content": "from django.contrib.auth.models import AnonymousUser, User\nfrom django.test import TestCase, RequestFactory\n\nfrom .views import index\n\nclass SimpleTest(TestCase):\n    def setUp(self):\n        # Every test needs access to the request factory.\n        self.factory = RequestFactory()\n\n    def test_details(self):\n        # Create an instance of a GET request.\n        request = self.factory.get('/')\n        request.user = AnonymousUser()\n\n        # Test my_view() as if it were deployed at /customer/details\n        response = index(request)\n        self.assertEqual(response.status_code, 200)"
  },
  {
    "path": "hello/views.py",
    "content": "from django.shortcuts import render\nfrom django.http import HttpResponse\n\nfrom .models import Greeting\n\n# Create your views here.\ndef index(request):\n    # return HttpResponse('Hello from Python!')\n    return render(request, 'index.html')\n\n\ndef db(request):\n\n    greeting = Greeting()\n    greeting.save()\n\n    greetings = Greeting.objects.all()\n\n    return render(request, 'db.html', {'greetings': greetings})\n\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html class=\"no-js\" lang=\"en\">\n\n\n\n<head>\n\t\t<meta http-equiv=\"refresh\" content=\"0; url=https://bovespastockratings.firebaseapp.com\" />\n</head>\n</html>\n"
  },
  {
    "path": "manage.py",
    "content": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"gettingstarted.settings\")\n\n    from django.core.management import execute_from_command_line\n\n    execute_from_command_line(sys.argv)\n"
  },
  {
    "path": "requirements.txt",
    "content": "asn1crypto==0.24.0\ncertifi==2019.9.11\ncffi==1.12.3\nchardet==3.0.4\ncrypto==1.4.1\ncryptography==3.3.2\ndnspython==1.16.0\ngcloud==0.18.3\ngoogleapis-common-protos==1.6.0\nhttplib2==0.19.0\nidna==2.8\njwcrypto==0.6.0\nlxml==4.6.3\nNaked==0.1.31\noauth2client==4.1.3\nprotobuf==3.10.0rc1\npyasn1==0.4.7\npyasn1-modules==0.2.6\npycparser==2.19\npycryptodome==3.6.6\npymongo==3.9.0\npython-jwt==3.2.4\nPyYAML==5.4\nrequests==2.22.0\nrequests-toolbelt==0.9.1\nrsa==4.7\nshellescape==3.4.1\nsix==1.12.0\nsseclient==0.0.24\nurllib3==1.26.5\nsendgrid==6.1.1\n"
  },
  {
    "path": "services.sh",
    "content": "#!/bin/bash\ndocker-compose -f docker-compose.yml up -d"
  },
  {
    "path": "waitingbar.py",
    "content": "#!/usr/bin/env python3\n\nimport sys\nimport threading\nimport time\n\nfrom itertools import cycle\n\n\nclass WaitingBar(object):\n    '''\n    This class prints a fancy waiting bar with Greek chars and spins.\n    It uses a thread to keep printing the bar while the main program runs\n\n    Usage:\n\n    THE_BAR = WaitingBar('Your Message Here')\n    # Do something slow here\n    (...)\n    THE_BAR.stop()\n    \n    copyright phoemur - 2016\n    '''\n\n    def __init__(self, message='[*] Wait until loading is complete...'):\n        self.MESSAGE = ' ' + str(message)\n        self.CYCLES = ['-', '-', '\\\\', '\\\\', '|', '|', '/', '/', '-', '-', '\\\\', '\\\\', '|', '|', '/', '/']\n        self.intab = u'abcdefghijklmnopqrstuvwxyzáàãâéèẽêíìîĩóòôõúùũûçABCDEFGHIJKLMNOPQRSTUVWXYZÁÀÃÂÉÈẼÊÍÌÎĨÓÒÔÕÚÙŨÛÇ'\n        self.outab = u'αβ¢ΔεϝγηιφκλμνΩπσϼΣτυϞωχψζααααεεεειιιιΩΩΩΩυυυυ¢αβ¢ΔεϝγηιφκλμνΩπσϼΣτυϞωχψζααααεεεειιιιΩΩΩΩυυυυ¢'\n        self.TABLE = {x: y for x, y in zip(self.intab, self.outab)}\n\n        self.event = threading.Event()\n        self.waiting_bar = threading.Thread(target=self.start, args=(self.event,))\n        self.waiting_bar.start()\n\n    def start(self, e):\n        for index in cycle(range(len(self.MESSAGE))):\n            if e.is_set():\n                break\n            if not self.MESSAGE[index].isalpha():\n                continue\n            for c in self.CYCLES:\n                buff = list(self.MESSAGE)\n                buff.append(c)\n\n                try:\n                    if sys.stdout.encoding.upper() == 'UTF-8':\n                        buff[index] = self.TABLE[buff[index]]\n                    else:\n                        buff[index] = buff[index].swapcase()\n                except KeyError:\n                    pass\n\n                sys.stdout.write(''.join(buff))\n                time.sleep(0.05)\n                sys.stdout.write('\\r')\n                sys.stdout.flush()\n\n    def stop(self):\n        self.event.set()\n        self.waiting_bar.join()\n        sys.stdout.write(self.MESSAGE + ' \\n')\n\n\nif __name__ == '__main__':\n    '''\n    A simple example to demonstrate the class in action\n    '''\n\n    # Start the bar\n    THE_BAR = WaitingBar('[*] Calculating useless stuff...')\n\n    # Do something slow\n    import math\n    from pprint import pprint\n\n    a_list = {a: b for a, b in zip(range(1, 41), map(math.factorial, range(1, 41)))}\n    time.sleep(20)\n\n    # Stop the bar and print result\n    THE_BAR.stop()\n    pprint(a_list)\n"
  }
]