diff --git a/.gitignore b/.gitignore index 7bbc71c..0bcaff9 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,9 @@ ENV/ # mypy .mypy_cache/ + +# Nikola stuff +bitblog/cache/ +bitblog/output/ +bitblog/.doit.db* +.idea/ diff --git a/CNAME b/CNAME deleted file mode 100644 index bfef833..0000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -blog.bitson.com.ar diff --git a/bitblog/Pipfile b/bitblog/Pipfile new file mode 100644 index 0000000..32ffc6b --- /dev/null +++ b/bitblog/Pipfile @@ -0,0 +1,19 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + + +[packages] + +nikola = {extras = ["extras"]} + + +[dev-packages] + + + +[requires] + +python_version = "3.6" diff --git a/bitblog/Pipfile.lock b/bitblog/Pipfile.lock new file mode 100644 index 0000000..1234ae0 --- /dev/null +++ b/bitblog/Pipfile.lock @@ -0,0 +1,629 @@ +{ + "_meta": { + "hash": { + "sha256": "c72c5148079e5583e44056617d3e17d24a70fdfb689230c9a4caa3a365147c94" + }, + "host-environment-markers": { + "implementation_name": "cpython", + "implementation_version": "3.6.4", + "os_name": "posix", + "platform_machine": "x86_64", + "platform_python_implementation": "CPython", + "platform_release": "4.14.14-300.fc27.x86_64", + "platform_system": "Linux", + "platform_version": "#1 SMP Fri Jan 19 13:19:54 UTC 2018", + "python_full_version": "3.6.4", + "python_version": "3.6", + "sys_platform": "linux" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "argh": { + "hashes": [ + "sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3", + "sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65" + ], + "version": "==0.26.2" + }, + "bleach": { + "hashes": [ + "sha256:cf567e7ed30ea5e05b31231d88ae170af1c5544758b9d7bebbc20590b7c30b1e", + "sha256:38fc8cbebea4e787d8db55d6f324820c7f74362b70db9142c1ac7920452d1a19" + ], + "version": "==2.1.2" + }, + "blinker": { + "hashes": [ + "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" + ], + "version": "==1.4" + }, + "certifi": { + "hashes": [ + "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296", + "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d" + ], + "version": "==2018.1.18" + }, + "chardet": { + "hashes": [ + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691", + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae" + ], + "version": "==3.0.4" + }, + "cloudpickle": { + "hashes": [ + "sha256:604c1cb39c2043ba44f017444dd89b7f82541701dfa8a64f5ae72e6346755c0b", + "sha256:b0e63dd89ed5285171a570186751bc9b84493675e99e12789e9a5dc5490ef554" + ], + "version": "==0.5.2" + }, + "decorator": { + "hashes": [ + "sha256:94d1d8905f5010d74bbbd86c30471255661a14187c45f8d7f3e5aa8540fdb2e5", + "sha256:7d46dd9f3ea1cf5f06ee0e4e1277ae618cf48dfb10ada7c8427cd46c42702a0e" + ], + "version": "==4.2.1" + }, + "docutils": { + "hashes": [ + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6", + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274" + ], + "version": "==0.14" + }, + "doit": { + "hashes": [ + "sha256:2988c8450fb3fb281877eb9a16860e1a8873c6ee0bb75ef0d78bb03a18d59ab9" + ], + "markers": "python_version >= '3.4'", + "version": "==0.30.3" + }, + "entrypoints": { + "hashes": [ + "sha256:10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b", + "sha256:d2d587dde06f99545fb13a383d2cd336a8ff1f359c5839ce3a64c917d10c029f" + ], + "version": "==0.2.3" + }, + "ghp-import2": { + "hashes": [ + "sha256:1172fa772abc3dba7f3ff902e7b202eb8ebaf4a463e9d63b8e90cc9edd57330e", + "sha256:fdf95846b26c5b42964b3146ffc4f22107bbba7baa42659f0f22bfe08ec96d7f" + ], + "version": "==1.0.1" + }, + "html5lib": { + "hashes": [ + "sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3", + "sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736" + ], + "version": "==1.0.1" + }, + "husl": { + "hashes": [ + "sha256:8a1d622565a01ca553a87f52de97244f33d04c20d9e4d0dac76ddfeccb6850b9" + ], + "version": "==4.0.3" + }, + "idna": { + "hashes": [ + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4", + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f" + ], + "version": "==2.6" + }, + "ipykernel": { + "hashes": [ + "sha256:9b9a9c1c566eabed6dc1536e9ea0cdb7b3a642cdb8a23b67e2047d8d7d61f5f7", + "sha256:8622cd42d952849057db38b81f0837a0ee6b865dea65d4b0b660164c96e6d052", + "sha256:dedc199df6a38725c732986dfa606c245fb8fe0fe999b33a0c305b73d80c6774" + ], + "version": "==4.8.0" + }, + "ipython": { + "hashes": [ + "sha256:fcc6d46f08c3c4de7b15ae1c426e15be1b7932bcda9d83ce1a4304e8c1129df3", + "sha256:51c158a6c8b899898d1c91c6b51a34110196815cc905f9be0fa5878e19355608" + ], + "version": "==6.2.1" + }, + "ipython-genutils": { + "hashes": [ + "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", + "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" + ], + "version": "==0.2.0" + }, + "jedi": { + "hashes": [ + "sha256:d795f2c2e659f5ea39a839e5230d70a0b045d0daee7ca2403568d8f348d0ad89", + "sha256:d6e799d04d1ade9459ed0f20de47c32f2285438956a677d083d3c98def59fa97" + ], + "version": "==0.11.1" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "jsonschema": { + "hashes": [ + "sha256:000e68abd33c972a5248544925a0cae7d1125f9bf6c58280d37546b946769a08", + "sha256:6ff5f3180870836cae40f06fa10419f557208175f13ad7bc26caa77beb1f6e02" + ], + "version": "==2.6.0" + }, + "jupyter-client": { + "hashes": [ + "sha256:e144e7ba1670424b1670a6325b00dae7f7b043f99486d2f77bdbc14cc90f2c2f", + "sha256:83d5e23132f0d8f79ccd3939f53fb9fa97f88a896a85114dc48d0e86909b06c4" + ], + "version": "==5.2.2" + }, + "jupyter-core": { + "hashes": [ + "sha256:927d713ffa616ea11972534411544589976b2493fc7e09ad946e010aa7eb9970", + "sha256:ba70754aa680300306c699790128f6fbd8c306ee5927976cbe48adacf240c0b7" + ], + "version": "==4.4.0" + }, + "logbook": { + "hashes": [ + "sha256:f37048f33600bb836b4a840cedb216ee52417d98d47f80a237669841310a4d6f", + "sha256:82206c17d08cb5aa47655b51f735b6dd5a62543c13154bdca8eb6fc5d720022e", + "sha256:49b39ff2db6950a8e8bed2ae21e4418ee89d7a2d13b6b687ef346a9d39a517a8", + "sha256:b42b6dd6caf9fa9ed69d074659584aaa36f2617ddc1217bfb25c8a3f77e109e8", + "sha256:dcd4a2fa711a5fb4fa9792629ca3c2c3d03ead50c8c181371352bb273a0ab3a9", + "sha256:9615ff1c55fe7632d6909eb01b97d64b323077323f1a5d6e4b657180e0bc1e6e", + "sha256:66d8cf296edbb64a68a47762f2cf78da7d70690c0a54ce7fbdeec1325db3306e", + "sha256:1ac26372b97a9d93be13968a30bcc110610960b688c5164a2890a75b3ad6668f", + "sha256:ef1397e6e82d8cbe3667c743f46144ccb252eca3173e4fc78e3afbe500e61c17", + "sha256:9f68a6f87234798417130efab7e190ee5dc7e8ced500f82cd200bfa15e9b6987", + "sha256:0e37a18f4f8244b02a1c44cfd2a3bab9513e6e22b67986ab6a91d52b87f0940b" + ], + "version": "==1.1.0" + }, + "lxml": { + "hashes": [ + "sha256:41f59cbdab232f11680d5d4dec9f2e6782fd24d78e37ee833447702e34e675f4", + "sha256:e7e41d383f19bab9d57f5f3b18d158655bcd682e7e723f441b9e183e1e35a6b5", + "sha256:155521c337acecf8202091cff85bb9f709f238130ebadf04280fb1db11f5ad8b", + "sha256:d2c985d2460b81c6ca5feb8b86f1bc594ad59405d0bdf68626b85852b701553c", + "sha256:950e63387514aa1b881eba5ac6cb2ec51a118b3dafe99dd80ca19d8fb0142f30", + "sha256:470d7ce41e8047208ba1a376560bad17f1468df1f3097bc83902b26cfafdbb0c", + "sha256:e608839a5ee2180164424ccf279c8e2d9bbe8816d002c58fd97d6b621ba4aa94", + "sha256:87a66bcadac270fc010cb029022a93fc722bf1204a8b03e782d4c790f0edf7ca", + "sha256:2dedfeeecc2d5a939cf622602f5a1ce443ca82407f386880f739f1a9f08053ad", + "sha256:ba05732e4bcf59e948f61588851dcf620fd60d5bbd9d704203e5f59bbaa60219", + "sha256:2190266059fec3c5a55f9d6c30532c64c6d414d3228909c0af573fe4907e78d1", + "sha256:dd291debfaa535d9cb6cee8d7aca2328775e037d02d13f1634e57f49bc302cc4", + "sha256:29a36e354c39b2e24bc4ee103de53417ebb80f976a6ab9e8d093d559e2ac03e1", + "sha256:e37427d5a27eefbcfc48847e0b37f348113fac7280bc857421db39ffc6372570", + "sha256:b106d4d2383382399ad82108fd187e92f40b1c90f55c2d36bbcb1c44bcf940fc", + "sha256:0ee07da52d240f1dc3c83eef5cd5f1b7f018226c1121f2a54d446645779a6d17", + "sha256:3b33549fb8f91b38a7500078242b03cca513f3412a2cdae722e89bf83f95971d", + "sha256:4c12e90886d9c53ab434c8d0cebea122321cce19614c3c6b6d1a7700d7cc6212", + "sha256:79322000279cda10b53c374d53ca632ead3bc51c6aebf8e62c8fa93a4d08b750", + "sha256:6cba398eb37e0631e60e0e080c101cfe91769b2c8267105b64b4625e2581ea21", + "sha256:49a655956f8de69e1258bc0fcfc43eb3bd1e038655784d77d1869b4b81444e37", + "sha256:af8a5373241d09b8fc53e0490e1719ce5dc90a21b19db89b6596c1adcdd52270", + "sha256:e6b6698415c7e8d227a47a3b1038e1b37c2b438a1b48c2db7ad9e74ddbcd1149", + "sha256:155c916cf2645b4a8f2bd5d09065e92d1b67b8d464bdc001e0b524af84bedf6f", + "sha256:fa7320679ced5e25b20203d157280680fc84eb783b6cc650cb0c98e1858b7dd3", + "sha256:4187c4b0cefc3353181db048c51f42c489d9ac51e40b86c4851dc0671372971d", + "sha256:d5d29663e979e83b3fc361e97200f959cddb3a14797391d15273d84a5a8ae44b", + "sha256:940caef1ec7c78e0c34b0f6b94fe42d0f2022915ffc78643d28538a5cfd0f40e" + ], + "version": "==4.1.1" + }, + "mako": { + "hashes": [ + "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" + ], + "version": "==1.0.7" + }, + "markdown": { + "hashes": [ + "sha256:9ba587db9daee7ec761cfc656272be6aabe2ed300fece21208e4aab2e457bc8f", + "sha256:a856869c7ff079ad84a3e19cd87a64998350c2b94e9e08e44270faef33400f81" + ], + "version": "==2.6.11" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "micawber": { + "hashes": [ + "sha256:f950dc2f5c7e8b706b0085f8936cdcceec832f69496f75f21d306932dafbf369" + ], + "version": "==0.3.4" + }, + "mistune": { + "hashes": [ + "sha256:b4c512ce2fc99e5a62eb95a4aba4b73e5f90264115c40b70a21e1f7d4e0eac91", + "sha256:bc10c33bfdcaa4e749b779f62f60d6e12f8215c46a292d05e486b869ae306619" + ], + "version": "==0.8.3" + }, + "natsort": { + "hashes": [ + "sha256:ee2f7715bf45a65cc1ab1d80360b00299102c7bf9d87757a27e14ddaafa57d0e", + "sha256:9ffbfb74bf3fc3905be1b9b052ed865675651e38fcd972ed1ed5c64a02f93cbd" + ], + "version": "==5.1.1" + }, + "nbconvert": { + "hashes": [ + "sha256:260d390b989a647575b8ecae2cd06a9eaead10d396733d6e50185d5ebd08996e", + "sha256:12b1a4671d4463ab73af6e4cbcc965b62254e05d182cd54995dda0d0ef9e2db9" + ], + "version": "==5.3.1" + }, + "nbformat": { + "hashes": [ + "sha256:b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", + "sha256:f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402" + ], + "version": "==4.4.0" + }, + "nikola": { + "hashes": [ + "sha256:3b61f785c973637e9a5439ca0b25ece9a7f9066252b2aa2c8f2010c170a4507d", + "sha256:10d95b3af84e61496ef729665eafa2235fd0fd4cc6c57644dd0f2c19a968dd0f" + ], + "version": "==7.8.11" + }, + "notebook": { + "hashes": [ + "sha256:9063a0daaac7816e1b7fc7dfcf69ee173904dcf3b460b45f5b6df06818969bd6", + "sha256:dd431fad9bdd25aa9ff8265da096ef770475e21bf1d327982611a7de5cd904ca" + ], + "version": "==5.4.0" + }, + "pandocfilters": { + "hashes": [ + "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9" + ], + "version": "==1.4.2" + }, + "parso": { + "hashes": [ + "sha256:a7bb86fe0844304869d1c08e8bd0e52be931228483025c422917411ab82d628a", + "sha256:5815f3fe254e5665f3c5d6f54f086c2502035cb631a91341591b5a564203cffb" + ], + "version": "==0.1.1" + }, + "pathtools": { + "hashes": [ + "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0" + ], + "version": "==0.1.2" + }, + "pexpect": { + "hashes": [ + "sha256:144939a072a46d32f6e5ecc866509e1d613276781f7182148a08df52eaa7b022", + "sha256:8e287b171dbaf249d0b06b5f2e88cb7e694651d2d0b8c15bccb83170d3c55575" + ], + "markers": "sys_platform != 'win32'", + "version": "==4.3.1" + }, + "phpserialize": { + "hashes": [ + "sha256:bf672d312d203d09a84c26366fab8f438a3ffb355c407e69974b7ef2d39a0fa7" + ], + "version": "==1.3" + }, + "pickleshare": { + "hashes": [ + "sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5", + "sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b" + ], + "version": "==0.7.4" + }, + "piexif": { + "hashes": [ + "sha256:47befcbc9a6ee171a0b8c35b981eb02df2120427eb19418d257450b055c622ac", + "sha256:1d3dde03bd6298393645bc11d585b67a6ea98fd7e9e1aded6d5d6ec3e4cfbdda" + ], + "version": "==1.0.13" + }, + "pillow": { + "hashes": [ + "sha256:718ec7a122b28d64afc5fbc3a9b99bb0545ef511373cac06fe7624520e82cb20", + "sha256:801cca8923508311bf5d6d0f7da5362552e8208ebd8ec0d7b9f2cd2ff5705734", + "sha256:43334f9581cd067945b8898cef9eb5714ee4883f8de0304c011f1dbdb1d4e2aa", + "sha256:153ec6f18f7b61641e0e6e502acfaf4a06c9aba2ea11c0b4b3578ea9f13a4a4a", + "sha256:25193f934d37d836a6b1f4c062ce574a96cbca7c6d9dc8ddfbbac7f9c54deaa4", + "sha256:b85f703c2ffe539313e39ce0676bed0f355cec45a16e58c9ab7417445843047c", + "sha256:8580fc58074a16b749905b26cf8363f7b628dd167ba0130f5382cdc91c86b509", + "sha256:2fcde9954c8882d1c7f93bb828caa34a4c5e3ee69dbc7895dc8652ad972b455a", + "sha256:1a5b93084e01328a1cb1ecdad99d11d75e881e89a95f88d85b523646553b36c2", + "sha256:b2240f298482f823576f397bb9f32ea913ad9456c526e141bc6f0a022b37a3e8", + "sha256:b1d33c63a55d0d85df0ad02b2c16158fb4d8153afa7b908f1a67330fac694cd6", + "sha256:6977cf073d83358b34f93abf5c1f1193b88675fe0e4441e0e28318bc3dcba7a0", + "sha256:1912b7230459fd53682dae32b83cbd8e5d642ba36d4be18566f00a9c063aa13d", + "sha256:4bd4a71501b6d51db4abc07e1f43f5a6fed0a1a9583cca0b401d6af50284b0db", + "sha256:0013f590a8f260df60bcfd65db19d18efc04e7f046c3c82a40e2e2b3292a937c", + "sha256:a224651a81e45ef4f1d0164e256c5f6b4abb49f2ae8f22ba2f3a9d0ff338e608", + "sha256:c793dfaa130847ccff958492b76ae8b9304e60b8a79a92962cb19e368276a22b", + "sha256:0b899ee80920bb533f26581af9b4660bc12aff4562555afe74e429101ebf3c94", + "sha256:9525cd680a6f9e80c6c0af03cf973e6505c59f60b4745f682cd1a449e54b31bb", + "sha256:35f7d998b8e82fb3fb51ff88b30485eb81cd7dd56ec7e1a8deba23eb88532d44", + "sha256:5b0d657460d9f3615876fec6306e97ca15a471f6169b622d76a47e270998acf1", + "sha256:ddd16ab250b4fc97db1c47407e78c25216a75c29d29d10ad37e51b7a2ec7b2c3", + "sha256:b9f63451084a718eccdeb1e382768c94647915653af4d6019f64560d9e98642b", + "sha256:a370d1c570f1d72e877099651e752332444b1c5009381f043c9da5fd47f3ebae", + "sha256:dc4b018d5c9b636f7546583c5591b9ea00c328c3e5871992ef5b95bac353f097", + "sha256:e126ff4fed71e78333840c07279e1617f63cfca76d63ad5b27d65a7277206a3d", + "sha256:fcf64c91fd44485100a2965d23bb0e227d093e91f7e776c5ca3b32574766eb56", + "sha256:2c042352b430d678db50c78c5214e19638eff8b688941271da2de21fd298dfe5", + "sha256:17fe25efc785194d48c38fad85dce470013ba19d2fb66639e149f14bccf1327f", + "sha256:2e818dbe445e86fc6c266973fe540c35125c42eb2cf13a6095e9adaa89c0deb5", + "sha256:135e9aa65150c53f7db85bf2bebb8a0e1a48ea850e80cf66e16dd04fa09d309c", + "sha256:7dfbefdb3fb911ca9faed307bf309861e9995e36cca6b761c7ba6d9b77a9744a", + "sha256:12f29d6c23424f704c66b5b68c02fe0b571504459605cfe36ab8158359b0e1bb", + "sha256:f8d49be8c282df8d2e1ab6ab53ab8abd859b1fa6fed384457ee85c9eff64ef97", + "sha256:82b172e3264e62372c01b5b009b5b1a02fbb9276cbe5cc57ab00a6d6e5ed9a18", + "sha256:57aa6198ba8acba1313c3b743e267d821a60cac77e6026caf0b55ca58d3d23be", + "sha256:d60c1625b108432ace8b1fa1a584017e5efa73f107d0f493c7f39c79bebf1d41", + "sha256:82d1ff571489765df2816785d532e243bde213752156c227fca595723ec5ff42", + "sha256:37cc0339abfa9e295c75d9a7f227d35cb44716feb95057f9449c4a9e9a17daf7", + "sha256:931030d1d6282b7900e6b0a7ff9ecdb503b5e1e6781800dab2b71a9f39405bff", + "sha256:5cd36804f9f06a914a883fe682df5711d16d7b4f44d43189c5f013e7cd91e149" + ], + "version": "==5.0.0" + }, + "prompt-toolkit": { + "hashes": [ + "sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4", + "sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381", + "sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917" + ], + "version": "==1.0.15" + }, + "ptyprocess": { + "hashes": [ + "sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a", + "sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365" + ], + "version": "==0.5.2" + }, + "pygal": { + "hashes": [ + "sha256:27abab93cbc31e21f3c6bdecc05bda6cd3570cbdbd8297b7caa6904051b50d72", + "sha256:9204f05380b02a8a32f9bf99d310b51aa2a932cba5b369f7a4dc3705f0a4ce83" + ], + "version": "==2.4.0" + }, + "pygments": { + "hashes": [ + "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", + "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + ], + "version": "==2.2.0" + }, + "pyinotify": { + "hashes": [ + "sha256:9c998a5d7606ca835065cdabc013ae6c66eb9ea76a00a1e3bc6e0cfe2b4f71f4" + ], + "version": "==0.9.6" + }, + "pyphen": { + "hashes": [ + "sha256:3ad2ae9b5a077c234cdc18329e7a4aad58c0d1bf0ab0ddd2be938a4292b3ade9", + "sha256:abfa9a0ab055341f6e250c1a6bef395c3a06f0e4cba216eeef37f617b32c0bd7" + ], + "version": "==0.9.4" + }, + "pyrss2gen": { + "hashes": [ + "sha256:7960aed7e998d2482bf58716c316509786f596426f879b05f8d84e98b82c6ee7" + ], + "version": "==1.1" + }, + "python-dateutil": { + "hashes": [ + "sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c", + "sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca" + ], + "version": "==2.6.1" + }, + "pyyaml": { + "hashes": [ + "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", + "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", + "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269", + "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", + "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", + "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", + "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", + "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", + "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", + "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", + "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", + "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", + "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", + "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7" + ], + "version": "==3.12" + }, + "pyzmq": { + "hashes": [ + "sha256:1478287e2e0d251aaed4442b6e9b9883485328bf455a461b6910fe13912f8a6e", + "sha256:fa1024749c667aa234292c973760eb6b6416981a55ed91ec4ab320af55301cc9", + "sha256:890143082ac2444d01187dfd0284a1d70db9be199fdacefefc9894f476da5e2a", + "sha256:d586bc45a89d20be90f44df6f3ee8fb95d99091089ba399a95ca25b76fcab93d", + "sha256:fae9be78bccf89284e970ce42b5cc7d825bd0187027109c762b8c61be37ce763", + "sha256:6a9d15f4c18b2d7f4437ca48dfced25a891d99346c06a58e564ad1af55f2dca7", + "sha256:14c43a839fe454ee4cc4289f77c791bff24dc3dc151005c6178eea697766aedd", + "sha256:165ddf9222af3a9fe7a016eb0d59ae2460e6032b070ceff7341147c1e4af588e", + "sha256:17012c4b95f92b9983c9b7a341d730743092592c89a60b522bf78c6c95a4d71a", + "sha256:7ed4a8568213d78acaafe93388c568b062a428d5d6b8e6bc6c17521a120126d3", + "sha256:cee2ea5f8630975787dc50ca0d154e28170c15bc6f406208f8d104818930f5a2", + "sha256:0033622ceaf46350b8b69ef93198cebf2a631f775279f857c3637961689951fa", + "sha256:fa7f09cbca8a7a2c0c19ff14e203016d82e6f8cc54df6d0fc8c011cf7ec755ff", + "sha256:a5c9bb522653a137cda07cc2dc6200644074181181296b617bdf3d9f8df419e6", + "sha256:b7fe5a6286778171db895d4cf846476ef3197f29fc2f644c39d5d78131dbc8be", + "sha256:ce5073b889eec66734ffcf547e4bdb75c26692e3471b700b6a6c5ef18c3374b3", + "sha256:513573d9b4d47ace0fefbd8e5577c1aa821d8a07deb069115bbad0898f877794", + "sha256:5f4c356d278a1017caeec91194b499f550a2c16cf2cb0c6a5ce7f1b3dff8d323", + "sha256:67e50b0f66aa606370a0790e4d64ef7d1b3b0617928f4734cdae4d3463926ab7", + "sha256:d6b5b6196ba51f22d0c708748b9859eb6e3aa50c620bd4025429db6252775cc1", + "sha256:a84df0111779d231130f2d62b47d63b1732d89c02d252981bac87b955943e133", + "sha256:22a94263f806decdd1277630afd93dff5d70461ddbe8fde337ce9c8cce98add6", + "sha256:bc23fad15d6da82081e89ea0b254a7b6efe6d1c4c58edb16f28e4b4d880086b2" + ], + "version": "==16.0.4" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "version": "==2.18.4" + }, + "send2trash": { + "hashes": [ + "sha256:b308bfafe781617f57b69315f7f0636662405137da667dde3913bf5ff720a3c4", + "sha256:725fbce571dffe0b640e2f1788d52c3c544b510f9d8f69b2597c8c2555bc8441" + ], + "version": "==1.4.2" + }, + "simplegeneric": { + "hashes": [ + "sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173" + ], + "version": "==0.8.1" + }, + "six": { + "hashes": [ + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb", + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9" + ], + "version": "==1.11.0" + }, + "smartypants": { + "hashes": [ + "sha256:8db97f7cbdf08d15b158a86037cd9e116b4cf37703d24e0419a0d64ca5808f0d" + ], + "version": "==2.0.1" + }, + "terminado": { + "hashes": [ + "sha256:65011551baff97f5414c67018e908110693143cfbaeb16831b743fe7cad8b927", + "sha256:55abf9ade563b8f9be1f34e4233c7b7bde726059947a593322e8a553cc4c067a" + ], + "version": "==0.8.1" + }, + "testpath": { + "hashes": [ + "sha256:039fa6a6c9fd3488f8336d23aebbfead5fa602c4a47d49d83845f55a595ec1b4", + "sha256:0d5337839c788da5900df70f8e01015aec141aa3fe7936cb0d0a2953f7ac7609" + ], + "version": "==0.3.1" + }, + "toml": { + "hashes": [ + "sha256:b3953bffe848ad9a6d554114d82f2dcb3e23945e90b4d9addc9956f37f336594" + ], + "version": "==0.9.2" + }, + "tornado": { + "hashes": [ + "sha256:92b7ca81e18ba9ec3031a7ee73d4577ac21d41a0c9b775a9182f43301c3b5f8e", + "sha256:b36298e9f63f18cad97378db2222c0e0ca6a55f6304e605515e05a25483ed51a", + "sha256:ab587996fe6fb9ce65abfda440f9b61e4f9f2cf921967723540679176915e4c3", + "sha256:5ef073ac6180038ccf99411fe05ae9aafb675952a2c8db60592d5daf8401f803", + "sha256:6d14e47eab0e15799cf3cdcc86b0b98279da68522caace2bd7ce644287685f0a" + ], + "version": "==4.5.3" + }, + "traitlets": { + "hashes": [ + "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9", + "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835" + ], + "version": "==4.3.2" + }, + "typogrify": { + "hashes": [ + "sha256:8be4668cda434163ce229d87ca273a11922cb1614cb359970b7dc96eed13cb38" + ], + "version": "==2.0.7" + }, + "unidecode": { + "hashes": [ + "sha256:72f49d3729f3d8f5799f710b97c1451c5163102e76d64d20e170aedbbd923582", + "sha256:8c33dd588e0c9bc22a76eaa0c715a5434851f726131bd44a6c26471746efabf5" + ], + "version": "==1.0.22" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "watchdog": { + "hashes": [ + "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" + ], + "version": "==0.8.3" + }, + "wcwidth": { + "hashes": [ + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c", + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e" + ], + "version": "==0.1.7" + }, + "webassets": { + "hashes": [ + "sha256:e7d9c8887343123fd5b32309b33167428cb1318cdda97ece12d0907fd69d38db" + ], + "version": "==0.12.1" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, + "ws4py": { + "hashes": [ + "sha256:7ac69ce3e6ec6917a5d678b65f0a18e244a4dc670db6414bc0271b3f4911237f" + ], + "version": "==0.4.2" + }, + "yapsy": { + "hashes": [ + "sha256:428d7e3037d5ea02870d5c52d2fb383877621ed7e62e03158ffbda3fca9f6e12", + "sha256:c1968456ed490107371895423b42062308aba11f9ff4619a7653485fdd64cf41", + "sha256:45bb39a72461913388d7f3e92ce33816e84fff59946c45e16796eb1fb1d5f2a6" + ], + "version": "==1.11.223" + } + }, + "develop": {} +} diff --git a/bitblog/conf.py b/bitblog/conf.py new file mode 100644 index 0000000..0f63cde --- /dev/null +++ b/bitblog/conf.py @@ -0,0 +1,1373 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals +import time + +# !! This is the configuration of Nikola. !! # +# !! You should edit it to your liking. !! # + + +# ! Some settings can be different in different languages. +# ! A comment stating (translatable) is used to denote those. +# ! There are two ways to specify a translatable setting: +# ! (a) BLOG_TITLE = "My Blog" +# ! (b) BLOG_TITLE = {"en": "My Blog", "es": "Mi Blog"} +# ! Option (a) is used when you don't want that setting translated. +# ! Option (b) is used for settings that are different in different languages. + + +# Data about this site +BLOG_AUTHOR = "Cooperativa de Trabajo BITSON Ltda." # (translatable) +BLOG_TITLE = "Blog Bitson. Aprendimos de unos. Enseñamos a otros. Apostamos a la cultura colectiva." # (translatable) +# This is the main URL for your site. It will be used +# in a prominent link. Don't forget the protocol (http/https)! +SITE_URL = "http://blog.bitson.group/" +# This is the URL where Nikola's output will be deployed. +# If not set, defaults to SITE_URL +# BASE_URL = "http://blog.bitson.com.ar/" +BLOG_EMAIL = "info@bitson.group" +BLOG_DESCRIPTION = " Blog..." # (translatable) + + +# Nikola is multilingual! +# +# Currently supported languages are: +# +# en English +# ar Arabic +# az Azerbaijani +# bg Bulgarian +# bs Bosnian +# ca Catalan +# cs Czech [ALTERNATIVELY cz] +# da Danish +# de German +# el Greek [NOT gr] +# eo Esperanto +# es Spanish +# et Estonian +# eu Basque +# fa Persian +# fi Finnish +# fr French +# gl Galician +# he Hebrew +# hi Hindi +# hr Croatian +# hu Hungarian +# id Indonesian +# it Italian +# ja Japanese [NOT jp] +# ko Korean +# lt Lithuanian +# nb Norwegian (Bokmål) +# nl Dutch +# pa Punjabi +# pl Polish +# pt Portuguese +# pt_br Portuguese (Brazil) +# ru Russian +# sk Slovak +# sl Slovene +# sq Albanian +# sr Serbian (Cyrillic) +# sr_latin Serbian (Latin) +# sv Swedish +# te Telugu +# tr Turkish [NOT tr_TR] +# uk Ukrainian +# ur Urdu +# zh_cn Chinese (Simplified) +# zh_tw Chinese (Traditional) +# +# If you want to use Nikola with a non-supported language you have to provide +# a module containing the necessary translations +# (cf. the modules at nikola/data/themes/base/messages/). +# If a specific post is not translated to a language, then the version +# in the default language will be shown instead. + +# What is the default language? +DEFAULT_LANG = "es" + +# What other languages do you have? +# The format is {"translationcode" : "path/to/translation" } +# the path will be used as a prefix for the generated pages location +TRANSLATIONS = { + DEFAULT_LANG: "", + # Example for another language: + # "es": "./es", +} + +# What will translated input files be named like? + +# If you have a page something.rst, then something.pl.rst will be considered +# its Polish translation. +# (in the above example: path == "something", ext == "rst", lang == "pl") +# this pattern is also used for metadata: +# something.meta -> something.pl.meta + +TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}" + +# Links for the sidebar / navigation bar. (translatable) +# This is a dict. The keys are languages, and values are tuples. +# +# For regular links: +# ('https://getnikola.com/', 'Nikola Homepage') +# +# For submenus: +# ( +# ( +# ('https://apple.com/', 'Apple'), +# ('https://orange.com/', 'Orange'), +# ), +# 'Fruits' +# ) +# +# WARNING: Support for submenus is theme-dependent. +# Only one level of submenus is supported. +# WARNING: Some themes, including the default Bootstrap 3 theme, +# may present issues if the menu is too large. +# (in bootstrap3, the navbar can grow too large and cover contents.) +# WARNING: If you link to directories, make sure to follow +# ``STRIP_INDEXES``. If it’s set to ``True``, end your links +# with a ``/``, otherwise end them with ``/index.html`` — or +# else they won’t be highlighted when active. + +NAVIGATION_LINKS = { + DEFAULT_LANG: ( + ("/archive.html", "Archivo"), + ("/categories/", "Etiquetas"), + ("/rss.xml", "Canal RSS"), + ), +} + +# Name of the theme to use. +THEME = "bootstrap3" + +# Primary color of your theme. This will be used to customize your theme and +# auto-generate related colors in POSTS_SECTION_COLORS. Must be a HEX value. +THEME_COLOR = '#236ab7' + +# POSTS and PAGES contains (wildcard, destination, template) tuples. +# (translatable) +# +# The wildcard is used to generate a list of source files +# (whatever/thing.rst, for example). +# +# That fragment could have an associated metadata file (whatever/thing.meta), +# and optionally translated files (example for Spanish, with code "es"): +# whatever/thing.es.rst and whatever/thing.es.meta +# +# This assumes you use the default TRANSLATIONS_PATTERN. +# +# From those files, a set of HTML fragment files will be generated: +# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es) +# +# These files are combined with the template to produce rendered +# pages, which will be placed at +# output/TRANSLATIONS[lang]/destination/pagename.html +# +# where "pagename" is the "slug" specified in the metadata file. +# The page might also be placed in /destination/pagename/index.html +# if PRETTY_URLS are enabled. +# +# The difference between POSTS and PAGES is that POSTS are added +# to feeds, indexes, tag lists and archives and are considered part +# of a blog, while PAGES are just independent HTML pages. +# +# Finally, note that destination can be translated, i.e. you can +# specify a different translation folder per language. Example: +# PAGES = ( +# ("pages/*.rst", {"en": "pages", "de": "seiten"}, "page.tmpl"), +# ("pages/*.md", {"en": "pages", "de": "seiten"}, "page.tmpl"), +# ) + +POSTS = ( + ("posts/*.rst", "posts", "post.tmpl"), + ("posts/*.md", "posts", "post.tmpl"), + ("posts/*.txt", "posts", "post.tmpl"), + ("posts/*.html", "posts", "post.tmpl"), +) +PAGES = ( + ("pages/*.rst", "pages", "page.tmpl"), + ("pages/*.md", "pages", "page.tmpl"), + ("pages/*.txt", "pages", "page.tmpl"), + ("pages/*.html", "pages", "page.tmpl"), +) + + +# Below this point, everything is optional + +# Post's dates are considered in UTC by default, if you want to use +# another time zone, please set TIMEZONE to match. Check the available +# list from Wikipedia: +# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +# (e.g. 'Europe/Zurich') +# Also, if you want to use a different time zone in some of your posts, +# you can use the ISO 8601/RFC 3339 format (ex. 2012-03-30T23:00:00+02:00) +TIMEZONE = "America/Argentina/Buenos_Aires" + +# If you want to use ISO 8601 (also valid RFC 3339) throughout Nikola +# (especially in new_post), set this to True. +# Note that this does not affect DATE_FORMAT. +# FORCE_ISO8601 = False + +# Date format used to display post dates. (translatable) +# (str used by datetime.datetime.strftime) +# DATE_FORMAT = '%Y-%m-%d %H:%M' + +# Date format used to display post dates, if local dates are used. (translatable) +# (str used by moment.js) +# JS_DATE_FORMAT = 'YYYY-MM-DD HH:mm' + +# Date fanciness. +# +# 0 = using DATE_FORMAT and TIMEZONE +# 1 = using JS_DATE_FORMAT and local user time (via moment.js) +# 2 = using a string like “2 days ago” +# +# Your theme must support it, bootstrap and bootstrap3 already do. +# DATE_FANCINESS = 0 + +# While Nikola can select a sensible locale for each language, +# sometimes explicit control can come handy. +# In this file we express locales in the string form that +# python's locales will accept in your OS, by example +# "en_US.utf8" in Unix-like OS, "English_United States" in Windows. +# LOCALES = dict mapping language --> explicit locale for the languages +# in TRANSLATIONS. You can omit one or more keys. +# LOCALE_FALLBACK = locale to use when an explicit locale is unavailable +# LOCALE_DEFAULT = locale to use for languages not mentioned in LOCALES; if +# not set the default Nikola mapping is used. + +# LOCALES = {} +# LOCALE_FALLBACK = None +# LOCALE_DEFAULT = None + +# One or more folders containing files to be copied as-is into the output. +# The format is a dictionary of {source: relative destination}. +# Default is: +# FILES_FOLDERS = {'files': ''} +# Which means copy 'files' into 'output' + +# One or more folders containing code listings to be processed and published on +# the site. The format is a dictionary of {source: relative destination}. +# Default is: +# LISTINGS_FOLDERS = {'listings': 'listings'} +# Which means process listings from 'listings' into 'output/listings' + +# A mapping of languages to file-extensions that represent that language. +# Feel free to add or delete extensions to any list, but don't add any new +# compilers unless you write the interface for it yourself. +# +# 'rest' is reStructuredText +# 'markdown' is Markdown +# 'html' assumes the file is HTML and just copies it +COMPILERS = { + "rest": ('.rst', '.txt'), + "markdown": ('.md', '.mdown', '.markdown'), + "textile": ('.textile',), + "txt2tags": ('.t2t',), + "bbcode": ('.bb',), + "wiki": ('.wiki',), + "ipynb": ('.ipynb',), + "html": ('.html', '.htm'), + # PHP files are rendered the usual way (i.e. with the full templates). + # The resulting files have .php extensions, making it possible to run + # them without reconfiguring your server to recognize them. + "php": ('.php',), + # Pandoc detects the input from the source filename + # but is disabled by default as it would conflict + # with many of the others. + # "pandoc": ('.rst', '.md', '.txt'), +} + +# Create by default posts in one file format? +# Set to False for two-file posts, with separate metadata. +# ONE_FILE_POSTS = True + +# Preferred metadata format for new posts +# "Nikola": reST comments wrapped in a comment if needed (default) +# "YAML": YAML wrapped in "---" +# "TOML": TOML wrapped in "+++" +# "Pelican": Native markdown metadata or reST docinfo fields. Nikola style for other formats. +# METADATA_FORMAT = "Nikola" + +# Use date-based path when creating posts? +# Can be enabled on a per-post basis with `nikola new_post -d`. +# The setting is ignored when creating pages (`-d` still works). +# NEW_POST_DATE_PATH = False + +# What format to use when creating posts with date paths? +# Default is '%Y/%m/%d', other possibilities include '%Y' or '%Y/%m'. +# NEW_POST_DATE_PATH_FORMAT = '%Y/%m/%d' + +# If this is set to True, the DEFAULT_LANG version will be displayed for +# untranslated posts. +# If this is set to False, then posts that are not translated to a language +# LANG will not be visible at all in the pages in that language. +# Formerly known as HIDE_UNTRANSLATED_POSTS (inverse) +# SHOW_UNTRANSLATED_POSTS = True + +# Nikola supports logo display. If you have one, you can put the URL here. +# Final output is . +# The URL may be relative to the site root. +# LOGO_URL = '' + +# If you want to hide the title of your website (for example, if your logo +# already contains the text), set this to False. +# SHOW_BLOG_TITLE = True + +# Writes tag cloud data in form of tag_cloud_data.json. +# Warning: this option will change its default value to False in v8! +WRITE_TAG_CLOUD = True + +# Generate pages for each section. The site must have at least two sections +# for this option to take effect. It wouldn't build for just one section. +POSTS_SECTIONS = True + +# Setting this to False generates a list page instead of an index. Indexes +# are the default and will apply GENERATE_ATOM if set. +# POSTS_SECTIONS_ARE_INDEXES = True + +# Final locations are: +# output / TRANSLATION[lang] / SECTION_PATH / SECTION_NAME / index.html (list of posts for a section) +# output / TRANSLATION[lang] / SECTION_PATH / SECTION_NAME / rss.xml (RSS feed for a section) +# (translatable) +# SECTION_PATH = "" + +# Each post and section page will have an associated color that can be used +# to style them with a recognizable color detail across your site. A color +# is assigned to each section based on shifting the hue of your THEME_COLOR +# at least 7.5 % while leaving the lightness and saturation untouched in the +# HUSL colorspace. You can overwrite colors by assigning them colors in HEX. +# POSTS_SECTION_COLORS = { +# DEFAULT_LANG: { +# 'posts': '#49b11bf', +# 'reviews': '#ffe200', +# }, +# } + +# Associate a description with a section. For use in meta description on +# section index pages or elsewhere in themes. +# POSTS_SECTION_DESCRIPTIONS = { +# DEFAULT_LANG: { +# 'how-to': 'Learn how-to things properly with these amazing tutorials.', +# }, +# } + +# Sections are determined by their output directory as set in POSTS by default, +# but can alternatively be determined from file metadata instead. +# POSTS_SECTION_FROM_META = False + +# Names are determined from the output directory name automatically or the +# metadata label. Unless overwritten below, names will use title cased and +# hyphens replaced by spaces. +# POSTS_SECTION_NAME = { +# DEFAULT_LANG: { +# 'posts': 'Blog Posts', +# 'uncategorized': 'Odds and Ends', +# }, +# } + +# Titles for per-section index pages. Can be either one string where "{name}" +# is substituted or the POSTS_SECTION_NAME, or a dict of sections. Note +# that the INDEX_PAGES option is also applied to section page titles. +# POSTS_SECTION_TITLE = { +# DEFAULT_LANG: { +# 'how-to': 'How-to and Tutorials', +# }, +# } + +# A list of dictionaries specifying sections which translate to each other. +# For example: +# [ +# {'en': 'private', 'de': 'Privat'}, +# {'en': 'work', 'fr': 'travail', 'de': 'Arbeit'}, +# ] +# POSTS_SECTION_TRANSLATIONS = [] + +# If set to True, a section in a language will be treated as a translation +# of the literally same section in all other languages. Enable this if you +# do not translate sections, for example. +# POSTS_SECTION_TRANSLATIONS_ADD_DEFAULTS = True + +# Paths for different autogenerated bits. These are combined with the +# translation paths. + +# Final locations are: +# output / TRANSLATION[lang] / TAG_PATH / index.html (list of tags) +# output / TRANSLATION[lang] / TAG_PATH / tag.html (list of posts for a tag) +# output / TRANSLATION[lang] / TAG_PATH / tag.xml (RSS feed for a tag) +# (translatable) +# TAG_PATH = "categories" + +# By default, the list of tags is stored in +# output / TRANSLATION[lang] / TAG_PATH / index.html +# (see explanation for TAG_PATH). This location can be changed to +# output / TRANSLATION[lang] / TAGS_INDEX_PATH +# with an arbitrary relative path TAGS_INDEX_PATH. +# (translatable) +# TAGS_INDEX_PATH = "tags.html" + +# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain +# the posts themselves. If set to False, it will be just a list of links. +# TAG_PAGES_ARE_INDEXES = False + +# Set descriptions for tag pages to make them more interesting. The +# default is no description. The value is used in the meta description +# and displayed underneath the tag list or index page’s title. +# TAG_PAGES_DESCRIPTIONS = { +# DEFAULT_LANG: { +# "blogging": "Meta-blog posts about blogging about blogging.", +# "open source": "My contributions to my many, varied, ever-changing, and eternal libre software projects." +# }, +# } + +# Set special titles for tag pages. The default is "Posts about TAG". +# TAG_PAGES_TITLES = { +# DEFAULT_LANG: { +# "blogging": "Meta-posts about blogging", +# "open source": "Posts about open source software" +# }, +# } + +# If you do not want to display a tag publicly, you can mark it as hidden. +# The tag will not be displayed on the tag list page, the tag cloud and posts. +# Tag pages will still be generated. +HIDDEN_TAGS = ['mathjax'] + +# Only include tags on the tag list/overview page if there are at least +# TAGLIST_MINIMUM_POSTS number of posts or more with every tag. Every tag +# page is still generated, linked from posts, and included in the sitemap. +# However, more obscure tags can be hidden from the tag index page. +# TAGLIST_MINIMUM_POSTS = 1 + +# A list of dictionaries specifying tags which translate to each other. +# Format: a list of dicts {language: translation, language2: translation2, …} +# See POSTS_SECTION_TRANSLATIONS example above. +# TAG_TRANSLATIONS = [] + +# If set to True, a tag in a language will be treated as a translation +# of the literally same tag in all other languages. Enable this if you +# do not translate tags, for example. +# TAG_TRANSLATIONS_ADD_DEFAULTS = True + +# Final locations are: +# output / TRANSLATION[lang] / CATEGORY_PATH / index.html (list of categories) +# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.html (list of posts for a category) +# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.xml (RSS feed for a category) +# (translatable) +# CATEGORY_PATH = "categories" +# CATEGORY_PREFIX = "cat_" + +# By default, the list of categories is stored in +# output / TRANSLATION[lang] / CATEGORY_PATH / index.html +# (see explanation for CATEGORY_PATH). This location can be changed to +# output / TRANSLATION[lang] / CATEGORIES_INDEX_PATH +# with an arbitrary relative path CATEGORIES_INDEX_PATH. +# (translatable) +# CATEGORIES_INDEX_PATH = "categories.html" + +# If CATEGORY_ALLOW_HIERARCHIES is set to True, categories can be organized in +# hierarchies. For a post, the whole path in the hierarchy must be specified, +# using a forward slash ('/') to separate paths. Use a backslash ('\') to escape +# a forward slash or a backslash (i.e. '\//\\' is a path specifying the +# subcategory called '\' of the top-level category called '/'). +CATEGORY_ALLOW_HIERARCHIES = False +# If CATEGORY_OUTPUT_FLAT_HIERARCHY is set to True, the output written to output +# contains only the name of the leaf category and not the whole path. +CATEGORY_OUTPUT_FLAT_HIERARCHY = False + +# If CATEGORY_PAGES_ARE_INDEXES is set to True, each category's page will contain +# the posts themselves. If set to False, it will be just a list of links. +# CATEGORY_PAGES_ARE_INDEXES = False + +# Set descriptions for category pages to make them more interesting. The +# default is no description. The value is used in the meta description +# and displayed underneath the category list or index page’s title. +# CATEGORY_PAGES_DESCRIPTIONS = { +# DEFAULT_LANG: { +# "blogging": "Meta-blog posts about blogging about blogging.", +# "open source": "My contributions to my many, varied, ever-changing, and eternal libre software projects." +# }, +# } + +# Set special titles for category pages. The default is "Posts about CATEGORY". +# CATEGORY_PAGES_TITLES = { +# DEFAULT_LANG: { +# "blogging": "Meta-posts about blogging", +# "open source": "Posts about open source software" +# }, +# } + +# If you do not want to display a category publicly, you can mark it as hidden. +# The category will not be displayed on the category list page. +# Category pages will still be generated. +HIDDEN_CATEGORIES = [] + +# A list of dictionaries specifying categories which translate to each other. +# Format: a list of dicts {language: translation, language2: translation2, …} +# See POSTS_SECTION_TRANSLATIONS example above. +# CATEGORY_TRANSLATIONS = [] + +# If set to True, a category in a language will be treated as a translation +# of the literally same category in all other languages. Enable this if you +# do not translate categories, for example. +# CATEGORY_TRANSLATIONS_ADD_DEFAULTS = True + +# If ENABLE_AUTHOR_PAGES is set to True and there is more than one +# author, author pages are generated. +# ENABLE_AUTHOR_PAGES = True + +# Path to author pages. Final locations are: +# output / TRANSLATION[lang] / AUTHOR_PATH / index.html (list of authors) +# output / TRANSLATION[lang] / AUTHOR_PATH / author.html (list of posts by an author) +# output / TRANSLATION[lang] / AUTHOR_PATH / author.xml (RSS feed for an author) +# (translatable) +# AUTHOR_PATH = "authors" + +# If AUTHOR_PAGES_ARE_INDEXES is set to True, each author's page will contain +# the posts themselves. If set to False, it will be just a list of links. +# AUTHOR_PAGES_ARE_INDEXES = False + +# Set descriptions for author pages to make them more interesting. The +# default is no description. The value is used in the meta description +# and displayed underneath the author list or index page’s title. +# AUTHOR_PAGES_DESCRIPTIONS = { +# DEFAULT_LANG: { +# "Juanjo Conti": "Python coder and writer.", +# "Roberto Alsina": "Nikola father." +# }, +# } + + +# If you do not want to display an author publicly, you can mark it as hidden. +# The author will not be displayed on the author list page and posts. +# Tag pages will still be generated. +HIDDEN_AUTHORS = ['Guest'] + +# Final location for the main blog page and sibling paginated pages is +# output / TRANSLATION[lang] / INDEX_PATH / index-*.html +# (translatable) +# INDEX_PATH = "" + +# Optional HTML that displayed on “main” blog index.html files. +# May be used for a greeting. (translatable) +FRONT_INDEX_HEADER = { + DEFAULT_LANG: '' +} + +# Create per-month archives instead of per-year +# CREATE_MONTHLY_ARCHIVE = False +# Create one large archive instead of per-year +# CREATE_SINGLE_ARCHIVE = False +# Create year, month, and day archives each with a (long) list of posts +# (overrides both CREATE_MONTHLY_ARCHIVE and CREATE_SINGLE_ARCHIVE) +# CREATE_FULL_ARCHIVES = False +# If monthly archives or full archives are created, adds also one archive per day +# CREATE_DAILY_ARCHIVE = False +# Create previous, up, next navigation links for archives +# CREATE_ARCHIVE_NAVIGATION = False +# Final locations for the archives are: +# output / TRANSLATION[lang] / ARCHIVE_PATH / ARCHIVE_FILENAME +# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / index.html +# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / MONTH / index.html +# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / MONTH / DAY / index.html +# ARCHIVE_PATH = "" +# ARCHIVE_FILENAME = "archive.html" + +# If ARCHIVES_ARE_INDEXES is set to True, each archive page which contains a list +# of posts will contain the posts themselves. If set to False, it will be just a +# list of links. +# ARCHIVES_ARE_INDEXES = False + +# URLs to other posts/pages can take 3 forms: +# rel_path: a relative URL to the current page/post (default) +# full_path: a URL with the full path from the root +# absolute: a complete URL (that includes the SITE_URL) +# URL_TYPE = 'rel_path' + +# If USE_BASE_TAG is True, then all HTML files will include +# something like to help +# the browser resolve relative links. +# Most people don’t need this tag; major websites don’t use it. Use +# only if you know what you’re doing. If this is True, your website +# will not be fully usable by manually opening .html files in your web +# browser (`nikola serve` or `nikola auto` is mandatory). Also, if you +# have mirrors of your site, they will point to SITE_URL everywhere. +USE_BASE_TAG = False + +# Final location for the blog main RSS feed is: +# output / TRANSLATION[lang] / RSS_PATH / rss.xml +# (translatable) +# RSS_PATH = "" + +# Slug the Tag URL. Easier for users to type, special characters are +# often removed or replaced as well. +# SLUG_TAG_PATH = True + +# Slug the Author URL. Easier for users to type, special characters are +# often removed or replaced as well. +# SLUG_AUTHOR_PATH = True + +# A list of redirection tuples, [("foo/from.html", "/bar/to.html")]. +# +# A HTML file will be created in output/foo/from.html that redirects +# to the "/bar/to.html" URL. notice that the "from" side MUST be a +# relative URL. +# +# If you don't need any of these, just set to [] +REDIRECTIONS = [] + +# Presets of commands to execute to deploy. Can be anything, for +# example, you may use rsync: +# "rsync -rav --delete output/ joe@my.site:/srv/www/site" +# And then do a backup, or run `nikola ping` from the `ping` +# plugin (`nikola plugin -i ping`). Or run `nikola check -l`. +# You may also want to use github_deploy (see below). +# You can define multiple presets and specify them as arguments +# to `nikola deploy`. If no arguments are specified, a preset +# named `default` will be executed. You can use as many presets +# in a `nikola deploy` command as you like. +# DEPLOY_COMMANDS = { +# 'default': [ +# "rsync -rav --delete output/ joe@my.site:/srv/www/site", +# ] +# } + +# github_deploy configuration +# For more details, read the manual: +# https://getnikola.com/handbook.html#deploying-to-github +# You will need to configure the deployment branch on GitHub. +GITHUB_SOURCE_BRANCH = 'src' +GITHUB_DEPLOY_BRANCH = 'master' + +# The name of the remote where you wish to push to, using github_deploy. +GITHUB_REMOTE_NAME = 'origin' + +# Whether or not github_deploy should commit to the source branch automatically +# before deploying. +GITHUB_COMMIT_SOURCE = True + +# Where the output site should be located +# If you don't use an absolute path, it will be considered as relative +# to the location of conf.py +# OUTPUT_FOLDER = 'output' + +# where the "cache" of partial generated content should be located +# default: 'cache' +# CACHE_FOLDER = 'cache' + +# Filters to apply to the output. +# A directory where the keys are either: a file extensions, or +# a tuple of file extensions. +# +# And the value is a list of commands to be applied in order. +# +# Each command must be either: +# +# A string containing a '%s' which will +# be replaced with a filename. The command *must* produce output +# in place. +# +# Or: +# +# A python callable, which will be called with the filename as +# argument. +# +# By default, only .php files uses filters to inject PHP into +# Nikola’s templates. All other filters must be enabled through FILTERS. +# +# Many filters are shipped with Nikola. A list is available in the manual: +# +# +# from nikola import filters +# FILTERS = { +# ".html": [filters.typogrify], +# ".js": [filters.closure_compiler], +# ".jpg": ["jpegoptim --strip-all -m75 -v %s"], +# } + +# Executable for the "yui_compressor" filter (defaults to 'yui-compressor'). +# YUI_COMPRESSOR_EXECUTABLE = 'yui-compressor' + +# Executable for the "closure_compiler" filter (defaults to 'closure-compiler'). +# CLOSURE_COMPILER_EXECUTABLE = 'closure-compiler' + +# Executable for the "optipng" filter (defaults to 'optipng'). +# OPTIPNG_EXECUTABLE = 'optipng' + +# Executable for the "jpegoptim" filter (defaults to 'jpegoptim'). +# JPEGOPTIM_EXECUTABLE = 'jpegoptim' + +# Executable for the "html_tidy_withconfig", "html_tidy_nowrap", +# "html_tidy_wrap", "html_tidy_wrap_attr" and "html_tidy_mini" filters +# (defaults to 'tidy5'). +# HTML_TIDY_EXECUTABLE = 'tidy5' + +# List of XPath expressions which should be used for finding headers +# ({hx} is replaced by headers h1 through h6). +# You must change this if you use a custom theme that does not use +# "e-content entry-content" as a class for post and page contents. +# HEADER_PERMALINKS_XPATH_LIST = ['*//div[@class="e-content entry-content"]//{hx}'] +# Include *every* header (not recommended): +# HEADER_PERMALINKS_XPATH_LIST = ['*//{hx}'] + +# File blacklist for header permalinks. Contains output path +# (eg. 'output/index.html') +# HEADER_PERMALINKS_FILE_BLACKLIST = [] + +# Expert setting! Create a gzipped copy of each generated file. Cheap server- +# side optimization for very high traffic sites or low memory servers. +# GZIP_FILES = False +# File extensions that will be compressed +# GZIP_EXTENSIONS = ('.txt', '.htm', '.html', '.css', '.js', '.json', '.atom', '.xml') +# Use an external gzip command? None means no. +# Example: GZIP_COMMAND = "pigz -k {filename}" +# GZIP_COMMAND = None +# Make sure the server does not return a "Accept-Ranges: bytes" header for +# files compressed by this option! OR make sure that a ranged request does not +# return partial content of another representation for these resources. Do not +# use this feature if you do not understand what this means. + +# Compiler to process LESS files. +# LESS_COMPILER = 'lessc' + +# A list of options to pass to the LESS compiler. +# Final command is: LESS_COMPILER LESS_OPTIONS file.less +# LESS_OPTIONS = [] + +# Compiler to process Sass files. +# SASS_COMPILER = 'sass' + +# A list of options to pass to the Sass compiler. +# Final command is: SASS_COMPILER SASS_OPTIONS file.s(a|c)ss +# SASS_OPTIONS = [] + +# ############################################################################# +# Image Gallery Options +# ############################################################################# + +# One or more folders containing galleries. The format is a dictionary of +# {"source": "relative_destination"}, where galleries are looked for in +# "source/" and the results will be located in +# "OUTPUT_PATH/relative_destination/gallery_name" +# Default is: +# GALLERY_FOLDERS = {"galleries": "galleries"} +# More gallery options: +# THUMBNAIL_SIZE = 180 +# MAX_IMAGE_SIZE = 1280 +# USE_FILENAME_AS_TITLE = True +# EXTRA_IMAGE_EXTENSIONS = [] +# +# If set to False, it will sort by filename instead. Defaults to True +# GALLERY_SORT_BY_DATE = True + +# If set to True, EXIF data will be copied when an image is thumbnailed or +# resized. (See also EXIF_WHITELIST) +# PRESERVE_EXIF_DATA = False + +# If you have enabled PRESERVE_EXIF_DATA, this option lets you choose EXIF +# fields you want to keep in images. (See also PRESERVE_EXIF_DATA) +# +# For a full list of field names, please see here: +# http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf +# +# This is a dictionary of lists. Each key in the dictionary is the +# name of a IDF, and each list item is a field you want to preserve. +# If you have a IDF with only a '*' item, *EVERY* item in it will be +# preserved. If you don't want to preserve anything in a IDF, remove it +# from the setting. By default, no EXIF information is kept. +# Setting the whitelist to anything other than {} implies +# PRESERVE_EXIF_DATA is set to True +# To preserve ALL EXIF data, set EXIF_WHITELIST to {"*": "*"} + +# EXIF_WHITELIST = {} + +# Some examples of EXIF_WHITELIST settings: + +# Basic image information: +# EXIF_WHITELIST['0th'] = [ +# "Orientation", +# "XResolution", +# "YResolution", +# ] + +# If you want to keep GPS data in the images: +# EXIF_WHITELIST['GPS'] = ["*"] + +# Embedded thumbnail information: +# EXIF_WHITELIST['1st'] = ["*"] + +# Folders containing images to be used in normal posts or pages. +# IMAGE_FOLDERS is a dictionary of the form {"source": "destination"}, +# where "source" is the folder containing the images to be published, and +# "destination" is the folder under OUTPUT_PATH containing the images copied +# to the site. Thumbnail images will be created there as well. + +# To reference the images in your posts, include a leading slash in the path. +# For example, if IMAGE_FOLDERS = {'images': 'images'}, write +# +# .. image:: /images/tesla.jpg +# +# See the Nikola Handbook for details (in the “Embedding Images” and +# “Thumbnails” sections) + +# Images will be scaled down according to IMAGE_THUMBNAIL_SIZE and MAX_IMAGE_SIZE +# options, but will have to be referenced manually to be visible on the site +# (the thumbnail has ``.thumbnail`` added before the file extension by default, +# but a different naming template can be configured with IMAGE_THUMBNAIL_FORMAT). + +IMAGE_FOLDERS = {'images': 'images'} +# IMAGE_THUMBNAIL_SIZE = 400 +# IMAGE_THUMBNAIL_FORMAT = '{name}.thumbnail{ext}' + +# ############################################################################# +# HTML fragments and diverse things that are used by the templates +# ############################################################################# + +# Data about post-per-page indexes. +# INDEXES_PAGES defaults to ' old posts, page %d' or ' page %d' (translated), +# depending on the value of INDEXES_PAGES_MAIN. +# +# (translatable) If the following is empty, defaults to BLOG_TITLE: +# INDEXES_TITLE = "" +# +# (translatable) If the following is empty, defaults to ' [old posts,] page %d' (see above): +# INDEXES_PAGES = "" +# +# If the following is True, INDEXES_PAGES is also displayed on the main (the +# newest) index page (index.html): +# INDEXES_PAGES_MAIN = False +# +# If the following is True, index-1.html has the oldest posts, index-2.html the +# second-oldest posts, etc., and index.html has the newest posts. This ensures +# that all posts on index-x.html will forever stay on that page, now matter how +# many new posts are added. +# If False, index-1.html has the second-newest posts, index-2.html the third-newest, +# and index-n.html the oldest posts. When this is active, old posts can be moved +# to other index pages when new posts are added. +# INDEXES_STATIC = True +# +# (translatable) If PRETTY_URLS is set to True, this setting will be used to create +# prettier URLs for index pages, such as page/2/index.html instead of index-2.html. +# Valid values for this settings are: +# * False, +# * a list or tuple, specifying the path to be generated, +# * a dictionary mapping languages to lists or tuples. +# Every list or tuple must consist of strings which are used to combine the path; +# for example: +# ['page', '{number}', '{index_file}'] +# The replacements +# {number} --> (logical) page number; +# {old_number} --> the page number inserted into index-n.html before (zero for +# the main page); +# {index_file} --> value of option INDEX_FILE +# are made. +# Note that in case INDEXES_PAGES_MAIN is set to True, a redirection will be created +# for the full URL with the page number of the main page to the normal (shorter) main +# page URL. +# INDEXES_PRETTY_PAGE_URL = False +# +# If the following is true, a page range navigation will be inserted to indices. +# Please note that this will undo the effect of INDEXES_STATIC, as all index pages +# must be recreated whenever the number of pages changes. +# SHOW_INDEX_PAGE_NAVIGATION = False + +# If the following is True, a meta name="generator" tag is added to pages. The +# generator tag is used to specify the software used to generate the page +# (it promotes Nikola). +# META_GENERATOR_TAG = True + +# Color scheme to be used for code blocks. If your theme provides +# "assets/css/code.css" this is ignored. Leave empty to disable. +# Can be any of: +# algol, algol_nu, autumn, borland, bw, colorful, default, emacs, friendly, +# fruity, igor, lovelace, manni, monokai, murphy, native, paraiso-dark, +# paraiso-light, pastie, perldoc, rrt, tango, trac, vim, vs, xcode +# This list MAY be incomplete since pygments adds styles every now and then. +# Check with list(pygments.styles.get_all_styles()) in an interpreter. +# CODE_COLOR_SCHEME = 'default' + +# FAVICONS contains (name, file, size) tuples. +# Used to create favicon link like this: +# +# FAVICONS = ( +# ("icon", "/favicon.ico", "16x16"), +# ("icon", "/icon_128x128.png", "128x128"), +# ) + +# Show teasers (instead of full posts) in indexes? Defaults to False. +INDEX_TEASERS = True + +# HTML fragments with the Read more... links. +# The following tags exist and are replaced for you: +# {link} A link to the full post page. +# {read_more} The string “Read more” in the current language. +# {reading_time} An estimate of how long it will take to read the post. +# {remaining_reading_time} An estimate of how long it will take to read the post, sans the teaser. +# {min_remaining_read} The string “{remaining_reading_time} min remaining to read” in the current language. +# {paragraph_count} The amount of paragraphs in the post. +# {remaining_paragraph_count} The amount of paragraphs in the post, sans the teaser. +# {post_title} The title of the post. +# {{ A literal { (U+007B LEFT CURLY BRACKET) +# }} A literal } (U+007D RIGHT CURLY BRACKET) + +# 'Read more...' for the index page, if INDEX_TEASERS is True (translatable) +INDEX_READ_MORE_LINK = '

{read_more}…

' +# 'Read more...' for the feeds, if FEED_TEASERS is True (translatable) +FEED_READ_MORE_LINK = '

{read_more}… ({min_remaining_read})

' + +# Append a URL query to the FEED_READ_MORE_LINK in Atom and RSS feeds. Advanced +# option used for traffic source tracking. +# Minimum example for use with Piwik: "pk_campaign=feed" +# The following tags exist and are replaced for you: +# {feedRelUri} A relative link to the feed. +# {feedFormat} The name of the syndication format. +# Example using replacement for use with Google Analytics: +# "utm_source={feedRelUri}&utm_medium=nikola_feed&utm_campaign={feedFormat}_feed" +FEED_LINKS_APPEND_QUERY = False + +# A HTML fragment describing the license, for the sidebar. +# (translatable) +LICENSE = "" +# I recommend using the Creative Commons' wizard: +# https://creativecommons.org/choose/ +# LICENSE = """ +# +# Creative Commons License BY-NC-SA""" + +# A small copyright notice for the page footer (in HTML). +# (translatable) +CONTENT_FOOTER = 'Contents © {date} {author} - Powered by Nikola {license}' + +# Things that will be passed to CONTENT_FOOTER.format(). This is done +# for translatability, as dicts are not formattable. Nikola will +# intelligently format the setting properly. +# The setting takes a dict. The keys are languages. The values are +# tuples of tuples of positional arguments and dicts of keyword arguments +# to format(). For example, {'en': (('Hello'), {'target': 'World'})} +# results in CONTENT_FOOTER['en'].format('Hello', target='World'). +# If you need to use the literal braces '{' and '}' in your footer text, use +# '{{' and '}}' to escape them (str.format is used) +# WARNING: If you do not use multiple languages with CONTENT_FOOTER, this +# still needs to be a dict of this format. (it can be empty if you +# do not need formatting) +# (translatable) +CONTENT_FOOTER_FORMATS = { + DEFAULT_LANG: ( + (), + { + "email": BLOG_EMAIL, + "author": BLOG_AUTHOR, + "date": time.gmtime().tm_year, + "license": LICENSE + } + ) +} + +# A simple copyright tag for inclusion in RSS feeds that works just +# like CONTENT_FOOTER and CONTENT_FOOTER_FORMATS +RSS_COPYRIGHT = 'Contents © {date} {author} {license}' +RSS_COPYRIGHT_PLAIN = 'Contents © {date} {author} {license}' +RSS_COPYRIGHT_FORMATS = CONTENT_FOOTER_FORMATS + +# To use comments, you can choose between different third party comment +# systems. The following comment systems are supported by Nikola: +# disqus, facebook, googleplus, intensedebate, isso, livefyre, muut +# You can leave this option blank to disable comments. +COMMENT_SYSTEM = "disqus" +# And you also need to add your COMMENT_SYSTEM_ID which +# depends on what comment system you use. The default is +# "nikolademo" which is a test account for Disqus. More information +# is in the manual. +COMMENT_SYSTEM_ID = "blog-bitson" + +# Enable annotations using annotateit.org? +# If set to False, you can still enable them for individual posts and pages +# setting the "annotations" metadata. +# If set to True, you can disable them for individual posts and pages using +# the "noannotations" metadata. +# ANNOTATIONS = False + +# Create index.html for page folders? +# WARNING: if a page would conflict with the index file (usually +# caused by setting slug to `index`), the PAGE_INDEX +# will not be generated for that directory. +# PAGE_INDEX = False +# Enable comments on pages (i.e. not posts)? +# COMMENTS_IN_PAGES = False +# Enable comments on picture gallery pages? +# COMMENTS_IN_GALLERIES = False + +# What file should be used for directory indexes? +# Defaults to index.html +# Common other alternatives: default.html for IIS, index.php +# INDEX_FILE = "index.html" + +# If a link ends in /index.html, drop the index.html part. +# http://mysite/foo/bar/index.html => http://mysite/foo/bar/ +# (Uses the INDEX_FILE setting, so if that is, say, default.html, +# it will instead /foo/default.html => /foo) +# (Note: This was briefly STRIP_INDEX_HTML in v 5.4.3 and 5.4.4) +STRIP_INDEXES = True + +# Should the sitemap list directories which only include other directories +# and no files. +# Default to True +# If this is False +# e.g. /2012 includes only /01, /02, /03, /04, ...: don't add it to the sitemap +# if /2012 includes any files (including index.html)... add it to the sitemap +# SITEMAP_INCLUDE_FILELESS_DIRS = True + +# List of files relative to the server root (!) that will be asked to be excluded +# from indexing and other robotic spidering. * is supported. Will only be effective +# if SITE_URL points to server root. The list is used to exclude resources from +# /robots.txt and /sitemap.xml, and to inform search engines about /sitemapindex.xml. +# ROBOTS_EXCLUSIONS = ["/archive.html", "/category/*.html"] + +# Instead of putting files in .html, put them in /index.html. +# No web server configuration is required. Also enables STRIP_INDEXES. +# This can be disabled on a per-page/post basis by adding +# .. pretty_url: False +# to the metadata. +PRETTY_URLS = True + +# If True, publish future dated posts right away instead of scheduling them. +# Defaults to False. +# FUTURE_IS_NOW = False + +# If True, future dated posts are allowed in deployed output +# Only the individual posts are published/deployed; not in indexes/sitemap +# Generally, you want FUTURE_IS_NOW and DEPLOY_FUTURE to be the same value. +# DEPLOY_FUTURE = False +# If False, draft posts will not be deployed +# DEPLOY_DRAFTS = True + +# Allows scheduling of posts using the rule specified here (new_post -s) +# Specify an iCal Recurrence Rule: http://www.kanzaki.com/docs/ical/rrule.html +# SCHEDULE_RULE = '' +# If True, use the scheduling rule to all posts by default +# SCHEDULE_ALL = False + +# Do you want a add a Mathjax config file? +# MATHJAX_CONFIG = "" + +# If you want support for the $.$ syntax (which may conflict with running +# text!), just use this config: +# MATHJAX_CONFIG = """ +# +# """ + +# Want to use KaTeX instead of MathJax? While KaTeX may not support every +# feature yet, it's faster and the output looks better. +# USE_KATEX = False + +# KaTeX auto-render settings. If you want support for the $.$ syntax (wihch may +# conflict with running text!), just use this config: +# KATEX_AUTO_RENDER = """ +# delimiters: [ +# {left: "$$", right: "$$", display: true}, +# {left: "\\\[", right: "\\\]", display: true}, +# {left: "$", right: "$", display: false}, +# {left: "\\\(", right: "\\\)", display: false} +# ] +# """ + +# Do you want to customize the nbconversion of your IPython notebook? +# IPYNB_CONFIG = {} +# With the following example configuration you can use a custom jinja template +# called `toggle.tpl` which has to be located in your site/blog main folder: +# IPYNB_CONFIG = {'Exporter':{'template_file': 'toggle'}} + +# What Markdown extensions to enable? +# You will also get gist, nikola and podcast because those are +# done in the code, hope you don't mind ;-) +# Note: most Nikola-specific extensions are done via the Nikola plugin system, +# with the MarkdownExtension class and should not be added here. +# The default is ['fenced_code', 'codehilite'] +MARKDOWN_EXTENSIONS = ['markdown.extensions.fenced_code', 'markdown.extensions.codehilite', 'markdown.extensions.extra'] + +# Extra options to pass to the pandoc command. +# by default, it's empty, is a list of strings, for example +# ['-F', 'pandoc-citeproc', '--bibliography=/Users/foo/references.bib'] +# Pandoc does not demote headers by default. To enable this, you can use, for example +# ['--base-header-level=2'] +# PANDOC_OPTIONS = [] + +# Social buttons. This is sample code for AddThis (which was the default for a +# long time). Insert anything you want here, or even make it empty (which is +# the default right now) +# (translatable) +# SOCIAL_BUTTONS_CODE = """ +# +#
+# Share +#
  • +#
  • +#
  • +#
  • +#
+#
+# +# +# """ + +# Show link to source for the posts? +# Formerly known as HIDE_SOURCELINK (inverse) +# SHOW_SOURCELINK = True +# Copy the source files for your pages? +# Setting it to False implies SHOW_SOURCELINK = False +# COPY_SOURCES = True + +# Modify the number of Post per Index Page +# Defaults to 10 +# INDEX_DISPLAY_POST_COUNT = 10 + +# By default, Nikola generates RSS files for the website and for tags, and +# links to it. Set this to False to disable everything RSS-related. +# GENERATE_RSS = True + +# By default, Nikola does not generates Atom files for indexes and links to +# them. Generate Atom for tags by setting TAG_PAGES_ARE_INDEXES to True. +# Atom feeds are built based on INDEX_DISPLAY_POST_COUNT and not FEED_LENGTH +# Switch between plain-text summaries and full HTML content using the +# FEED_TEASER option. FEED_LINKS_APPEND_QUERY is also respected. Atom feeds +# are generated even for old indexes and have pagination link relations +# between each other. Old Atom feeds with no changes are marked as archived. +# GENERATE_ATOM = False + +# Only include teasers in Atom and RSS feeds. Disabling include the full +# content. Defaults to True. +# FEED_TEASERS = True + +# Strip HTML from Atom and RSS feed summaries and content. Defaults to False. +# FEED_PLAIN = False + +# Number of posts in Atom and RSS feeds. +# FEED_LENGTH = 10 + +# Include preview image as a
at the top of the entry. +# Requires FEED_PLAIN = False. If the preview image is found in the content, +# it will not be included again. Image will be included as-is, aim to optmize +# the image source for Feedly, Apple News, Flipboard, and other popular clients. +# FEED_PREVIEWIMAGE = True + +# RSS_LINK is a HTML fragment to link the RSS or Atom feeds. If set to None, +# the base.tmpl will use the feed Nikola generates. However, you may want to +# change it for a FeedBurner feed or something else. +# RSS_LINK = None + +# A search form to search this site, for the sidebar. You can use a Google +# custom search (https://www.google.com/cse/) +# Or a DuckDuckGo search: https://duckduckgo.com/search_box.html +# Default is no search form. +# (translatable) +# SEARCH_FORM = "" +# +# This search form works for any site and looks good in the "site" theme where +# it appears on the navigation bar: +# +# SEARCH_FORM = """ +# +# +# +# """ % SITE_URL +# +# If you prefer a Google search form, here's an example that should just work: +# SEARCH_FORM = """ +# +# +# +# """ % SITE_URL + +# Use content distribution networks for jQuery, twitter-bootstrap css and js, +# and html5shiv (for older versions of Internet Explorer) +# If this is True, jQuery and html5shiv are served from the Google CDN and +# Bootstrap is served from BootstrapCDN (provided by MaxCDN) +# Set this to False if you want to host your site without requiring access to +# external resources. +# USE_CDN = False + +# Check for USE_CDN compatibility. +# If you are using custom themes, have configured the CSS properly and are +# receiving warnings about incompatibility but believe they are incorrect, you +# can set this to False. +# USE_CDN_WARNING = True + +# Extra things you want in the pages HEAD tag. This will be added right +# before +# (translatable) +# EXTRA_HEAD_DATA = "" +# Google Analytics or whatever else you use. Added to the bottom of +# in the default template (base.tmpl). +# (translatable) +# BODY_END = "" + +# The possibility to extract metadata from the filename by using a +# regular expression. +# To make it work you need to name parts of your regular expression. +# The following names will be used to extract metadata: +# - title +# - slug +# - date +# - tags +# - link +# - description +# +# An example re is the following: +# '.*\/(?P\d{4}-\d{2}-\d{2})-(?P.*)-(?P.*)\.rst' +# (Note the '.*\/' in the beginning -- matches source paths relative to conf.py) +# FILE_METADATA_REGEXP = None + +# If enabled, extract metadata from docinfo fields in reST documents +# USE_REST_DOCINFO_METADATA = False + +# If enabled, hide docinfo fields in reST document output +# HIDE_REST_DOCINFO = False + +# Map metadata from other formats to Nikola names. +# Supported formats: yaml, toml, rest_docinfo, markdown_metadata +# METADATA_MAPPING = {} +# +# Example for Pelican compatibility: +# METADATA_MAPPING = { +# "rest_docinfo": {"summary": "description", "modified": "updated"}, +# "markdown_metadata": {"summary": "description", "modified": "updated"} +# } +# Other examples: https://getnikola.com/handbook.html#mapping-metadata-from-other-formats + +# If you hate "Filenames with Capital Letters and Spaces.md", you should +# set this to true. +UNSLUGIFY_TITLES = True + +# Additional metadata that is added to a post when creating a new_post +# ADDITIONAL_METADATA = {} + +# Nikola supports Open Graph Protocol data for enhancing link sharing and +# discoverability of your site on Facebook, Google+, and other services. +# Open Graph is enabled by default. +# USE_OPEN_GRAPH = True + +# Nikola supports Twitter Card summaries, but they are disabled by default. +# They make it possible for you to attach media to Tweets that link +# to your content. +# +# IMPORTANT: +# Please note, that you need to opt-in for using Twitter Cards! +# To do this please visit https://cards-dev.twitter.com/validator +# +# Uncomment and modify to following lines to match your accounts. +# Images displayed come from the `previewimage` meta tag. +# You can specify the card type by using the `card` parameter in TWITTER_CARD. +# TWITTER_CARD = { +# 'use_twitter_cards': True, # enable Twitter Cards / Open Graph +# 'site': '@bitsonArgentina', # twitter nick for the website +# 'site:id':422000229 , # Same as site, but the website's Twitter user ID instead. +# 'creator': '@bitsonArgentina', # Username for the content creator / author. +# 'creator:id':422000229 , # Same as creator, but the Twitter user's ID. +# } + +# If webassets is installed, bundle JS and CSS into single files to make +# site loading faster in a HTTP/1.1 environment but is not recommended for +# HTTP/2.0 when caching is used. Defaults to True. +# USE_BUNDLES = True + +# Plugins you don't want to use. Be careful :-) +# DISABLED_PLUGINS = ["render_galleries"] + +# Special settings to disable only parts of the indexes plugin (to allow RSS +# but no blog indexes, or to allow blog indexes and Atom but no site-wide RSS). +# Use with care. +# DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED = False +# DISABLE_INDEXES_PLUGIN_RSS_FEED = False + +# Add the absolute paths to directories containing plugins to use them. +# For example, the `plugins` directory of your clone of the Nikola plugins +# repository. +# EXTRA_PLUGINS_DIRS = [] + +# Add the absolute paths to directories containing themes to use them. +# For example, the `v7` directory of your clone of the Nikola themes +# repository. +# EXTRA_THEMES_DIRS = [] + +# List of regular expressions, links matching them will always be considered +# valid by "nikola check -l" +# LINK_CHECK_WHITELIST = [] + +# If set to True, enable optional hyphenation in your posts (requires pyphen) +# Enabling hyphenation has been shown to break math support in some cases, +# use with caution. +# HYPHENATE = False + +# The <hN> tags in HTML generated by certain compilers (reST/Markdown) +# will be demoted by that much (1 → h1 will become h2 and so on) +# This was a hidden feature of the Markdown and reST compilers in the +# past. Useful especially if your post titles are in <h1> tags too, for +# example. +# (defaults to 1.) +# DEMOTE_HEADERS = 1 + +# Docutils, by default, will perform a transform in your documents +# extracting unique titles at the top of your document and turning +# them into metadata. This surprises a lot of people, and setting +# this option to True will prevent it. +# NO_DOCUTILS_TITLE_TRANSFORM = False + +# If you don’t like slugified file names ([a-z0-9] and a literal dash), +# and would prefer to use all the characters your file system allows. +# USE WITH CARE! This is also not guaranteed to be perfect, and may +# sometimes crash Nikola, your web server, or eat your cat. +# USE_SLUGIFY = True + +# Templates will use those filters, along with the defaults. +# Consult your engine's documentation on filters if you need help defining +# those. +# TEMPLATE_FILTERS = {} + +# Put in global_context things you want available on all your templates. +# It can be anything, data, functions, modules, etc. +GLOBAL_CONTEXT = { +# 'TWITTER_URL': 'https://twitter.com/getnikola', + # 'GITHUB_URL': 'https://github.com/getnikola', + 'BANNER_URL': '/assets/img/logotipo.svg', +# 'logo_url': '/assets/img/bitson.png' +} + +# Add functions here and they will be called with template +# GLOBAL_CONTEXT as parameter when the template is about to be +# rendered +GLOBAL_CONTEXT_FILLER = [] diff --git a/bitblog/files/CNAME b/bitblog/files/CNAME new file mode 100644 index 0000000..21d3bd2 --- /dev/null +++ b/bitblog/files/CNAME @@ -0,0 +1 @@ +blog.bitson.group diff --git a/bitblog/files/README.md b/bitblog/files/README.md new file mode 100644 index 0000000..13915b3 --- /dev/null +++ b/bitblog/files/README.md @@ -0,0 +1,9 @@ +# bitson blog + +This is the static site files. + +If you want to edit this blog, please do it on the `src` branch. + +```bash +git checkout src +``` diff --git a/bitblog/files/code/ai/binarizacion.py b/bitblog/files/code/ai/binarizacion.py new file mode 100644 index 0000000..5a35269 --- /dev/null +++ b/bitblog/files/code/ai/binarizacion.py @@ -0,0 +1,11 @@ +import numpy as np +from sklearn import preprocessing + +matriz_ejemplo = np.array([[2.1, 2.9, -1.3, 5.2], + [1.3, -3.8, 2.1, 4.3], + [-8.9, 2.4, -1.1, 0], + [4.1, -3.9, 2.5, 2.1]]) + +matriz_binarizada = preprocessing.Binarizer(threshold=2.4).transform(matriz_ejemplo) + +print("Matriz binarizada:\n", matriz_binarizada) diff --git a/bitblog/files/code/ai/eliminar_valor_medio.py b/bitblog/files/code/ai/eliminar_valor_medio.py new file mode 100644 index 0000000..2032aeb --- /dev/null +++ b/bitblog/files/code/ai/eliminar_valor_medio.py @@ -0,0 +1,22 @@ +import numpy as np +from sklearn import preprocessing + +matriz_ejemplo = np.array([[2.1, 2.9, -1.3, 5.2], + [1.3, -3.8, 2.1, 4.3], + [-8.9, 2.4, -1.1, 0], + [4.1, -3.9, 2.5, 2.1]]) + +print("Matriz de ejemplo:") +print(matriz_ejemplo) +print("Promedio =", matriz_ejemplo.mean(axis=0)) +print("Desviación típica =", matriz_ejemplo.std(axis=0)) + +promedio_eliminado = preprocessing.scale(matriz_ejemplo) +print("\nMatriz procesada:") +print(promedio_eliminado) +print("Promedio =", promedio_eliminado.mean(axis=0)) +print("Desviación Típica =", promedio_eliminado.std(axis=0)) + + + + diff --git a/bitblog/files/code/ai/escalando.py b/bitblog/files/code/ai/escalando.py new file mode 100644 index 0000000..acd8287 --- /dev/null +++ b/bitblog/files/code/ai/escalando.py @@ -0,0 +1,11 @@ +import numpy as np +from sklearn import preprocessing + +matriz_ejemplo = np.array([[2.1, 2.9, -1.3, 5.2], + [1.3, -3.8, 2.1, 4.3], + [-8.9, 2.4, -1.1, 0], + [4.1, -3.9, 2.5, 2.1]]) + +datos_escalados = preprocessing.MinMaxScaler(feature_range=(0, 1)) +datos_escalados = datos_escalados.fit_transform(matriz_ejemplo) +print("Datos escalados:\n", datos_escalados) diff --git a/bitblog/files/code/ai/normalizacion.py b/bitblog/files/code/ai/normalizacion.py new file mode 100644 index 0000000..d492846 --- /dev/null +++ b/bitblog/files/code/ai/normalizacion.py @@ -0,0 +1,12 @@ +import numpy as np +from sklearn import preprocessing + +matriz_ejemplo = np.array([[2.1, 2.9, -1.3, 5.2], + [1.3, -3.8, 2.1, 4.3], + [-81.9, 2.4, -1.1, 0], + [4.1, -3.9, 2.5, 2.1]]) + +datos_normalizados_l1 = preprocessing.normalize(matriz_ejemplo, norm='l1') +datos_normalizados_l2 = preprocessing.normalize(matriz_ejemplo, norm='l2') +print("Datos con Normalización L1:\n", datos_normalizados_l1) +print("\nDatos con Normalización L2:\n", datos_normalizados_l2) diff --git a/bitblog/files/img/adwords.png b/bitblog/files/img/adwords.png new file mode 100644 index 0000000..1ff71a7 Binary files /dev/null and b/bitblog/files/img/adwords.png differ diff --git a/bitblog/files/img/coding-computer-hacker-97077.jpg b/bitblog/files/img/coding-computer-hacker-97077.jpg new file mode 100644 index 0000000..54b4f59 Binary files /dev/null and b/bitblog/files/img/coding-computer-hacker-97077.jpg differ diff --git a/bitblog/files/img/explicacion_grafica_recursiva.png b/bitblog/files/img/explicacion_grafica_recursiva.png new file mode 100644 index 0000000..defe2d0 Binary files /dev/null and b/bitblog/files/img/explicacion_grafica_recursiva.png differ diff --git a/bitblog/files/img/logo_nikola.png b/bitblog/files/img/logo_nikola.png new file mode 100644 index 0000000..bf8d141 Binary files /dev/null and b/bitblog/files/img/logo_nikola.png differ diff --git a/bitblog/files/img/pixel/confi-pixel.png b/bitblog/files/img/pixel/confi-pixel.png new file mode 100644 index 0000000..50de2be Binary files /dev/null and b/bitblog/files/img/pixel/confi-pixel.png differ diff --git a/bitblog/files/img/pixel/google-analytics.png b/bitblog/files/img/pixel/google-analytics.png new file mode 100644 index 0000000..4d11e8e Binary files /dev/null and b/bitblog/files/img/pixel/google-analytics.png differ diff --git a/bitblog/files/img/pixel/gtag.pdf b/bitblog/files/img/pixel/gtag.pdf new file mode 100644 index 0000000..c6e76ee Binary files /dev/null and b/bitblog/files/img/pixel/gtag.pdf differ diff --git a/bitblog/files/img/pixel/gtag.png b/bitblog/files/img/pixel/gtag.png new file mode 100644 index 0000000..48829ae Binary files /dev/null and b/bitblog/files/img/pixel/gtag.png differ diff --git a/bitblog/files/img/pixel/instalacion-manual.png b/bitblog/files/img/pixel/instalacion-manual.png new file mode 100644 index 0000000..36ee464 Binary files /dev/null and b/bitblog/files/img/pixel/instalacion-manual.png differ diff --git a/bitblog/files/img/pixel/intro-pixel.png b/bitblog/files/img/pixel/intro-pixel.png new file mode 100644 index 0000000..733ed8b Binary files /dev/null and b/bitblog/files/img/pixel/intro-pixel.png differ diff --git a/bitblog/files/img/pixel/script-facebook.png b/bitblog/files/img/pixel/script-facebook.png new file mode 100644 index 0000000..cf7f274 Binary files /dev/null and b/bitblog/files/img/pixel/script-facebook.png differ diff --git a/bitblog/files/img/pixel/script-google.png b/bitblog/files/img/pixel/script-google.png new file mode 100644 index 0000000..585574d Binary files /dev/null and b/bitblog/files/img/pixel/script-google.png differ diff --git a/bitblog/posts/acceso-root-ssh-desde-ip-o-dominio.md b/bitblog/posts/acceso-root-ssh-desde-ip-o-dominio.md new file mode 100644 index 0000000..97f458e --- /dev/null +++ b/bitblog/posts/acceso-root-ssh-desde-ip-o-dominio.md @@ -0,0 +1,76 @@ +<!-- +.. title: Acceso root SSH desde IP o dominio +.. slug: acceso-root-ssh-desde-ip-o-dominio +.. date: 2018-04-13 10:15:07 UTC-03:00 +.. tags: devops ssh root +.. category: tutorial ssh +.. link: +.. description: accediendo por SSH como root desde una IP o dominio. +.. type: text +.. author: lecovi +--> + +![Image](/img/coding-computer-hacker-97077.jpg) + +Hace poco con la coope nos mudamos y tuvimos que cambiar el ISP (*Internet +Service Provider*) y eso motivó a que tuviéramos que hacer algunos cambios, en +muchos aspectos pero no viene al caso, puntualmente en el server que tenemos +dentro de la ofi. +Tuve que desempastarme un poco y volver a leer el manual de **ssh** para +recordar algunas cuestiones que les comparto a continuación. + +<!-- TEASER_END --> + + +# Archivo de configuración + +El *daemon* de SSH lee el archivo de configuración que está en +`/etc/ssh/sshd_config`. Este archivo tiene muchíiiiiiiisimas opciones de +configuración. + +## Match + +Lo interesante de este archivo de configuración es que acepta configuraciones +condicionales. Es decir, si se cumple una condición específica, se modifican +las opciones de configuración en cuestión. + +Por ejemplo, es normal no permitir el acceso SSH como root desde cualquier +lado. En Debian, cuando instalás el servidor SSH es una opción por defecto. +Sólo podés acceder por SSH a la máquina con un usuario sin privilegios. + +Pero podrías querer entrar por ejemplo desde una máquina local. Para eso usamos +las opciones de configuración condicionales. + +``` +Match Address 192.168.1.50 + PermitRootLogin yes +``` + +En este caso, lo que estamos indicando es que si el acceso SSH proviene desde +la IP 192.168.1.50 dejamos que se acceda como el usuario root. Esto es muy +útil para cuando queremos configurar acceso rápido desde máquinas "confiables". +Es decir, terminales que nosotros solemos utilizar, son de nuestra propiedad o +resultan conocidas. + +También existe la posibilidad de asignarlo a través de un dominio. En cuyo caso +la opción de configuración será: + +``` +Match Host foo.bitson.group + PermitRootLogin yes +``` + +Sólo nos resta reiniciar el servicio de SSH para que el *daemon* tome los +cambios. + +``` +systemctl restart ssh +``` + +Espero que les haya sido útil. Nos vemos en la próxima! + +### Enlaces de interés + +- [Manual Config SSH](https://linux.die.net/man/5/sshd_config) +- [How to allow root login from one IP address with ssh public keys only](https://www.cyberciti.biz/faq/match-address-sshd_config-allow-root-loginfrom-one_ip_address-on-linux-unix/) +- [Allow SSH Root Login From Specific IP](https://stackpointer.io/unix/linux-allow-ssh-root-login-specific-ip/618/) diff --git a/bitblog/posts/alias-pretty-url-con-nginx.md b/bitblog/posts/alias-pretty-url-con-nginx.md new file mode 100644 index 0000000..caad648 --- /dev/null +++ b/bitblog/posts/alias-pretty-url-con-nginx.md @@ -0,0 +1,118 @@ +<!-- +.. title: Alias & Pretty URL con Nginx +.. slug: alias-pretty-url-con-nginx +.. date: 2018-02-07 22:24:22 UTC-03:00 +.. tags: devops, nginx, alias, deploy +.. category: tutorial, nginx, devops +.. link: +.. description: Una breve descripción de configuración de Nginx +.. type: text +.. author: lecovi +--> + +En este artículo te voy a contar cómo hacer para publicar en un mismo servidor +diferentes carpetas con archivos estáticos de tu sitio. + +# Primer deploy + +Supongamos que tenemos un sitio estático, por ejemplo, el sitio institucional +de [bitson](https://bitson.group). Eso lo tenemos en un repo y es un conjunto +de archivos de texto (HTML, js, css y demás) que conforman el sitio. + +> Se le dice **estático** no porque esté *"quieto"* sino porque sólo contiene +> archivos de texto y no necesita correr un *backend* para funcionar. + +Supongamos que tenemos los archivos en https://github.com/bitson/sitio1.git +clonamos el repo en el server y tendremos una configuración del Nginx que será +algo similar a: + +```bash +server { + listen 80; + listen [::]:80; + server_name bitson.group www.bitson.group; + return 301 https://$host/$request_uri; +} +server { + listen 443 ssl; + listen [::]:443 ssl; + + root /home/bitson/sitio1; + + server_name bitson.group www.bitson.group; + + location / { + try_files $uri $uri/ =404; + } + + ssl_certificate /etc/letsencrypt/live/bitson.group/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/bitson.group/privkey.pem; +} +``` + +Esta configuración hace que todas las peticiones que lleguen vía HTTP sean +redireccionadas al HTTPS y se sirvan del directorio `/home/bitson/sitio1` donde +tenemos clonado el repo. + +> Para los certificados usamos Let's Encrypt y esa es la ruta usual en donde +> se guardan en un sistema Debian. + +Además en esta configuración vemos una sentencia de `try_files` para la +locación de la raíz (`/`). Lo que nos quiere decir esto es que cuando alquien +haga una petición a, por ejemplo: `bitson.group/saraza` Nginx tiene que buscar +si existe el archivo `/home/bitson/sitio1/saraza` o si existe el directorio +`/home/bitson/sitio1/saraza/`. En caso de que no exista ninguno entonces el +Nginx responderá con un 404, el código de HTTP que corresponde a `Not Found`. + +# Agregando el alias + +Supongamos ahora que tenemos otro repositorio, por ejemplo, +https://github.com/bitson/presentaciones.git y queremos publicarlo en el mismo +servidor. Algo así como lo que podemos ver en +[bitson.group/slides](https://bitson.group/slides/). + +Para no tener que publicarlo en otro server, podemos aprovechar un alias de +Nginx. Suponiendo que tenemos ese repositorio en el server en +`/home/bitson/presentaciones` tenemos que poner una configuración como: + +```bash +server { + listen 443 ssl; + listen [::]:443 ssl; + + root /home/bitson/sitio1; + + server_name bitson.group www.bitson.group; + + location / { + try_files $uri $uri/ =404; + } + + location /slides { + alias /home/bitson/presentaciones; + } + + ssl_certificate /etc/letsencrypt/live/bitson.group/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/bitson.group/privkey.pem; +} +``` + +# Pretty URLs + +Si queremos omitir tener que poner el `.html` en cada una de las URLs a las que +queremos acceder en nuestro sitio. Sólo tenemos que agregar una sentencia de +`try_files` en nuestra configuración. Por ejemlo: + +```bash + location /slides { + alias /home/bitson/presentaciones; + try_files $uri $uri.html =404; + } +``` + +Así, si queremos entrar a `https://bitson.group/slides/presentacion1.html` +podremos hacerlo con sólo ir a `https://bitson.group/slides/presentacion1` + +---- + +Espero que les haya gustado! Los leemos en los comentarios! diff --git a/bitblog/posts/cooperativismo-software-libre-y-feminismo.md b/bitblog/posts/cooperativismo-software-libre-y-feminismo.md new file mode 100644 index 0000000..e2f5154 --- /dev/null +++ b/bitblog/posts/cooperativismo-software-libre-y-feminismo.md @@ -0,0 +1,35 @@ +<!-- +.. title: Cooperativismo, Software Libre y Feminismo +.. slug: cooperativismo-software-libre-y-feminismo +.. date: 2018-03-08 15:48:31 UTC-03:00 +.. tags: feminismo, software libre, cooperativismo +.. category: opinion valores convicciones +.. link: +.. description: +.. type: text +.. author: cuberti +--> + +# Cooperativismo, software libre y feminismo. + +Uno crece en un entorno delimitado y pareciera que siempre tiene que mantenerse dentro de esos parámetros. ¿Acaso no se ve como un logro que un niñx pueda pintar dentro de los bordes? ¿Es realmente un triunfo propio? ¿De la sociedad? ¿Es un simple proceso de aprendizaje? + +Asociarnos a una Cooperativa implicó un proceso de resignificación de nuestra vida laboral. Incluso, y con el perdón de los amigos y familias, esos límites entre “el horario de oficina” y “casa” se fueron borrando. Creemos en un sistema solidario, donde las verticalidades son solo un fantasma, donde la asamblea arrasa con la meritocracia, donde la lucha es continua. Creemos en nosotros y no como una mínima parte de un sistema sino como seres libres y pensantes. + +Convicción desde nuestro punto de vista es implicancia. + +Desde esa estructura decidimos realizar nuestras tareas en sistemas operativos libres. Una vez más nos encontramos cuestionando lo establecido. No podemos ceder nuestra libertad a sistemas restrictivos, capitalistas y excluyentes. Creemos con convicción que las tecnologías libres nos pueden abrir terreno para la emancipación individual y colectiva ¡Lo colectivo por sobre las individualidades! + +Convicción desde nuestro punto de vista es implicancia. + +Entonces, desde nuestros cimientos: cooperativismo y software libre no nos queda otra que gritar por el feminismo. Nuestras banderas son la igualdad y la libertad pero no sólo como expresiones de deseo sino desde nuestra cotidianidad. + +Margarita Salas explica en “Género y software libre en América Latina. Un estudio de caso” que el movimiento de los sistemas operativos libres está vinculada a “la creación colectiva, la apropiación comunitaria del conocimiento y la promoción de una filosofía de inclusión, diversidad y solidaridad”. + +Convicción desde nuestro punto de vista es implicancia. + +Al día de hoy, se calcula que en el sector de producción de software apenas el 20% son mujeres. Y esta desigualdad es aún más fuerte cuando hablamos de software libre donde la participación femenina es del 2% ¡Queremos que este porcentaje cambie! + +Hoy y siempre vamos a luchar por nuestros ideales. ¡Libertad, igualdad, inclusión, solidaridad y diversidad! + +¡Creemos en esta forma y queremos ver un mundo así! diff --git a/bitblog/posts/creando-articulos-en-nikola.md b/bitblog/posts/creando-articulos-en-nikola.md new file mode 100644 index 0000000..b976546 --- /dev/null +++ b/bitblog/posts/creando-articulos-en-nikola.md @@ -0,0 +1,289 @@ +<!-- +.. title: Creando artículos en Nikola +.. slug: creando-articulos-en-nikola +.. date: 2018-02-16 16:10:50 UTC-03:00 +.. tags: nikola, blog +.. category: +.. link: +.. description: Cómo crear un artículo para el blog de bitson con Nikola +.. type: text +.. author: nespino +--> + +Hoy les presentamos nuestro primer post recursivo. + +## Cómo crear un artículo para el blog de bitson + + +[logo-nikola]: /img/logo_nikola.png "Logo de Nikola" + +Ingredientes: + +* [pipenv](https://github.com/pypa/pipenv "Repositorio de pipenv") (Para más información ver la guía [Empezando con pipenv](http://blog.bitson.group/posts/empezando-con-pipenv/ "Empezando con pipenv")) +* [GitHub Pages](https://pages.github.com/ "Páginas de GitHub") +* [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet "Guía rápida de Markdown") como lenguaje de marcado +* [![nikola logo][logo-nikola]](https://getnikola.com/ "Sitio oficial de Nikola") + +Sin más preámbulo, dejo la receta a continuación... + + +# Configurando el entorno pipenv + +Primero, nos aseguramos de tener [pipenv instalado](https://bryson3gps.wordpress.com/2017/11/08/stop-everything-start-using-pipenv/ "Cómo instalar pipenv"). Resulta práctico disponer del comando pipenv desde cualquier ruta, por lo que sugerimos agregar la ubicación de la misma a la variable de entorno PATH en el archivo .bashrc (.zshrc, o el que corresponda al shell que usen). Para saber dónde está ubicado pipenv podemos ejecutar el siguiente comando desde la consola: + +__which pipenv__ + +> /home/nespino/.local/bin/pipenv + +Por lo que la línea de código para agregar pipenv al PATH sería: + +__export PATH=$PATH:~/.local/bin__ + + +# Clonando nuestro repositorio de GitHub Pages + +Una vez configurado el entorno pipenv, procedemos a clonar el [repositorio](https://github.com/bitson/bitson.github.io.git "Repositorio del blog de bitson") donde se alojan todas las entradas de nuestro blog. + +__git clone https://github.com/bitson/bitson.github.io.git__ + +No necesitamos permisos especiales para clonarlo, pero no podremos subir el nuevo contenido del blog sin estar debidamente autorizado. + +## IMPORTANTE + +Debemos usar la rama __src__, en donde tenemos disponible los archivos necesarios para instalar Nikola y todas los artículos del blog. + +__git checkout src__ + +# Instalando Nikola + +Dentro del mismo, en la carpeta __bitblog__ se encuentra el archivo __Pipfile__, que es el que nos permitirá instalar [__Nikola__](https://getnikola.com/ "Sitio oficial de Nikola") a través del siguiente comando en consola: + +__pipenv --three install__ + +El parámetro __--three__ indica que vamos a usar la versión 3 de Python. En caso de omitirlo, usaremos la versión que esté configurado por defecto en nuestro sistema. + +--- +__Nota:__ Es posible las dependencias que tengamos en el sistema choquen con las que están declaradas en el archivo Pipfile.lock. En ese caso, podemos ignorar este archivo durante la instalación usando el comando: + +__pipenv --three install --skip-lock__ + +--- + +__Otra nota:__ + +Es posible que el instalador de pipenv nos devuelva la siguiente advertencia: + +> Warning: Your Pipfile requires python_version 3.6, but you are using 3.5.2 (/home/n/./b/bin/python). + +> $ pipenv check will surely fail. + +No es algo de qué preocuparse. + +--- + +### Instalación en curso... + +>Virtualenv location: /home/nespino/.virtualenvs/bitblog-Dccxvb6W + +>Installing dependencies from Pipfile... + +> 🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 1/1 — 00:01:23 + +>To activate this project's virtualenv, run the following: + +> $ pipenv shell + +¡Éxito! Sólo nos falta verificar que Nikola esté funcionando correctamente. + +__pipenv run nikola auto__ + +En mi caso, al ejecutar ese comando recibo un Traceback que termina en + +> OSError: [Errno 98] La dirección ya se está usando + +Lo que significa que el puerto usado por defecto (8000) está ocupado. Para especificar el puerto a usar basta con agregar __-p <puerto>__ al final del comando. En el ejemplo, usaremos el puerto 8001. + +> ➜ bitblog git:(src) ✗ pipenv run nikola auto -p 8001 + +> Scanning posts........done! + +> [2018-02-16T20:03:24Z] INFO: auto: Watching files for changes... + +> [2018-02-16T20:03:24Z] INFO: ws4py: Using epoll + +> [2018-02-16T20:03:24Z] INFO: auto: Serving HTTP on 127.0.0.1 port 8001... + +> [2018-02-16T20:03:24Z] INFO: ws4py: Managing websocket [Local => 127.0.0.1:8001 | Remote => 127.0.0.1:56708] + +> [2018-02-16T20:03:24Z] INFO: auto: <--- {'command': 'hello', 'protocols': ['http://livereload.com/protocols/official-6', 'http://livereload.com/protocols/official-7'], 'snipver': 1, 'ver': '2.2.1'} + +> [2018-02-16T20:03:24Z] INFO: auto: ---> {"command": "hello", "protocols": ["http://livereload.com/protocols/official-7"], "serverName": "nikola-livereload"} +<a name="voila" title="Usado solamente para el efecto recursivo"></a> +> +> [2018-02-16T20:03:24Z] INFO: auto: <--- {'command': 'info', 'plugins': {'less': {'version': '1.0', 'disable': False}}, 'url': 'http://localhost:8001/'} + +> [2018-02-16T20:03:24Z] INFO: auto: ****** Browser connected: http://localhost:8001/ + +> [2018-02-16T20:03:24Z] INFO: auto: ****** sending 0 pending messages + + +# Voilá! + +Nikola está listo para ser usado. Para ver el estado actual del blog, ingresar a [http://localhost:8001/](http://localhost:8001/ "8001 o el puerto en el que esté corriendo Nikola") y buscar esta misma [entrada](/posts/creando-articulos-en-nikola/#voila "Haga clic aquí para sentir el efecto recursivo en sus propias venas"). Todo este procedimiento para llegar al tan deseado momento... + +# Creando artículos en Nikola + +Antes de crear una nueva entrada, es *muy* importante tener el blog local actualizado, para no perder los últimos cambios ni generar conflictos con las ramas. Para esto basta con ejecutar: + +__git pull__ + +Ahora sí, para crear una nueva entrada en el blog, nos posicionamos en el directorio __bitblog__ y ejecutamos: + +__pipenv run nikola new_post -f markdown__ + +Sin desperdiciar un segundo, Nikola nos pedirá un título para el artículo... + +>Creating New Post + +>----------------- + +> + +>Title: Creando artículos en Nikola + +>Scanning posts........done! + +>[2018-02-16T19:10:50Z] INFO: new_post: Your post's text is at: posts/creando-articulos-en-nikola.md + +>➜ bitblog git:(src) ✗ ls + +--- + +Con el parámetro __-f markdown__ estamos especificando que el formato de marcado será [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet "Guía rápida de Markdown"). Si no lo especificamos, Nikola usará por defecto [reStructuredText](https://github.com/ralsina/rst-cheatsheet/blob/master/rst-cheatsheet.rst "Guía rápida de reStructuredText). Al día de la fecha, [Nikola soporta](https://getnikola.com/handbook.html#id17 "Lista de lenguajes soportados por Nikola") reStructuredText, Markdown, Jupyter (IPython) Notebooks y HTML, entre otras. + +__Nota:__ El mismo [blog de Nikola creado con Nikola](https://getnikola.com/blog/ "Blog de Nikola") tiene una [nota](https://getnikola.com/blog/markdown-can-affect-performance.html "Nota sobre el rendimiento de Markdown") sobre el rendimiento del Markdown con respecto a otros lenguajes de formateo. + +--- + +Estamos listos para redactar la publicación... +> __Your post's text is at: posts/creando-articulos-en-nikola.md__ + + Abrimos el archivo que Nikola nos generó automáticamente y podemos ver que incluye un encabezado donde principalmente podemos: + +* Cambiarle fecha y título a la entrada +* Agregarle tags separados por coma y definirle categorías +* Agregar una descripción +* Declarar quién es el autor + +Para esto último, alcanza con agregar la línea __.. author: @nespino__ al final del encabezado. Lo que debería quedar algo similar a: + +> <!-- + +> .. title: Creando artículos en Nikola + +> .. slug: creando-articulos-en-nikola + +> .. date: 2018-02-16 16:10:50 UTC-03:00 + +> .. tags: nikola, blog + +> .. category: + +> .. link: + +> .. description: Cómo crear un artículo para el blog de bitson con Nikola + +> .. type: text + +> .. author: @nespino + +> --> + +> Escribe tu publicación aquí. + + +De acá en adelante es fácil. Escribimos la entrada y guardamos el archivo. + +__ INFO: auto: Watching files for changes...__ + +Nikola nos informa que cada vez que el contenido se modifique, el servidor local intentará reiniciar, reflejando los cambios en el navegador. + +--- + +# Símbolos básicos del markdown + +Les dejo una síntesis de los elementos de markdown usados para la creación de esta nota: + +____Este renglón fue escrito envuelto entre dos guiones bajos seguidos____ +>>>> \>\>\>\> Este renglón comienza con cuatro símbolos de mayor (>>>>) +# # Este título empieza con almohadilla (hasthag, símbolo de numeral, ta-te-tí...) +*Este renglón está en cursiva* +[explicacion-grafica-recursiva]: /img/explicacion_grafica_recursiva.png "Explicación gráfica recursiva" +![explicacion grafica recursiva][explicacion-grafica-recursiva] + +\> \# \__no tan importante__ \!\[recurso] Nosotros somos símbolos libres (estamos escapados) + +Este separador de línea de acá abajo se hace poniendo tres guiones seguidos (---) + +--- + + +# Insertando imágenes + +Para agregar imágenes a nuestra publicación podemos hacerlo a través de su URL accesible desde internet o bien copiando la imagen a la carpeta: + +> bitblog/files/img/ejemplo.png + +De esta manera podremos declararla usando el siguiente formato: + +__\[identificador-del-recurso-de-imagen]: /img/ejemplo.png "Título de la imagen"__ + +Esto es, el identificador de la imagen entre corchetes, seguido de dos puntos, la URL de la imagen (que en este caso empieza con / porque saldrá + de la carpeta files/img/ previamente cargada en nuestro repositorio de GitHub Pages) y entre comillas el título de la imagen, el que aparecerá +al posicionar el cursor del mouse sobre la misma. + +Una vez que tengamos esta declaración (que no generará nada por pantalla) podremos insertar la imagen cuantas veces queramos, con un ! seguido de + las palabras alternativas entre corchetes, y pegado al identificador de la imagen entre corchetes, como muestra la siguiente línea: + +__\!\[description alt imagen asistencia discapacidad visual yapa optimiza seo][identificador-del-recurso-de-imagen]__ + + +--- + +# Aplicando los cambios +# + +Una vez que hayamos terminado de redactar la nota y verifiquemos que se vea correctamente, sólo debemos ejecutar el comando: + +# pipenv run nikola github_deploy + +lo que subirá los cambios al repositorio en la rama __src__ y GitHub Pages se encargará de mostrarlo en la dirección que tengamos configurada. + +# +> [2018-02-19T15:58:09Z] INFO: github_deploy: Successful deployment + +## ¡Éxito! + +--- + +PD: Hallazgos completamente inútiles aparecidos durante la redacción de la nota + +* [guthub.com](http://guthub.com "GitHub mal escrito") redirecciona a [github.com](http://github.com "GitHub bien escrito") + +* Animate a ejecutar __pipenv --jumbotron__ + + + + + + + + + + + + + + + + diff --git a/bitblog/posts/debugueando-react-native-en-android.md b/bitblog/posts/debugueando-react-native-en-android.md new file mode 100644 index 0000000..2f13a7b --- /dev/null +++ b/bitblog/posts/debugueando-react-native-en-android.md @@ -0,0 +1,109 @@ +<!-- +.. title: Debugueando react-native en Android +.. slug: debugueando-react-native-en-android +.. date: 2018-03-16 13:24:15 UTC-03:00 +.. tags: react-native,android,javascript,react +.. author: D +.. category: +.. link: +.. description: +.. type: text +--> + +En este post vamos a mostrar herramientas para debuguear la aplicacion que estemos desarrollando en react-native, igual que en mi post anterior voy a mostrar como hacerlo en linux. + +## Requisitos + +- Internet (claramente). +- Tener una aplicacion en react-native (de ser posible la del post anterior, paso el [link](http://blog.bitson.group/posts/empezando-con-android-y-react-native/)). +- Paciencia. + +## Manos a la obra + +Abrimos el Android Studio, vamos a `tools > AVD Manager` y corremos un emulador de Android. + +Una vez que tengamos el emulador corriendo abrimos en una terminal el directorio donde tengamos nuestra app. En este caso seguimos usando la `rn-app` que hicimos el post anterior. Una vez en el directorio ejecutamos `npm run android`. + +Una vez que la aplicacion se haya abierto en el emulador hacemos `ctrl + m` eso va a abrir una serie de opciones, ya iremos explicando una por una (aunque hayan opciones bastante obvias). Hacemos click en `Debug JS Remotely`. + +Eso lo que va hacer es abrirnos una tab en chrome/firefox con una texto parecido a este: + +``` +React Native JS code runs as a web worker inside this tab. + +Press Ctrl⇧J to open Developer Tools. Enable Pause On Caught Exceptions for a better debugging experience. + +You may also install the standalone version of React Developer Tools to inspect the React component hierarchy, their props, and state. + +Status: Debugger session #0 active. +``` + +Abrimos la consola del explorador con la tecla `F12` y vemos que dice + +``` +Running application "rnapp" with appParams: {"rootTag":11}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF +``` + +Eso quiere decir que nuestro navegador ya esta "escuchando" a la aplicacion de react-native. Lo que podemos hacer para probarlo es ir al archivo `app.js` y dentro de la funcion `render()` hacer un simple `console.log('testing debug...');` eso se va a mostrar en la consola de su explorador. + +Pero vamos un poco mas alla, creemos un boton y veamoslo funcionar un poco mas copado. + +Vamos a poner un `Button` en nuestra app y ver por consola un mensaje que se escribe cuando hacemos click. En esta parte vamos a copiar y pegar el codigo, ya haremos un post explicando componentes y funciones. + +``` +import React from 'react'; +import { StyleSheet, Text, View, Button } from 'react-native'; + +export default class App extends React.Component { + testDebug = () => { + console.log('testing debug'); + } + render() { + return ( + <View style={styles.container}> + <Text>Open up App.js to start working on your app!</Text> + <Text>Changes you make will automatically reload.</Text> + <Text>Shake your phone to open the developer menu.</Text> + <Button + onPress={this.testDebug} + title="Press Me!" + color="#841584" + accessibilityLabel="Learn more about this purple button" + /> + </View> + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center', + }, +}); +``` + +Simplemente lo que hace este mini codigo, es mostrar un mensaje en el press(click) del boton de nuestra app. Ahora cada vez que cliqueamos podemos ver por consola que se muestra un mensaje que dice `testing debug`. + + +## Otras herramientas + +Contamos con una herramienta similar a la consola, pero que corre independientemente del navegador, [react-native-debugger](https://github.com/jhen0409/react-native-debugger). +Vamos a la parte de Installation al link que dice `releases`, y nos bajamos la version para linux. + +Cerramos la tab donde estabamos debugueando anteriormente y volvemos a hacer `ctrl + M` para desactivar el `Debug JS Remotely`. +Vamos a la carpeta donde haya descargado, extraemos el zip y abrimos el archivo `React Native Debugger`. Vamos a ver que es similar al inspector de elementos de chrome. Repetimos los pasos pero con la aplicacion abierta y vemos que ahora el mensaje nos lo tira en la consola del `React Native Debugger`. +Lo que es interesante de esta aplicacion es que en el panel de abajo a la izquierda podemos ver el arbol del "DOM" (no es un DOM exactamente pero es simil) y podemos editar al vuelo las propiedades lo cual nos ahorra mucho tiempo de prueba y recarga. +Por ejemplo vayamos al `<Button>` dentro del explorador de elementos y cambiemos la propiedad `color` a `#333` veamos como el boton cambia de color, tambien podemos hacer "click" (press) y ver como nuestro mensaje sale por la consola. + +Muy bien, ya tenemos la aplicacion instalada y las herramientas para debuguearla, FELICITACIONES! + +<hr /> + +Gracias por leer, cualquier consulta la pueden dejar escrita en el blog y la contestamos. + +Saludos, + +D. diff --git a/bitblog/posts/deployando-directamente-con-git.md b/bitblog/posts/deployando-directamente-con-git.md new file mode 100644 index 0000000..3571c45 --- /dev/null +++ b/bitblog/posts/deployando-directamente-con-git.md @@ -0,0 +1,99 @@ +<!-- +.. title: Deployando directamente con git +.. slug: deployando-directamente-con-git +.. date: 2018-02-07 22:52:17 UTC-03:00 +.. tags: deploy, devops, git +.. category: devops, git +.. link: +.. description: Tutorial sobre como deployar directamente con git +.. type: text +.. author: lecovi +--> + +Hoy les quiero contar cómo se puede configurar `git` para que deployemos +directamente con un `push` en nuestro server. + +# Entorno + +Vamos a suponer que ya tenés tu sitio en un repositorio y que lo que estás +haciendo ahora en tu ciclo de *deploy* es algo similar a esto: + +1. Hacés tus cambios en tu repo y commiteás a **master**. +2. Te conectás por `ssh` a tu server y te parás en el directorio donde tenés tu + sitio +3. Hacés un `git pull` para descargar tu nuevo sitio. + +Si bien no es algo complejo, puede llegar a ser medio tedioso. Y qué mejor si +se puede hacer un deploy simplemente haciendo `git push`, no? xD. + +# Configuración + +## Server + +Vamos a suponer que estás sirviendo tus archivos con un Apache o un Nginx en el +directorio `/home/bitson/mi_sitio/`. +Para poder llevar adelante esta configuración, vamos a separar por un lado los +archivos del sitio y por el otro los archivos del control de versiones. +Necesitamos tener un nuevo repo en `/home/bitson/mi_sitio.git`. Para eso nos +conectamos al server por ssh como siempre y ejecutamos: + +```bash +mkdir -p /home/bitson/mi_sitio.git +cd /home/bitson/mi_sitio.git +git init --bare +``` + +> Con el parámetro `--bare` le decimos que no vamos a tener los archivos con +> código fuente, sólo los archivos *internos* de `git`. + +### Hooks + +Ahora que tenemos el repositorio creado, tenemos que tener un directorio +`hooks`. Ahí dentro vamos a crear un archivo que se llame `post-receive` con el +con permisos de ejecución siguiente contenido: + +```bash +#!/bin/sh +git --work-tree=/home/bitson/mi_sitio --git-dir=/home/bitson/mi_sitio.git checkout -f +``` + +> Para darle permisos de ejecución, corré el comando: `chmod a+x post-receive` + +Ahora cuando hagamos un `push` a este repositorio en `mi_sitio.git` se va a +ejecutar el `hook` que acabamos de crear en `post-receive`. + +## Máquina local + +Ahora lo que tenés que hacer es agregar un repositorio remoto a tu repositorio +local: + +```bash +git remote add deploy ssh://usuario@tu_dominio.com/home/bitson/mi_sitio.git +``` + +Ahora trabajamos localmente y cuando queremos deployar lo que vamos a hacer es: + +```bash +git push deploy master +``` + +Y *voilà!* Asunto resuelto. + +# Limpieza + +Si tu entorno era similar a lo que describimos al principio del artículo, si te +conectás al server, te parás en `/home/bitson/mi_sitio` y tirás un `git status` +te va a decir que hubo cambios. Porque claramente ese repositorio no sabe que +se actualizó... De hecho ya no necesitás tener ese repositorio porque los +archivos de `git` los tenés en `/home/bitson/mi_sitio.git`. + +Así que lo que podés hacer para evitar confusiones es borrar el `.git` que +tenés en `/home/bitson/mi_sitio`. + +```bash +rm -rf /home/bitson/mi_sitio/.git +``` + +---- + +Fácil? Dejanos tu comentario diff --git a/bitblog/posts/diaspora.md b/bitblog/posts/diaspora.md new file mode 100644 index 0000000..3702a20 --- /dev/null +++ b/bitblog/posts/diaspora.md @@ -0,0 +1,32 @@ +<!-- +.. title: Diaspora +.. slug: diaspora +.. date: 2018-08-29 11:04:09 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> +Diaspora + +Diaspora es una red social descentralizada basada en software libre. El proyecto inició en el año 2010 y sus fundadores son cuatro estudiantes del Instituto Courant de Ciencias Matemáticas, de la Universidad de Nueva York: Ilya Zhitomirskiy, Daniel Grippi, Maxwell Salzberg y Raphael Sofaer. + +Al ser una red descentralizada, como el e-mail, Jabber/XMPP o Pump.io, no hay una empresa o entidad concreta dando el servicio a todo el mundo, sino que existe diversidad de servidores, todos interconectados entre sí. Al ser diversos los servidores si uno tiene problemas no afecta a todos. Un usuario puede crearse una cuenta en cualquier servidor de Diaspora, e interactuar con sus contactos independientemente de donde estos tengan sus cuentas. + +Es decir, Diaspora no es propiedad de ninguna persona o entidad, manteniéndose así libre de adquisiciones corporativas, publicidad, y otras amenazas. En este sentido Dan Grippi expresó: “…nuestro diseño distribuido significa que ninguna gran corporación controlará jamás a Diaspora. Diaspora nunca venderá tu vida social a los anunciantes, y nunca tendrás que ajustarte a las reglas arbitrarias de alguien más, o mirar por encima del hombro antes de hablar”. + +En las redes convencionales uno debe pensar previamente qué contenido compartir ¿Afecta a mi trabajo? ¿Mi relación con mi familia? ¿Con amigos? ¿Quiero que mi mensaje llegue a todos? ¿Quiero que sepan todos los aspectos de mi vida? + +En eso pensaron los creadores al definir la forma de agrupar a los contactos en “aspectos”. Permite agrupar en “trabajo”, “familiar”, esto implica que tanto a la hora de leer como de publicar se selecciona el aspecto adecuado, de manera que solo leeremos a la gente en dicho aspecto, y si publicamos algo, solo será visto por gente en dicho aspecto. También se pueden manejar varios aspectos al mismo tiempo. + +Al igual que GNU Social o Twitter podemos seguir los #tags de los temas que nos despiertan curiosidad y también podemos añadirlos a nuestras publicaciones para llegar a usuarios que busquen esa información y que no nos siguen a nosotros. + +A la hora de publicar, es posible utilizar texto con formato e imágenes, para crear textos elaborados, utilizando los sencillos códigos Markdown. También se pueden incrustar vídeos y audio tan solo pegando la dirección. + +Esto es posible usarlo también en los mensajes privados, así como en el campo “Biografía” del perfil, donde se puede detallar todo tipo de datos usando diferentes fuentes e insertando imágenes, para crear un perfil sin restricciones. + +Esta red social basada en software libre busca proteger la libertad de los usuarios, brindarles mayores posibilidades de privacidad y de diseño ¡Una vez más el software libre nos da libertad! + +¿La probaron? ¡Escuchamos sus experiencias! diff --git a/bitblog/posts/django-introduccion-a-internacionalizacion-y-localizacion.md b/bitblog/posts/django-introduccion-a-internacionalizacion-y-localizacion.md new file mode 100644 index 0000000..4ffbbee --- /dev/null +++ b/bitblog/posts/django-introduccion-a-internacionalizacion-y-localizacion.md @@ -0,0 +1,148 @@ +<!-- +.. title: Django: Introducción a internacionalización y localización +.. slug: django-introduccion-a-internacionalizacion-y-localizacion +.. date: 2018-06-18 22:02:41 UTC-03:00 +.. tags: django, internationalization, localization, internacionalización, localización +.. category: django +.. link: +.. description: Introducción a internacionalización y localización en Django +.. type: text +.. author: marcosdmyr +--> + +# Django: Introducción a internacionalización y localización + +Cuando escribimos código, solemos hacerlo por defecto en inglés, ya que es el lenguaje predominante. Sin embargo, sucede que en algunos casos los usuarios de nuestro desarrollo necesitan ver la aplicación en su lenguaje local y este no es el inglés. Este artículo no es más que una breve guía o bitácora de las acciones a seguir para conseguir aprovechar las capacidades de traducción de Django. + +Particularmente los ejemplos serán en función de Django 2, y la documentación se encuentra disponible en el [sitio oficial](https://docs.djangoproject.com/en/2.0/topics/i18n/) + +<!-- TEASER_END --> + +Los pasos para conseguir traducir una aplicación web escrita en Django son los siguientes: + +- [Configurar el sitio](#configuracion-del-sitio) +- [Marcar las cadenas de caracteres](#marcar-las-cadenas) (*Strings*) que deseamos que sean traducibles +- [Crear los archivos de traducción](#crear-archivos-de-traduccion) (*Archivos con extensión po*) +- [Compilar los mensajes](#compilar-los-mensajes) o cadenas de caracteres para que la aplicación pueda mostrarlos + + +Ahora, si te interesa abordar los fundamentos, de qué tratan estos dos conceptos comunes a casi cualquier framework moderno? + +El objetivo de la internacionalización y localización es que una aplicación web disponga de contenido en lenguajes y formatos relacionados con sus usuarios. + +En principio Django hace dos cosas: + +- Permite a los desarrolladores *marcar* qué partes de la aplicación deberían ser traducibles o formateadas en lenguajes locales (**internacionalización**) +- Usa estas marcas para localizar la aplicación web en correspondencia con el usuario (**localización**) + +*(Sólo a modo de aclaración, ya que evaluamos que los usuarios disponen de los navegadores de mayor uso. La intención de traducir a un lenguajes depende en última instancia de que el navegador acepte el header **Accpet-Language**)* + + +## Configuración del sitio {#configuracion-del-sitio} + +Antes de empezar a traducir el sitio, debemos indicarle a Django qué lenguajes están disponibles, y cómo encontrar las traducciones. Estas dos cosas se hacen en el archivo de configuración **settings.py**. + +Veamos como ejemplo, un sitio que queremos traducir al español. + +```python +# The LocaleMiddleware check's the incoming request for the +# user's preferred language settings. Add the LocaleMiddleware +# after SessionMiddleware and CacheMiddleware, and before the +# CommonMiddleware. +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', +) +# Provide a lists of languages which your site supports. +LANGUAGES = ( + ('en', _('English')), + ('es', _('Spanish')), +) +# Set the default language for your site. +LANGUAGE_CODE = 'en' +# Tell Django where the project's translation files should be. +LOCALE_PATHS = ( + os.path.join(BASE_DIR, 'locale'), +) +``` + +Si bien las instrucciones están documentadas a través de los comentarios, veamos los detalles: + +- **LocalMiddleware** debe estar después de **SessionMiddleware** y antes de **SessionMiddleware** +- **LANGUAGES** es una tupla de tuplas, donde cada una indica el código del lenguaje y un nombre detallado +- **LANGUAGE_CODE** es el lenguaje por defecto en el sitio +- **LOCALE_PATH** es la ruta donde se encuentran los archivos de traducción + + +## Marcar las cadenas de caracteres {#marcar-las-cadenas} + +En este punto, Django es capaz de determinar el lenguaje del usuario y ubicar los archivos de traducción. Para simplificar, siguiendo con el ejemplo de un sitio que queremos que esté disponible en español, veamos cómo marcar una cadena como traducible en un template. + + +```html +{% load i18n %} + +<h1>{% trans 'Title' %}</h1> +``` + +En esta instancia estamos haciendo dos cosas: + +- Indicamos que vamos a realizar trauducciones al incluir el tag *{% load i18n %}*. Esto se debe hacer al principio del arhivo, inclusive si el template extendie a otro que ya lo tiene. +- Además, marcamos la cadena **Title** como traducible + + +## Crear los archivos de traducción {#crear-archivos-de-traduccion} + +En este paso, una vez que marcamos los textos a traducir, creamos los archivos de traducción desde la línea de comando de la siguiente manera: + +``` +> python manage.py makemessages -l 'es' +``` + +Esto sencillamente crea un archivo **.po** dentro de **locale**. + +``` +locale/ + es/ + LOCALE_MESSAGES/ + django.po +``` + + +``` +#: your-template-or-py-file:the-line-number +msgid "Title" +msgstr "" +``` + +Y después de actualizar el archivo .po: + +``` +#: your-template-or-py-file:the-line-number +msgid "Title" +msgstr "Título" +``` + + +## Compilar las traducciones {#compilar-los-mensajes} + +Como último paso, es necesario entender que Django buscará las traducciones en un archivo compilado con extensión **.mo**. Este archivo nuevamente lo generamos desde la línea de comando: + +``` +> python manage.py compilemessages +``` + +Podemos ver el nuevo archivo generado en la misma ruta que el correspondiente **.po**. + +``` +locale/ + es/ + LOCALE_MESSAGES/ + django.po + django.mo +``` + +Una vez completado el primer paso, durante el proceso de traducción estaremos ciclando sobre el resto, es decir, marcando textos como traducibles, actualizando el **.po** y compilando las traducciones. + +Finalmente, cualquier texto generado en Django tiene que ser traducible, por lo que sólo hace falta algo de paciencia para ver cuál es el lugar adecuado. Esta reseña tomó como ejemplo, una cadena en un template, pero también es posible traducir cualquier sección del administrador de Django. diff --git a/bitblog/posts/empezando-a-usar-google-adwords-express.md b/bitblog/posts/empezando-a-usar-google-adwords-express.md new file mode 100644 index 0000000..e725797 --- /dev/null +++ b/bitblog/posts/empezando-a-usar-google-adwords-express.md @@ -0,0 +1,147 @@ +<!-- +.. title: Empezando a usar Google AdWords Express +.. slug: empezando-a-usar-google-adwords-express +.. date: 2018-03-01 14:24:36 UTC-03:00 +.. tags: adwordsexpress, google, comunicacion, sem, publicidad, marketing +.. category: comunicacion +.. link: +.. description: Empezando a usar Google AdWords Express para nuestras campañas +.. type: text +.. author: nespino +--> + +El día de hoy vamos a ver cómo empezar a usar [Google AdWords Express](https://adwords.google.com/express "Google AdWords Express"), aprovechando los descuentos que ofrecen y andan dando vueltas. En caso de no haber recibido uno, podés ponerte en contacto y hacer ruido de que tenés una empresa o un dominio o aparición en internet y te lo envían. + +Para empezar, les dejo el número de teléfono gratuito para asistencia a cuentas con inversiones de bajo monto (al día del a fecha, inversiones menores a $2500 ARS mensuales): + +> 0800-222-4664 + +Si la inversión supera ese monto, el número entonces será: + +> 0800-666-1866 ó 0800-666-0668 + +__A continuación, el tutorial empleará el signo $ para referirse a ARS (Pesos Argentinos)__ + + +## Empezando a usar Google AdWords Express + +Nos llegó por correo tradicional a las oficinas de Bitson, un código que otorgaba $700 de crédito en Adwords, con el único requisito de hacer un pago previo de $300. Pero como estábamos de suerte, también le llegó otro a @lecovi, donde el monto para el mismo requisito era de $175. Se pueden imaginar cuál de los dos usamos, de todas formas el camino a recorrer es exactamente igual. + +El código: + +> AHT9T-KURGR-A9MP + +Las condiciones detalladas: + +>- Activar o reactivar una cuenta en Google AdWords +>- Antes de los 14 días de dicha activación, ingresar el código en el [apartado correspondiente](https://adwords.google.com/aw/promotions "Ingresar cupones de descuento") +>- Usar $175 en publicidad +>- Abonar esos $175 a través de Banelco, PagoMisCuentas, tarjeta de débito o crédito ([https://billing.google.com/payments/u/0/paymentsinfofinder](https://billing.google.com/payments/u/0/paymentsinfofinder "Información de >pago")) +>- Esperar 5 días hábiles hasta que se acredite el beneficio, del cual cabe destacar, que el sistema no dará aviso. + +__AdWords tampoco emitirá ninguna clase de aviso cuando se acabe el crédito promocional, es necesario revisar periódicamente la cuenta para no generar deudas indeseables.__ + + +También es posible que ingresemos a un nuevo programa llamado AdWords Express. Tiene las mismas funciones y costos que AdWords tradicional, pero la interfaz gráfica es muchísimo más sencilla. ¡Altamente recomendado para principiantes! + +------------------------------------------ + + +## Configuración de la primer campaña en Google AdWords Express + +Estos son los datos que nos fueron requeridos. Es bastante intuitivo, y algunos no requieren explicación adicional... + +Sitio a difundir: <br /> +(La [URL](https://es.wikipedia.org/wiki/Localizador_de_recursos_uniforme "Significado de URL...") del sitio que queremos promocionar) +> [https://bitson.group/cursos/](https://bitson.group/cursos/ "Cursos de bitson") + +Objetivo: <br /> +(Qué es lo que esperamos que pase en nuestro sitio) +> Acción en el sitio web (registro en el formulario) + +Radio de acción:<br /> +(¿Dónde queremos que se muestre nuestro anuncio?) +> Mostrar el anuncio en un radio de 15km desde la empresa + +Para esto, se puede definir una dirección específica o vincular directamente con [Google My Business](https://www.google.es/intl/es/business/ "Google My Business"), que tomará la dirección automáticamente. +En base a esta configuración, AdWords nos presenta la siguiente estimación: + +> El tamaño de la audiencia potencial, será entonces de 18.424.498 personas por mes. + +Esto significa que se prevé que 18 millones de personas verán el anuncio. ¿Y tenemos que pagar por todo esto? Por supuesto que no, sólo pagaremos por cada click. A este costo se lo define como [CPC](https://support.google.com/adwords/answer/116495 "Costo por click") (Costo por click o Cost per click). Este valor está determinado por el ranking de nuestro anuncio y la oferta para el mismo tipo de anuncio en la misma región. En definitiva, este valor lo va a definir Google, y no podemos tomar control sobre eso, pero sí podemos limitar cuánto estamos dispuestos a pagar por ese click. En función de ese límite, se establecerá este ranking, lo que definirá en qué orden será mostrado en el navegador junto a las publicidades de la competencia. A todo este proceso complejo se lo llama subasta. Cuando muchos anunciantes compiten por la misma aparición de publicidad, AdWords seleccionará y mostrará únicamente a los anuncios de mayor ranking. + +En adelante, para acceder al panel de control, podemos hacerlo a través de [https://adwords.google.com/express/plus/](https://adwords.google.com/express/plus/ "Panel de Control de Google AdWords Express") + +# Definiendo el producto + +Se promociona: <br /> +(¿Qué clase de producto o servicio estamos ofreciendo?) +>Curso de programación + +Mostrar anuncio a personas que busquen:<br /> +(Listado de categorías relativas a nuestro producto o servicio) +>- Curso de Programación +>- Introducción a la programación web +>- Informática y Programación +>- Python + +Gracias a la información brindada, Google AdWords filtrará a los destinatarios de nuestro anuncio, de manera de no desperdiciar clicks (que paguemos por aquellas personas curiosas que entran sólo para ver qué es) y para no llenar las búsquedas de Google con publicidad no relevante para quien esté navegando. + +> El tamaño de la audiencia potencial, será entonces de 11.516 personas por mes. + +Diseño del anuncio:<br /> +(Dentro del formato ofrecido por AdWords, contamos con 3 renglones para atraer a nuestros clientes hacia nuestro sitio) +> Aprendé Python en bitson - Sumate a los que saben +> Anuncio bitson.group +> Aprovechá el año y arrancá en Febrero! Precio promocional + +Lo que nos da como resultado:<br /><br /> + +[![adwords curso bitson python][adwords-cursos-bitson]](https://bitson.group/cursos "Cursos en bitson") + +[adwords-cursos-bitson]: /img/adwords.png "Anuncio de Curso de Python en bitson" + + +------------------------ + +# ¿Cuanto vamos a invertir? + +Como primera prueba, decidimos invertir lo mínimo requerido para acceder a la asistencia telefónica, $2500 ARS mensuales. Por menos de ese valor la ayuda que recibís por teléfono es mínima, por el contrario, a partir de ese valor de inversión la asistencia es muy completa y por demás, agradable. + +> Inversión $82,24 ARS$ al día de media ($2500 al meś de máximo) + +> Rendimiento estimado: 996 - 1669 visualizaciones, 244 - 409 clics + +> <br /> +> Cuándo pagas + +> Solo pagarás cuando alguien haga clic en tu anuncio o llame a tu empresa. + +> <br /> +> Cuánto cuesta + +> Cada clic tiene un coste distinto, pero no gastarás más del presupuesto mensual que hayas establecido. + +><br /> +> Qué ocurre si cambias de idea + +> Prueba a publicar el anuncio sin compromiso, ya que puedes cambiar el presupuesto o cancelar su publicación en cualquier momento. + + +Para facilitar los pagos, dejé registrada una tarjeta de crédito, de manera que los pagos se hagan en forma automática. También es posible entrar a la sección de Facturación y emitir los pagos manualmente. + +--------------------- + +Les recomendamos aumentar el seguimiento sobre sus publicaciones, conectando nuestro sitio con [Google Analytics](https://www.google.com/analytics/ "Google Analytics"), usando el tag que ofrece Adwords Express. Para una mejor medición de nuestro sitio les recomendamos utilizar el [Píxel de seguimiento](https://developers.google.com/analytics/resources/concepts/gaConceptsTrackingOverview?hl=es-419 "Píxel de seguimiento"). + +# ¿Cómo hacer para recibir el dinero promocional? + +En nuestro caso, pasadas las 48hs de haber el pago mínimo requerido para la activación del cupón promocional ($175 ARS), nos apareció el crédito de $700 ARS en nuestra cuenta. + +¡OJO! Uno debe ser responsable a la hora de armar las campañas. Lo mejor es darles una fecha de comienzo y una de finalización, contemplando el costo diario, de manera que sepamos de antemano cuánto dinero estamos dispuestos a invertir en publicidad. Para Google AdWords, es suficiente con que hayan hecho click en nuestro anuncio para cargarlo en nuestra cuenta. ¿Es confiable? Podríamos decir que sí. El mismo AdWords te ofrece la posibilidad de analizar desde donde viene el tráfico, y armar estadísticas basado en distintos paramétros. Hay mucho para investigar al respecto, y muchas consideraciones a la hora de armar una campaña. + +Así fue que dimos nuestro primer curso en [bitson](https://bitson.group "bitson"), y que lo publicitamos a través de [Google AdWords](https://adwords.google.com/ "Google AdWords"). + + + + diff --git a/bitblog/posts/empezando-con-android-y-react-native.md b/bitblog/posts/empezando-con-android-y-react-native.md new file mode 100644 index 0000000..7ba8083 --- /dev/null +++ b/bitblog/posts/empezando-con-android-y-react-native.md @@ -0,0 +1,199 @@ +<!-- +.. title: Empezando con Android y React-Native +.. slug: empezando-con-android-y-react-native +.. date: 2018-02-27 18:43:18 UTC-03:00 +.. author: D +.. tags: +.. category: +.. link: +.. description: +.. type: text +--> + + +En este post vamos a configurar el ambiente en linux para empezar a programar aplicaciones +en react-native para android (iOS queda fuera por razones obvias :grimacing:) + +## Requisitos: + +- Internet (claramente). +- Conocimientos minimos sobre variables de entorno (como setearlas). +- Paciencia. + +## 1: Instalar Java + + +- Abrimos la terminal e instalamos java (version 8). + +``` +sudo apt-get update +sudo apt-get install openjdk-8-jdk +``` + +Una vez finalizado de instalar ejecutamos + +`java -version` + +Para ver si instalo correctamente y deberiamos ver algo similar a esto + +``` +openjdk version "1.8.0_151" +OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-1~deb9u1-b12) +OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) +``` + +## 2: Descargar e Instalar Android Studio + + +Paso simple vamos a este [link](https://developer.android.com/studio/index.html?hl=es-419) y descargamos +Android Studio (for linux). +Una vez que lo bajamos, extraemos la carpeta en `/opt/` y dentro de la carpeta `android-studio` ejecutamos el archivo `studio.sh`. + +Seleccionar la opcion que queramos si queremos importar configuraciones de instalaciones previas de Android Studio o no, click en OK. + +Aca es donde deciamos que habia que tener paciencia, el wizard de instalacion de Android Studio te va a guiar el resto del proceso, el cual incluye la descarga del SDK (Software Development Kit), componentes que son necesarios para el desarrollo de apps. Parece que se va a trabar pero simplemente hay que esperar a que baje todos los archivos, va a depender mucho de tu velocidad de internet. + +## 2.1: Librerias para PCs de 64-bit + + +Si tenes una pc con un SO de 64-bits tenes que instalarte estas librerias para poder trabajar. + +``` +sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386 +``` + + + +## 3: Descarga version de SDK en AS + + +Abrimos el android studio, creamos un proyecto (esto es obligatorio, pero no le den demasiada importancia no vamos a usarlo). Dejamos trabajar al IDE y en la consola vemos que nos va a pedir de updatar `gradle`, hacemos click e instalamos. Una vez terminado de instalar, vamos a `Tools > Android > SDK Manager` ahi vamos a seleccionar la version de Android con la que queremos trabajar (yo elijo la version 6 uds pueden elegir la que quieran). Despues vamos a la tab `SDK Tools` y nos fijamos que esten chequeadas las opciones `Android SDK Tools` y `Android SDK Platform-Tools` de no estarlas las chequeamos, e instalamos ambas o la que falte. + +## 4: Variables de entorno + + +Vamos a setear las variables de entorno para "decirle" al sistema donde ir a buscar las SDK-Tools. +Abrimos la terminal y escribimos: + +``` +export ANDROID_HOME=$HOME/Android/Sdk +export PATH=$PATH:$ANDROID_HOME/tools +export PATH=$PATH:$ANDROID_HOME/platform-tools +``` + +Si queres que queden fijas en la terminal modifica tu archivo `~/.bashrc` agregando esas 3 lineas al final y reiniciando la consola. +Para testear si expusimos bien las variables en una terminal ejecutamos el comando + +`adb --version` + +El comando adb es una herramienta dentro de los SDK-Tools simplemente vamos a ver si encuentra ese archivo pidiendole la version, la salida deberia verse parecida a esta: + +``` +Android Debug Bridge version 1.0.39 +Version 0.0.1-4500957 +Installed as /home/{USER}/Android/Sdk/platform-tools/adb +``` + +## 5: Android Virtual Device Manager + + +El Android Studio cuenta con un emulador de android que podemos ejecutar en la PC, muy util para desarrollar y debuguear. Dentro del AS vamos a `Tools > Android > AVD Manager` y cliqueamos `Create Virtual Device` esto va a crear un nuevo emulador, seleccionan el tipo de dispositivo que quieren, la version de Android (instalada previamente en el paso 3). Una vez creada van a ver en la lista de dispositivos que se encuentra el suyo y a la derecha dentro de la columna `Actions` hay un boton de play que les permite ejecutarla. + +## 5.1: Detalle sobre AVD + + +El emulador consume mucha RAM, lo cual va a ser que se realentice el proceso de buildear y de ejecutar la aplicacion, tambien presenta problemas en placas de video. Por ejemplo yo tengo una placa nVidia y para poder correr el AVD en mi maquina tuve que instalarme los drivers de linux de lo contrario el emulador abria y cerraba automaticamente. Les dejo el [link](https://wiki.debian.org/es/NvidiaGraphicsDrivers) para instalar los drivers de nVidia en debian, para los drivers de otras placas de video consulten con nuestro buen amigo google. + +## 6: Node.js & npm + + +Ya tenemos instalado y corriendo nuestro emulador de android en nuestra pc ahora bien la pregunta del millon...Como arrancamos a programar? +Simple, tenemos que bajarnos (para variar) `nodejs` y `npm`, son programas que nos van a permitir compilar nuestro codigo en JS y ejecutarlo como si fuera nativo, manos a la obra! +Para node vamos a la terminal de linux y ejecutamos: + +``` +curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - +sudo apt-get install -y nodejs +``` + +Eso basta para tener `node` y `npm` (node package manager) instalados en tu PC, para comprobarlo hacemos +`node -v && npm -v` + +La salida deberia ser similar a: +``` +v6.13.0 +3.10.10 +``` + +## 7: create-react-native-app + + +Muy bien, continuando con nuestro brevisimo post, en la terminal hacemos un `sudo npm i -g create-react-native-app` lo cual va a instalar un paquete de node de forma global (por eso sudo y por eso -g), para facilitarnos la creacion desde 0 de un proyecto en react native, dejo el [link](https://github.com/react-community/create-react-native-app) para que puedan ver el readme e interiorizarse mas si quieren. + +## 8: Ejecucion + + +Una vez instalado el paquete vamos al destino donde querramos instalar el proyecto y en una terminal hacemos `create-react-native-app rn-app` eso nos va a crear una app llamada rn-app (uds le pueden poner el nombre que quieran). Va a tardar un rato (otra vez), pero una vez que termine ya estamos listos para trabajar. Entramos a la carpeta `cd rn-app` y ejecutamos `npm start` en una consola y en otra `npm run android` si tenemos el emulador abierto la aplicacion se va a ejecutar en el mismo, sino va a fallar y salir. + +## 8.1: Ejecucion en dispositivo + + +Para este paso vamos a necesitar un cable usb y un celular (con android obviamente). +Vamos a habilitar el debug con USB en el celular, para eso hay que tener las opciones de desarrollador activadas, eso lo hacemos yendo a `Configuracion > Acerca de` y cliqueamos el numero de build 7 veces, despues volvemos a configuracion y vamos a tener las `Opciones de Desarrollador`, entramos y habilitamos el "Debug por USB". + +Enchufamos el celular a la computadora y seleccionamos la opcion de transferir fotos via PTP. + +En la terminal ejecutamos `lsusb` y obtenemos algo similar a esto: +``` +Bus 002 Device 007: ID 1004:631d LG Electronics, Inc. Optimus Android Phone (Camera/PTP Mode) +Bus 002 Device 003: ID 1a81:1006 Holtek Semiconductor, Inc. +Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub +Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 001 Device 003: ID 04f2:b1d6 Chicony Electronics Co., Ltd CNF9055 Toshiba Webcam +Bus 001 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub +Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub + +``` + +Esta claro que mi celular es: + +`ID 1004:631d LG Electronics, Inc. Optimus Android Phone (Camera/PTP Mode)` + +De la linea de arriba agarramos los primeros 4 digitos del dispositivo: + +`1004:631d` + +En este caso `1004` es el identificador para LG. + +Ingresamos lo siguiente en la consola: +``` +echo SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" | sudo tee /etc/udev/rules.d/51-android-usb.rules +``` + +Por ultimo hacemos un check para ver si el adb lo detecta en la consola: + +`adb devices` + +Y deberiamos ver algo similar (depende del dispositivo que tengan) + +``` +List of devices attached +LGD62093133844 device +``` +Ahora puden hacer en la carpeta de su `rn-app` `npm run android` y la aplicacion se va a abrir en su celular. COPADO! + +<hr /> + +Gracias por leer, cualquier consulta la pueden dejar escrita en el blog y la contestamos. + +Saludos, + +D. + +<hr /> +Fuentes y ayudas: + +- [Establishing a build enviorment](https://source.android.com/setup/initializing) +- [Install android studio](https://developer.android.com/studio/install.html) +- [Este link de stackoferflow](https://stackoverflow.com/questions/26256279/how-to-set-android-home-path-in-ubuntu-please-provide-the-steps) +- [Instalar node](https://nodejs.org/es/download/package-manager/#distribuciones-de-linux-basadas-en-debian-y-ubuntu) diff --git a/bitblog/posts/empezando-con-pipenv.md b/bitblog/posts/empezando-con-pipenv.md new file mode 100644 index 0000000..94952a0 --- /dev/null +++ b/bitblog/posts/empezando-con-pipenv.md @@ -0,0 +1,59 @@ +<!-- +.. title: Empezando con Pipenv +.. slug: empezando-con-pipenv +.. date: 2018-01-31 12:26:18 UTC-03:00 +.. tags: python pipenv virtualenv +.. category: dev python +.. link: +.. description: Introducción a Pipenv +.. type: text +.. author: lecovi +--> + +En este brevísimo artículo te explicamos cómo empezar a usar `pipenv`. + +# Instalado Pipenv + +`pipenv` es una herramienta para manejar paquetes y entornos virtuales de +manera sencilla en tu entorno de desarrollo. Te recomiendo que le eches un ojo +a la [Documentacion Oficila](http://pipenv.readthedocs.io/en/latest/). +Ahora te voy a mostrar cómo instalar `pipenv` y cómo usarlo en tus proyectos. + +<!-- TEASER_END --> + +## Instalar Pipenv + +La forma más fácil de instalar `pipenv` es a través de `pipsi`. Si no tenés +`pipsi` instalado, lo podés instalar con: + +```bash +$ curl https://raw.githubusercontent.com/mitsuhiko/pipsi/master/get-pipsi.py | python3 +``` +Para poder ejecutar desde la línea de comandos tenés que agregar a tu variable +de entorno `PATH` la ruta donde está el ejecutable de `pipsi`. + +Con `bash`: +```bash +export PATH=$PATH:~/.local/bin/pipsi +``` +Con `fish`: +```fish +set PATH $PATH ~/.local/bin/pipsi +``` + +Y después tenés que instalar `pew` y `pipenv`: + +```bash +$ pipsi install pew +$ pipsi install pipenv +``` + +### Comandos útiles + +- `pipenv --three install <paquete>`: instala <paquete> en el virtualenv. +- `pipenv --three install -r <archivo_de_requerimientos>`: instala los requerimientos en el virtualenv. +- `pipenv shell`: activa el virtualenv en la shell. +- `pipenv run <archivo>`: ejecuta <archivo> desde el virtualenv. +- `pipenv --rm`: borra el virtualenv. +- `pipenv --update`: actualiza `pip` & `pipenv`. +- `pipenv --venv`: muestra el PATH del virtualenv. diff --git a/bitblog/posts/evitando-las-malas-practicas.md b/bitblog/posts/evitando-las-malas-practicas.md new file mode 100644 index 0000000..72a515b --- /dev/null +++ b/bitblog/posts/evitando-las-malas-practicas.md @@ -0,0 +1,67 @@ +<!-- +.. title: Evitando las malas prácticas en Python +.. slug: evitando-las-malas-practicas +.. date: 2018-02-21 22:57:25 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: Abrunacci +--> + +Cuando uno empieza a programar en Python suele suceder que incurrimos en errores que son considerados +"leves" a nivel programación pero que a la hora de inspeccionar nuestro código y ver si cumple con las +[reglas PEP8](https://www.fing.edu.uy/inco/cursos/fpr/wiki/index.php/Python_PEP8) nos encontramos con +la sorpresa de que dudosamente una parte del código escrito logra aprobar el "examen". + +A continuación un breve listado de cosas que podés estar haciendo mal sin saber. + +<div class="img-with-text" style="text-align:justify; width: 720px;"> + <img src="https://static.simpsonswiki.com/images/4/46/KnifeSafetyBook.png" alt="10 'SI' y 500 'NO' de la seguridad con las navajas" style="margin:0; display:block;"/> + <p><code>No niego ni confirmo haber escrito este post solo para utlizar esta imágen.</code></p> +</div> + + + +* ##*Real programmers don't use TABs* + + >O sí, pero decídanse por uno y sigan siempre con ese. 4 espacios o TABs, pero si vamos variando las indentaciones + de nuestros módulos con unos y otros, no estaríamos cumpliendo con las primeras dos reglas de PEP8 + +* ##*Respete los espacios* + + > Evite dejar espacios en blanco en las siguientes situaciones: + + - Dentro de paréntesis curvos, llaves, o paréntesis rectos + - Antes de una coma o punto y coma + - Antes del paréntesis que abre la lista de argumentos en el llamado a una función + - Más de un espacio alrededor de una asignación del operador para alinearlo con otro + + +* ##*79 Máxima* + + A la hora de codear en Python debemos tener en cuenta el largo de las líneas ya que, como bien lo dice [el zen de python](http://www.python.org.ar/wiki/PythonZen "El Zen de Python"), + la legibilidad cuenta. + + Y para que podamos tener código mas legible, PEP8 recomienda que el máximo de caracteres por linea sean 79. + +* ##*KISS* + + Keep it simple, ~~stupid~~ Sir. + + > Las sentencias compuestas (varias instrucciones en la misma línea) son generalmente tomadas como malas prácticas de programación. + + Aunque a veces está bien poner if/for/while con una pequeña instrucción en la misma línea, no hacer esto para las declaraciones con múltiples instrucciones + +* ##*Usted tiene 1934 actualizaciones pendientes...* + + El código debería estar comentado y que esos comentarios no contradigan lo que la función esta haciendo. + El código mal comentado es peor que el que no lo está. Procuren mantener actualizados los comentarios para que cualquiera + que lo lea lo pueda interpretar correctamente y no tenga que adivinar qué es lo que hace cada función. + + + +Eso es todo por ahora, más adelante subiré otros consejos sobre Python. + +Saludos! diff --git a/bitblog/posts/freedcamp.md b/bitblog/posts/freedcamp.md new file mode 100644 index 0000000..979dc48 --- /dev/null +++ b/bitblog/posts/freedcamp.md @@ -0,0 +1,50 @@ +<!-- +.. title: Freedcamp +.. slug: freedcamp +.. date: 2018-08-15 11:55:30 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> +Freedcamp + +Como ya les contamos en Bitson estamos en una búsqueda por mejorar nuestra organización interna para mejorar nuestra eficiencia como equipo y nuestra relación con el cliente y sus requerimientos. + +Primero tuvimos que definir qué técnica usar para la gestión de proyectos y establecimos utilizar tableros siguiendo la idea de Kanban (link a kanban). Una vez resuelto eso analizamos qué herramientas usar y cuál es la mejor para nuestro caso. + +Determinamos nuestras necesidades. Lo más importante era encontrar una herramienta que permita la gestión de proyectos tanto de forma individual para incrementar la productividad personal y por otro lado coordinar proyectos entre todos los socios tanto para los que están en la oficina como para los que estamos lejos. + +Buscamos todas las herramientas de Project Management y fuimos descartando en nuestros casos las que no nos servían. Por eso es importante definir qué queremos y qué es útil y práctico para todos los miembros del equipo. + +Probamos Bitrix24 pero no nos convenció. La UI muy saturada y poco clara. De las Open Source probamos OrangeScrum. La UI un poco rebuscada y con fallas. Y Open Project no me permitía evaluar el conjunto de proyectos. Por eso ganó Freedcamp y hasta ahora los resultados son positivos. + +Freedcamp permite agrupar a todos los proyectos creados de manera más conveniente y poner una descripción que sirva para que todos los involucrados sepan de qué se trata el proyecto. + +La opción “manage projects” (gestión de proyectos) permite añadir o quitar miembros del proyecto. Hay tres opciones disponibles de usuario: administrador, usuario y cliente. Este último es muy útil cuando trabajas con diversos clientes. Ya que esta herramienta les puede servir para gestionar las tareas de cada proyecto de forma más transparente y con una comunicación más efectiva. + +También permite añadir aplicaciones a cada proyecto dependiendo de las necesidades de gestión. La gran mayoría son gratuitas aunque también hay algunas pagas. Igualmente el costo es accesible, y cuenta con 7 días de test. Algunas de estas aplicaciones pueden ser “To do’s”, “Discussions” (para registrar las conversaciones y guardar así el histórico en la herramienta), “Milestones” (o hitos del proyecto), “Calendar” (con sincronización con Google Calendar) , entre otras. + +Dentro de las características destacamos las que más usamos en nuestro caso. + +- Últimos cambios: podemos visualizar los cambios realizados por nosotros mismo o por algún otro socio. + +- To do list: escribimos las tareas que nos faltan para terminar los proyectos, añadimos una etiqueta de prioridad, y comentamos las de otros compañeros. + +- Gestor de documentos online: compartimos entre los socios los archivos más importantes o ponemos en común la última versión + +- Foro de discusión: debatimos las nuevas ideas, analizamos las ventajas y desventajas, encontramos soluciones y todo queda +registrado. + +- Gestor de tiempo: se puede escribir cuánto tiempo se ha tardado en realizar una tarea o poner el reloj en marcha. Es decir, cuando empieces a trabajar en una tarea específica dentro del proyecto pones en marcha el contador, y él se encargará de gestionar el tiempo que llevas trabajando. + +- Calendario, especialmente diseñado para destacar las fechas de entrega de los proyectos, puesto que siempre aparecerá en la parte derecha de la interfaz de Freedcamp recordando el evento. + +¡Recomendamos Freedcamp porque es sencillo, con una interfaz gráfica muy buena y gratis! + +¿Vos usas alguna otra herramienta? ¡Contanos en nuestros canalaes cuál y cómo fue tu experiencia! + + + diff --git a/bitblog/posts/historias-de-usuarios.md b/bitblog/posts/historias-de-usuarios.md new file mode 100644 index 0000000..f0e625e --- /dev/null +++ b/bitblog/posts/historias-de-usuarios.md @@ -0,0 +1,37 @@ +<!-- +.. title: Historias de usuarios +.. slug: historias-de-usuarios +.. date: 2018-07-26 10:56:09 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> + +#Historias de usuarios + +Hace más de un año comenzamos el camino de utilizar metodologías ágiles. El cambio significó modificar nuestra forma de trabajar e incluso nuestra cultura pero sabíamos que era el camino correcto en pos de buscar la eficiencia en nuestro trabajo. + +Trabajar con Scrum nos hizo conocer las “historias de usuarios”, las cuales se enfocan en definir lo que el usuario necesita hacer, sin describir el cómo, por lo que representa el inicio y no el final de las conversaciones. De esta manera dejamos atrás la forma menos práctica de levantar los requerimientos de los usuarios mediante documentación detallada que sólo representa el final de las conversaciones. + +Utilizando esta metodología se establece que el encargado de elaborar los elementos del Product Backlog es el Product Owner. Pero el Scrum Master +Sin embargo, el Scrum Master tiene la misión de colaborar con el equipo Scrum para que el Product Backlog sea claro. En nuestro caso utilizamos la historia de usuarios con la base de una [plantilla preestablecida](https://docs.google.com/spreadsheets/d/1MYYvXNzlVvkRYhLEw83IhosMJDhnAcsgh88GLw0CcIk/edit#gid=0 "plantilla preestablecida") +(¡Descargala!) + + + +Si usamos correctamente esta plantilla logramos tener un enunciado que nos ayudará a identificar los requerimientos de los usuarios ¡Tendremos el qué pero faltará el cómo! La frase quedará de la siguiente forma: Yo como un [Rol], necesito [Descripción de la funcionalidad], con la finalidad de [Descripción de la consecuencia]. + +Estos son lo elementos de la plantilla que utilizamos para crear el enunciado. + +- Identificador (ID) de la historia*: Código que identifica unívocamente a la historia en el Proyecto que se esté desarrollando. El formato debe ser elegido por el equipo. *esto es para una mejor clasificación +- Rol: Es el rol que está desempeñando el usuario cuando utiliza la funcionalidad que se está describiendo. Debe ser lo más específico posible. Por ejemplo: + - Yo como cliente registrado. + - Desempeñando el rol de cliente registrado. + - Como un cliente registrado. +- Funcionalidad: Representa la función que el rol quiere o necesita hacer en el sistema que se está desarrollando. Se puede diferenciar las acciones obligatorias de las opcionales utilizando las palabras puedo o necesito. Por ejemplo: + - Necesito realizar búsquedas de productos por categorías. + - Puedo seleccionar una categoría para ver el número de productos que tiene asociado. +- Razón / Resultados: Lo que el rol necesita lograr al ejecutar la acción. Este es el resultado de ejecutar la acción desde el punto de vista del rol. Este punto puede ser opcional, pues la historia puede documentarse sólo con la definición del rol y la acción (sin definir la consecuencia). diff --git a/bitblog/posts/indice-net-promoter-score-nps.md b/bitblog/posts/indice-net-promoter-score-nps.md new file mode 100644 index 0000000..1c1a74e --- /dev/null +++ b/bitblog/posts/indice-net-promoter-score-nps.md @@ -0,0 +1,20 @@ +<!-- +.. title: Índice Net Promoter Score (NPS) +.. slug: indice-net-promoter-score-nps +.. date: 2018-09-21 13:15:52 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> +#Índice Net Promoter Score (NPS) + +NPS (Net Promoter Score) es un indicador para medir la satisfacción de los clientes, y también podemos comprobar si los clientes están satisfechos hasta el punto de recomendar nuestros productos o servicios a sus amigos y allegados. + +Fue elaborado por un estudiante de Harward,[Fred Reichheld](http://www.netpromotersystem.com/speaking-engagements/fred-reichheld.aspx"Fred Reichheld") en el año 1993, mientras estaba trabajando para la consultoría [Bain & Company](https://www.bain.com/"Bain & Company"). Después de probar varios tipos de cuestionarios en su trabajo, Reichheld observó que de las preguntas utilizadas, la que mayor correlación establecía con la compra de productos eran las recomendaciones que hacían los clientes de estos. De este modo, esta pregunta sobre la recomendación del producto o servicio se ha convertido en la base del NPS. Posteriormente, en 2006 Fred Reichheld publicó su libro, [The Ultimate Question](http://www.netpromotersystemblog.com/2013/01/25/resumen-rapido-de-the-ultimate-question-2-0-la-pregunta-decisiva-2-0/ "The Ultimate Question"), con Rob Marke, generando gran aceptación y comenzando a usarse por multitud de empresas. + +Para medir la lealtad de los clientes, NPS formula una única pregunta: "¿Qué probabilidades hay de que recomienden nuestro producto a un amigo?" Tras plantearles esta pregunta, le pedimos a los clientes que la respondan a partir de un parámetro del 0 al 10, cuyos resultados son categorizados posteriormente por el sistema NPS en detractores (0-6), pasivos (7-8) y promotores (9-10). + +El NPS nos permite determinar cómo de contentos o descontentos están nuestros clientes y así poder adaptar nuestra estrategia empresarial hacia ciertos ámbitos y comparar continuamente nuestra empresa con nuestras competidoras, ya que una de las grandes ventajas del indicador es que ya es usado por muchas compañías que publican continuamente sus informes y con cuyos datos podemos compararnos. De este modo, con un buen enfoque, equipo y software adecuados pueden conseguirse grandes resultados que podrán repercutir en la estrategia futura y el crecimiento de la compañía. diff --git a/bitblog/posts/kanban.md b/bitblog/posts/kanban.md new file mode 100644 index 0000000..f65b33b --- /dev/null +++ b/bitblog/posts/kanban.md @@ -0,0 +1,37 @@ +<!-- +.. title: Kanban +.. slug: kanban +.. date: 2018-08-08 13:36:04 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> +Kanban + +Empezamos a utilizar Kanban hace ya seis meses y los resultados han sido muy positivos. Es un método que mejora la organización de la Cooperativa y es realmente fácil de aplicar a las necesidades diarias. + +El método Kanban, perfeccionado y ampliado por David J. Anderson es una alternativa muy popular para comenzar en la agilidad organizacional. En este artículo se describen sus elementos más importantes y cómo empezar a usarlo + +Kanban es una palabra japonesa que viene a significar cartel o panel, elemento clave de este método productivo. El sistema Kanban como tal surgió en Toyota, el fabricante japonés de automóviles, para organizar mejor su producción de vehículos dividiendo el proceso en fases bien delimitadas que se tenían que cubrir correctamente para pasar a la siguiente fase, garantizando así un producto de calidad. + +Luego este método ha sido ampliado por David J. Anderson, quien adaptó esta filosofía al desarrollo de software. Quienes estamos en este rubro sabemos que hay muchos puntos en común con el desarrollo industrial. Es decir, diferentes fases, equipos de trabajo y el requisito de que cada pieza del programa a crear funcione correctamente y sea de la mejor calidad posible. + +Esta versión moderna fue utilizada por primera vez en Microsoft, y desde entonces se aplicó a cientos de proyectos en todo el mundo ¡Y finalmente nos tocó a nosotros como organización! Por esto te contamos nuestra experiencia. + +El método Kanban recomienda usar un panel con tarjetas (que dan nombre al método) que definan cada tarea dividiéndola en columnas que indican cada fase del proyecto. + +Lo primero que necesitamos es un sitio físico en donde poder visualizar el trabajo. En nuestro caso utilizamos una pizarra porque es lo más práctico para corregir y para que quede a la vista de todos los socios. Igualmente hay varios programas que recomendamos como [Taiga](https://taiga.io/ "Taiga"), [Wekan](https://wekan.github.io/ "Wekan"), [Freedcamp](https://freedcamp.com/ "Freedcamp"). + +Una vez resuelto esto es importante destacar las fases del trabajo pero no hay que limitarnos solamente a una sección de “En progreso” sino también detallar todo lo que nos pueda servir para el desarrollo de nuestro producto o servicio. Identificar las otras fases nos ayuda a entender mejor el proceso y a identificar posibles problemas que surjan en esta fase. + +A medida que avanzamos nos surgió la inquietud de quién podría cambiar el ítem de un estado al otro ¿Todos podemos hacerlo? ¿Tenemos que estar presentes? ¿Elegimos a un responsable? Esas respuestas las fuimos respondiendo con la práctica. Para algunos items tenemos un referente, y otros tienen mayor libertad para todos los socios. Es importante determinar quién hace qué para que todos los socios determinen su trabajo y entiendan las reglas o especificaciones de cada caso. + +Es importante también identificar cada item y darle prioridad a los que así se determine. Las clases de servicio tienen características explícitas. Normalmente su urgencia se mide por el coste de retraso. Por ejemplo, en el caso de una fecha de entrega que si se retrasa puede costar dinero a la compañía, se utiliza una política distinta de si es una tarea mecánica que aporta poco valor a la organización. + +Descubrimos también que hay que limitar el trabajo en curso. Hacer muchas cosas a medias no sirve y la utilización del tablero nos sirve para visualizar si la tarea se ha terminado completamente. Este es uno de los pilares para un proyecto. + +Kanban no sólo mejoró la organización sino también el trabajo en equipo. La mejora debe ser acordada en equipo, al igual que la organización de los tableros y las tareas ¡Les recomendamos su utilización! + diff --git a/bitblog/posts/kimai.md b/bitblog/posts/kimai.md new file mode 100644 index 0000000..f390fcb --- /dev/null +++ b/bitblog/posts/kimai.md @@ -0,0 +1,29 @@ +<!-- +.. title: Kimai +.. slug: kimai +.. date: 2018-08-22 12:57:23 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> +Kimai + +En Bitson buscamos una herramienta que nos permita medir las horas de trabajo. Esto nos da la posibilidad de medir cuánto tiempo nos lleva un desarrollo y de aquí sacamos el valor del producto terminado (calculamos las horas invertidas) y también saber cómo va mejorando nuestro tiempo invertido. En nuestro caso también nos permite calcular el retiro (nuestro sueldo). + +En esa búsqueda encontramos [Kimai](https://www.kimai.org/"Kimai"). una aplicación web gratuita y de fuente abierta para medir el tiempo. Una de las principales características de Kimai es la posibilidad de acceder a su interfaz web, iniciar el cronómetro de una tarea y salir posteriormente de la aplicación. Kimai sigue contabilizando el tiempo internamente hasta que volvamos a acceder y detengamos de nuevo la cuenta. + +Kimai es un script, de código abierto y gratuito, que podemos instalarnos en un servidor local o en la web, en el que podemos gestionar el tiempo que pasamos en un determinado proyecto e imprimir los resultados según nuestra demanda, ya sea por fechas, por trabajos o por clientes. + +Desde su web nos indica que es necesario un servidor con soporte php y mysql, configurar los datos en /includes/conf.php y se nos generará las tablas en nuestra base de datos de forma automática una vez entremos desde nuestro navegador. Según anuncian en su web, es que no funciona con Internet Explorer, aunque funciona con Firefox y Safari. ¿Pero quién usa Internet Explorer? + +La función más importante que destacamos es la posibilidad de descargar reportes. De esta manera podemos medir y analizar qué es mejor para nosotros y cómo invertir nuestro tiempo de manera correcta. + +El servicio se encuentra disponible en más de 15 idiomas. Entre esos se encuentra inglés, alemán, español, italiano, entre otros. + +También permite la versión demo. Donde podes tener una primera impresión sobre el software y qué funcionalidad proporciona. + +A nosotros nos resulta muy útil y lo recomendamos. + diff --git a/bitblog/posts/origenes-del-scrum.md b/bitblog/posts/origenes-del-scrum.md new file mode 100644 index 0000000..1ecad41 --- /dev/null +++ b/bitblog/posts/origenes-del-scrum.md @@ -0,0 +1,27 @@ +<!-- +.. title: Orígenes del Scrum +.. slug: origenes-del-scrum +.. date: 2018-07-13 11:12:18 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> + + +#Orígenes del Scrum + +Primero lo primero ¿De dónde viene el término Scrum? Ikujiro Nonaka e Hirotaka Takeuchi publicaron en 1986 en la Harvard Business Review el artículo: “El nuevo nuevo juego para el desarrollo de productos”. Allí definieron el término Scrum basado en el avance de las formaciones en partidos de rugby. Pero la modalidad de trabajo ya existía en empresas tecnológicas como Hondo, Canon y Fuji-Xerox. Con los años fue evolucionando y se ha extendido a muchos sectores no sólo el tecnológico. + +Takeuchi And Nonoka explicaron lo siguiente: “el enfoque de “carrera de relevos” para el desarrollo de productos entra en conflicto con el objetivo de obtener la máxima velocidad y flexibilidad. En su lugar un enfoque como el rugby – donde el equipo intenta avanzar como equipo, enviando el balón hacia atrás y luego avanzar – sirve mejor a los desarrollos competitivos que se ven hoy en día”. Por eso Scrum y equipo auto organizado van siempre de la mano ¡Cooperativa y autogestión son sinónimos así que en nuestro caso para a utilizar esta metodología es muy enriquecedor. + +Esta metodología implica realizar entregas parciales y regulares del producto final, priorizadas por el beneficio que aportan al receptor del proyecto. s, donde se necesita obtener resultados pronto, donde los requisito. En la actualidad, los proyectos se desarrollan en contextos muy versátiles. Son más complejos que antes, frente a unas exigencias del cliente y del mercado mucho más variables, y con una incertidumbre elevada. Por eso, la aplicación del método Scrum se ha extendido como la pólvora en numerosos sectores, fuera del mundo del desarrollo de software. Por este motivo nosotros utilizamos y se recomienda para proyectos en entornos complejo. + +Asimismo le permite en cualquier momento realinear el software con los objetivos de negocio de su empresa, ya que puede introducir cambios funcionales o de prioridad en el inicio de cada nueva iteración sin ningún problema. + +¡Una gran metodología para implementar camino a la eficiencia! + + + diff --git a/bitblog/posts/pdf/Historias de usuarios - Historias de usuarios.pdf b/bitblog/posts/pdf/Historias de usuarios - Historias de usuarios.pdf new file mode 100644 index 0000000..fdd1a7c Binary files /dev/null and b/bitblog/posts/pdf/Historias de usuarios - Historias de usuarios.pdf differ diff --git a/bitblog/posts/pixel-de-seguimiento.md b/bitblog/posts/pixel-de-seguimiento.md new file mode 100644 index 0000000..5d2643c --- /dev/null +++ b/bitblog/posts/pixel-de-seguimiento.md @@ -0,0 +1,56 @@ +<!-- +.. title: Píxel de seguimiento +.. slug: pixel-de-seguimiento +.. date: 2018-05-21 15:34:00 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: maleCuervo +--> + +En este post voy a mostrar como agregar un píxel de Facebook y Google Analitycs a nuestro sitio web. + +¿Qué son y para qué sirven los píxeles de seguimiento? + +Los píxeles de seguimiento son una herramienta de análisis con la que podemos medir la eficacia de nuestras publicacines y entender las acciones que las personas realizan en nuestro sitio web. + +--- + +#Agregando píxel de Facebook + +Agregar el píxel de facebook a nuestra web es relativamente sencillo, basta con seguir los pasos que están en la propia documentación de facebook. Aquí les mostraremos ese paso a paso. + +![imagen](/img/pixel/intro-pixel.png) + +1) Vamos a la pestaña píxeles del administrador de anuncios, hacemos click en crear píxel e inmediatamente nos pide asignarle un nombre identificador, en este caso nuestro píxel se llama **bitson.** + +![imagen](/img/pixel/confi-pixel.png) + +2) A continuación ingresamos a las configuraciones del píxel y hacemos click en "Instala el código manualmente". + +![imagen](/img/pixel/instalacion-manual.png) + +3) En este momento nos muestra la pantalla con los pasos para terminar la configración. +Seleccionamos el código que nos brinda la configuración y lo pegamos en el encabezado de nuestras páginas, a las que le haremos seguimiento. + +![imagen](/img/pixel/script-facebook.png) + +--- + +#Agregando píxel de Google Analytics + +Para agregar este píxel debemos ingresar a [Google Analytics](https://developers.google.com/analytics "Google Analytics") aquí encontraremos las diferentes opciones de configuración que nos brinda esta herramienta, debemos elegir la opción de [Configurar Google Analytics](https://developers.google.com/analytics/devguides/collection/?hl=es-419 "Configurar Google Analytics"). + +![imagen](/img/pixel/google-analytics.png) + +Cuando accedemos con esta opción, acontinuación nos muestra que configuración esta disponible para ser usada. En nuestro caso vamos a usar la opción [gtag.js](https://developers.google.com/analytics/devguides/collection/gtagjs/?hl=es-419 "gtag.js"). + +![imagen](/img/pixel/gtag.png) + +Luego de esto, vamos a copiar el siguiente código, este fragmento que copiamos debe ser insertado después de la etiquet `<head></head>` en todas las páginas de nuestro sitio web. + +![imagen](/img/pixel/script-google.png) + +Esto es todo lo que necesitamos para realizar el seguimiento en nuestros sitios, controlando publicaciones e interacciones de nuestros visitantes, solo necesitamos hacer uso del código que nos brinda Facebook y Google Analytics. diff --git a/bitblog/posts/por-que-decidi-formar-parte-de-una-cooperativa.md b/bitblog/posts/por-que-decidi-formar-parte-de-una-cooperativa.md new file mode 100644 index 0000000..9890b7a --- /dev/null +++ b/bitblog/posts/por-que-decidi-formar-parte-de-una-cooperativa.md @@ -0,0 +1,26 @@ +<!-- +.. title: ¿Por qué decidí formar parte de una cooperativa? +.. slug: por-que-decidi-formar-parte-de-una-cooperativa +.. date: 2018-07-05 11:36:05 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: maleCuervo +--> + +#¿Por qué decidí formar parte de una cooperativa? + +Soy Maria Alejandra Cuervo, tengo 24 años, soy Colombiana y vivo en Buenos Aires hace 7 años. En este momento me encuentro cerca de culminar mi carrera en Analista de Sistemas. Quiero contarles por qué tomé la decisión de formar parte de Bitson + +La idea de trabajo que la mayoría de nosotrxs tiene es muy similar; realizamos tareas por las que recibimos un pago a cambio, todo en pos de cumplir con los objetivos que nos marca nuestrx jefe, o en el mejor de los casos, cumpliendo objetivos marcados por nosotrxs mismos. Por lo menos de esa manera lo percibía hasta hace unos meses atrás. +Es común encontrarnos en la zona de confort, donde estamos cómodos desempeñando nuestras labores diarias como empleadxs pero qué pasa si tenemos la oportunidad de salir de nuestra zona de confort. Por mi parte se resume a sentir miedo, ansiedad, y rodeada de una montaña de preguntas ¿Es para mi? ¿Es lo que realmente quiero? ¿Me permito decir que no? ¿Es un riesgo?. + +Ya que Bitson es una cooperativa de trabajo que se encarga del desarrollo de software y hardware a medida, y va de la mano con todo lo que aprendí en mi carrera, era más que un reto poder insertarme en el rubro de la informática desde el lado del cooperativismo, una oportunidad que tenía que aprovechar para poder poner en práctica los conocimientos adquiridos y desafiarme. + +Formar parte de una cooperativa nunca estuvo en mis objetivos a corto plazo, por lo que, recibir la propuesta para formar parte de una , fue una invitación que claramente me sacó del molde y acepte aun cuando no estaba enterada de cómo funcionaba. Mis primeros meses fueron de aprendizaje continuo. En una cooperativa de trabajo no existe jerarquía dada su horizontalidad, por lo tanto todos sus integrantes tienen derecho de entre otras cosas a opinar, debatir, aportar y planificar. Esto hace parte del día a día de una cooperativa, terreno que empezaba a gustarme. + +Tomar decisiones que afecten a todo el equipo, solidaridad, humanidad, pro actividad, todas cosas que estaban lejos de ser un campo que conociera pero que me generaba tanto interés. Me arriesgue y me adapté, un nuevo desafío: complementar al equipo, ayudar, cooperar, aportar, planificar, debatir, consensuar, reconfortar, acompañar. Por estas y otras tantas cosas más elegí ser parte de Bitson. Elegí ver a Bitson crecer de la mano de cada uno de mis socixs que da todo para que nos consolidemos como un grupo de trabajo fuerte y coordinado. + + diff --git a/bitblog/posts/por-que-emplear-la-tecnica-de-entrega-continua.md b/bitblog/posts/por-que-emplear-la-tecnica-de-entrega-continua.md new file mode 100644 index 0000000..1a4065d --- /dev/null +++ b/bitblog/posts/por-que-emplear-la-tecnica-de-entrega-continua.md @@ -0,0 +1,23 @@ +<!-- +.. title: ¿Por qué emplear la técnica de Entrega Continua? +.. slug: por-que-emplear-la-tecnica-de-entrega-continua +.. date: 2018-07-05 11:09:48 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> + +#¿Por qué emplear la técnica de Entrega Continua? + +La técnica de Entrega Continua (CD) trae como consecuencia mayor velocidad y menor complejidad en el proceso de desarrollo de software. A su vez, permite lanzamientos mucho más seguidos, proporcionando retroalimentación inmediata. + +Implementar este proceso suele ser difícil para las organizaciones esto se debe principalmente a que no es un cambio en el proyecto tecnológico sino un cambio organizacional. + +La entrega continua automatiza todo el proceso de publicación de software. Cada revisión efectuada activa un proceso automatizado que crea, prueba y almacena la actualización. Las pruebas pueden incluir pruebas de la UI, de carga, de integración, de fiabilidad de la API, etc. De este modo, los desarrolladores pueden validar las actualizaciones de forma más exhaustiva y descubrir problemas por anticipado. Con la nube, resulta sencillo y rentable automatizar la creación y replicación de varios entornos de pruebas, algo que anteriormente era complicado en las instalaciones. La decisión definitiva de implementarla en un entorno de producción en vivo la toma el desarrollador. + +Cuando se la entrega continua se implementa de manera adecuada, los desarrolladores dispondrán siempre de un artefacto listo para su implementación que se ha sometido a un proceso de pruebas estandarizado. Esto significa mayor autonomía para el desarrollado. + +Con la entrega continua, todos los cambios en el código se crean, se prueban y se envían a un entorno de almacenamiento o pruebas de no producción. Pueden efectuarse varias pruebas al mismo tiempo antes de la implementación en producción. La diferencia entre la entrega continua y la implementación continua es la diferencia de aprobación manual para actualizar la producción. Con la implementación continua, la producción tiene lugar de manera automática, sin aprobación explícita. diff --git a/bitblog/posts/preprocesando-datos-para-machine-learning.md b/bitblog/posts/preprocesando-datos-para-machine-learning.md new file mode 100644 index 0000000..78737cf --- /dev/null +++ b/bitblog/posts/preprocesando-datos-para-machine-learning.md @@ -0,0 +1,216 @@ +<!-- +.. title: Preprocesando datos para Machine Learning +.. slug: preprocesando-datos-para-machine-learning +.. date: 2018-06-11 02:30:15 UTC-03:00 +.. tags: python, machine learning, scikit, numpy, scipy, artificial inteligence, inteligencia artificial, ai, ia, preprocessing +.. category: Programación +.. link: +.. description: Cómo preprocesar datos para Machine Learning usando la librería scikit en Python +.. type: text +.. author: nespino +--> + +A todos nos gustaría llegar a casa y que la cena esté lista. A los algoritmos de [Machine Learning](https://es.wikipedia.org/wiki/Aprendizaje_autom%C3%A1tico "¿Qué es Machine Learning?") también, por eso es que hoy vamos a dejarles cuatro recetas para que puedan alimentar en forma eficiente a sus procesos de entrenamiento. + +Las recetas que repasaremos el día de hoy son: + +* Binarización +* Eliminación del valor medio +* Escalando +* Normalización + +> Cada caso puede requerir el uso de uno o más de estos métodos en forma combinada. + +Para simplificarnos las tareas matemáticas, vamos a hacer uso de dos paquetes [Open Source](https://es.wikipedia.org/wiki/Software_libre_y_de_c%C3%B3digo_abierto "Diferencias entre Software Libre y Código Abierto") para desarrollos científicos: + +* [Numpy](http://www.numpy.org/ "Numpy"), el cual se puede instalar junto a las de herramientas de [SciPy](https://www.scipy.org/install.html "¿Cómo instalar SciPy?") +* El paquete de aprendizaje de Machine Learning [scikit](http://scikit-learn.org/stable/install.html "Scikit Learn") + +Ambos se pueden instalar fácilmente desde **pip** con los siguientes comandos: + +> pip install scipy + +> pip install scikit-learn + +Primero vamos a importar las librerías necesarias y definir una matriz de ejemplo en numpy para usar en cada uno de los métodos que explicaremos a continuación + +> import numpy as np + +> from sklearn import preprocessing + +> + +> matriz_ejemplo = np.array([[2.3, 2.9, -1.3, 5.2], + +>                          +                   [1.3, -3.8, 2.1, 4.3], + +>                          +                   [-8.9, 2.4, -1.1, 0], + +>                          +                   [4.1, -3.9, 2.5, 2.1]]) + + +# Binarización + +Este método es comparable al que utilizan las entradas de las [Compuertas Lógicas](https://es.wikipedia.org/wiki/Puerta_l%C3%B3gica "Compuertas Lógicas") con las que están hechas todos nuestros dispositivos electrónicos, en el que, habiendo definido un valor de umbral, podemos separar a los datos que ingresan de manera que los menores a ese umbral correspondan a 0 (False) y los mayores correspondan a 1 (True). Vamos a transformar esos valores numéricos en valores booleanos, usando un umbral de 2.4 con la función Binarizer: + +> matriz_binarizada = preprocessing.Binarizer(threshold=2.4).transform(matriz_ejemplo) + +> print("Matriz binarizada:\n", matriz_binarizada) + +y el resultado será: + +> Matriz binarizada: + +>   [[0. 1. 0. 1.] + +>   [0. 0. 0. 1.] + +>   [0. 0. 0. 0.] + +>   [1. 0. 1. 0.]] + +Observen que el segundo elemento de la tercer fila de la matriz de ejemplo es 2.4, y al binarizarlo con el umbral 2.4 se obtiene un 0 en la misma posición. + +*Pueden encontrar el código completo de este método en el archivo de ejemplo <a href="/code/ai/binarizacion.py" download>binarizacion.py</a>.* + +# Eliminación del valor medio + +Este método es muy usado en preprocesamiento de datos para Machine Learning, con el cual se elimina el sesgo de las características en nuestro vector característico. La función que nos permite esta transformación se llama **scale** y es muy sencilla de usar. Para verificar los resultados paso a paso incluímos algunos **prints**. + +> print("Matriz de ejemplo:") + +> print(matriz_ejemplo) + +> print("Promedio =", matriz_ejemplo.mean(axis=0)) + +> print("Desviación típica =", matriz_ejemplo.std(axis=0)) + +>   + +> promedio_eliminado = preprocessing.scale(matriz_ejemplo) + +> print("\nMatriz procesada:") + +> print(promedio_eliminado) + +> print("Promedio =", promedio_eliminado.mean(axis=0)) + +> print("Desviación Típica =", promedio_eliminado.std(axis=0)) + +Lo que debería darnos como resultado: + +> Matriz de ejemplo: + +>  [[ 2.1 2.9 -1.3 5.2] + +>  [ 1.3 -3.8 2.1 4.3] + +>  [-8.9 2.4 -1.1 0. ] + +>  [ 4.1 -3.9 2.5 2.1]] + +> Promedio = [-0.35 -0.6 0.55 2.9 ] + +> Desviación típica = [5.04058528 3.25499616 1.75712834 2.01866292] + +>   + +> Matriz procesada: + +>  [[ 0.48605467 1.07527009 -1.05285423 1.13936803] + +>  [ 0.32734294 -0.98310408 0.88212111 0.69352837] + +>  [-1.69623159 0.92166007 -0.93903215 -1.43659447] + +>  [ 0.88283399 -1.01382608 1.10976527 -0.39630192]] + +> Promedio = [ 0.00000000e+00 0.00000000e+00 -1.11022302e-16 4.16333634e-17] + +> Desviación Típica = [1. 1. 1. 1.] + +Como pueden observar el promedio en la matriz procesada está cerca de 0 y la desviación típica es 1. + +*Pueden encontrar el código completo de este método en el archivo de ejemplo <a href="/code/ai/eliminar_valor_medio.py" download>eliminar_valor_medio.py</a>.* + + +# Escalando + +Es posible que nuestro vector característico incluya valores extremadamente altos y/o extremadamente bajos, por eso es importante escalar esos valores para que nuestro algoritmo opere con valores cercanos, y así evitamos características con valores desorbitantes. + +> datos_escalados = preprocessing.MinMaxScaler(feature_range=(0, 1)) + +> datos_escalados = datos_escalados.fit_transform(matriz_ejemplo) + +> print("Datos escalados:\n", datos_escalados) + +Podemos comprobar que cada fila fue escalada para que sus valores mínimos y máximos sean 0 y 1 respectivamente, y los demás se transformaron en forma proporcional: + +> Datos escalados: + +>  [[0.84615385 1.                 0. +                1.                  ] + +>   [0.78461538  0.01470588 0.89473684 0.82692308 ] + +>   [0.                  0.92647059 0.05263158 0. +                ] + +>   [1.                  0. +                1. +                0.40384615 ]] + +*Pueden encontrar el código completo de este método en el archivo de ejemplo <a href="/code/ai/escalando.py" download>escalando.py</a>.* + + +# Normalización + +La normalización se usa para modificar los valores en el vector característico y así poder medirlos en una escala común. Existen varios métodos para esto, así que vamos a presentarles los dos más comunes. + +__Normalización L1__: Busca las menores desviaciones absolutas, y funciona asegurándose que la suma de los valores absolutos en cada fila sea 1. + +__Normalización L2__: Busca los menores cuadrados, y funciona asegurándose que la suma de los cuadrados sea 1. + +En general el método de Normalización L1 se considera más robusto que el de Normalización L2, porque el primero es más resistente a valores atípicos en los datos de origen. Es frecuente encontrar valores atípicos y no hay nada que podamos hacer al respecto, por eso buscamos técnicas que los ignoren de forma segura y efectiva durante los cálculos. En cambio, si los valores atípicos son importantes para el problema que estamos resolviendo, podríamos inclinarnos a usar la Normalización L2. + +> datos_normalizados_l1 = preprocessing.normalize(matriz_ejemplo, norm='l1') + +> datos_normalizados_l2 = preprocessing.normalize(matriz_ejemplo, norm='l2') + +> print("Datos con Normalización L1:\n", datos_normalizados_l1) + +> print("\nDatos con Normalización L2:\n", datos_normalizados_l2) + +Usamos la función **normalize**, indicando el tipo de normalización, y así podremos apreciar la diferencia por pantalla: + +> Datos con Normalización L1: + +> [[ 0.1826087 0.25217391 -0.11304348 0.45217391] + +> [ 0.11304348 -0.33043478 0.1826087 0.37391304] + +> [-0.71774194 0.19354839 -0.08870968 0. ] + +> [ 0.32539683 -0.30952381 0.1984127 0.16666667]] + +>   + +> Datos con Normalización L2: + +> [[ 0.32578702 0.44989636 -0.20167768 0.80671072] + +> [ 0.20808658 -0.60825309 0.33613986 0.68828639] + +> [-0.95870891 0.25852824 -0.11849211 0. ] + +> [ 0.62758369 -0.59696986 0.38267298 0.32144531]] + + +*Pueden encontrar el código completo de este método en el archivo de ejemplo <a href="/code/ai/normalizacion.py" download>normalizacion.py</a>.* + +Espero que con estos métodos le den un merecido banquete a sus algoritmos, y que tengan ustedes una deliciosa y nutritiva cena. + + diff --git a/bitblog/posts/scrum-como-aplicarlo.md b/bitblog/posts/scrum-como-aplicarlo.md new file mode 100644 index 0000000..bfc16db --- /dev/null +++ b/bitblog/posts/scrum-como-aplicarlo.md @@ -0,0 +1,39 @@ +<!-- +.. title: SCRUM ¿Cómo aplicarlo? +.. slug: scrum-como-aplicarlo +.. date: 2018-08-02 10:49:14 UTC-03:00 +.. tags: +.. category: +.. link: +.. description: +.. type: text +.. author: cuberti +--> + +#SCRUM ¿Cómo aplicarlo? + +Ya conocemos qué es [Scrum](http://blog.bitson.group/posts/origenes-del-scrum/ 'Scrum') pero ahora falta profundizar sobre qué fases tiene esta metodología. + +En Scrum un proyecto se ejecuta en ciclos temporales cortos y de duración fija (sprint -iteraciones- que normalmente son de 2 semanas, aunque en algunos equipos son de 3 y hasta 4 semanas, límite máximo de feedback de producto real y reflexión). Cada sprint tiene que proporcionar un resultado completo, un incremento de producto final que sea susceptible de ser entregado con el mínimo esfuerzo al cliente cuando lo solicite. + +Dentro de cada sprint tenemos las siguientes etapas. + +- Planificación del sprint: duración, objetivo y cómo realizarlo. + +- Scrum diario. Se basa en poner en común y sincronizar actividades para elaborar el plan del día. +Trabajo de desarrollo durante el sprint. Nos aseguramos que los objetivos se están cumpliendo, que no se producen cambios que alteran el objetivo del sprint y se mantiene un feedback constante con el cliente o dueño del proyecto. + +- Revisión del sprint. Reunión con el cliente o dueño del proyecto, en la que se estudia y revisa el Product Backlog del sprint. Se definen los aspectos a cambiar, en caso necesario, de mayor valor o probables para planificarlo en el siguiente Sprint. + +- Retrospectiva del proyecto. Oportunidad del equipo de desarrollo para mejorar su proceso de trabajo y aplicar los cambios en los siguientes sprints. + +Utilizar esta metodología también significa definir roles y responsabilidades para los implicados. Son los siguientes: + +###Project Owner: +Se asegura de que el proyecto se esté desarrollando acorde con la estrategia del negocio. Escribe [historias de usuario](http://blog.bitson.group/posts/historias-de-usuarios/ 'historias de uuario'), las prioriza, y las coloca en el Product Backlog. + +###Srcum Master: +Elimina los obstáculos que impiden que el equipo cumpla con su objetivo. Su misión es que los equipos de trabajo alcancen sus objetivos hasta llegar a la fase de “sprint final”, eliminando cualquier dificultad que puedan encontrar en el camino. + +###Equipo: +Los encargados de crear el producto para que pueda estar listo con los requerimientos necesarios. diff --git a/bitblog/posts/usando-python-en-funciones-de-postgresql.md b/bitblog/posts/usando-python-en-funciones-de-postgresql.md new file mode 100644 index 0000000..18bcd6a --- /dev/null +++ b/bitblog/posts/usando-python-en-funciones-de-postgresql.md @@ -0,0 +1,72 @@ +<!-- +.. title: Usando Python en funciones de Postgresql +.. slug: usando-python-en-funciones-de-postgresql +.. date: 2018-06-05 23:57:46 UTC-03:00 +.. tags: postgresql python functions sql bitson +.. category: Database tricks +.. link: +.. description: Usando Python dentro de Postgresql +.. type: text +--> + + +Usando Python en funciones de Postgresql + +Además de ser súper robusto a muy bajo costo, Postgresql, posee una muy buena característica, que es poder generar distintos tipos de funciones haciendo uso del lenguaje procedural, en este caso vamos a hablar de PL/Python, el cual, como pueden deducir por el titulpo del post, nos permite escribir codigo python dentro de las funciones. + +En el post de hoy nos vamos a concentrar en dejar la extensión disponible para una base de datos en particular y también haremos un pequeño ejemplo de uso para poder sacarnos las ganas. +<!-- TEASER_END --> + +#_Algunas cuestiones que debemos tener en cuenta:_ + +Si queremos utilizar explícitamente Python 2.7 (No entiendo bien porque alguien lo haría, pero lo explico igual) debemos llamar a la extensión ‘plpython2u’ +De igual manera, si queremos usar Python 3, debemos llamar a la extensión ‘plpython3u’ + +Por una cuestión de calendario (ya estamos en el 2018) y de sentido común (python 2 debe morir) nos vamos a focalizar en Python 3. + +# Instalando... + +Como primer paso, deberemos instalar el PLPythonu para dejarlo disponible en nuestra base de datos. + +Lo instalamos con apt-get y definimos que motor de postgresql tenemos instalado, en mi caso uso Postgresql 9.6 así que instalo de la siguiente manera: + +```SHELL +sudo apt-get install postgresql-plpython3-9.6 +``` + +Nota: para saber la version instalada e postgres, desde una consola hacemos: +```SQL +SELECT version(); +``` +# Preparando el entorno + +Una vez instalada la extensión la dejamos disponible para nuestra base de datos, para ello lo hacemos asi: +‘CREATE EXTENSION plpython3u’ + +con eso deberia ser suficiente para generar una funcion en la base de datos que en su interior tenga codigo python. + +# 1,2,3... Probando + +Como prueba podemos usar la siguiente funcion: + +```SQL +CREATE FUNCTION pymax (a integer, b integer) + RETURNS integer +AS $$ + if (a is None) or (b is None): + return None + if a > b: + return a + return b +$$ LANGUAGE plpythonu; + +-- Llamo a la función: +SELECT pymax(2, 3); +-- devuelve 3 + +``` + +#Referencias y algunos ejemplos mas: +- [Documentacion Oficial](https://www.postgresql.org/docs/9.6/static/plpython-funcs.html) +- [Pagina de Python Argentina](http://www.python.org.ar/wiki/PlPython) + diff --git a/bitblog/themes.backup/canterville/assets/img/abrunacci.png b/bitblog/themes.backup/canterville/assets/img/abrunacci.png new file mode 100644 index 0000000..5bc2cc3 Binary files /dev/null and b/bitblog/themes.backup/canterville/assets/img/abrunacci.png differ diff --git a/bitblog/themes.backup/canterville/assets/img/d.png b/bitblog/themes.backup/canterville/assets/img/d.png new file mode 100644 index 0000000..a048334 Binary files /dev/null and b/bitblog/themes.backup/canterville/assets/img/d.png differ diff --git a/bitblog/themes.backup/canterville/assets/img/hbrunacci.png b/bitblog/themes.backup/canterville/assets/img/hbrunacci.png new file mode 100644 index 0000000..02d52a1 Binary files /dev/null and b/bitblog/themes.backup/canterville/assets/img/hbrunacci.png differ diff --git a/bitblog/themes.backup/canterville/assets/img/mesmer.png b/bitblog/themes.backup/canterville/assets/img/mesmer.png new file mode 100644 index 0000000..52ce32a Binary files /dev/null and b/bitblog/themes.backup/canterville/assets/img/mesmer.png differ diff --git a/bitblog/themes.backup/canterville/assets/img/nespino.png b/bitblog/themes.backup/canterville/assets/img/nespino.png new file mode 100644 index 0000000..2d8c0f0 Binary files /dev/null and b/bitblog/themes.backup/canterville/assets/img/nespino.png differ