From 869e0b4529b11ff78a2350bf6394473fa2c837b3 Mon Sep 17 00:00:00 2001 From: jolav Date: Tue, 10 Sep 2024 16:58:18 +0200 Subject: [PATCH] varios, expressjs, js-snippets, nodejs, nodejs-snippets, nodejs-bbdd --- docs/expressjs.md | 2 +- docs/javascript-snippets.md | 36 ++ docs/nodejs-bases-de-datos.md | 827 ++++-------------------- docs/nodejs-snippets.md | 10 +- docs/nodejs.md | 120 +--- www/404.html | 2 +- www/css/index.html | 2 +- www/debian/index.html | 2 +- www/expressjs/index.html | 4 +- www/frontend/index.html | 2 +- www/golang-bases-de-datos/index.html | 2 +- www/golang-para-web/index.html | 2 +- www/golang-snippets/index.html | 2 +- www/golang/index.html | 2 +- www/html/index.html | 2 +- www/index.html | 2 +- www/javascript-apis/index.html | 2 +- www/javascript-para-web/index.html | 2 +- www/javascript-snippets/index.html | 44 +- www/javascript/index.html | 2 +- www/nodejs-bases-de-datos/index.html | 918 +++++---------------------- www/nodejs-snippets/index.html | 12 +- www/nodejs/index.html | 127 ++-- www/reactjs/index.html | 2 +- www/search/search_index.json | 2 +- www/sitemap.xml | 38 +- www/sitemap.xml.gz | Bin 325 -> 325 bytes www/varios/index.html | 2 +- 28 files changed, 480 insertions(+), 1690 deletions(-) diff --git a/docs/expressjs.md b/docs/expressjs.md index a379e88..ea5738d 100644 --- a/docs/expressjs.md +++ b/docs/expressjs.md @@ -1,4 +1,4 @@ -# EXPRESS 4.16.X +# EXPRESS 4.20.X --- diff --git a/docs/javascript-snippets.md b/docs/javascript-snippets.md index ef8d4b3..e37fa18 100644 --- a/docs/javascript-snippets.md +++ b/docs/javascript-snippets.md @@ -119,6 +119,42 @@ function objectIsEmpty(obj) { --- +## FETCH + +```js +async function fetchData(c, data) { + const options = { + timeout: c.timeout, + host: c.host, + port: c.port, + path: c.api, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept-Charset': 'utf-8' + }, + body: new URLSearchParams({ + 'key': c.API_KEY, + 'data': JSON.stringify(data) + }), + }; + const url = c.API_URL + c.API_ENDPOINT; + try { + const response = await fetch(url, options); + if (response.ok) { + const data = await response.json(); + return data; + } else { + throw new Error(response.status + " " + response.statusText); + } + } catch (err) { + console.log('ERROR fetchData => ', err); + } +} +``` + +--- + ## AJAX REQUESTS ### GET diff --git a/docs/nodejs-bases-de-datos.md b/docs/nodejs-bases-de-datos.md index b5a726e..1e5c045 100644 --- a/docs/nodejs-bases-de-datos.md +++ b/docs/nodejs-bases-de-datos.md @@ -3,7 +3,138 @@ --- -## MYSQL +## SQLITE + +### driver + +[better-sqlite3](https://github.com/WiseLibs/better-sqlite3) + +### backups + +Al activar pragma('journal_mode=WAL'), en vez de un archivo hay 3 para la DB. +`nombre.db3` +`nombre.db3-shm` +`nombre.db3-wal` + +Para hacer un backup sin riesgo consolidando los tres archivos +```sh +apt install sqlite3 +sqlite3 myArchivo.db3 ".backup backup-MyArchivo.db3" +``` + +### Select, Replace e Insert + +```js +/* */ +const options = {}; + +import sqlite3 from 'better-sqlite3'; +const myDB = new sqlite3('./path/to/databaseFile.db3', options); +myDB.pragma('journal_mode = WAL'); + +const store = { + + table1: "table1", + readTable1: function () { + const sql = `SELECT * FROM ${this.table1}`; + const stmt = myDB.prepare(sql); + const rows = stmt.all(); + return rows.map(function (row) { + return { + server: row.server, + data: row.data + }; + }); + }, + saveTable1: function (req) { + const data = req.body.data; + const server = req.body.server; + if (!server || !data) { + return; + } + const sql = `REPLACE INTO ${this.table1} (server, data) + VALUES (?, ?)`; + const stmt = myDB.prepare(sql); + stmt.run(server, data); + }, + + table2: "table2", + readTable2: function () { + const sql = `SELECT * FROM "${this.table2}"`; + const stmt = myDB.prepare(sql); + const rows = stmt.all(); + return rows.map(function (row) { + return { + day: row.day, + alexa: row.alexa, + loc: row.loc, + stars: row.stars, + proxy: row.proxy, + headers: row.headers, + weather: row.weather, + geoip: row.geoip, + video2gif: row.video2gif, + sp500: row.sp500, + tetris: row.tetris, + random: row.random, + }; + }); + }, + readTodayTable2: function () { + const today = new Date().toISOString().split('T')[0]; + const sql = `SELECT * FROM "${this.table2}" WHERE day = ?`; + const stmt = myDB.prepare(sql); + const rows = stmt.all(today); + return rows[0]; + }, + saveTable2: function (data) { + const inserts = [ + data.day, + data.alexa, + data.loc, + data.stars, + data.proxy, + data.headers, + data.weather, + data.geoip, + data.video2gif, + data.random, + ]; + const sql = ` + INSERT INTO "${this.table2}" + (day, alexa, loc, stars, proxy, headers, weather, + geoip, video2gif, random) + VALUES (?, 0, 0, 0, 0, 0, 0, 0, 0, 0) + ON CONFLICT(day) DO UPDATE SET + alexa = ?, + loc = ?, + stars = ?, + proxy = ?, + headers = ?, + weather = ?, + geoip = ?, + video2gif = ?, + random = ? + `; + const stmt = myDB.prepare(sql); + stmt.run(inserts); + }, +}; + +export { + store +}; + +``` + +## MYSQL 8 + +### driver + +[documentacion](https://sidorares.github.io/node-mysql2/docs) +[github](https://github.com/sidorares/node-mysql2) + +## MYSQL 5 (desactualizado) ### driver @@ -299,699 +430,5 @@ const db = { --- -## REDIS 4.0.X - -### driver - -```sh -npm install redis -``` - -### test - -```js -const redis = require('redis'); -// default redis.createClient() will use 127.0.0.1 and port 6379 -const client = redis.createClient(); -// custom -const client = redis.createClient(port, host); - -client.on('connect', function() { - console.log('Redis OK'); -}); - -client.on('error', function (err) { - console.log('Error => ' + err); -}); -``` - ---- - -## MONGODB 3.6.X - -### Instalar - -```sh -apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv -2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5 -nano /etc/apt/sources.list // strectch repo not yet -deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.6 main -apt-get update -apt-get install mongodb-org -``` - -[create systemd service](https://jolav.github.io/chuletas/debian/#systemd) -``` -[Unit] -Description=High-performance, schema-free document-oriented database -After=network.target -Documentation=https://docs.mongodb.org/manual - -[Service] -Restart=on-failure -User=mongodb -Group=mongodb -ExecStart=/usr/bin/mongod --quiet --auth --config /etc/mongod.conf - -[Install] -WantedBy=multi-user.target -``` - -* **Desinstalar** - -```sh -service mongod stop -apt-get purge mongodb-org* -rm -r /var/log/mongodb -rm -r /var/lib/mongodb -``` - -### Configurar - -```sh -nano /etc/mongod.conf -bindIp : X.X.X.X -// 127.0.0.1 only localhost -// 0.0.0.0 any Ipv4 allowed -``` - -* **crear usuarios** -```sh -$ mongo -> use admin -> db.createUser({user:"adminUser",pwd:"password" -> ,roles:[{role:"root",db:"admin"}]}) - -$ mongo -u 'adminUser' -p 'password' --authenticationDatabase 'admin' -> use some_db -> db.createUser({user: "username",pwd: "password",roles: ["readWrite"]}) -``` - -### Snippets - -#### driver - -[3.0.1 - https://github.com/mongodb/node-mongodb-native](https://github.com/mongodb/node-mongodb-native) - -`npm install --save mongodb` - -```js -const mongo = require('mongodb'); -connection="mongodb://user:password@database.host.com:port/database" -``` - -#### test - -```js -// try - catch doesnt work because of asynchronous -function testDB () { - mongo.connect(connection, function (err, db) { - if (err) return console.log(err); - console.log('Connected to database ... OK'); - db.close(); - }); -} -``` - -#### configurar la conexion - -```js -let c = { - connection: process.env.DB_URI, - dbname: process.env.DB_NAME, - collectionName: collectioName -}; -``` - -#### buscar - -* **Buscar solo uno** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.findOne({'field': value}, function (err, result) { - const id = mongo.ObjectID(id); - collection.findOne({ '_id': id }, function (err, result) { - if (err) throw err; - db.close(); - cb(result); - }); -}); -``` - -```js -function getBook (c, bookid, cb) { - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) throw err; - const database = db.db(c.dbname); - const collection = database.collection(target); - collection.findOne({ '_id': parseInt(bookid) }, - function (err, result) { - if (err) throw err; - db.close(); - if (!result) { - const err = { - message: 'no book exists', - status: 400 - }; - return cb(err); - } - cb(result); - }); - }); -} - -``` - -* **buscar** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.find({ 'field': value }, {}).next(function (err, result) { - if (err) throw err; - db.close(); - cb(result); - }); -}); - -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.find({}, {projection: {'_id': 0}} - .toArray(function (err, result) { - if (err) throw err; - db.close(); - cb(result); - }); -}); - -// eq => equal -// gte => greater or equal -// gt => greater -// in => in array -// lt => less than -// lte => less or equal -// ne => not equal -// nin => not in array -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.find({ 'time': { '$gte': new Date(otherDate) } }, - {projection: {'_id': 0}}) - .toArray(function (err, result) { - if (err) throw err; - db.close(); - cb(result); - }); -}); - - -const search = { - user: req.query.user, - from: req.query.from, - to: req.query.to, - limit: req.query.limit || 0 -}; -function searchExercises (c, s, cb) { - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - const collection = database.collection(target); - let option1 = { 'user': s.user }; - let option2 = { - 'user': s.user, - 'date': { - '$gte': s.from, - '$lte': s.to - } - }; - let search = option1; - if (s.from) { - search = option2; - } - let limit = parseInt(s.limit); - if (isNaN(limit) || limit < 1) limit = 100; - collection.find(search, {projection: {'_id': 0}}).limit(limit) - toArray(function (err, result) { - if (err) return console.log(err); - db.close(); - cb(result); - }); - }); -} -``` - -#### insert - -* **insertar** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.insert(input, function (err, result) { - if (err) throw err; - db.close(); - }); -}); -``` - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database') - const collection = database.collection('collection') - collection.insertMany(docs, function (err, result) { - if (err) { - console.log('ERR =>', err); - throw err; - } - console.log('Inserted = ', result.result.n, ' - ', result.ops.length); - }); -}); -``` - -#### delete - -* **borrar uno** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.deleteOne({'field': value}, function (err, result) { - if (err) throw err; - db.close(); - }); -}); -``` - -* **borrar muchos** - -```js -function deleteAll (c, cb) { - const msg = { - message: undefined, - status: 200 - }; - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) throw err; - const database = db.db(c.dbname); - const collection = database.collection(target); - collection.deleteMany({ '_id': {$gt: 0}}, function (err, result) { - if (err) throw err; - db.close(); - cb(msg); - }); - }); -} -``` - -#### update - -* **actualizar uno** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.updateOne({ 'field':value }, - { $set: { 'field': newValue}}, // changes field to newValue - { $push: { 'array': newElement } }, // adds newElement to array - function (err, res) { - if (err) throw err; - db.close(); - }); -}); -``` - -```js -function saveComment (c, bookid, comment, cb) { - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - const collection = database.collection(target); - collection.updateOne({'_id': parseInt(bookid)}, - { - $push: { 'comments': comment }, - $inc: { 'commentCount': 1 } - }, - function (err, result) { - if (err) return console.log(err); - console.log('RESULT=>', result.ok); - db.close(); - const msg = { - message: undefined, - status: 200 - }; - cb(msg); - }); - }); -} -``` - -* **actualizar muchos** - -```js -mongo.connect(connection, function (err, db) { - if (err) throw err; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.updateMany({}, {$set: {time: Date.now() / 1000}}, - function (err, hits) { - if (err) throw err; - db.close(); - }); -}); -``` - -* **buscar y actualizar** - -```js -// change all records in a collection -mongo.connect(connection, function (err, db) { - if (err) throw err; - let cont = 0; - const database = db.db('database'); - const collection = database.collection('collection'); - collection.find({}).forEach(function (doc) { - if (err) throw err; - const newTime = new Date(doc.time).toISOString().split('T')[0] - collection.updateOne({'_id': doc._id}, { $set: { time: newTime } }) - cont++ - console.log(cont) - }, function () { - db.close(); - });); -}); -``` - -#### crear coleccion - -```js -function createCollection (c, cb) { - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - database.createCollection(target, function (err, created) { - if (err) return console.log(err); - if (created) console.log('Collection ', c.collectionName, - ' created'); - db.close(); - return cb(); - }); - }); -} -``` - -#### eliminar coleccion - -```js -function dropCollection (c, cb) { - const target = c.collectionName; - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - database.dropCollection(target, function (err, isDrop) { - if (err) return console.log(err); - if (isDrop) console.log('Collection ', c.collectionName, - ' deleted'); - db.close(); - return cb(); - }); - }); -} -``` - -#### autoincrementable _id - -```js -// collection counters -{ - "_id": "library", - "sequence_value": 0 -} -function saveBook (c, title, cb) { - const target = c.collectionName; - getNextSequenceValue(c, 'library', function (nextID) { - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - const collection = database.collection(target); - const book = { - '_id': nextID, - 'title': title, - 'comments': [], - 'commentCount': 0 - }; - collection.insert(book, function (err, result) { - if (err) return console.log(err); - db.close(); - const msg = { - message: undefined, - status: 200 - }; - cb(msg); - }); - }); - }); -} -function getNextSequenceValue (c, sequenceName, cb) { - mongo.connect(c.connection, function (err, db) { - if (err) return console.log(err); - const database = db.db(c.dbname); - const collection = database.collection('counters'); - collection.findAndModify( - { '_id': sequenceName }, - [], // sort - { '$inc': { sequence_value: 1 } }, - { new: true }, - function (err, doc) { - return cb(doc.value.sequence_value); - }); - }); -} -``` - -### Backup - -* **mongoexport** - -```sh -mongoexport --db dbname --collection collectioname --out output.json --u 'adminuser' -p 'password' --authenticationDatabase 'admin' -``` - ---- - -## RETHINKDB - -**¡ OJO ! Esto es del 2016. Desde entonces no lo he probado** - -* **Instalacion** - -```sh -nano /etc/apt/sources.list // y añadir -"deb http://download.rethinkdb.com/apt jessie main" -wget -qO- https://download.rethinkdb.com/apt/pubkey.gpg | apt-key add - -apt-get update -apt-get install rethinkdb -``` - -* **Configuracion** - -Para que arranque al inicio - -```sh -cp /etc/rethinkdb/default.conf.sample - /etc/rethinkdb/instances.d/instance1.conf -/etc/init.d/rethinkdb restart -``` - -Archivo configuracion: -`nano /etc/rethinkdb/instances.d/instance1.conf` - -Para levantar el servicio con el usuario rethinkdb usar -`/etc/init.d/rethinkdb restart` - -* **Web segura** - -` nano /etc/nginx/sites-available/jolav` para añadir la nueva ruta - -```nginx -# HTTPS server -server { - listen 443 ssl; - server_name domain.tld; - ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem; - ssl_session_cache shared:SSL:1m; - ssl_session_timeout 5m; - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers on; - location / { - ssi on; - try_files $uri $uri/ =404; - root /var/www/html; - index index.html index.htm; - } - location /rethinkdb-admin/ { - auth_basic "Restricted"; - auth_basic_user_file /etc/nginx/.rethinkdb.pass; - proxy_pass http://127.0.0.1:8080/; - proxy_redirect off; - proxy_set_header Authorization ""; - } -} -``` - -Opcion con subdirectorios - -```nginx -## Sub -server { - listen 80; - listen [::]:80; - server_name s.domain.tld; - return 301 https://s.domain.tld$request_uri; -} -# HTTPS server -server { - listen 443 ssl; - server_name s.domain.tld; - ssl_certificate /etc/letsencrypt/live/s.domain.tld/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/s.domain.tld/privkey.pem; - ssl_session_cache shared:SSL:1m; - ssl_session_timeout 5m; - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers on; - location / { - try_files $uri $uri/ =404; - } - location /rethinkdb-admin/ { - auth_basic "Restricted"; - auth_basic_user_file /etc/nginx/.rethinkdb.pass; - proxy_pass http://127.0.0.1:8080/; - proxy_redirect off; - proxy_set_header Authorization ""; - } -} -``` - -`cp /etc/nginx/sites-available/jolav /etc/nginx/sites-enabled/jolav` -```sh -apt-get install apache2-utils -cd /etc/nginx -htpasswd -c .rethinkdb.pass // nombre que queramos -service nginx restart -``` - -Ahoya ya en el navegador -`http://domain.tld/rethinkdb-admin` - -* **Crear usuarios** - -Un usuario `admin` que no se puede corrar ya existe. Por defecto esta sin -contraseña pero se puede poner una con un update. -La webUI siempre se conecta como admin y se salta el proceso de autenticacion - -```sql -// Insertando en la tabla del sistema `users` -r.db('rethinkdb').table('users').insert({id: 'bob', password: 'secret'}) - -// update to a new value or remove it by using false -r.db('rethinkdb').table('users').get('bob').update({password: false}) -``` - -* **Permisos** se almacenan en la tabla del sistema `permissions` - -`read` - leer datos de las tablas -`write` - modificar datos -`connect` - par abrir conexiones http, por seguridad no usar -`config` - permite hacer cosas segun el alcance - -* **Alcance** - -`table` - afecta solo a una tabla -`database` - lo anterior mas crear y eliminar tablas -`global` - lo anterior mas crear y eliminar databases - -* **grant** comando para otorgar permisos - -```js -// set database scope -r.db('field_notes').grant('bob', - {read: true, write: true, config: false}); - -// set table scopes -r.db('field_notes').table('calendar').grant('bob', - {write: false}); -r.db('field_notes').table('supervisor_only').grant('bob', - {read: false, write: false}); -``` - -* **ejemplo** - -la tabla test de ejemplo inicial mejor borrarla y crearla si se quiere de nuevo -pues parece que permite entrar a todo el mundo . - -Si no le pones pass al admin todas las conexiones las interpreta como admin y -entra directamente - -```js -r.db("rethinkdb").table("users").get("admin").update({password: "pass"}) -r.db("rethinkdb").table("users").get("user").update({password: "pass"}) -r.table("users").get("usuario").update({password: "pass"}) -r.db('test').grant('usuario', {read: true, write: true, - cnginxonfig: true}) -``` - -* **Conexion** - -```js -var config = require('./config.json'); -var r = require('rethinkdb'); - -r.connect(config.rethinkdb) - .then(function (conn) { - console.log(conn); - }) - .error(function (error) { - console.log(error.message); - }); -``` - -```json -{ - "rethinkdb": { - "host": "dominio.com", - "port": 5555, - "db": "test", - "username" : "userName", - "password" : "userPassword" - }, - "express": { - "port": 3000 - } -} -``` - ---- diff --git a/docs/nodejs-snippets.md b/docs/nodejs-snippets.md index 20bc084..1014556 100644 --- a/docs/nodejs-snippets.md +++ b/docs/nodejs-snippets.md @@ -272,10 +272,12 @@ form.parse(req, function (err, fields, files) { ### get IP ```javascript -function getIP (req) { - return (req.headers['x-forwarded-for'] || - req.connection.remoteAddress || req.socket.remoteAddress || - req.connection.socket.remoteAddress).split(',')[0]; +function getIP(req) { + return ( + req.headers['x-forwarded-for'] || + req.connection.remoteAddress || + req.socket.remoteAddress || + req.connection.socket.remoteAddress).split(',')[0]; } ``` diff --git a/docs/nodejs.md b/docs/nodejs.md index 58b67af..c211df6 100644 --- a/docs/nodejs.md +++ b/docs/nodejs.md @@ -1,4 +1,4 @@ -# NODEJS 20.X.X +# NODEJS 22.X.X --- @@ -36,61 +36,17 @@ --- +## DOCS + +[Documentacion oficial de la API](https://nodejs.org/docs/latest/api/) + +Este enlace va a la ultima version de node, si usas LTS u otra desde ahi te salen todas las opciones + ## MODULOS DEL CORE ### fs (sistema de archivos) -[File System node 12.x](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html) - -`fs.appendFile(file, data[, options], callback)` - añadir datos al final del -fichero -`fs.appendFileSync(file, data[, options])` - añadir datos al final del -fichero de forma sincrona -`fs.close(fd, callback)` - cierra un archivo -`fs.closeSync(fd)` - cierra un archivo de forma sincrona -`fs.createReadStream(path[, options])` - crea un nuevo objeto ReadStream -`fs.createWriteStream(path[, options])` - crea un nuevo objeto WriteStream -`fs.mkdir(path[, mode], callback)` - crea un directorio -`fs.mkdirSync(path[, mode])` - crea un directorio de forma sincrona -`fs.open(path, flags[, mode], callback)` - abre un archivo -`fs.openSync(path, flags[, mode])` - abre un archivo de forma sincrona -`fs.readdir(path, callback)` - leer un directorio -`fs.readdirSync(path)` - leer un directorio de forma sincrona -`fs.readFile(file[, options], callback)` - leer el contenido entero de un archivo -`fs.readFileSync(file[, options])` - leer el contenido entero de un archivo de -forma sincrona -`fs.read(fd, buffer, offset, length, position, callback)` - lee datos de un archivo -`fs.readSync(fd, buffer, offset, length, position)` - lee datos de un archivo de -forma sincrona -`fs.rename(oldPath, newPath, callback)` - cambia el nombre o ubicacion de un -archivo -`fs.renameSync(oldPath, newPath)` - cambia el nombre o ubicacion de un archivo de forma sincrona -`fs.rmdir(path, callback)` - borra un directorio -`fs.rmdirSync(path)` - borra un directorio de forma sincrona -`fs.stat(path, callback)` - consigue el estado de un archivo -`fs.statSync(path)` - consigue el estado de un archivo de forma sincrona -`fs.unlink(path, callback)` - borra un archivo -`fs.unlinkSync(path)` - borra un archivo de forma sincrona -`fs.unwatchFile(filename[, listener])` - deja de vigilar cuando se producen cambios -en un archivo -`fs.watch(filename[, options][, listener])` - vigila cuando se producen cambios en -un archivo o directorio -`fs.watchFile(filename[, options], listener)` - vigila cuando se producen cambios -en un archivo -`fs.write(fd, buffer, offset, length[, position], callback)` - escribe el buffer al -archivo -`fs.writeSync(fd, buffer, offset, length[, position])` - escribe el buffer al -archivo de forma sincrona -`fs.write(fd, data[, position[, encoding]], callback)` - escribe los data al -archivo -`fs.writeSync(fd, data[, position[, encoding]])` - escribe los data al archivo de -forma sincrona -`fs.writeFile(file, data[, options], callback)` - escribe data al archivo -`fs.writeFileSync(file, data[, options])` - escribe data al archivo de forma -sincrona -`fs.stat(path, callback)` - consigue informacion del archivo - ### os (sistema operativo) `const os = require('os')` @@ -110,41 +66,19 @@ sincrona ## ASYNC-AWAIT ```js -async function doSomething() { - //... - const rate = await getApiLimit(); - // avoid unhandled promise rejection with - const rate = await getApiLimit().catch(() => {}); - // or - try { - const rate = await getApiLimit(); - } catch(){ - //... - } +function sleep(sleepTime) { + return new Promise(function (resolve, reject) { + setTimeout(resolve, sleepTime); + }); } -function getApiLimit() { - return new Promise((resolve, reject) => { - const options = { - hostname: 'api.github.com', - port: 443, - path: "/rate_limit", - method: 'GET', - headers: { - 'Authorization': 'Bearer ' + token[lib.getRandomNumber(0, 9)], - "User-Agent": "github stars repos", - 'Accept': '/application/vnd.github.v3.star+json', - } - }; - lib.makeRequest(options, null, function (err, data, headers) { - if (err) { - console.log('Error => ', err); - reject(-1); - } - resolve(data); - }); - }); +async function go() { + console.log('Starting'); + await sleep(1000); + console.log('Ending'); } + +go(); ``` ### Patrones @@ -209,29 +143,37 @@ catch(e) { ### Paralelismo ```js -// Asi tardaria 1000ms +// Asi tarda 1000ms async function series() { + console.log("series"); await wait(500); await wait(500); - return "done!"; + console.log("series done"); } -// Asi tardaria 500ms +// Asi tarda 500ms async function parallel() { + console.log('parallel'); const wait1 = wait(500); const wait2 = wait(500); await wait1; await wait2; - return "done!"; + console.log('parallel done'); } -async function parallel() { +// Asi tarda 500ms +async function parallel2() { + console.log("parallel2"); const [wait1, wait2] = await Promise.all([ wait(500), wait(500), ]); - return "done!"; + console.log('parallel2 done'); } + +series(); +parallel(); +parallel2(); ``` --- diff --git a/www/404.html b/www/404.html index 2fc3381..e8b907a 100644 --- a/www/404.html +++ b/www/404.html @@ -384,7 +384,7 @@

Contenidos

diff --git a/www/css/index.html b/www/css/index.html index 161f992..64b9d4e 100644 --- a/www/css/index.html +++ b/www/css/index.html @@ -1504,7 +1504,7 @@

Contenidos

diff --git a/www/debian/index.html b/www/debian/index.html index 52fdc50..d14cc55 100644 --- a/www/debian/index.html +++ b/www/debian/index.html @@ -2488,7 +2488,7 @@

Contenidos

diff --git a/www/expressjs/index.html b/www/expressjs/index.html index 225607b..3663345 100644 --- a/www/expressjs/index.html +++ b/www/expressjs/index.html @@ -43,7 +43,7 @@
-

EXPRESS 4.16.X

+

EXPRESS 4.20.X


USO

instalacion

@@ -1489,7 +1489,7 @@

Contenidos

diff --git a/www/frontend/index.html b/www/frontend/index.html index cf6d55c..12f92f2 100644 --- a/www/frontend/index.html +++ b/www/frontend/index.html @@ -537,7 +537,7 @@

Contenidos

diff --git a/www/golang-bases-de-datos/index.html b/www/golang-bases-de-datos/index.html index 0090708..0e197c2 100644 --- a/www/golang-bases-de-datos/index.html +++ b/www/golang-bases-de-datos/index.html @@ -738,7 +738,7 @@

Contenidos

diff --git a/www/golang-para-web/index.html b/www/golang-para-web/index.html index 5bacf64..92de944 100644 --- a/www/golang-para-web/index.html +++ b/www/golang-para-web/index.html @@ -1556,7 +1556,7 @@

Contenidos

diff --git a/www/golang-snippets/index.html b/www/golang-snippets/index.html index d212e72..402280d 100644 --- a/www/golang-snippets/index.html +++ b/www/golang-snippets/index.html @@ -2464,7 +2464,7 @@

Contenidos

diff --git a/www/golang/index.html b/www/golang/index.html index 3cc2fbb..745fc2e 100644 --- a/www/golang/index.html +++ b/www/golang/index.html @@ -3125,7 +3125,7 @@

Contenidos

diff --git a/www/html/index.html b/www/html/index.html index c3777c3..01911bf 100644 --- a/www/html/index.html +++ b/www/html/index.html @@ -1282,7 +1282,7 @@

Contenidos

diff --git a/www/index.html b/www/index.html index 0d52a4c..82ca1f6 100644 --- a/www/index.html +++ b/www/index.html @@ -370,7 +370,7 @@

Quick search

diff --git a/www/javascript-apis/index.html b/www/javascript-apis/index.html index 7e1ea4d..febda72 100644 --- a/www/javascript-apis/index.html +++ b/www/javascript-apis/index.html @@ -1622,7 +1622,7 @@

Contenidos

diff --git a/www/javascript-para-web/index.html b/www/javascript-para-web/index.html index 7e811e5..397ee0c 100644 --- a/www/javascript-para-web/index.html +++ b/www/javascript-para-web/index.html @@ -1736,7 +1736,7 @@

Contenidos

diff --git a/www/javascript-snippets/index.html b/www/javascript-snippets/index.html index 1fcfc7e..0b45503 100644 --- a/www/javascript-snippets/index.html +++ b/www/javascript-snippets/index.html @@ -126,6 +126,38 @@

isEmpty(Object)

}
+

FETCH

+
async function fetchData(c, data) {
+  const options = {
+    timeout: c.timeout,
+    host: c.host,
+    port: c.port,
+    path: c.api,
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/x-www-form-urlencoded',
+      'Accept-Charset': 'utf-8'
+    },
+    body: new URLSearchParams({
+      'key': c.API_KEY,
+      'data': JSON.stringify(data)
+    }),
+  };
+  const url = c.API_URL + c.API_ENDPOINT;
+  try {
+    const response = await fetch(url, options);
+    if (response.ok) {
+      const data = await response.json();
+      return data;
+    } else {
+      throw new Error(response.status + " " + response.statusText);
+    }
+  } catch (err) {
+    console.log('ERROR fetchData => ', err);
+  }
+}
+
+

AJAX REQUESTS

GET

function getAjaxData (urlData, callback) {
@@ -570,6 +602,11 @@ 

Contenidos

+ + +
  • FETCH
  • +
      +
  • AJAX REQUESTS
  • @@ -898,6 +935,11 @@

    Contenidos

    + + +
  • FETCH
  • +
      +
  • AJAX REQUESTS
  • @@ -1027,7 +1069,7 @@

    Contenidos

    diff --git a/www/javascript/index.html b/www/javascript/index.html index 2e374c6..76dccfe 100644 --- a/www/javascript/index.html +++ b/www/javascript/index.html @@ -2287,7 +2287,7 @@

    Contenidos

    diff --git a/www/nodejs-bases-de-datos/index.html b/www/nodejs-bases-de-datos/index.html index cfc28dd..a0bc8bc 100644 --- a/www/nodejs-bases-de-datos/index.html +++ b/www/nodejs-bases-de-datos/index.html @@ -45,8 +45,126 @@

    NODEJS para BASES DE DATOS


    -

    MYSQL

    +

    SQLITE

    driver

    +

    better-sqlite3

    +

    backups

    +

    Al activar pragma('journal_mode=WAL'), en vez de un archivo hay 3 para la DB.
    +nombre.db3
    +nombre.db3-shm
    +nombre.db3-wal

    +

    Para hacer un backup sin riesgo consolidando los tres archivos

    +
    apt install sqlite3
    +sqlite3 myArchivo.db3 ".backup backup-MyArchivo.db3"
    +
    +

    Select, Replace e Insert

    +
    /* */
    +const options = {};
    +
    +import sqlite3 from 'better-sqlite3';
    +const myDB = new sqlite3('./path/to/databaseFile.db3', options);
    +myDB.pragma('journal_mode = WAL');
    +
    +const store = {
    +
    +  table1: "table1",
    +  readTable1: function () {
    +    const sql = `SELECT * FROM ${this.table1}`;
    +    const stmt = myDB.prepare(sql);
    +    const rows = stmt.all();
    +    return rows.map(function (row) {
    +      return {
    +        server: row.server,
    +        data: row.data
    +      };
    +    });
    +  },
    +  saveTable1: function (req) {
    +    const data = req.body.data;
    +    const server = req.body.server;
    +    if (!server || !data) {
    +      return;
    +    }
    +    const sql = `REPLACE INTO ${this.table1} (server, data) 
    +    VALUES (?, ?)`;
    +    const stmt = myDB.prepare(sql);
    +    stmt.run(server, data);
    +  },
    +
    +  table2: "table2",
    +  readTable2: function () {
    +    const sql = `SELECT * FROM "${this.table2}"`;
    +    const stmt = myDB.prepare(sql);
    +    const rows = stmt.all();
    +    return rows.map(function (row) {
    +      return {
    +        day: row.day,
    +        alexa: row.alexa,
    +        loc: row.loc,
    +        stars: row.stars,
    +        proxy: row.proxy,
    +        headers: row.headers,
    +        weather: row.weather,
    +        geoip: row.geoip,
    +        video2gif: row.video2gif,
    +        sp500: row.sp500,
    +        tetris: row.tetris,
    +        random: row.random,
    +      };
    +    });
    +  },
    +  readTodayTable2: function () {
    +    const today = new Date().toISOString().split('T')[0];
    +    const sql = `SELECT * FROM "${this.table2}" WHERE day = ?`;
    +    const stmt = myDB.prepare(sql);
    +    const rows = stmt.all(today);
    +    return rows[0];
    +  },
    +  saveTable2: function (data) {
    +    const inserts = [
    +      data.day,
    +      data.alexa,
    +      data.loc,
    +      data.stars,
    +      data.proxy,
    +      data.headers,
    +      data.weather,
    +      data.geoip,
    +      data.video2gif,
    +      data.random,
    +    ];
    +    const sql = `
    +    INSERT INTO "${this.table2}" 
    +    (day, alexa, loc, stars, proxy, headers, weather, 
    +    geoip, video2gif, random)
    +    VALUES (?, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    +    ON CONFLICT(day) DO UPDATE SET
    +      alexa = ?,
    +      loc = ?,
    +      stars = ?,
    +      proxy = ?,
    +      headers = ?,
    +      weather = ?,
    +      geoip = ?,
    +      video2gif = ?,
    +      random = ?
    +    `;
    +    const stmt = myDB.prepare(sql);
    +    stmt.run(inserts);
    +  },
    +};
    +
    +export {
    +  store
    +};
    +
    +
    +

    MYSQL 8

    +

    driver

    +

    documentacion
    +github

    +

    MYSQL 5 (desactualizado)

    +

    driver

    2.17.X https://github.com/mysqljs/mysql

    npm install --save mysql

    const mysql = require('mysql');
    @@ -306,616 +424,6 @@ 

    trucos

    • testConnection - si lo ejecutas varias veces una vez da error la otra bien y asi todo el rato. Es por algo de que al ser asincrono no cierra bien. Si no usas connect ni end, solo con querys va bien
    -
    -

    REDIS 4.0.X

    -

    driver

    -
    npm install redis
    -
    -

    test

    -
    const redis = require('redis');
    -// default redis.createClient() will use 127.0.0.1 and port 6379
    -const client = redis.createClient();
    -// custom
    -const client = redis.createClient(port, host);
    -
    -client.on('connect', function() {
    -    console.log('Redis OK');
    -});
    -
    -client.on('error', function (err) {
    -    console.log('Error => ' + err);
    -});
    -
    -
    -

    MONGODB 3.6.X

    -

    Instalar

    -
    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv
    -2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
    -nano /etc/apt/sources.list // strectch repo not yet
    -deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.6 main
    -apt-get update
    -apt-get install mongodb-org
    -
    -

    create systemd service

    -
    [Unit]
    -Description=High-performance, schema-free document-oriented database
    -After=network.target
    -Documentation=https://docs.mongodb.org/manual
    -
    -[Service]
    -Restart=on-failure
    -User=mongodb
    -Group=mongodb
    -ExecStart=/usr/bin/mongod --quiet --auth --config /etc/mongod.conf
    -
    -[Install]
    -WantedBy=multi-user.target
    -
    -
      -
    • Desinstalar
    • -
    -
    service mongod stop
    -apt-get purge mongodb-org*
    -rm -r /var/log/mongodb
    -rm -r /var/lib/mongodb
    -
    -

    Configurar

    -
    nano /etc/mongod.conf
    -bindIp : X.X.X.X
    -// 127.0.0.1 only localhost 
    -// 0.0.0.0 any Ipv4 allowed
    -
    -
      -
    • crear usuarios
    • -
    -
    $ mongo
    -> use admin
    -> db.createUser({user:"adminUser",pwd:"password"
    ->                   ,roles:[{role:"root",db:"admin"}]})
    -
    -$ mongo -u 'adminUser' -p 'password' --authenticationDatabase 'admin'
    -> use some_db
    -> db.createUser({user: "username",pwd: "password",roles: ["readWrite"]})
    -
    -

    Snippets

    -

    driver

    -

    3.0.1 - https://github.com/mongodb/node-mongodb-native

    -

    npm install --save mongodb

    -
    const mongo = require('mongodb');
    -connection="mongodb://user:password@database.host.com:port/database"
    -
    -

    test

    -
    // try - catch doesnt work because of asynchronous
    -function testDB () {
    -  mongo.connect(connection, function (err, db) {
    -    if (err) return console.log(err);
    -    console.log('Connected to database ... OK');
    -    db.close();
    -  });
    -}
    -
    -

    configurar la conexion

    -
    let c = {
    -  connection: process.env.DB_URI,
    -  dbname: process.env.DB_NAME,
    -  collectionName: collectioName
    -};
    -
    -

    buscar

    -
      -
    • Buscar solo uno
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.findOne({'field': value}, function (err, result) {
    -  const id = mongo.ObjectID(id);
    -  collection.findOne({ '_id': id }, function (err, result) {
    -    if (err) throw err;
    -    db.close();
    -    cb(result);
    -  });
    -});
    -
    -
    function getBook (c, bookid, cb) {
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) throw err;
    -    const database = db.db(c.dbname);
    -    const collection = database.collection(target);
    -    collection.findOne({ '_id': parseInt(bookid) }, 
    -    function (err, result) {
    -      if (err) throw err;
    -      db.close();
    -      if (!result) {
    -        const err = {
    -          message: 'no book exists',
    -          status: 400
    -        };
    -        return cb(err);
    -      }
    -      cb(result);
    -    });
    -  });
    -}
    -
    -
    -
      -
    • buscar
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.find({ 'field': value }, {}).next(function (err, result) {
    -    if (err) throw err;
    -    db.close();
    -    cb(result);
    -  });
    -});
    -
    -mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.find({}, {projection: {'_id': 0}}
    -  .toArray(function (err, result) {
    -    if (err) throw err;
    -    db.close();
    -    cb(result);
    -  });
    -});
    -
    -// eq => equal
    -// gte => greater or equal
    -// gt => greater
    -// in => in array 
    -// lt => less than
    -// lte => less or equal
    -// ne => not equal
    -// nin => not in array
    -mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.find({ 'time': { '$gte': new Date(otherDate) } },
    -  {projection: {'_id': 0}})
    -    .toArray(function (err, result) {
    -      if (err) throw err;
    -      db.close();
    -      cb(result);  
    -    });
    -});
    -
    -
    -const search = {
    -  user: req.query.user,
    -  from: req.query.from,
    -  to: req.query.to,
    -  limit: req.query.limit || 0
    -};
    -function searchExercises (c, s, cb) {
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) return console.log(err);
    -    const database = db.db(c.dbname);
    -    const collection = database.collection(target);
    -    let option1 = { 'user': s.user };
    -    let option2 = {
    -      'user': s.user,
    -      'date': {
    -        '$gte': s.from,
    -        '$lte': s.to
    -      }
    -    };
    -    let search = option1;
    -    if (s.from) {
    -      search = option2;
    -    }
    -    let limit = parseInt(s.limit);
    -    if (isNaN(limit) || limit < 1) limit = 100;
    -    collection.find(search, {projection: {'_id': 0}}).limit(limit)
    -    toArray(function (err, result) {
    -      if (err) return console.log(err);
    -      db.close();
    -      cb(result);
    -    });
    -  });
    -}
    -
    -

    insert

    -
      -
    • insertar
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.insert(input, function (err, result) {
    -    if (err) throw err;
    -    db.close();
    -  });
    -});
    -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database')
    -  const collection = database.collection('collection')
    -  collection.insertMany(docs, function (err, result) {
    -    if (err) {
    -      console.log('ERR =>', err);
    -      throw err;
    -    }
    -    console.log('Inserted = ', result.result.n, ' - ', result.ops.length);
    -  });
    -});
    -
    -

    delete

    -
      -
    • borrar uno
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.deleteOne({'field': value}, function (err, result) {
    -    if (err) throw err;
    -      db.close();
    -  });
    -});
    -
    -
      -
    • borrar muchos
    • -
    -
    function deleteAll (c, cb) {
    -  const msg = {
    -    message: undefined,
    -    status: 200
    -  };
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) throw err;
    -    const database = db.db(c.dbname);
    -    const collection = database.collection(target);
    -    collection.deleteMany({ '_id': {$gt: 0}}, function (err, result) {
    -      if (err) throw err;
    -      db.close();
    -      cb(msg);
    -    });
    -  });
    -}
    -
    -

    update

    -
      -
    • actualizar uno
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');  
    -  collection.updateOne({ 'field':value }, 
    -    { $set: { 'field': newValue}}, // changes field to newValue 
    -    { $push: { 'array': newElement } }, // adds newElement to array
    -    function (err, res) {
    -      if (err) throw err;
    -      db.close();
    -  });
    -});
    -
    -
    function saveComment (c, bookid, comment, cb) {
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) return console.log(err);
    -    const database = db.db(c.dbname);
    -    const collection = database.collection(target);
    -    collection.updateOne({'_id': parseInt(bookid)},
    -      {
    -        $push: { 'comments': comment },
    -        $inc: { 'commentCount': 1 }
    -      },
    -      function (err, result) {
    -        if (err) return console.log(err);
    -        console.log('RESULT=>', result.ok);
    -        db.close();
    -        const msg = {
    -          message: undefined,
    -          status: 200
    -        };
    -        cb(msg);
    -      });
    -  });
    -}
    -
    -
      -
    • actualizar muchos
    • -
    -
    mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.updateMany({}, {$set: {time: Date.now() / 1000}},
    -    function (err, hits) {
    -      if (err) throw err;
    -      db.close();
    -    });
    -});
    -
    -
      -
    • buscar y actualizar
    • -
    -
    // change all records in a collection
    -mongo.connect(connection, function (err, db) {
    -  if (err) throw err;
    -  let cont = 0;
    -  const database = db.db('database');
    -  const collection = database.collection('collection');
    -  collection.find({}).forEach(function (doc) {
    -    if (err) throw err;
    -    const newTime = new Date(doc.time).toISOString().split('T')[0]
    -    collection.updateOne({'_id': doc._id}, { $set: { time: newTime } })
    -    cont++
    -    console.log(cont)
    -  }, function () {
    -    db.close();
    -  }););
    -});
    -
    -

    crear coleccion

    -
    function createCollection (c, cb) {
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) return console.log(err);
    -    const database = db.db(c.dbname);
    -    database.createCollection(target, function (err, created) {
    -      if (err) return console.log(err);
    -      if (created) console.log('Collection ', c.collectionName, 
    -            ' created');
    -      db.close();
    -      return cb();
    -    });
    -  });
    -}
    -
    -

    eliminar coleccion

    -
    function dropCollection (c, cb) {
    -  const target = c.collectionName;
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) return console.log(err);
    -    const database = db.db(c.dbname);
    -    database.dropCollection(target, function (err, isDrop) {
    -      if (err) return console.log(err);
    -      if (isDrop) console.log('Collection ', c.collectionName, 
    -              ' deleted');
    -      db.close();
    -      return cb();
    -    });
    -  });
    -}
    -
    -

    autoincrementable _id

    -
    // collection counters
    -{
    -    "_id": "library",
    -    "sequence_value": 0
    -}
    -function saveBook (c, title, cb) {
    -  const target = c.collectionName;
    -  getNextSequenceValue(c, 'library', function (nextID) {
    -    mongo.connect(c.connection, function (err, db) {
    -      if (err) return console.log(err);
    -      const database = db.db(c.dbname);
    -      const collection = database.collection(target);
    -      const book = {
    -        '_id': nextID,
    -        'title': title,
    -        'comments': [],
    -        'commentCount': 0
    -      };
    -      collection.insert(book, function (err, result) {
    -        if (err) return console.log(err);
    -        db.close();
    -        const msg = {
    -          message: undefined,
    -          status: 200
    -        };
    -        cb(msg);
    -      });
    -    });
    -  });
    -}
    -function getNextSequenceValue (c, sequenceName, cb) {
    -  mongo.connect(c.connection, function (err, db) {
    -    if (err) return console.log(err);
    -    const database = db.db(c.dbname);
    -    const collection = database.collection('counters');
    -    collection.findAndModify(
    -      { '_id': sequenceName },
    -      [], // sort
    -      { '$inc': { sequence_value: 1 } },
    -      { new: true },
    -      function (err, doc) {
    -        return cb(doc.value.sequence_value);
    -      });
    -  });
    -}
    -
    -

    Backup

    -
      -
    • mongoexport
    • -
    -
    mongoexport --db dbname --collection collectioname --out output.json 
    --u 'adminuser' -p 'password' --authenticationDatabase 'admin'
    -
    -
    -

    RETHINKDB

    -

    ¡ OJO ! Esto es del 2016. Desde entonces no lo he probado

    -
      -
    • Instalacion
    • -
    -
    nano /etc/apt/sources.list // y añadir
    -"deb http://download.rethinkdb.com/apt jessie main"
    -wget -qO- https://download.rethinkdb.com/apt/pubkey.gpg | apt-key add -
    -apt-get update
    -apt-get install rethinkdb
    -
    -
      -
    • Configuracion
    • -
    -

    Para que arranque al inicio

    -
    cp /etc/rethinkdb/default.conf.sample
    -      /etc/rethinkdb/instances.d/instance1.conf
    -/etc/init.d/rethinkdb restart
    -
    -

    Archivo configuracion:
    -nano /etc/rethinkdb/instances.d/instance1.conf

    -

    Para levantar el servicio con el usuario rethinkdb usar
    -/etc/init.d/rethinkdb restart

    -
      -
    • Web segura
    • -
    -

    nano /etc/nginx/sites-available/jolav para añadir la nueva ruta

    -
    # HTTPS server
    -server {
    -   listen 443 ssl;
    -   server_name domain.tld;
    -   ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
    -   ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
    -   ssl_session_cache shared:SSL:1m;
    -   ssl_session_timeout 5m;
    -   ssl_ciphers HIGH:!aNULL:!MD5;
    -   ssl_prefer_server_ciphers on;
    -   location / {
    -        ssi on;
    -        try_files $uri $uri/ =404;
    -        root /var/www/html;
    -        index index.html index.htm;
    -   }
    -   location /rethinkdb-admin/ {
    -       auth_basic "Restricted";
    -       auth_basic_user_file /etc/nginx/.rethinkdb.pass;
    -       proxy_pass http://127.0.0.1:8080/;
    -       proxy_redirect off;
    -       proxy_set_header Authorization "";
    -   }
    -}
    -
    -

    Opcion con subdirectorios

    -
    ## Sub
    -server {
    -        listen 80;
    -        listen [::]:80;
    -        server_name s.domain.tld;
    -        return 301 https://s.domain.tld$request_uri;
    -}
    -# HTTPS server
    -server {
    -   listen 443 ssl;
    -   server_name s.domain.tld;
    -   ssl_certificate /etc/letsencrypt/live/s.domain.tld/fullchain.pem;
    -   ssl_certificate_key /etc/letsencrypt/live/s.domain.tld/privkey.pem;
    -   ssl_session_cache shared:SSL:1m;
    -   ssl_session_timeout 5m;
    -   ssl_ciphers HIGH:!aNULL:!MD5;
    -   ssl_prefer_server_ciphers on;
    -   location / {
    -       try_files $uri $uri/ =404;
    -   }
    -   location /rethinkdb-admin/ {
    -       auth_basic "Restricted";
    -       auth_basic_user_file /etc/nginx/.rethinkdb.pass;
    -       proxy_pass http://127.0.0.1:8080/;
    -       proxy_redirect off;
    -       proxy_set_header Authorization "";
    -   }
    -}
    -
    -

    cp /etc/nginx/sites-available/jolav /etc/nginx/sites-enabled/jolav

    -
    apt-get install apache2-utils
    -cd /etc/nginx
    -htpasswd -c .rethinkdb.pass <username> // <username> nombre que queramos
    -service nginx restart
    -
    -

    Ahoya ya en el navegador -http://domain.tld/rethinkdb-admin

    -
      -
    • Crear usuarios
    • -
    -

    Un usuario admin que no se puede corrar ya existe. Por defecto esta sin -contraseña pero se puede poner una con un update.
    -La webUI siempre se conecta como admin y se salta el proceso de autenticacion

    -
    // Insertando en la tabla del sistema `users`
    -r.db('rethinkdb').table('users').insert({id: 'bob', password: 'secret'})
    -
    -// update to a new value or remove it by using false
    -r.db('rethinkdb').table('users').get('bob').update({password: false})
    -
    -
      -
    • Permisos se almacenan en la tabla del sistema permissions
    • -
    -

    read - leer datos de las tablas
    -write - modificar datos
    -connect - par abrir conexiones http, por seguridad no usar
    -config - permite hacer cosas segun el alcance

    -
      -
    • Alcance
    • -
    -

    table - afecta solo a una tabla
    -database - lo anterior mas crear y eliminar tablas
    -global - lo anterior mas crear y eliminar databases

    -
      -
    • grant comando para otorgar permisos
    • -
    -
    // set database scope
    -r.db('field_notes').grant('bob',
    -        {read: true, write: true, config: false});
    -
    -// set table scopes
    -r.db('field_notes').table('calendar').grant('bob',
    -        {write: false});
    -r.db('field_notes').table('supervisor_only').grant('bob',
    -        {read: false, write: false});
    -
    -
      -
    • ejemplo
    • -
    -

    la tabla test de ejemplo inicial mejor borrarla y crearla si se quiere de nuevo -pues parece que permite entrar a todo el mundo .

    -

    Si no le pones pass al admin todas las conexiones las interpreta como admin y -entra directamente

    -
    r.db("rethinkdb").table("users").get("admin").update({password: "pass"})
    -r.db("rethinkdb").table("users").get("user").update({password: "pass"})
    -r.table("users").get("usuario").update({password: "pass"})
    -r.db('test').grant('usuario', {read: true, write: true, 
    -  cnginxonfig: true})
    -
    -
      -
    • Conexion
    • -
    -
    var config = require('./config.json');
    -var r = require('rethinkdb');
    -
    -r.connect(config.rethinkdb)
    -  .then(function (conn) {
    -    console.log(conn);
    -  })
    -  .error(function (error) {
    -    console.log(error.message);
    -  });
    -
    -
    {
    -    "rethinkdb": {
    -        "host": "dominio.com",
    -        "port": 5555,
    -        "db": "test",
    -        "username" : "userName",
    -        "password" : "userPassword"
    -    },
    -    "express": {
    -        "port": 3000
    -    }
    -}
    -

    @@ -1066,7 +574,7 @@

    Contenidos

    - -
  • REDIS 4.0.X
  • +
  • MYSQL 8
  • -
  • MONGODB 3.6.X
  • - - -
  • Backup
  • +
  • trucos
    - - -
  • RETHINKDB
  • -
      -
    @@ -1384,7 +827,7 @@

    Contenidos

    -
  • REDIS 4.0.X
  • +
  • MYSQL 8
    • driver
    • @@ -1447,27 +855,9 @@

      Contenidos

    -
  • test
  • -
      - -
    - - - -
  • MONGODB 3.6.X
  • - - -
  • Backup
  • +
  • trucos
    - - -
  • RETHINKDB
  • -
      -
    @@ -1561,7 +939,7 @@

    Contenidos

    diff --git a/www/nodejs-snippets/index.html b/www/nodejs-snippets/index.html index 9937b91..a9bf30f 100644 --- a/www/nodejs-snippets/index.html +++ b/www/nodejs-snippets/index.html @@ -280,10 +280,12 @@

    Upload File


    NETWORK

    get IP

    -
    function getIP (req) {
    -  return (req.headers['x-forwarded-for'] ||
    -  req.connection.remoteAddress || req.socket.remoteAddress ||
    -  req.connection.socket.remoteAddress).split(',')[0];
    +
    function getIP(req) {
    +  return (
    +    req.headers['x-forwarded-for'] ||
    +    req.connection.remoteAddress ||
    +    req.socket.remoteAddress ||
    +    req.connection.socket.remoteAddress).split(',')[0];
     }
     

    check url exists

    @@ -990,7 +992,7 @@

    Contenidos

    diff --git a/www/nodejs/index.html b/www/nodejs/index.html index 9151f14..9f2c031 100644 --- a/www/nodejs/index.html +++ b/www/nodejs/index.html @@ -43,7 +43,7 @@
    -

    NODEJS 20.X.X

    +

    NODEJS 22.X.X


    NPM

    npm install paquete -g - Instala paquete globalmente.Asi convertimos el paquete un comando ejecutable
    @@ -68,56 +68,11 @@

    NPM

    Semver versiones semanticas

    node


    +

    DOCS

    +

    Documentacion oficial de la API

    +

    Este enlace va a la ultima version de node, si usas LTS u otra desde ahi te salen todas las opciones

    MODULOS DEL CORE

    fs (sistema de archivos)

    -

    File System node 12.x

    -

    fs.appendFile(file, data[, options], callback) - añadir datos al final del -fichero
    -fs.appendFileSync(file, data[, options]) - añadir datos al final del -fichero de forma sincrona
    -fs.close(fd, callback) - cierra un archivo
    -fs.closeSync(fd) - cierra un archivo de forma sincrona
    -fs.createReadStream(path[, options]) - crea un nuevo objeto ReadStream
    -fs.createWriteStream(path[, options]) - crea un nuevo objeto WriteStream
    -fs.mkdir(path[, mode], callback) - crea un directorio
    -fs.mkdirSync(path[, mode]) - crea un directorio de forma sincrona
    -fs.open(path, flags[, mode], callback) - abre un archivo
    -fs.openSync(path, flags[, mode]) - abre un archivo de forma sincrona
    -fs.readdir(path, callback) - leer un directorio
    -fs.readdirSync(path) - leer un directorio de forma sincrona
    -fs.readFile(file[, options], callback) - leer el contenido entero de un archivo
    -fs.readFileSync(file[, options]) - leer el contenido entero de un archivo de -forma sincrona
    -fs.read(fd, buffer, offset, length, position, callback) - lee datos de un archivo
    -fs.readSync(fd, buffer, offset, length, position) - lee datos de un archivo de -forma sincrona
    -fs.rename(oldPath, newPath, callback) - cambia el nombre o ubicacion de un -archivo
    -fs.renameSync(oldPath, newPath) - cambia el nombre o ubicacion de un archivo de forma sincrona
    -fs.rmdir(path, callback) - borra un directorio
    -fs.rmdirSync(path) - borra un directorio de forma sincrona
    -fs.stat(path, callback) - consigue el estado de un archivo
    -fs.statSync(path) - consigue el estado de un archivo de forma sincrona
    -fs.unlink(path, callback) - borra un archivo
    -fs.unlinkSync(path) - borra un archivo de forma sincrona
    -fs.unwatchFile(filename[, listener]) - deja de vigilar cuando se producen cambios -en un archivo
    -fs.watch(filename[, options][, listener]) - vigila cuando se producen cambios en -un archivo o directorio
    -fs.watchFile(filename[, options], listener) - vigila cuando se producen cambios -en un archivo
    -fs.write(fd, buffer, offset, length[, position], callback) - escribe el buffer al -archivo
    -fs.writeSync(fd, buffer, offset, length[, position]) - escribe el buffer al -archivo de forma sincrona
    -fs.write(fd, data[, position[, encoding]], callback) - escribe los data al -archivo
    -fs.writeSync(fd, data[, position[, encoding]]) - escribe los data al archivo de -forma sincrona
    -fs.writeFile(file, data[, options], callback) - escribe data al archivo
    -fs.writeFileSync(file, data[, options]) - escribe data al archivo de forma -sincrona
    -fs.stat(path, callback) - consigue informacion del archivo

    os (sistema operativo)

    const os = require('os')

    console.log('Hostname: ' + os.hostname())
    @@ -131,41 +86,19 @@

    os (sistema operativo)

    console.log('Free memory: ' + (os.freemem() / 1e6).toFixed(1) + ' MB')


    ASYNC-AWAIT

    -
    async function doSomething() {
    -  //...
    -  const rate = await getApiLimit(); 
    -  // avoid unhandled promise rejection with
    -  const rate = await getApiLimit().catch(() => {}); 
    -  // or 
    -  try {
    -    const rate = await getApiLimit();
    -  } catch(){
    -    //...
    -  }
    +
    function sleep(sleepTime) {
    +  return new Promise(function (resolve, reject) {
    +    setTimeout(resolve, sleepTime);
    +  });
     }
     
    -function getApiLimit() {
    -  return new Promise((resolve, reject) => {
    -    const options = {
    -      hostname: 'api.github.com',
    -      port: 443,
    -      path: "/rate_limit",
    -      method: 'GET',
    -      headers: {
    -        'Authorization': 'Bearer ' + token[lib.getRandomNumber(0, 9)],
    -        "User-Agent": "github stars repos",
    -        'Accept': '/application/vnd.github.v3.star+json',
    -      }
    -    };
    -    lib.makeRequest(options, null, function (err, data, headers) {
    -      if (err) {
    -        console.log('Error => ', err);
    -        reject(-1);
    -      }
    -      resolve(data);
    -    });
    -  });
    +async function go() {
    +  console.log('Starting');
    +  await sleep(1000);
    +  console.log('Ending');
     }
    +
    +go();
     

    Patrones

    Funcion asincrona anonima

    @@ -211,29 +144,37 @@

    Manejo de errores

    }

    Paralelismo

    -
    // Asi tardaria 1000ms
    +
    // Asi tarda 1000ms
     async function series() {
    +  console.log("series");
       await wait(500);
       await wait(500);
    -  return "done!";
    +  console.log("series done");
     }
     
    -// Asi tardaria 500ms
    +// Asi tarda 500ms
     async function parallel() {
    +  console.log('parallel');
       const wait1 = wait(500);
       const wait2 = wait(500);
       await wait1;
       await wait2;
    -  return "done!";
    +  console.log('parallel done');
     }
     
    -async function parallel() {
    +// Asi tarda 500ms
    +async function parallel2() {
    +  console.log("parallel2");
       const [wait1, wait2] = await Promise.all([
         wait(500),
         wait(500),
       ]);
    -  return "done!";
    +  console.log('parallel2 done');
     }
    +
    +series();
    +parallel();
    +parallel2();
     

    @@ -388,6 +329,11 @@

    Contenidos

  • NPM
    • +
    + +
  • DOCS
  • +
      +
  • MODULOS DEL CORE
  • @@ -596,6 +542,11 @@

    Contenidos

  • NPM
    • +
    + +
  • DOCS
  • +
      +
  • MODULOS DEL CORE
  • @@ -660,7 +611,7 @@

    Contenidos

    diff --git a/www/reactjs/index.html b/www/reactjs/index.html index 6440b46..e580946 100644 --- a/www/reactjs/index.html +++ b/www/reactjs/index.html @@ -1994,7 +1994,7 @@

    Contenidos

    diff --git a/www/search/search_index.json b/www/search/search_index.json index bdcfea4..020dc17 100644 --- a/www/search/search_index.json +++ b/www/search/search_index.json @@ -1 +1 @@ -{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Volver al inicio . Jolav \u00a9 2024 - Ver el c\u00f3digo en GitHub MENU","title":"Menu"},{"location":"#menu","text":"","title":"MENU"},{"location":"css/","text":"CSS SNIPPETS Alinear imagenes .imgV { vertical-align: middle; } .imgH { display: flex; margin: 0 auto; max-width: 100%; } Enlaces animados y sin subrayar a, a:visited { text-decoration: none; color: #375EAB; } a:hover { color: lightblue; } div:hover { transform: scale(1.2); } Desactivar enlace a.notYet { pointer-events: none; text-decoration: line-through; color: #404040; } hr gradual hr { margin: 10px 10% 10px 10%; border: 0; height: 1px; background: #333; background-image: linear-gradient(to right, #ccc, #888, #ccc); } Problema en Chrome con la lista de puntos ul { text-align: center; /* para evitar los puntos */ display: inline; /* poner los numeros en Chrome de listas ordenadas dentro del texto*/ list-style-position: inside; list-style-type: none; } Fijar pie al final de pantalla html { height: 100%; box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } body { position: relative; margin: 0 auto; /*padding-bottom: 6rem;*/ min-height: 97%; } .footer { position: absolute; right: 0; bottom: 0; left: 0; padding: 1rem; background-color: lightblue; text-align: center; } Tama\u00f1o fuente como navegador html { font-size:16px; } /* Fijando el css en 16px y usando em despues conseguiremos resultados consistentes en firefox y chrome */ body { font-size:0.90em; } CSS3 INTRODUCCION Enlaces a css Externo CSS Externo Si hay multiples hojas de estilo : uno para cada hoja de estilo En la hoja de estilo que se enlaza incluir @import url(\"estilo2.css);\" Interno - NO USAR CSS Interno Selectores Selectores CSS Selectores de atributos Cascada y herencia Cascada - Ultima Regla: la ultima regla aplicada es la que manda - !important a\u00f1adiendo esto despues de la regla asi toma prioridad color: blue !important; - Especificidad : prevalecera la regla del selector que sea mas especifico h3 es mas especifico que * p otro es mas especifico que p p#intro es mas especifico que p Herencia Casi todos los selectores anidados dentro de otros heredan las propiedades asignadas al selector exterior. Por ejemplo un color en body tambien se aplicara al texto de un parrafo. Hay excepciones evidentes como margin-top (un parrafo no tiene el mismo margen superior que el body del documento). Puedes forzar heredar valores de propiedades de los padres usando inherit como valor de la propiedad body { padding: 20px;} .pagina { padding: inherit;} COLOR color - h1 { color: DarkCyan;} /* color name */ h2 { color: #ee3e80;} /* hex code */ p { color: rgb(100,100,90);} /* rgb value */ background color - body { background-color: rgb(150,150,150); } h1 { background-color: DarkCyan; } h2 { background-color: ##ee3e80: } p { background-color: red; } opacity , rgba - p.one { background-color: rgb(0,0,0); opacity: 0.5;} p.two { background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.5);} TEXTO cursor - Controla el tipo de cursor del raton que se muestra auto|crosshair|default|pointer|move|text|wait|help|url(\"cursor.png\") a { cursor: move;} font-family - Familias : serif , sans-serif , cursive , fantasy y monospace font-family: Arial, Verdana, sans-serif font-size - Pixel: Por defecto en los navegadores el texto es de 16px Porcentaje : porcentaje sobre los 16px estandar, p.ej 75% es 12px em : unidad equivalente a la anchura de la m font-face - @font-face { font-family: 'PT Sans'; src: url('_public/fonts/PTSans.ttf') ; font-display: fallback; } @font-face { font-family: 'ChunkFiveRegular'; src: url('fonts/chunkfive.eot'); src: url('fonts/chunkfive.eot?#iefix') format('embedded-opentype'), url('fonts/chunkfive.woff') format('woff'), url('fonts/chunkfive.ttf') format('truetype'), url('fonts/chunkfive.svg#ChunkFiveRegular') format('svg');} font-weight - normal|bold font-style - normal|italic|oblique text-transform - uppercase : convierte el texto a mayusculas lowercase : convierte el texto a minusculas capitalize : pone mayusculas la primera letra de cada palabra h1 { text-transform: uppercase;} text-decoration - none : elimina cualquier decoracion del texto underline : subraya el texto overline : coloca una linea por encima del texto line-through : linea tachando el texto blink : hace que el texto brille y deje brillar a { text-decoration: none;} line-height - distancia entre lineas p { line-height: 1.4em; } letter-spacing , word-spacing - distancia entre letras, distancia entre palabras, por defecto es 0.25em h1, h2 { text-transform: uppercase; letter-spacing: 0.2em; } .credits { font-weight: bold; word-spacing: 1em; } text-align - left : el texto se alinea a la izquierda right : el texto se alinea a la derecha center : el texto se centra justify : Cada linea excepto la ultima ocupa toda la anchura disponible h1 { text-align: left; } vertical-align - Usada con elementos en linea como y es muy similar al atributo align de Valores : baseline , sub , super , top , text-top , middle , bottom , text-bottom #six-months { vertical-align: text-top;} #one-year { vertical-align: baseline;} #two-years { vertical-align: text-bottom;} text-indent - indenta el texto h2 { text-indent: 20px; } text-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado de la sombra color de la sombra p { text-shadow: 2px 2px 1px #222222} :first-letter , :first-line (pseudo-elementos) - Para especificar diferentes valores a la primera letra o primera linea del texto p.intro:first-letter { font-size: 200%;} p.intro:first-line { font-weight: bold;} :link , :visited (pseudo-clases) - Los navegadores muestran los enlaces en azul y subrayados por defecto y cambian el color cuando han sido visitados :link : para poner estilos a enlaces no visitados :visited : para poner estilos a enlaces visitados a:link { color: deeppink; text-decoration: none;} a:visited { color: black;} a:hover { color: deeppink; text-decoration: underline;} a:active { color: darkcyan;} :hover , :active , :focus (pseudo-clases) - :hover : se aplica cuando el raton esta encima (no funciona en tactiles) :active : se aplica cuando se pulsa algo :focus : se aplica cuando el elemento tiene el foco cajetinTexto { padding: 6px 12px 6px 12px; border: 1px solid #665544; color: #ffffff;} boton.submit:hover { background-color: #665544;} boton.submit:active { background-color: chocolate;} cajetinTexto.text { color: #cccccc;} cajetinTexto.text:focus { color: #665544;} BOXES Dimensiones width , height - Por defecto las cajas tienen el tama\u00f1o justo para contener a su elemento. Podemos establecer nosotros ese tama\u00f1o usando pixeles , o porcentajes relativos a la ventana del navegador o a la caja en que ya esta si esta dentro de otra caja, o ems div.box { height: 300px; width: 300px; background-color: #bbbbaa;} min-width , max-width - Minimo y maximo anchura que una caja de un elemento puede tener min-height , max-height - Minimo y maximo anchura que una caja de un elemento puede tener overflow - Indica como actuar si el contenido dentro de la caja es mayor que la caja. hidden : el contenido extra que no cabe sencillamente se esconde scroll : aparece un scroll para acceder a ese contenido extra p.one { overflow: hidden;} p.two { overflow: scroll;} Visibilidad display - Permite convertir un elemento en linea en un bloque o al reves. Tambien vale para esconder un elemento en la pagina inline : convierte un elemento de bloque en un elemento en linea block : convierte un elemento en linea en un elemento de bloque inline-block : permite a un elemento de bloque fluir como un elemento en linea pero manteniendo las caracteristicas de un elemento de bloque none : esconde el elemento de la pagina li { display: inline; margin-right: 10px;} li.coming-soon { display: none;} visibility - Permite esconder cajas pero deja un espacio donde se supone que esta hidden : esconde el elemento visible : muestra el elemento li.coming-soon { visibility: hidden;} box-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado del borde. Con cero la sombra es una linea solida Extension de la sombra, positiva hacia fuera, negativa hacia dentro p { box-shadow: 2px 2px 1px 5px #777777} Bordes border-padding-margin - border-width - espesor de la linea de borde thin|medium|thick . border-top-width , border-right-width , border-bottom-width border-left-width en orden de las agujas del reloj empezando por top p.one { border-width: 2px;} p.two { border-width: thick;} p.three { border-width: 1px 4px 12px 4px;} border-style - define el tipo de borde solid|dotted|dashed|double|groove|ridge|inset|outset|hidden/none . border-top-style ... - Puedes elegir bordes individuales p.one {border-style: dashed;} border-color - elegir color para el borde border-top-color ... - Tambien se puede elegir el color para cada borde p.one { border-color: #0088dd;} p.two { border-color: #bbbbaa blue orange #0088dd;} border-image - Permite usar imagenes como bordes de las cajas border-radius - border-top-right-radius - border-bottom-right-radius - border-bottom-left-radius - border-top-left-radius - p { border-radius: 5px, 10px, 5px, 10px; } p.one { border-radius: 80px 50px; } p.two { border-top-left-radius: 80px 50px;} Margenes margin - Espacio entre el borde y la caja. Lo normal en px aunque tambien se puede en ems o porcentajes. Si dos cajas se solapan usaremos el mayor de los dos margenes y el otro no Tambien individualmente para cada lado margin-top, margin-right ... p.example1 { margin: 10px 2px 10px 5px; p.example2 { margin: 10px;} padding - Espacio entre el borde y el contenido. Lo normal es en px pero se pueden usar ems o porcentajes (% de la ventana del navegador o de la caja donde este contenido el elemento). Existen tambien individualmente para cada lado padding-top, padding-right ... p.example1 { padding: 10px 2px 10px 5px; p.example2 { padding: 10px;} centrando contenido - Para centrar una caja en la pagina ( o centrarla dentro del elemento en el que esta Establecer una width para la caja (sino tomara toda la anchura de la pagina) Poner margin-left: auto y margin-rigth: auto p { width: 300px; padding: 50px; border: 20px solid #0088dd;} p.example { margin: 10px auto 10px auto; LISTAS list-style - Permite declaras las siguientes opciones type, imagen y position en cualquier orden. ul { list-style: inside circle; } list-style-type - Para poner el estilo al marcador de las listas - Listas ordenadas decimal|decimal-leading-zero|lower-alpha|upper-alpha|lower-roman|upper-roman - Listas desordenadas none|disc|circle|square ol { list-style-type: lower-roman;} list-style-imagen - Usar una imagen como marcador de listas. Se puede usar en
      y
    • ul { list-style-image: url(\"images/star.png\");} list-style-position - Por defecto el marcador de lista aparece outside del indentado de la lista. Podemos cambiarlo por inside para que el marcador entre en la caja del texto el cual esta indentado ul.t1 { list-style-position: outside;} ul.t2 { list-style-position: inside;} TABLAS Consejos: Diferenciar cabeceras en negrita, mayusculas o algo mas Oscurecer filas alternativas Columnas con numeros alinearlos a la derecha width : poner la anchura de la tabla padding : de las celdas
      y text-transform : en las cabeceras letter-spacing, font-size : para diferenciar el texto de las cabeceras border-top, border-bottom : para fiferenciar los bordes de la cabecera text-align : para alinear el texto de las celdas a conveniencia background-color : cambiar el color de fondo alternando filas :hover : iluminar la fila con el puntero encima body { font-family: Arial, Verdana, sans-serif; color: #111111;} table { width: 600px;} th, td { padding: 7px 10px 10px 10px;} th { text-transform: uppercase; letter-spacing: 0.1em; font-size: 90%; border-bottom: 2px solid #111111; border-top: 1px solid #999; text-align: left;} tr.even { background-color: #efefef;} tr:hover { background-color: #c3e6e5;} .money { text-align: right;} empty-cells - show|hide|inherit indicar en las celdas vacias si mostramos los bordes o no o hereda el comportamiento de la tabla que le contiene table.one { empty-cells: show;} table.two { empty-cells: hide;} border-spacing ajusta la distancia entre celdas adyacentes, por defecto es minima. Se pone en px. Si pones dos valores son la separacion horizontal y la vertical border-collapse los bordes se juntan en un solo borde table.one { border-spacing: 5px 15px;} table.two { border-collapse: collapse;} FORMULARIOS Dar estilo a entradas de texto input { font-size: 120%; // tama\u00f1o del texto color: #5a5854; // color del texto background-color: #f2f2f2; // color del fondo de la entrada border: 1px solid #bdbdbd; // marca los bordes de la entrada border-radius: 5px; // redondea esos bordes padding: 5px 5px 5px 30px; background-repeat: no-repeat; background-position: 8px 9px; display: block; margin-bottom: 10px;} input:focus { // cambia el color de fondo background-color: #ffffff; border: 1px solid #b1e1e4;} input#email { background-image: url(\"images/email.png\");} input#twitter { background-image: url(\"images/twitter.png\");} input#web { background-image: url(\"images/web.png\");} Dar estilo a botones submit input#submit { color: #444444; // color del texto del boton text-shadow: 0px 1px 1px #ffffff; // apariencia 3d border-bottom: 2px solid #b2b2b2; // para el borde del boton background-color: #b9e4e3; background: -webkit-gradient(linear, left top, left bottom, from(#beeae9), to(#a8cfce)); background: -moz-linear-gradient(top, #beeae9, #a8cfce); background: -o-linear-gradient(top, #beeae9, #a8cfce); background: -ms-linear-gradient(top, #beeae9, #a8cfce);} input#submit:hover { // cambia la apariencia del boton color: #333333; // al pasar por encima border: 1px solid #a4a4a4; border-top: 2px solid #b2b2b2; background-color: #a0dbc4; background: -webkit-gradient(linear, left top, left bottom, from(#a8cfce), to(#beeae9)); background: -moz-linear-gradient(top, #a8cfce, #beeae9); background: -o-linear-gradient(top, #a8cfce, #beeae9); background: -ms-linear-gradient(top, #a8cfce, #beeae9);} Poner estilo a fieldsets y legends fieldset { width: 350px; // controlar el tama\u00f1o del form border: 1px solid #dcdcdc; border-radius: 10px; padding: 20px; text-align: right;} legend { background-color: #efefef; // color de fondo border: 1px solid #dcdcdc; border-radius: 10px; padding: 10px 20px; text-align: left; text-transform: uppercase;} Alinear formularios div { border-bottom: 1px solid #efefef; margin: 10px; padding-bottom: 10px; width: 260px;} .title { float: left; width: 100px; text-align: right; padding-right: 10px;} .radio-buttons label { float: none;} .submit { text-align: right;} LAYOUT Tipos posicionamiento position: static normal o estatico es el usado por defecto. Los elementos de bloque se ponen uno a continuacion de otro ocupando todo el ancho de la ventana del navegador salvo que lo limite con `width. position: relative - Los elementos se posicionan en relacion a donde deberian estar en posicion normal. Los desplazamos dando valor a top, bottom, left, right . Estos valores se ponen en px, porcentajes o ems p.example { position: relative; top: 10px; left: 100px;} position: absolute - El elemento se posiciona de forma absolita respecto a su elemento contenedor y el resto de elementos de la pagina le ignoran h1 { position: absolute; top: 0px; left: 500px; width: 250px;} position: fixed - Como el absoluto pero el elemento ahora es inamovible, su posicion permanece igual independiente del resto de elemntos e incluso si se sube o baja en la ventana del navegador. Util para hacer menus fijos por ejemplo en la parte superior de la ventana h1 { position: fixed; top: 0px; left: 50px; padding: 10px; margin: 0px; width: 100%; background-color: #efefef;} position: inherit , hereda la posicion del padre float: left|right - Desplaza los elementos todo lo que puede hacia la dcha o izda segun la propiedad float . Cualquier otro elemento dentro del elemento contenedor fluira alrededor del elemento que flota blockquote { float: right; width: 275px; font-size: 130%; font-style: italic; font-family: Georgia, Times, serif; margin: 0px 0px 10px 10px; padding: 10px; border-top: 1px solid #665544; border-bottom: 1px solid #665544;} propiedades de apoyo clear: left|right|both|none - indica que ningun otro elemento del mismo contenedot debe tocar el lado indicado de ese elemento .clear { clear: left;} overflow: auto; width:100% - Si todos los elemento de un contenedor son flotantes puede hacer problemas en ciertos navegadores a la hora de mostrar los bordes div { border: 1px solid #665544; overflow: auto; width: 100%;} multicolumna - Crear dise\u00f1os multicolumna con floats. Usar un
      para cada columna y con las siguientes propiedades width , float y margin para cerrar un hueco entre las columnas z-index - Al usar posicionamiento relativo, fijo o absoluto los elementos se pueden solapar. Si es asi el ultimo que aparece en el codigo HTML es el que se ve. Para controlar eso esta la propiedad z-index , se ve el elemento con el mayor valor de esa propiedad h1 { position: fixed; z-index: 10;} Tipos de Layout Anchura fija La anchura se especifica en pixeles (a veces tambien la altura) body { width: 960px; margin: 0 auto;} #content { overflow: auto; height: 100%;} #nav, #feature, #footer { background-color: #efefef; padding: 10px; margin: 10px;} .column1, .column2, .column3 { background-color: #efefef; width: 300px; float: left; margin: 10px;} li { display: inline; padding: 5px;} Liquidos La anchura se especifica en porcentajes. 90% de anchura cada columna se le pone un margin: 1% min-width, max-width para limitar los estiramientos body { width: 90%; margin: 0 auto;} #content {overflow: auto;} #nav, #feature, #footer { margin: 1%;} .column1, .column2, .column3 { width: 31.3%; float: left; margin: 1%;} .column3 {margin-right: 0%;} li { display: inline; padding: 0.5em;} #nav, #footer { background-color: #efefef; padding: 0.5em 0;} #feature, .article { height: 10em; margin-bottom: 1em; background-color: #efefef;} Dise\u00f1o 960px IMAGENES Controlar tama\u00f1o Creas tres clases de imagenes, peque\u00f1as, medianas y grandes. Despues a cada imagen le pones la clase a la que pertenece y asi automaticamente se pone a ese tama\u00f1o img.large { width: 500px; height: 500px;} img.medium { width: 250px; height: 250px;} img.small { width: 100px; height: 100px;} Alinear imagenes Se recomienda usar float en lugar de align . Creamos clases align-left align-right y luego a las imagenes les a\u00f1adimos la clase que nos interese img.align-left { float: left; margin-right: 10px;} img.align-right { float: right; margin-left: 10px;} Centrar imagenes Debemos convertir la imagen en en elemento de bloque y luego usar margin img.align-center { display: block; margin: 0px auto;} background background - Orden de las propiedades: background-color background-image background-repeat background-attachment background-position body { background: #ffffff url(\"images/tulip.gif\") no-repeat top right;} background-image - la imagen se ponde de fondo del elemento al que se lo asignamos p { background-image: url(\"images/pattern.gif\");} background-repeat - repeat la imagen se repite horizontal y verticalmente repeat-x la imagen solo se repite horizontalmente repeat-y la imagen solo se repite verticalmente no-repeat la imagen se muestra solo una vez body { background-image: url(\"images/header.gif\"); background-repeat: repeat-x;} background-attachment - fixed la imagen permanece fija scroll la imagen se mueve con el scroll body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-attachment: fixed;} background-position - Para especificar donde sale una imagen que no se repite. La propiedad tiene dos valores: Si solo se indica uno el segundo valor sera center . Tambien se puede usar px o porcentajes posicion horizontal left|center|right posicion vertical top|center|bottom body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: center top;} body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: 50% 50%;} rollover y sprites Enlaces o botones que tienen un segundo estilo al ponerse el puntero encima y un tercer estilo al pincharlos. Se usan sprites que son una sola imagen con diferentes partes a usar. Add to basket Framing options a.button { height: 36px; background-image: url(\"images/sprite.png\"); text-indent: -9999px; display: inline-block;} a#add-to-basket { width: 174px; background-position: 0px 0px;} a#framing-options { width: 210px; background-position: -175px 0px;} a#add-to-basket:hover { background-position: 0px -40px;} a#framing-options:hover { background-position: -175px -40px;} a#add-to-basket:active { background-position: 0px -80px;} a#framing-options:active { background-position: -175px -80px;} TRANSITION .tecla { color: deepskyblue; background: rgba(0, 0, 0, 0.4); text-shadow: 0 0 1px black; transition: background-color 0.2s; } .pulsada { background-color: orange; transform: scale(1.1, 1.1); }
      Aclap
      function pressKey (e) { var valor = mapa.indexOf(e.key.toUpperCase()); if (valor !== -1) { document.getElementById(valor).addEventListener('transitionend', function () { document.getElementById(valor).classList.remove('pulsada'); }); document.getElementById(valor).classList.add('pulsada'); audio[valor].play(); } }","title":"CSS"},{"location":"css/#css","text":"","title":"CSS"},{"location":"css/#snippets","text":"","title":"SNIPPETS"},{"location":"css/#alinear-imagenes","text":".imgV { vertical-align: middle; } .imgH { display: flex; margin: 0 auto; max-width: 100%; }","title":"Alinear imagenes"},{"location":"css/#enlaces-animados-y-sin-subrayar","text":"a, a:visited { text-decoration: none; color: #375EAB; } a:hover { color: lightblue; } div:hover { transform: scale(1.2); } Desactivar enlace a.notYet { pointer-events: none; text-decoration: line-through; color: #404040; }","title":"Enlaces animados y sin subrayar"},{"location":"css/#hr-gradual","text":"hr { margin: 10px 10% 10px 10%; border: 0; height: 1px; background: #333; background-image: linear-gradient(to right, #ccc, #888, #ccc); }","title":"hr gradual"},{"location":"css/#problema-en-chrome-con-la-lista-de-puntos","text":"ul { text-align: center; /* para evitar los puntos */ display: inline; /* poner los numeros en Chrome de listas ordenadas dentro del texto*/ list-style-position: inside; list-style-type: none; }","title":"Problema en Chrome con la lista de puntos"},{"location":"css/#fijar-pie-al-final-de-pantalla","text":"html { height: 100%; box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } body { position: relative; margin: 0 auto; /*padding-bottom: 6rem;*/ min-height: 97%; } .footer { position: absolute; right: 0; bottom: 0; left: 0; padding: 1rem; background-color: lightblue; text-align: center; }","title":"Fijar pie al final de pantalla"},{"location":"css/#tamano-fuente-como-navegador","text":"html { font-size:16px; } /* Fijando el css en 16px y usando em despues conseguiremos resultados consistentes en firefox y chrome */ body { font-size:0.90em; }","title":"Tama\u00f1o fuente como navegador"},{"location":"css/#css3","text":"","title":"CSS3"},{"location":"css/#introduccion","text":"Enlaces a css Externo CSS Externo Si hay multiples hojas de estilo : uno para cada hoja de estilo En la hoja de estilo que se enlaza incluir @import url(\"estilo2.css);\" Interno - NO USAR CSS Interno ","title":"INTRODUCCION"},{"location":"css/#selectores","text":"Selectores CSS Selectores de atributos","title":"Selectores"},{"location":"css/#cascada-y-herencia","text":"Cascada - Ultima Regla: la ultima regla aplicada es la que manda - !important a\u00f1adiendo esto despues de la regla asi toma prioridad color: blue !important; - Especificidad : prevalecera la regla del selector que sea mas especifico h3 es mas especifico que * p otro es mas especifico que p p#intro es mas especifico que p Herencia Casi todos los selectores anidados dentro de otros heredan las propiedades asignadas al selector exterior. Por ejemplo un color en body tambien se aplicara al texto de un parrafo. Hay excepciones evidentes como margin-top (un parrafo no tiene el mismo margen superior que el body del documento). Puedes forzar heredar valores de propiedades de los padres usando inherit como valor de la propiedad body { padding: 20px;} .pagina { padding: inherit;}","title":"Cascada y herencia"},{"location":"css/#color","text":"color - h1 { color: DarkCyan;} /* color name */ h2 { color: #ee3e80;} /* hex code */ p { color: rgb(100,100,90);} /* rgb value */ background color - body { background-color: rgb(150,150,150); } h1 { background-color: DarkCyan; } h2 { background-color: ##ee3e80: } p { background-color: red; } opacity , rgba - p.one { background-color: rgb(0,0,0); opacity: 0.5;} p.two { background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.5);}","title":"COLOR"},{"location":"css/#texto","text":"cursor - Controla el tipo de cursor del raton que se muestra auto|crosshair|default|pointer|move|text|wait|help|url(\"cursor.png\") a { cursor: move;} font-family - Familias : serif , sans-serif , cursive , fantasy y monospace font-family: Arial, Verdana, sans-serif font-size - Pixel: Por defecto en los navegadores el texto es de 16px Porcentaje : porcentaje sobre los 16px estandar, p.ej 75% es 12px em : unidad equivalente a la anchura de la m font-face - @font-face { font-family: 'PT Sans'; src: url('_public/fonts/PTSans.ttf') ; font-display: fallback; } @font-face { font-family: 'ChunkFiveRegular'; src: url('fonts/chunkfive.eot'); src: url('fonts/chunkfive.eot?#iefix') format('embedded-opentype'), url('fonts/chunkfive.woff') format('woff'), url('fonts/chunkfive.ttf') format('truetype'), url('fonts/chunkfive.svg#ChunkFiveRegular') format('svg');} font-weight - normal|bold font-style - normal|italic|oblique text-transform - uppercase : convierte el texto a mayusculas lowercase : convierte el texto a minusculas capitalize : pone mayusculas la primera letra de cada palabra h1 { text-transform: uppercase;} text-decoration - none : elimina cualquier decoracion del texto underline : subraya el texto overline : coloca una linea por encima del texto line-through : linea tachando el texto blink : hace que el texto brille y deje brillar a { text-decoration: none;} line-height - distancia entre lineas p { line-height: 1.4em; } letter-spacing , word-spacing - distancia entre letras, distancia entre palabras, por defecto es 0.25em h1, h2 { text-transform: uppercase; letter-spacing: 0.2em; } .credits { font-weight: bold; word-spacing: 1em; } text-align - left : el texto se alinea a la izquierda right : el texto se alinea a la derecha center : el texto se centra justify : Cada linea excepto la ultima ocupa toda la anchura disponible h1 { text-align: left; } vertical-align - Usada con elementos en linea como y es muy similar al atributo align de Valores : baseline , sub , super , top , text-top , middle , bottom , text-bottom #six-months { vertical-align: text-top;} #one-year { vertical-align: baseline;} #two-years { vertical-align: text-bottom;} text-indent - indenta el texto h2 { text-indent: 20px; } text-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado de la sombra color de la sombra p { text-shadow: 2px 2px 1px #222222} :first-letter , :first-line (pseudo-elementos) - Para especificar diferentes valores a la primera letra o primera linea del texto p.intro:first-letter { font-size: 200%;} p.intro:first-line { font-weight: bold;} :link , :visited (pseudo-clases) - Los navegadores muestran los enlaces en azul y subrayados por defecto y cambian el color cuando han sido visitados :link : para poner estilos a enlaces no visitados :visited : para poner estilos a enlaces visitados a:link { color: deeppink; text-decoration: none;} a:visited { color: black;} a:hover { color: deeppink; text-decoration: underline;} a:active { color: darkcyan;} :hover , :active , :focus (pseudo-clases) - :hover : se aplica cuando el raton esta encima (no funciona en tactiles) :active : se aplica cuando se pulsa algo :focus : se aplica cuando el elemento tiene el foco cajetinTexto { padding: 6px 12px 6px 12px; border: 1px solid #665544; color: #ffffff;} boton.submit:hover { background-color: #665544;} boton.submit:active { background-color: chocolate;} cajetinTexto.text { color: #cccccc;} cajetinTexto.text:focus { color: #665544;}","title":"TEXTO"},{"location":"css/#boxes","text":"Dimensiones width , height - Por defecto las cajas tienen el tama\u00f1o justo para contener a su elemento. Podemos establecer nosotros ese tama\u00f1o usando pixeles , o porcentajes relativos a la ventana del navegador o a la caja en que ya esta si esta dentro de otra caja, o ems div.box { height: 300px; width: 300px; background-color: #bbbbaa;} min-width , max-width - Minimo y maximo anchura que una caja de un elemento puede tener min-height , max-height - Minimo y maximo anchura que una caja de un elemento puede tener overflow - Indica como actuar si el contenido dentro de la caja es mayor que la caja. hidden : el contenido extra que no cabe sencillamente se esconde scroll : aparece un scroll para acceder a ese contenido extra p.one { overflow: hidden;} p.two { overflow: scroll;} Visibilidad display - Permite convertir un elemento en linea en un bloque o al reves. Tambien vale para esconder un elemento en la pagina inline : convierte un elemento de bloque en un elemento en linea block : convierte un elemento en linea en un elemento de bloque inline-block : permite a un elemento de bloque fluir como un elemento en linea pero manteniendo las caracteristicas de un elemento de bloque none : esconde el elemento de la pagina li { display: inline; margin-right: 10px;} li.coming-soon { display: none;} visibility - Permite esconder cajas pero deja un espacio donde se supone que esta hidden : esconde el elemento visible : muestra el elemento li.coming-soon { visibility: hidden;} box-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado del borde. Con cero la sombra es una linea solida Extension de la sombra, positiva hacia fuera, negativa hacia dentro p { box-shadow: 2px 2px 1px 5px #777777} Bordes border-padding-margin - border-width - espesor de la linea de borde thin|medium|thick . border-top-width , border-right-width , border-bottom-width border-left-width en orden de las agujas del reloj empezando por top p.one { border-width: 2px;} p.two { border-width: thick;} p.three { border-width: 1px 4px 12px 4px;} border-style - define el tipo de borde solid|dotted|dashed|double|groove|ridge|inset|outset|hidden/none . border-top-style ... - Puedes elegir bordes individuales p.one {border-style: dashed;} border-color - elegir color para el borde border-top-color ... - Tambien se puede elegir el color para cada borde p.one { border-color: #0088dd;} p.two { border-color: #bbbbaa blue orange #0088dd;} border-image - Permite usar imagenes como bordes de las cajas border-radius - border-top-right-radius - border-bottom-right-radius - border-bottom-left-radius - border-top-left-radius - p { border-radius: 5px, 10px, 5px, 10px; } p.one { border-radius: 80px 50px; } p.two { border-top-left-radius: 80px 50px;} Margenes margin - Espacio entre el borde y la caja. Lo normal en px aunque tambien se puede en ems o porcentajes. Si dos cajas se solapan usaremos el mayor de los dos margenes y el otro no Tambien individualmente para cada lado margin-top, margin-right ... p.example1 { margin: 10px 2px 10px 5px; p.example2 { margin: 10px;} padding - Espacio entre el borde y el contenido. Lo normal es en px pero se pueden usar ems o porcentajes (% de la ventana del navegador o de la caja donde este contenido el elemento). Existen tambien individualmente para cada lado padding-top, padding-right ... p.example1 { padding: 10px 2px 10px 5px; p.example2 { padding: 10px;} centrando contenido - Para centrar una caja en la pagina ( o centrarla dentro del elemento en el que esta Establecer una width para la caja (sino tomara toda la anchura de la pagina) Poner margin-left: auto y margin-rigth: auto p { width: 300px; padding: 50px; border: 20px solid #0088dd;} p.example { margin: 10px auto 10px auto;","title":"BOXES"},{"location":"css/#listas","text":"list-style - Permite declaras las siguientes opciones type, imagen y position en cualquier orden. ul { list-style: inside circle; } list-style-type - Para poner el estilo al marcador de las listas - Listas ordenadas decimal|decimal-leading-zero|lower-alpha|upper-alpha|lower-roman|upper-roman - Listas desordenadas none|disc|circle|square ol { list-style-type: lower-roman;} list-style-imagen - Usar una imagen como marcador de listas. Se puede usar en
        y
      • ul { list-style-image: url(\"images/star.png\");} list-style-position - Por defecto el marcador de lista aparece outside del indentado de la lista. Podemos cambiarlo por inside para que el marcador entre en la caja del texto el cual esta indentado ul.t1 { list-style-position: outside;} ul.t2 { list-style-position: inside;}","title":"LISTAS"},{"location":"css/#tablas","text":"Consejos: Diferenciar cabeceras en negrita, mayusculas o algo mas Oscurecer filas alternativas Columnas con numeros alinearlos a la derecha width : poner la anchura de la tabla padding : de las celdas
        y text-transform : en las cabeceras letter-spacing, font-size : para diferenciar el texto de las cabeceras border-top, border-bottom : para fiferenciar los bordes de la cabecera text-align : para alinear el texto de las celdas a conveniencia background-color : cambiar el color de fondo alternando filas :hover : iluminar la fila con el puntero encima body { font-family: Arial, Verdana, sans-serif; color: #111111;} table { width: 600px;} th, td { padding: 7px 10px 10px 10px;} th { text-transform: uppercase; letter-spacing: 0.1em; font-size: 90%; border-bottom: 2px solid #111111; border-top: 1px solid #999; text-align: left;} tr.even { background-color: #efefef;} tr:hover { background-color: #c3e6e5;} .money { text-align: right;} empty-cells - show|hide|inherit indicar en las celdas vacias si mostramos los bordes o no o hereda el comportamiento de la tabla que le contiene table.one { empty-cells: show;} table.two { empty-cells: hide;} border-spacing ajusta la distancia entre celdas adyacentes, por defecto es minima. Se pone en px. Si pones dos valores son la separacion horizontal y la vertical border-collapse los bordes se juntan en un solo borde table.one { border-spacing: 5px 15px;} table.two { border-collapse: collapse;}","title":"TABLAS"},{"location":"css/#formularios","text":"Dar estilo a entradas de texto input { font-size: 120%; // tama\u00f1o del texto color: #5a5854; // color del texto background-color: #f2f2f2; // color del fondo de la entrada border: 1px solid #bdbdbd; // marca los bordes de la entrada border-radius: 5px; // redondea esos bordes padding: 5px 5px 5px 30px; background-repeat: no-repeat; background-position: 8px 9px; display: block; margin-bottom: 10px;} input:focus { // cambia el color de fondo background-color: #ffffff; border: 1px solid #b1e1e4;} input#email { background-image: url(\"images/email.png\");} input#twitter { background-image: url(\"images/twitter.png\");} input#web { background-image: url(\"images/web.png\");} Dar estilo a botones submit input#submit { color: #444444; // color del texto del boton text-shadow: 0px 1px 1px #ffffff; // apariencia 3d border-bottom: 2px solid #b2b2b2; // para el borde del boton background-color: #b9e4e3; background: -webkit-gradient(linear, left top, left bottom, from(#beeae9), to(#a8cfce)); background: -moz-linear-gradient(top, #beeae9, #a8cfce); background: -o-linear-gradient(top, #beeae9, #a8cfce); background: -ms-linear-gradient(top, #beeae9, #a8cfce);} input#submit:hover { // cambia la apariencia del boton color: #333333; // al pasar por encima border: 1px solid #a4a4a4; border-top: 2px solid #b2b2b2; background-color: #a0dbc4; background: -webkit-gradient(linear, left top, left bottom, from(#a8cfce), to(#beeae9)); background: -moz-linear-gradient(top, #a8cfce, #beeae9); background: -o-linear-gradient(top, #a8cfce, #beeae9); background: -ms-linear-gradient(top, #a8cfce, #beeae9);} Poner estilo a fieldsets y legends fieldset { width: 350px; // controlar el tama\u00f1o del form border: 1px solid #dcdcdc; border-radius: 10px; padding: 20px; text-align: right;} legend { background-color: #efefef; // color de fondo border: 1px solid #dcdcdc; border-radius: 10px; padding: 10px 20px; text-align: left; text-transform: uppercase;} Alinear formularios div { border-bottom: 1px solid #efefef; margin: 10px; padding-bottom: 10px; width: 260px;} .title { float: left; width: 100px; text-align: right; padding-right: 10px;} .radio-buttons label { float: none;} .submit { text-align: right;}","title":"FORMULARIOS"},{"location":"css/#layout","text":"Tipos posicionamiento position: static normal o estatico es el usado por defecto. Los elementos de bloque se ponen uno a continuacion de otro ocupando todo el ancho de la ventana del navegador salvo que lo limite con `width. position: relative - Los elementos se posicionan en relacion a donde deberian estar en posicion normal. Los desplazamos dando valor a top, bottom, left, right . Estos valores se ponen en px, porcentajes o ems p.example { position: relative; top: 10px; left: 100px;} position: absolute - El elemento se posiciona de forma absolita respecto a su elemento contenedor y el resto de elementos de la pagina le ignoran h1 { position: absolute; top: 0px; left: 500px; width: 250px;} position: fixed - Como el absoluto pero el elemento ahora es inamovible, su posicion permanece igual independiente del resto de elemntos e incluso si se sube o baja en la ventana del navegador. Util para hacer menus fijos por ejemplo en la parte superior de la ventana h1 { position: fixed; top: 0px; left: 50px; padding: 10px; margin: 0px; width: 100%; background-color: #efefef;} position: inherit , hereda la posicion del padre float: left|right - Desplaza los elementos todo lo que puede hacia la dcha o izda segun la propiedad float . Cualquier otro elemento dentro del elemento contenedor fluira alrededor del elemento que flota blockquote { float: right; width: 275px; font-size: 130%; font-style: italic; font-family: Georgia, Times, serif; margin: 0px 0px 10px 10px; padding: 10px; border-top: 1px solid #665544; border-bottom: 1px solid #665544;} propiedades de apoyo clear: left|right|both|none - indica que ningun otro elemento del mismo contenedot debe tocar el lado indicado de ese elemento .clear { clear: left;} overflow: auto; width:100% - Si todos los elemento de un contenedor son flotantes puede hacer problemas en ciertos navegadores a la hora de mostrar los bordes div { border: 1px solid #665544; overflow: auto; width: 100%;} multicolumna - Crear dise\u00f1os multicolumna con floats. Usar un
        para cada columna y con las siguientes propiedades width , float y margin para cerrar un hueco entre las columnas z-index - Al usar posicionamiento relativo, fijo o absoluto los elementos se pueden solapar. Si es asi el ultimo que aparece en el codigo HTML es el que se ve. Para controlar eso esta la propiedad z-index , se ve el elemento con el mayor valor de esa propiedad h1 { position: fixed; z-index: 10;} Tipos de Layout Anchura fija La anchura se especifica en pixeles (a veces tambien la altura) body { width: 960px; margin: 0 auto;} #content { overflow: auto; height: 100%;} #nav, #feature, #footer { background-color: #efefef; padding: 10px; margin: 10px;} .column1, .column2, .column3 { background-color: #efefef; width: 300px; float: left; margin: 10px;} li { display: inline; padding: 5px;} Liquidos La anchura se especifica en porcentajes. 90% de anchura cada columna se le pone un margin: 1% min-width, max-width para limitar los estiramientos body { width: 90%; margin: 0 auto;} #content {overflow: auto;} #nav, #feature, #footer { margin: 1%;} .column1, .column2, .column3 { width: 31.3%; float: left; margin: 1%;} .column3 {margin-right: 0%;} li { display: inline; padding: 0.5em;} #nav, #footer { background-color: #efefef; padding: 0.5em 0;} #feature, .article { height: 10em; margin-bottom: 1em; background-color: #efefef;} Dise\u00f1o 960px","title":"LAYOUT"},{"location":"css/#imagenes","text":"Controlar tama\u00f1o Creas tres clases de imagenes, peque\u00f1as, medianas y grandes. Despues a cada imagen le pones la clase a la que pertenece y asi automaticamente se pone a ese tama\u00f1o img.large { width: 500px; height: 500px;} img.medium { width: 250px; height: 250px;} img.small { width: 100px; height: 100px;} Alinear imagenes Se recomienda usar float en lugar de align . Creamos clases align-left align-right y luego a las imagenes les a\u00f1adimos la clase que nos interese img.align-left { float: left; margin-right: 10px;} img.align-right { float: right; margin-left: 10px;} Centrar imagenes Debemos convertir la imagen en en elemento de bloque y luego usar margin img.align-center { display: block; margin: 0px auto;} background background - Orden de las propiedades: background-color background-image background-repeat background-attachment background-position body { background: #ffffff url(\"images/tulip.gif\") no-repeat top right;} background-image - la imagen se ponde de fondo del elemento al que se lo asignamos p { background-image: url(\"images/pattern.gif\");} background-repeat - repeat la imagen se repite horizontal y verticalmente repeat-x la imagen solo se repite horizontalmente repeat-y la imagen solo se repite verticalmente no-repeat la imagen se muestra solo una vez body { background-image: url(\"images/header.gif\"); background-repeat: repeat-x;} background-attachment - fixed la imagen permanece fija scroll la imagen se mueve con el scroll body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-attachment: fixed;} background-position - Para especificar donde sale una imagen que no se repite. La propiedad tiene dos valores: Si solo se indica uno el segundo valor sera center . Tambien se puede usar px o porcentajes posicion horizontal left|center|right posicion vertical top|center|bottom body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: center top;} body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: 50% 50%;} rollover y sprites Enlaces o botones que tienen un segundo estilo al ponerse el puntero encima y un tercer estilo al pincharlos. Se usan sprites que son una sola imagen con diferentes partes a usar. Add to basket Framing options a.button { height: 36px; background-image: url(\"images/sprite.png\"); text-indent: -9999px; display: inline-block;} a#add-to-basket { width: 174px; background-position: 0px 0px;} a#framing-options { width: 210px; background-position: -175px 0px;} a#add-to-basket:hover { background-position: 0px -40px;} a#framing-options:hover { background-position: -175px -40px;} a#add-to-basket:active { background-position: 0px -80px;} a#framing-options:active { background-position: -175px -80px;}","title":"IMAGENES"},{"location":"css/#transition","text":".tecla { color: deepskyblue; background: rgba(0, 0, 0, 0.4); text-shadow: 0 0 1px black; transition: background-color 0.2s; } .pulsada { background-color: orange; transform: scale(1.1, 1.1); }
        Aclap
        function pressKey (e) { var valor = mapa.indexOf(e.key.toUpperCase()); if (valor !== -1) { document.getElementById(valor).addEventListener('transitionend', function () { document.getElementById(valor).classList.remove('pulsada'); }); document.getElementById(valor).classList.add('pulsada'); audio[valor].play(); } }","title":"TRANSITION"},{"location":"debian/","text":"DEBIAN 12 BOOKWORM STABLE Para andar con ojo en las actualizaciones instalar aptitude install apt-listbugs Debian Package Searcher Repositories nano /etc/apt/sources.list ## Debian stable deb https://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware ## Debian security deb https://deb.debian.org/debian-security bookworm-security non-free contrib main non-free-firmware ## Debian updates deb https://deb.debian.org/debian/ bookworm-updates non-free contrib main non-free-firmware ## Debian backports #deb https://deb.debian.org/debian/ bookworm-backports main contrib #non-free non-free-firmware ## Insync deb https://apt.insync.io/debian bookworm non-free contrib ## NodeSource #deb [signed-by=/etc/apt/keyrings/nodesource.gpg] #https://deb.nodesource.com/ node_20.x nodistro main ## Debian Multimedia #deb http://www.deb-multimedia.org/ bookworm main non-free # Chrome deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # Teamviewer #deb [signed-by=/usr/share/keyrings/teamviewer-keyring.gpg] #https://linux.teamviewer.com/deb stable main apt install aptitude htop smartmontools sshpass rsync curl wget nano apt-transport-https iperf zip arc arj bzip2 cabextract lzop nomarch p7zip p7zip-full pax tnef unrar-free unzip unrar deborphan net-tools intel-microcode hdparm ncdu rename iftop dns9utils nethogs tcptrack dnsutils curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg Para instalar Dropbox COMMANDS Add font fc-cache -f -v - tras haber copiado la fuente a /usr/share/fonts gpg gpg -c file.txt - cifra a archivo binario gpg -ca file.txt - cifra a archivo de texto gpg --output output.txt -d file.(gpg or txt) - para descifrar // convertir directorio en un archivo tar czf myfiles.tar.gz mydirectory/ // convertir archivo a un directorio tar xzf myfiles.tar.gz echo RELOADAGENT | gpg-connect-agent - para eliminar de la memoria la clave y que la pida al descomprimir grep Eliminar todas las lineas de una fichero que contienen un determinado 'texto' cat nombreArchivo | grep -v 'texto' > nuevoArchivo Coger solo las lineas de un archivo que contienen un determinado 'texto' grep -i \"texto\" nombreArchivo zip zip -er zipName.zip path/to/folder/ - Comprimir carpeta con contrase\u00f1a dpkg dpkg -i package.deb - apt-get -f install - reparar dependencias incumplidas si las hay dpkg -r onlyThaName - desinstalar debconf-show nombrePaquete - muestra configuracion del paquete instalado dpkg-reconfigure nombrePaquete - para reconfigurar el paquete Tama\u00f1o de ficheros y carpetas ls -lh du -ah /path du -h -d1 | sort -h Lista de directorios (ocultos incluidos) con su tama\u00f1o df -h du -sh * Lista de directorios (no ocultos) con su tama\u00f1o apt install ncdu ncdu Dividir archivo en varios Dividir archivo en trozos de 200mb asegurandoes que el corte no se produce en medio de una linea split -C 200m archivo.txt Limpieza apt-get autoclean && apt-get autoremove && apt-get remove --purge `deborphan` dpkg -l | grep -v ^ii | awk '{print $2}' | sed '1,5d'|xargs dpkg --purge Ver el tama\u00f1o de los logs y limpiar todos excepto los ultimos 3 dias journalctl --disk-usage journalctl --vacuum-time=3d Limpiar caches de imagenes du -sh ~/.cache/thumbnails rm -rf ~/.cache/thumbnails/* Process pgrep processName - buscar proceso ps - listar todos los procesos kill processNumber - matar proceso fg - continuar el proceso que estaba detenido nohup comando & - Ejecuta un comando en segundo plano y sigue ejecutandolo aunque salgamos de esa terminal ulimits error too many open files lsof - para encontrar file descriptors usados lsof -p PID | wc -l - indica cuantos file descriptors (archivos u otros recursos como conexiones http) tiene abiertos el proceso PID lsof -c PROCESS-NAME | wc -l - igual que arriba pero por nombre ulimit -n - muestra el limite de fd que el usuario puede usar ulimit -n 4096 - sube ese limite por ejemplo lo normal es 1024 a 4096 pero solo para esa sesion // Para Hacerlo permamente nano /etc/security/limits.conf userName soft nofile 2000 * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 // Cambiar el limite de fd de un proceso en ejecucion prlimit --pid pidID --nofile=soft:hard prlimit --pid XXXX --nofile=XXXX:XXXX en nginx user www-data; worker_processes 4; pid /run/nginx.pid; worker_rlimit_nofile 50000; events { worker_connections 4000; # multi_accept on; } Buena guia Incrementar limites -> Por usuario nano /etc/security/limits.conf A\u00f1adir al final * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 Guardar el archivo y hacer logout y login de nuevo Si esto no funciona probar con pam-limits nano /etc/pam.d/common-session a\u00f1adir session required pam_limits.so -> Para Todo el Sistema nano /etc/sysctl.conf a\u00f1adir fs.file-max = 2097152 Salimos y ejecutamos sysctl -p -> Verificar que funcionan los nuevos limites cat /proc/sys/fs/file-max Hard Limit ulimit -Hn Soft Limit ulimit -Sn verificar para un usuario su - nombreUsuario -c 'ulimit -aHS' -s '/bin/bash' Verificar para un proceso en ejecucion conseguimos el PID ps aux | grep nombreDelProceso cat /proc/XXX/limits Buscar find /path -name fileName - Buscar archivo find /path -type d -name dirName - Buscar carpeta Crear nuevo usuario useradd -d /home/username -m -s /bin/bash username - Crea un usuario con su carpeta home y consola para usar passwd username - Para crear la contrase\u00f1a del usuario Zona horaria dpkg-reconfigure tzdata - reconfigurar la zona horaria cpulimit apt-get install cpulimit ps aux | grep nombreProceso - nos da el id del proceso cpulimit -p id -l 30 - limita el proceso id al 30% cpulimit -e nombreProceso -l 50 - limita el proceso nombreProceso al 50% A\u00f1adir & para recuperar el control de la consola averiguar la version de debian lsb_release -a dns dig domain.tld @9.9.9.9 cron crontab -e // activar los logs de cron nano /etc/rsyslog.conf // descomentar la linea #cron.* -/var/log/cron service rsyslog restart // ejecutar algo al inicio del servidor crontab -e // como root @reboot cd /home/user/donde-sea && ./programa nmap nmap -Pn X.X.X.X || hostname rename multiple files at once apt install rename // Reemplazar la 1 ocurrencia de abc por xyz rename 's/abc/xyz/' * curl // tiempo en ir, procesar y volver curl -o /dev/null -s -w 'Total: %{time_total}s\\n' https://pagina.web SECURITY SSH aptitude install openssh-server openssh-client nano /etc/ssh/sshd_config // Para quitar acceso como root # Authentication: LoginGraceTime 120 PermitRootLogin without-password // jode mas que poner solo no StrictModes yes // Por seguridad # Para permitir contrase\u00f1as vacias pon yes (NI SE TE OCURRA HACERLO) PermitEmptyPasswords no service ssh restart sshpass -p contrase\u00f1a ssh usuario@dominio Broken pipe Para prevenir desconexiones del tipo broken pipe nano -c /etc/ssh/ssh_config Host * ServerAliveInterval 120 CLAMAV Antivirus para asegurarnos de que no somos conductores de virus entre maquinas windows y por si las moscas ... apt-get install clamav clamav-docs clamav-daemon clamav-freshclam aptitude install arc arj bzip2 cabextract lzop nomarch p7zip pax tnef unrar-free unzip zoo lha unrar - Para que escanee archivos comprimidos nano /etc/clamav/freshclam.conf - El archivo de configuracion por si queremos cambiar algo. service clamav-freshclam restart - hacerlo despues para cargar la nueva configuracion // Para actualizar, como root freshclam // Si esta bloqueado /etc/init.d/clamav-freshclam stop //despues => service clamav-freshclam start // para escanear como usuario normal clamscan -r /ruta/a/escanear RKHUNTER aptitude install rkhunter //para actualizar, como root rkhunter --propupd rkhunter --update //para usar, como root tambien rkhunter --check FAIL2BAN apt-get install fail2ban whois cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local nano /etc/fail2ban/jail.local // Aqui van las IPs que no tendran esas restricciones [DEFAULT] # \"ignoreip\" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1 192.168.1.0/24 bantime = 1800 maxretry = 3 // Correo al que avisar ante sucesos # Destination email address used solely for the interpolations in # jail.{conf,local} configuration files. destemail = root@localhost [webmin] enabled = true port = 10000 filter = webmin-auth banaction = iptables-multiport action = %(action_mwl)s logpath = /var/log/auth.log maxretry = 3 [ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [ssh-ddos] enabled = true port = ssh filter = sshd-ddos logpath = /var/log/auth.log maxretry = 3 service fail2ban restart service fail2ban status Los logs de baneos estan en estos dos archivos /var/log/fail2ban.log /var/log/auth.log manual unban fail2ban-client set ssh unbanip X.X.X.X UFW apt-get install ufw ufw allow ssh/tcp ufw logging on Antes de esto no se podia activar porque nos echa de la sesion de SSH. Ahora si => ufw enable ufw allow smtp/tcp ufw allow http/tcp ufw allow https/tcp ufw allow webmin ufw status - rules list ufw status numbered - numbered rules list ufw delete X - delete rule X bloquear IPs ufw insert 1 deny from X.X.X.X to any nano -c /etc/ufw/before.rules # End required lines -A ufw-before-input -s X.X.X.X -j DROP ufw reload PM2 Instalar npm install pm2 -g npm remove pm2 -g Configuracion DOCS pm2 startup - como usuario y seguir instrucciones para hacer que pm2 se ejecute en los reinicios sin necesitar ser root pm2 unstartup - para desmontar el chiringuito NO SIEMPRE Para ejecutar los procesos como user y no como root chmod -R 777 /home/user/.pm2 Comandos pm2 start app.js pm2 kill // para la ejecucion pero con un reboot se activara de nuevo pm2 list pm2 stop all|number pm2 restart all|number pm2 delete 7 // elimina el proceso especifico con ese id pm2 save // salva la lista de procesos en ese momento pm2 start app.js --name \"my-name\" pm2 restart app --name \"nuevo-nombre\" --update-env // para renombrar pm2 reset app // pone el contador de restarts a cero dev pm2-dev start app.js pm2-dev start app.js --ignore folder1,folder2,file3.txt cluster variables // -i numero de procesos que levanta pm2 start name.js -i max process.env.NODE_APP_INSTANCE; process.env.name process.env.pm_id max-memory-restart pm2 start geoip.js -i max --max-memory-restart 1300M 50M 50K 1G scale // Sumar 3 procesos al actual pm2 scale app +3 // deja 3 procesos activos de todos los que este usando actualmente pm2 scale app 3 cluster logs in the same file // ecosystem.config.js module.exports = { apps: [{ name: 'codetabs', script: 'codetabs.js', ignore_watch: [\"node_modules\", \"tmp\"], output: './../logs/hits.log', error: './../logs/errors.log', env: { NODE_ENV: \"development\", }, env_production: { NODE_ENV: \"production\", }, instances: 8, max_memory_restart: \"1G\", merge_logs: true, log_date_format: 'YYYY-MM-DD HH:mm:ss', }] }; pm2 start ecosystem.config.js --env production NPM sin ser ROOT Como instalar paquetes npm globalmente sin ser root // crear carpeta para los paquetes globales mkdir \"${HOME}/.npm-packages\" // crear .npmrc nano ${HOME}/.npmrc prefix=${HOME}/.npm-packages //editar .bashrc nano ${HOME}/.bashrc NPM_PACKAGES=\"${HOME}/.npm-packages\" PATH=\"$NPM_PACKAGES/bin:$PATH\" unset MANPATH # delete if already modified MANPATH elsewhere export MANPATH=\"$NPM_PACKAGES/share/man:$(manpath)\" // recargar la configuracion para aplicar los cambios source ~/.profile SYSTEMD systemctl status servidorGO - nos da informacion del servicion Crear Servicio nano /etc/systemd/servidorGO.service cp servidorGO.service /etc/systemd/system systemctl enable servidorGO.service service servidorGO.service start Borrar servicio systemctl stop [servicename] systemctl disable [servicename] rm /etc/systemd/system/[servicename] systemctl daemon-reload systemctl reset-failed nombre.service [Unit] Description= Descripcion de la tarea [Service] User=user Group=www-data Restart=on-failure WorkingDirectory=/var/www/path/to/binary/folder ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target Commandos service name status service name start systemctl enable name.service systemctl disable name.service systemctl start name.service systemctl stop name.service systemctl restart name.service systemctl status name.service systemctl reload name.service // Required files /etc/systemd/servidorGO.service /etc/systemd/system/servidorGO.service /etc/systemd/system/multi-user.target.wants/servidorGO.service /sys/fs/cgroup/systemd/system.slice/servidorGO.service Otra opcion ? nano /lib/systemd/system/name.service [Unit] Description= Task description [Service] Type=simple Restart=always RestartSec=5s ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target service name start service name status // para activarlo desde el reinicio del sistema systemctl enable name.service SYSTEMD sin ser ROOT Systemd sin ser ROOT Primero asegurarnos de que este instalado dbus para user apt install dbus-user-session apt install policykit-1 por si da guerra org.freedesktop.policytoolkit1 Creamos carpeta donde guardar los servicios mkdir -p ~/.config/systemd/user En esa carpeta creamos el nombreservicio.service [Unit] Description= Descripcion de la tarea [Service] RestartSec=5s Restart=always WorkingDirectory=/ruta/a/la/carpeta/del/binario ExecStart=/ruta/a/la/carpeta/del/binario/./nombreDelBinario [Install] WantedBy=default.target Ahora hacemos que systemd reconozca los cambios systemctl --user daemon-reload Ya podemos gestionar el servicio systemctl --user start nombreDelServicio systemctl --user stop nombreDelServicio systemctl --user restart nombreDelServicio systemctl --user status nombreDelServicio Para que el servicio se inicie automaticamente cuando el usuario se loguea systemctl --user enable nombreDelServicio // sin el .service al final Para desactivarlo systemctl --user disable nombreDelServicio Hay que hacer que el servicio corra siempre, este o no logueado el due\u00f1o y al inicio del sistema. Para ello como root ejecutamos loginctl enable-linger NOMBREUSUARIO Ya como usuario normal podemos ver el estado de los servicios loginctl user-status NOMBREUSUARIO NGINX Instalacion apt-get install nginx chown -R user:user /var/www - Para darle permisos al usuario para toda esa carpeta mkdir -p /var/www/site1 mkdir -p /var/www/site2 Configuracion nano /etc/nginx/nginx.conf El archivo de configuracion se llama default y esta en la carpeta /etc/nginx/sites-available .Lo borramos o lo renombramos a default.old . La copia de default que esta en /etc/nginx/sites-enabled hay que borrarla Ahora podemos crear nuestro archivo/s de configuracion. nano /etc/nginx/sites-available/domain cp /etc/nginx/sites-available/domain /etc/nginx/sites-enabled/domain service nginx restart nginx -s reload solo para recargar el archivo de configuracion server-side-includes Server Side Includes Directivas y variables ssi on - /etc/nginx/sites-available Para las rutas ojo porque es desde la raiz del servidor web nginx para esa location ocultar la version de nginx nano /etc/nginx/nginx.conf http { server_tokens off; } headers(cabeceras) Ojo, que algunas pueden restringir el comportamiento de las aplicaciones que tengamos # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; add_header Content-Security-Policy \"default-src 'self'\"; En el location block para evitar cualquier indexacion de esa location por parte de los robots de busqueda add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; Limitar tama\u00f1o de los archivos de subida location /count-loc/ { # set client body size to 10M client_max_body_size 10M; } rate Limit nano /etc/nginx/nginx.conf // aqui definimos por ejemplo la zona=one # limit requests limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s; //luego hay que aplicarlo, mejor en location que en server nano /etc/nginx/sites-available/domain location /count-loc/ { # requests limit limit_req zone=one burst=20; } Apply limits per IP geo $limit { default 1; X.X.X.X 0; Y.Y.Y.Y 0; } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=1r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; http2 nano /etc/nginx/nginx.conf // usar solo cifrados muy seguros ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256: RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; // hay que generar una nuevas claves, lo mejor en /etc/nginx/ssl cd /etc/nginx/ssl openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 // http2 solo funciona con https asi que en el bloque de listen 443 listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; // para mejorar rendimiento ssl_session_cache shared:SSL:5m; ssl_session_timeout 1h; cache // en sites-availables bloque propio # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } // luego en el bloque server que queramos a\u00f1adir expires $expires; zonas privadas // crear archivo con la contrase\u00f1a apt-get install apache2-utils cd /etc/nginx htpasswd -c .rethinkdb.pass // will ask for password service nginx restart server { listen 443 ssl; server_name sub.domain.com; location / { ... } location /private/ { auth_basic \"Restricted\"; auth_basic_user_file /etc/nginx/.rethinkdb.pass; ... root or proxy for this location } } custom 404 mkdir /var/www/error => 404.html 404.css , js, png ... server { error_page 404 /404.html; location = /404.html { root /var/www/error; internal; } location = /404.css { root /var/www/error; } location = /caution.png { root /var/www/error; } } En 404.html llamamos a los recursos usando rutas absolutas block domains map $http_referer $bad_referer { default 0; \"~spamdomain1.com\" 1; \"~spamdomain2.com\" 1; \"~spamdomain3.com\" 1; } if ($bad_referer) { return 444; } nginx.conf actualizado 2019-05-08 user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; server_names_hash_bucket_size 64; # 128? # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; # set client body size to 5M # client_max_body_size 2M; # limit requests geo $limit { default 1; X.X.X.X 0; #server1 X.X.X.X 0; #server2 X.X.X:X 0; #server3 X.X.X.X 0; #server4 } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=2r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; limit_req_zone $limit_key zone=five:10m rate=1r/s; limit_req_zone $limit_key zone=six:1000m rate=10r/s; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA +AES256:EECDH+3DES:RSA+3DES:!MD5; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_disable \"msie6\"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml applicati$ ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } dominio-template.conf actualizado 2019-05-08 ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; # server-side-includes ssi on; # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; #add_header Content-Security-Policy \"default-src 'self'\"; #cache # set client body size to 4M # # client_max_body_size 4M; expires $expires; # custom error error_page 404 /404.html; location = /404.html { root /var/www/codetabs/www/_error; internal; } location = /404.css { root /var/www/codetabs/www/_error; } location = /ct24r.png { root /var/www/codetabs/www/_error; } location = /ct64r.png { root /var/www/codetabs/www/_error; } error_page 429 /429.html; location = /429.html { root /var/www/codetabs/www/_error; #internal; } location /_public { # requests limit, ojo que enlentece la carga de la pagina # limit_req zone=one burst=50; alias /var/www/codetabs/www/_public; } SITES/DOMAIN actualizado 2019-05-08 # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } server { listen 80; # Listen to your server ip address server_name 212.24.108.85; # Redirect all traffic comming from your-server-ip to your domain return 301 https://domain.com$request_uri; } server { listen 80; listen [::]:80; server_name domain.com www.domain.com; return 301 https://domain.com$request_uri; server_name *.domain.com; return 301 https://*.domain.com$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name www.domain.com; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; return 301 https://domain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS # add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/html; index index.html; } location /freecodecamp { root /var/www/domain; index index.html; } location /notes { root /var/www/domain; index index.html; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name api.domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS add_header 'Access-Control-Allow-Origin' '*' always; location /github-stars/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3501/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /count-loc/ { # requests limit limit_req zone=three ;#burst=50; # set client body size to 10M client_max_body_size 10M; proxy_pass http://127.0.0.1:3502/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /game/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3503/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name test.domain.com; include /etc/nginx/sites-available/domain.conf; location /admin { # requests limit # limit_req zone=one ;#burst=50; auth_basic \"Area 51\"; auth_basic_user_file /etc/nginx/.admin.pass; root /var/www/domain; index admin.html; } } Subcarpeta con PHP Hracias serversforhackers.com server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS #add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/beta; index index.html; } location ^~ /blog { alias /var/www/wp-domain; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } } location @nested { rewrite /blog/(.*)$ /blog/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } } Dokuwiki # DokuWiki location ^~ /wiki { alias /var/www/dokuwiki; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } # dokuwiki security location ~ /wiki/(conf|bin|inc)/ { deny all; } location ~ /wiki/data/ { internal; } } location @nested { rewrite /wiki/(.*)$ /wiki/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } WEBMIN Instalacion Descarga el .deb de aqui dpkg -i package.deb Si debian protesta de dependencias instala las que pida. Estas son las mas posibles: apt install perl libnet-ssleay-perl openssl libpam-runtime libio-pty-perl python libauthen-pam-perl libio-pty-perl apt-show-versions Para desinstalar paramos service webmin stop y despues /etc/webmin/uninstall.sh Modulos nginx module - https://www.justindhoffman.com/project/nginx-webmin-module webmin -> webmin configuration -> webmin modules Actualizacion Despues de actualizarse hay veces que no arranca /etc/init.d/webmin stop /etc/init.d/webmin start Cambiar el password Para cambiar la contrase\u00f1a desde la consola /usr/share/webmin/changepass.pl /etc/webmin root NEWPASSWORD Lets Encrypt Webmin webmin > webmin Configuration > SSL Encryption > SSL Settings /etc/letsencrypt/live/nombreCert/privkey.pem /etc/letsencrypt/live/nombreCert/cert.pem Apply -> service nginx restart LETS ENCRYPT HTTPS certbot apt-get install certbot - install Create certificate // primero parar nginx service nginx stop // Usar la opcion standalone y creamos todos los dominios juntos // (domain.com www.domain.com sub.domain.com etc) certbot certonly Saving debug log to /var/log/letsencrypt/letsencrypt.log How would you like to authenticate with the ACME CA? ------------------------------------------------------------------------- 1: Place files in webroot directory (webroot) 2: Spin up a temporary webserver (standalone) ------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel):domain.com www.domain.com sub.domain.com Obtaining a new certificate Performing the following challenges: tls-sni-01 challenge for domain.com tls-sni-01 challenge for www.domain.com Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0067_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0067_csr-certbot.pem IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/domain.com/fullchain.pem. Your cert will expire on 2017-11-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run \"certbot renew\" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le Listar certificados certbot certificates - Lista de todos los certificados existentes A\u00f1adir certificado service nginx stop - paramos nginx certbot certonly -d admin.domain.com,api.domain.com,domain.com, sp500.domain.com,www.domain.com,otrosub.domain.com --expand - Eliminar certificado certbot delete - y seleccionamos el que queramos borrar Renovar certbot renew --dry-run - solo testea certbot renew - renueva de verdad certbot renew --force-renew - fuerza la renovacion aunque falte mucho tiempo aun para su caducidad certbot renew --dry-run --cert-name domain.tld ` webroot , no hace falta parar nginx para hacer las renovaciones Leer el manual de certot server { listen 80; listen [::]:80; server_name beta.domain.tld; # location / { # root /var/www/beta.domain.tld; # index index.html; # } return 301 https://beta.domain.tld$request_uri; # } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name beta.domain.tld; ssl_certificate /etc/letsencrypt/live/beta.domain.tld/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/beta.domain.tld/privkey.pem; # ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; #add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; location / { root /var/www/beta.domain.tld; index index.html; } } certbot certonly --webroot -w /var/www/domain.tld -d domain.tld -d www.domain.tld -d beta.domain.tld staging --staging - permite mayopr numero de intentos mientras testeamos MONITORIZAR RED vnstat - Bandwidth aptitude install vnstat // lista todas las interfaces de red disponibles vnstat --iflist // configura interface vnstat -u -i eth0 // comienza la ejecucion del servicio como demonio /etc/init.d/vnstat start // cambia de due\u00f1o para poder escribir en su propia base de datos chown -R vnstat:vnstat /var/lib/vnstat/ monitorizar (como un usuario normal) // tiempo real vnstat -l // serie historica por horas-dias-meses-semanas vnstat -h|d|w|m // top 10 dias vnstat -t archivo configuracion (para cambiar la interfaz que por defecto es eth0) nano /etc/vnstat.conf crontab -e 0 * * * * node /var/www/vnstat/vnstat.js // ejecutar cada hora vnstat -i eth0 --json d // dentro de vnstat.js nload apt install nload iftop apt install iftop nethogs apt install nethogs tcptrack apt install tcptrack tcptrack -i interface muestra todas las conexiones existentes en tiempo real nethogs apt install nethogs MYSQL Instalar MYSQL 5.7.X instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // redirige a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // Descomentar esta line para evitar acceso desde el exterior bind-address = 127.0.0.1 service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; truncate table with fk SET FOREIGN_KEY_CHECKS = 0; TRUNCATE table table_name; SET FOREIGN_KEY_CHECKS = 1; Instalar MYSQL 8.0.X Aviso sobre el nuevo sistema de autenticacion MySQL 8 uses a new authentication based on improved SHA256-based password methods. It is recommended that all new MySQL Server installations use this method going forward. This new authentication plugin requires new versions of connectors and clients, with support for this new 8 authentication(caching_sha2_password). Currently MySQL 8 Connectors and community drivers built with libmysqlclient21 support this new method. Clients built with older versions of libmysqlclient may not be able to connect to the new server. To retain compatibility with older client software, the default authentication plugin can be set to the legacy value (mysql_native_password) This should only be done if required third-party software has not been updated to work with the new authentication method. The change will be written to the file /etc/mysql/mysql.conf.d/default-auth-override.cnf After installation, the default can be changed by setting the default_authentication_plugin server setting. instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // se ven todos los sitios donde puede estar la configuracion // vamos a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // y debajo de [mysqld] escribimos bind_address = 127.0.0.1 // para prohibir acceso desde el exterior service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; // para apagar mysql password validation UNINSTALL COMPONENT 'file://component_validate_password'; REDIS Instalar REDIS 4.0.X Instalar apt -t stretch-backports install \"redis-server\" service redis status Configurar nano /etc/redis/redis.conf appendonly yes appendfsync everysec service redis restart VPS Benchmark (curl -s wget.racing/nench.sh | bash; curl -s wget.racing/nench.sh | bash) 2>&1 | tee nench.log wget -qO- bench.sh | bash Ram dmidecode -t 17 dd if=/dev/zero of=/dev/null bs=1024M count=200 iperf apt install iperf iperf -c iperf.online.net speedtest curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py chmod +x speedtest-cli http://speedtest.tele2.net/ download wget -O /dev/null http://speedtest.tele2.net/1GB.zip upload curl -T 1GB.zip ftp://speedtest.tele2.net/upload/ hard disk apt install smartmontools // informacion smartctl -a /dev/sda // testear smartctl -t short|long|select /dev/sda // resultados smartctl -a /dev/sda // o solo testear smartctl -l selftest /dev/sdc // informacion hdparm -I /dev/sda // testea hdparm -tT /dev/sda // testea dd if=/dev/zero of=/tmp/output conv=fdatasync bs=384k count=1k; rm -f /tmp/output more benchmarks openssl speed rsa openssl speed -multi numCores rsa2048 7z b SYS arm-XT arreglar el bug de poca velocidad de subida lowendtalk apt install linux-image-4.9.0-6-armmp linux-headers-4.9.0-6-armmp apt purge *armada* reboot modprobe error ufw wget http://last.public.ovh.hdaas.snap.mirrors.ovh.net/ubuntu/pool /main/l/linux-modules-armada375/linux-modules-armada375_4.5.2-4_armhf.deb dpkg -i linux-modules-armada375_4.5.2-4_armhf.deb grub-mkconfig -o /boot/grub/grub.cfg rsync De local a otra remota rsync -aP /home/user/data/ user@destiny.com:/home/user/data # automatizado sin preguntar contrase\u00f1a rsync -arv --delete -e \"sshpass -f '/file/with/passwd' || -p 'password' ssh -p PORT -o StrictHostKeyChecking=no\" --progress /source/data/ user@domain.com:/destination/data De otra remota a local * rsync -charvzP --delete -e \"sshpass -p 'pass' ssh -p port\" --progress user@remote.host:/remote/path /local/path/ TEST API siege siege -c 30 -r 1 --no-parser https://api.codetabs.com/v1/ siege -c250 -d10 -t3 https://api.codetabs.com/v1/proxy?quest=http Apache Bench apt-get install apache2-utils - -n numero de peticiones -c concurrencias Mas info ab -n 1000 -c 10 https://jolav.github.io/ \u00a1 Ojo porque ab asume que todas las respuestas son iguales !. Si content-length es distinta lo considera un error y aparece como failed request OPENVPN Script para instalar Crear un Kill Switch // ON-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default deny outgoing ufw allow out on tun0 from any to any ufw enable // OFF-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default allow outgoing ufw enable chmod +x ON-openvpn.sh OFF-openvpn.sh Conectarte a tu openVpn ./on-openvpn.sh ./off-openvpn.sh more FLASH FIREFOX Download from here tar -xzf flash_player_ppapi_linux*.tar.gz cp libpepflashplayer.so /usr/lib/mozilla/plugins cp -r usr/* /usr // restart firefox VIRTUALBOX Descargar de aqui en el apartado \"All distributions\" el archivo .run https://www.virtualbox.org/wiki/Linux_Downloads Si tras ejecutarlo e instalarlo dice que falta el dkms es ir aqui buscarlo, bajarlo e instalarlo https://tracker.debian.org/pkg/virtualbox Despues de instalarlo a veces sale este error There were problems setting up VirtualBox. To re-start the set-up process, ru /sbin/vboxconfig as root. If your system is using EFI Secure Boot you may need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information. modprobe vboxdrv GRE TUNNEL Tutorial patra configurar Hacerlo persistente con systemd apt install iptables iproute2 ps aux | grep gre ip tunnel show Pantalla modprobe ip_gre iptunnel del gre1 # Solo una vez #echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf #sysctl -p iptunnel add gre1 mode gre local IP_PANTALLA remote IP_SERVIDOR ttl 255 ip addr add 192.168.168.1/30 dev gre1 ip link set gre1 up # aqui ping a 192.168.168.2 # BUYVM # iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor # iptables -t nat -A PREROUTING -d IP_PANTALLA -j DNAT --to-destination 192.168.168.2 # iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # If you're wanting to get more specific, you could add: -p tcp --dport 25565 # HETZNER iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.168.2 iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.168.2 Extras keepalive en el servidor crontab -e */1 * * * * ping -c2 192.168.168.1 ps aux | grep gre ip tunnel show Servidor modprobe ip_gre iptunnel del gre1 iptunnel add gre1 mode gre local IP_SERVIDOR remote IP_PANTALLA ttl 255 ip addr add 192.168.168.2/30 dev gre1 ip link set gre1 up # TEST-1 ping a 192.168.168.1 # Solo una vez, esto solo se puede borrar luego manualmente # echo '100 GRETUNNEL1' >> /etc/iproute2/rt_tables ip rule add from 192.168.168.0/30 table GRETUNNEL1 ip route add default via 192.168.168.1 table GRETUNNEL1 # TEST-2 # curl http://www.cpanel.net/showip.cgi --interface 192.168.168.2 # wget http://www.cpanel.net/showip.cgi --bind-address=192.168.168.2 -q -O - Persistente crear en cliente y servidor en /etc/systemd/system un nuevo servicio greTunnel.service [Unit] Description=levantar gre tunnel After=network.target [Service] ExecStart=sh /ruta/hasta/el/script Restart=always User=root Group=root Type=simple [Install] WantedBy=multi-user.target","title":"Debian"},{"location":"debian/#debian-12-bookworm","text":"","title":"DEBIAN 12 BOOKWORM"},{"location":"debian/#stable","text":"Para andar con ojo en las actualizaciones instalar aptitude install apt-listbugs Debian Package Searcher Repositories nano /etc/apt/sources.list ## Debian stable deb https://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware ## Debian security deb https://deb.debian.org/debian-security bookworm-security non-free contrib main non-free-firmware ## Debian updates deb https://deb.debian.org/debian/ bookworm-updates non-free contrib main non-free-firmware ## Debian backports #deb https://deb.debian.org/debian/ bookworm-backports main contrib #non-free non-free-firmware ## Insync deb https://apt.insync.io/debian bookworm non-free contrib ## NodeSource #deb [signed-by=/etc/apt/keyrings/nodesource.gpg] #https://deb.nodesource.com/ node_20.x nodistro main ## Debian Multimedia #deb http://www.deb-multimedia.org/ bookworm main non-free # Chrome deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # Teamviewer #deb [signed-by=/usr/share/keyrings/teamviewer-keyring.gpg] #https://linux.teamviewer.com/deb stable main apt install aptitude htop smartmontools sshpass rsync curl wget nano apt-transport-https iperf zip arc arj bzip2 cabextract lzop nomarch p7zip p7zip-full pax tnef unrar-free unzip unrar deborphan net-tools intel-microcode hdparm ncdu rename iftop dns9utils nethogs tcptrack dnsutils curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg Para instalar Dropbox","title":"STABLE"},{"location":"debian/#commands","text":"Add font fc-cache -f -v - tras haber copiado la fuente a /usr/share/fonts gpg gpg -c file.txt - cifra a archivo binario gpg -ca file.txt - cifra a archivo de texto gpg --output output.txt -d file.(gpg or txt) - para descifrar // convertir directorio en un archivo tar czf myfiles.tar.gz mydirectory/ // convertir archivo a un directorio tar xzf myfiles.tar.gz echo RELOADAGENT | gpg-connect-agent - para eliminar de la memoria la clave y que la pida al descomprimir grep Eliminar todas las lineas de una fichero que contienen un determinado 'texto' cat nombreArchivo | grep -v 'texto' > nuevoArchivo Coger solo las lineas de un archivo que contienen un determinado 'texto' grep -i \"texto\" nombreArchivo zip zip -er zipName.zip path/to/folder/ - Comprimir carpeta con contrase\u00f1a dpkg dpkg -i package.deb - apt-get -f install - reparar dependencias incumplidas si las hay dpkg -r onlyThaName - desinstalar debconf-show nombrePaquete - muestra configuracion del paquete instalado dpkg-reconfigure nombrePaquete - para reconfigurar el paquete Tama\u00f1o de ficheros y carpetas ls -lh du -ah /path du -h -d1 | sort -h Lista de directorios (ocultos incluidos) con su tama\u00f1o df -h du -sh * Lista de directorios (no ocultos) con su tama\u00f1o apt install ncdu ncdu Dividir archivo en varios Dividir archivo en trozos de 200mb asegurandoes que el corte no se produce en medio de una linea split -C 200m archivo.txt Limpieza apt-get autoclean && apt-get autoremove && apt-get remove --purge `deborphan` dpkg -l | grep -v ^ii | awk '{print $2}' | sed '1,5d'|xargs dpkg --purge Ver el tama\u00f1o de los logs y limpiar todos excepto los ultimos 3 dias journalctl --disk-usage journalctl --vacuum-time=3d Limpiar caches de imagenes du -sh ~/.cache/thumbnails rm -rf ~/.cache/thumbnails/* Process pgrep processName - buscar proceso ps - listar todos los procesos kill processNumber - matar proceso fg - continuar el proceso que estaba detenido nohup comando & - Ejecuta un comando en segundo plano y sigue ejecutandolo aunque salgamos de esa terminal ulimits error too many open files lsof - para encontrar file descriptors usados lsof -p PID | wc -l - indica cuantos file descriptors (archivos u otros recursos como conexiones http) tiene abiertos el proceso PID lsof -c PROCESS-NAME | wc -l - igual que arriba pero por nombre ulimit -n - muestra el limite de fd que el usuario puede usar ulimit -n 4096 - sube ese limite por ejemplo lo normal es 1024 a 4096 pero solo para esa sesion // Para Hacerlo permamente nano /etc/security/limits.conf userName soft nofile 2000 * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 // Cambiar el limite de fd de un proceso en ejecucion prlimit --pid pidID --nofile=soft:hard prlimit --pid XXXX --nofile=XXXX:XXXX en nginx user www-data; worker_processes 4; pid /run/nginx.pid; worker_rlimit_nofile 50000; events { worker_connections 4000; # multi_accept on; } Buena guia Incrementar limites -> Por usuario nano /etc/security/limits.conf A\u00f1adir al final * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 Guardar el archivo y hacer logout y login de nuevo Si esto no funciona probar con pam-limits nano /etc/pam.d/common-session a\u00f1adir session required pam_limits.so -> Para Todo el Sistema nano /etc/sysctl.conf a\u00f1adir fs.file-max = 2097152 Salimos y ejecutamos sysctl -p -> Verificar que funcionan los nuevos limites cat /proc/sys/fs/file-max Hard Limit ulimit -Hn Soft Limit ulimit -Sn verificar para un usuario su - nombreUsuario -c 'ulimit -aHS' -s '/bin/bash' Verificar para un proceso en ejecucion conseguimos el PID ps aux | grep nombreDelProceso cat /proc/XXX/limits Buscar find /path -name fileName - Buscar archivo find /path -type d -name dirName - Buscar carpeta Crear nuevo usuario useradd -d /home/username -m -s /bin/bash username - Crea un usuario con su carpeta home y consola para usar passwd username - Para crear la contrase\u00f1a del usuario Zona horaria dpkg-reconfigure tzdata - reconfigurar la zona horaria cpulimit apt-get install cpulimit ps aux | grep nombreProceso - nos da el id del proceso cpulimit -p id -l 30 - limita el proceso id al 30% cpulimit -e nombreProceso -l 50 - limita el proceso nombreProceso al 50% A\u00f1adir & para recuperar el control de la consola averiguar la version de debian lsb_release -a dns dig domain.tld @9.9.9.9 cron crontab -e // activar los logs de cron nano /etc/rsyslog.conf // descomentar la linea #cron.* -/var/log/cron service rsyslog restart // ejecutar algo al inicio del servidor crontab -e // como root @reboot cd /home/user/donde-sea && ./programa nmap nmap -Pn X.X.X.X || hostname rename multiple files at once apt install rename // Reemplazar la 1 ocurrencia de abc por xyz rename 's/abc/xyz/' * curl // tiempo en ir, procesar y volver curl -o /dev/null -s -w 'Total: %{time_total}s\\n' https://pagina.web","title":"COMMANDS"},{"location":"debian/#security","text":"","title":"SECURITY"},{"location":"debian/#ssh","text":"aptitude install openssh-server openssh-client nano /etc/ssh/sshd_config // Para quitar acceso como root # Authentication: LoginGraceTime 120 PermitRootLogin without-password // jode mas que poner solo no StrictModes yes // Por seguridad # Para permitir contrase\u00f1as vacias pon yes (NI SE TE OCURRA HACERLO) PermitEmptyPasswords no service ssh restart sshpass -p contrase\u00f1a ssh usuario@dominio Broken pipe Para prevenir desconexiones del tipo broken pipe nano -c /etc/ssh/ssh_config Host * ServerAliveInterval 120","title":"SSH"},{"location":"debian/#clamav","text":"Antivirus para asegurarnos de que no somos conductores de virus entre maquinas windows y por si las moscas ... apt-get install clamav clamav-docs clamav-daemon clamav-freshclam aptitude install arc arj bzip2 cabextract lzop nomarch p7zip pax tnef unrar-free unzip zoo lha unrar - Para que escanee archivos comprimidos nano /etc/clamav/freshclam.conf - El archivo de configuracion por si queremos cambiar algo. service clamav-freshclam restart - hacerlo despues para cargar la nueva configuracion // Para actualizar, como root freshclam // Si esta bloqueado /etc/init.d/clamav-freshclam stop //despues => service clamav-freshclam start // para escanear como usuario normal clamscan -r /ruta/a/escanear","title":"CLAMAV"},{"location":"debian/#rkhunter","text":"aptitude install rkhunter //para actualizar, como root rkhunter --propupd rkhunter --update //para usar, como root tambien rkhunter --check","title":"RKHUNTER"},{"location":"debian/#fail2ban","text":"apt-get install fail2ban whois cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local nano /etc/fail2ban/jail.local // Aqui van las IPs que no tendran esas restricciones [DEFAULT] # \"ignoreip\" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1 192.168.1.0/24 bantime = 1800 maxretry = 3 // Correo al que avisar ante sucesos # Destination email address used solely for the interpolations in # jail.{conf,local} configuration files. destemail = root@localhost [webmin] enabled = true port = 10000 filter = webmin-auth banaction = iptables-multiport action = %(action_mwl)s logpath = /var/log/auth.log maxretry = 3 [ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [ssh-ddos] enabled = true port = ssh filter = sshd-ddos logpath = /var/log/auth.log maxretry = 3 service fail2ban restart service fail2ban status Los logs de baneos estan en estos dos archivos /var/log/fail2ban.log /var/log/auth.log manual unban fail2ban-client set ssh unbanip X.X.X.X","title":"FAIL2BAN"},{"location":"debian/#ufw","text":"apt-get install ufw ufw allow ssh/tcp ufw logging on Antes de esto no se podia activar porque nos echa de la sesion de SSH. Ahora si => ufw enable ufw allow smtp/tcp ufw allow http/tcp ufw allow https/tcp ufw allow webmin ufw status - rules list ufw status numbered - numbered rules list ufw delete X - delete rule X bloquear IPs ufw insert 1 deny from X.X.X.X to any nano -c /etc/ufw/before.rules # End required lines -A ufw-before-input -s X.X.X.X -j DROP ufw reload","title":"UFW"},{"location":"debian/#pm2","text":"Instalar npm install pm2 -g npm remove pm2 -g Configuracion DOCS pm2 startup - como usuario y seguir instrucciones para hacer que pm2 se ejecute en los reinicios sin necesitar ser root pm2 unstartup - para desmontar el chiringuito NO SIEMPRE Para ejecutar los procesos como user y no como root chmod -R 777 /home/user/.pm2 Comandos pm2 start app.js pm2 kill // para la ejecucion pero con un reboot se activara de nuevo pm2 list pm2 stop all|number pm2 restart all|number pm2 delete 7 // elimina el proceso especifico con ese id pm2 save // salva la lista de procesos en ese momento pm2 start app.js --name \"my-name\" pm2 restart app --name \"nuevo-nombre\" --update-env // para renombrar pm2 reset app // pone el contador de restarts a cero dev pm2-dev start app.js pm2-dev start app.js --ignore folder1,folder2,file3.txt cluster variables // -i numero de procesos que levanta pm2 start name.js -i max process.env.NODE_APP_INSTANCE; process.env.name process.env.pm_id max-memory-restart pm2 start geoip.js -i max --max-memory-restart 1300M 50M 50K 1G scale // Sumar 3 procesos al actual pm2 scale app +3 // deja 3 procesos activos de todos los que este usando actualmente pm2 scale app 3 cluster logs in the same file // ecosystem.config.js module.exports = { apps: [{ name: 'codetabs', script: 'codetabs.js', ignore_watch: [\"node_modules\", \"tmp\"], output: './../logs/hits.log', error: './../logs/errors.log', env: { NODE_ENV: \"development\", }, env_production: { NODE_ENV: \"production\", }, instances: 8, max_memory_restart: \"1G\", merge_logs: true, log_date_format: 'YYYY-MM-DD HH:mm:ss', }] }; pm2 start ecosystem.config.js --env production","title":"PM2"},{"location":"debian/#npm-sin-ser-root","text":"Como instalar paquetes npm globalmente sin ser root // crear carpeta para los paquetes globales mkdir \"${HOME}/.npm-packages\" // crear .npmrc nano ${HOME}/.npmrc prefix=${HOME}/.npm-packages //editar .bashrc nano ${HOME}/.bashrc NPM_PACKAGES=\"${HOME}/.npm-packages\" PATH=\"$NPM_PACKAGES/bin:$PATH\" unset MANPATH # delete if already modified MANPATH elsewhere export MANPATH=\"$NPM_PACKAGES/share/man:$(manpath)\" // recargar la configuracion para aplicar los cambios source ~/.profile","title":"NPM sin ser ROOT"},{"location":"debian/#systemd","text":"systemctl status servidorGO - nos da informacion del servicion Crear Servicio nano /etc/systemd/servidorGO.service cp servidorGO.service /etc/systemd/system systemctl enable servidorGO.service service servidorGO.service start Borrar servicio systemctl stop [servicename] systemctl disable [servicename] rm /etc/systemd/system/[servicename] systemctl daemon-reload systemctl reset-failed nombre.service [Unit] Description= Descripcion de la tarea [Service] User=user Group=www-data Restart=on-failure WorkingDirectory=/var/www/path/to/binary/folder ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target Commandos service name status service name start systemctl enable name.service systemctl disable name.service systemctl start name.service systemctl stop name.service systemctl restart name.service systemctl status name.service systemctl reload name.service // Required files /etc/systemd/servidorGO.service /etc/systemd/system/servidorGO.service /etc/systemd/system/multi-user.target.wants/servidorGO.service /sys/fs/cgroup/systemd/system.slice/servidorGO.service Otra opcion ? nano /lib/systemd/system/name.service [Unit] Description= Task description [Service] Type=simple Restart=always RestartSec=5s ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target service name start service name status // para activarlo desde el reinicio del sistema systemctl enable name.service","title":"SYSTEMD"},{"location":"debian/#systemd-sin-ser-root","text":"Systemd sin ser ROOT Primero asegurarnos de que este instalado dbus para user apt install dbus-user-session apt install policykit-1 por si da guerra org.freedesktop.policytoolkit1 Creamos carpeta donde guardar los servicios mkdir -p ~/.config/systemd/user En esa carpeta creamos el nombreservicio.service [Unit] Description= Descripcion de la tarea [Service] RestartSec=5s Restart=always WorkingDirectory=/ruta/a/la/carpeta/del/binario ExecStart=/ruta/a/la/carpeta/del/binario/./nombreDelBinario [Install] WantedBy=default.target Ahora hacemos que systemd reconozca los cambios systemctl --user daemon-reload Ya podemos gestionar el servicio systemctl --user start nombreDelServicio systemctl --user stop nombreDelServicio systemctl --user restart nombreDelServicio systemctl --user status nombreDelServicio Para que el servicio se inicie automaticamente cuando el usuario se loguea systemctl --user enable nombreDelServicio // sin el .service al final Para desactivarlo systemctl --user disable nombreDelServicio Hay que hacer que el servicio corra siempre, este o no logueado el due\u00f1o y al inicio del sistema. Para ello como root ejecutamos loginctl enable-linger NOMBREUSUARIO Ya como usuario normal podemos ver el estado de los servicios loginctl user-status NOMBREUSUARIO","title":"SYSTEMD sin ser ROOT"},{"location":"debian/#nginx","text":"Instalacion apt-get install nginx chown -R user:user /var/www - Para darle permisos al usuario para toda esa carpeta mkdir -p /var/www/site1 mkdir -p /var/www/site2","title":"NGINX"},{"location":"debian/#configuracion","text":"nano /etc/nginx/nginx.conf El archivo de configuracion se llama default y esta en la carpeta /etc/nginx/sites-available .Lo borramos o lo renombramos a default.old . La copia de default que esta en /etc/nginx/sites-enabled hay que borrarla Ahora podemos crear nuestro archivo/s de configuracion. nano /etc/nginx/sites-available/domain cp /etc/nginx/sites-available/domain /etc/nginx/sites-enabled/domain service nginx restart nginx -s reload solo para recargar el archivo de configuracion","title":"Configuracion"},{"location":"debian/#server-side-includes","text":"Server Side Includes Directivas y variables ssi on - /etc/nginx/sites-available Para las rutas ojo porque es desde la raiz del servidor web nginx para esa location ","title":"server-side-includes"},{"location":"debian/#ocultar-la-version-de-nginx","text":"nano /etc/nginx/nginx.conf http { server_tokens off; }","title":"ocultar la version de nginx"},{"location":"debian/#headerscabeceras","text":"Ojo, que algunas pueden restringir el comportamiento de las aplicaciones que tengamos # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; add_header Content-Security-Policy \"default-src 'self'\"; En el location block para evitar cualquier indexacion de esa location por parte de los robots de busqueda add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\";","title":"headers(cabeceras)"},{"location":"debian/#limitar-tamano-de-los-archivos-de-subida","text":"location /count-loc/ { # set client body size to 10M client_max_body_size 10M; }","title":"Limitar tama\u00f1o de los archivos de subida"},{"location":"debian/#rate-limit","text":"nano /etc/nginx/nginx.conf // aqui definimos por ejemplo la zona=one # limit requests limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s; //luego hay que aplicarlo, mejor en location que en server nano /etc/nginx/sites-available/domain location /count-loc/ { # requests limit limit_req zone=one burst=20; } Apply limits per IP geo $limit { default 1; X.X.X.X 0; Y.Y.Y.Y 0; } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=1r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s;","title":"rate Limit"},{"location":"debian/#http2","text":"nano /etc/nginx/nginx.conf // usar solo cifrados muy seguros ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256: RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; // hay que generar una nuevas claves, lo mejor en /etc/nginx/ssl cd /etc/nginx/ssl openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 // http2 solo funciona con https asi que en el bloque de listen 443 listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; // para mejorar rendimiento ssl_session_cache shared:SSL:5m; ssl_session_timeout 1h;","title":"http2"},{"location":"debian/#cache","text":"// en sites-availables bloque propio # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } // luego en el bloque server que queramos a\u00f1adir expires $expires;","title":"cache"},{"location":"debian/#zonas-privadas","text":"// crear archivo con la contrase\u00f1a apt-get install apache2-utils cd /etc/nginx htpasswd -c .rethinkdb.pass // will ask for password service nginx restart server { listen 443 ssl; server_name sub.domain.com; location / { ... } location /private/ { auth_basic \"Restricted\"; auth_basic_user_file /etc/nginx/.rethinkdb.pass; ... root or proxy for this location } }","title":"zonas privadas"},{"location":"debian/#custom-404","text":"mkdir /var/www/error => 404.html 404.css , js, png ... server { error_page 404 /404.html; location = /404.html { root /var/www/error; internal; } location = /404.css { root /var/www/error; } location = /caution.png { root /var/www/error; } } En 404.html llamamos a los recursos usando rutas absolutas ","title":"custom 404"},{"location":"debian/#block-domains","text":"map $http_referer $bad_referer { default 0; \"~spamdomain1.com\" 1; \"~spamdomain2.com\" 1; \"~spamdomain3.com\" 1; } if ($bad_referer) { return 444; }","title":"block domains"},{"location":"debian/#nginxconf","text":"actualizado 2019-05-08 user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; server_names_hash_bucket_size 64; # 128? # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; # set client body size to 5M # client_max_body_size 2M; # limit requests geo $limit { default 1; X.X.X.X 0; #server1 X.X.X.X 0; #server2 X.X.X:X 0; #server3 X.X.X.X 0; #server4 } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=2r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; limit_req_zone $limit_key zone=five:10m rate=1r/s; limit_req_zone $limit_key zone=six:1000m rate=10r/s; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA +AES256:EECDH+3DES:RSA+3DES:!MD5; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_disable \"msie6\"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml applicati$ ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }","title":"nginx.conf"},{"location":"debian/#dominio-templateconf","text":"actualizado 2019-05-08 ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; # server-side-includes ssi on; # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; #add_header Content-Security-Policy \"default-src 'self'\"; #cache # set client body size to 4M # # client_max_body_size 4M; expires $expires; # custom error error_page 404 /404.html; location = /404.html { root /var/www/codetabs/www/_error; internal; } location = /404.css { root /var/www/codetabs/www/_error; } location = /ct24r.png { root /var/www/codetabs/www/_error; } location = /ct64r.png { root /var/www/codetabs/www/_error; } error_page 429 /429.html; location = /429.html { root /var/www/codetabs/www/_error; #internal; } location /_public { # requests limit, ojo que enlentece la carga de la pagina # limit_req zone=one burst=50; alias /var/www/codetabs/www/_public; }","title":"dominio-template.conf"},{"location":"debian/#sitesdomain","text":"actualizado 2019-05-08 # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } server { listen 80; # Listen to your server ip address server_name 212.24.108.85; # Redirect all traffic comming from your-server-ip to your domain return 301 https://domain.com$request_uri; } server { listen 80; listen [::]:80; server_name domain.com www.domain.com; return 301 https://domain.com$request_uri; server_name *.domain.com; return 301 https://*.domain.com$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name www.domain.com; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; return 301 https://domain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS # add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/html; index index.html; } location /freecodecamp { root /var/www/domain; index index.html; } location /notes { root /var/www/domain; index index.html; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name api.domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS add_header 'Access-Control-Allow-Origin' '*' always; location /github-stars/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3501/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /count-loc/ { # requests limit limit_req zone=three ;#burst=50; # set client body size to 10M client_max_body_size 10M; proxy_pass http://127.0.0.1:3502/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /game/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3503/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name test.domain.com; include /etc/nginx/sites-available/domain.conf; location /admin { # requests limit # limit_req zone=one ;#burst=50; auth_basic \"Area 51\"; auth_basic_user_file /etc/nginx/.admin.pass; root /var/www/domain; index admin.html; } }","title":"SITES/DOMAIN"},{"location":"debian/#subcarpeta-con-php","text":"Hracias serversforhackers.com server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS #add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/beta; index index.html; } location ^~ /blog { alias /var/www/wp-domain; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } } location @nested { rewrite /blog/(.*)$ /blog/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } } Dokuwiki # DokuWiki location ^~ /wiki { alias /var/www/dokuwiki; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } # dokuwiki security location ~ /wiki/(conf|bin|inc)/ { deny all; } location ~ /wiki/data/ { internal; } } location @nested { rewrite /wiki/(.*)$ /wiki/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; }","title":"Subcarpeta con PHP"},{"location":"debian/#webmin","text":"Instalacion Descarga el .deb de aqui dpkg -i package.deb Si debian protesta de dependencias instala las que pida. Estas son las mas posibles: apt install perl libnet-ssleay-perl openssl libpam-runtime libio-pty-perl python libauthen-pam-perl libio-pty-perl apt-show-versions Para desinstalar paramos service webmin stop y despues /etc/webmin/uninstall.sh Modulos nginx module - https://www.justindhoffman.com/project/nginx-webmin-module webmin -> webmin configuration -> webmin modules Actualizacion Despues de actualizarse hay veces que no arranca /etc/init.d/webmin stop /etc/init.d/webmin start Cambiar el password Para cambiar la contrase\u00f1a desde la consola /usr/share/webmin/changepass.pl /etc/webmin root NEWPASSWORD Lets Encrypt Webmin webmin > webmin Configuration > SSL Encryption > SSL Settings /etc/letsencrypt/live/nombreCert/privkey.pem /etc/letsencrypt/live/nombreCert/cert.pem Apply -> service nginx restart","title":"WEBMIN"},{"location":"debian/#lets-encrypt","text":"HTTPS certbot apt-get install certbot - install Create certificate // primero parar nginx service nginx stop // Usar la opcion standalone y creamos todos los dominios juntos // (domain.com www.domain.com sub.domain.com etc) certbot certonly Saving debug log to /var/log/letsencrypt/letsencrypt.log How would you like to authenticate with the ACME CA? ------------------------------------------------------------------------- 1: Place files in webroot directory (webroot) 2: Spin up a temporary webserver (standalone) ------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel):domain.com www.domain.com sub.domain.com Obtaining a new certificate Performing the following challenges: tls-sni-01 challenge for domain.com tls-sni-01 challenge for www.domain.com Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0067_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0067_csr-certbot.pem IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/domain.com/fullchain.pem. Your cert will expire on 2017-11-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run \"certbot renew\" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le Listar certificados certbot certificates - Lista de todos los certificados existentes A\u00f1adir certificado service nginx stop - paramos nginx certbot certonly -d admin.domain.com,api.domain.com,domain.com, sp500.domain.com,www.domain.com,otrosub.domain.com --expand - Eliminar certificado certbot delete - y seleccionamos el que queramos borrar Renovar certbot renew --dry-run - solo testea certbot renew - renueva de verdad certbot renew --force-renew - fuerza la renovacion aunque falte mucho tiempo aun para su caducidad certbot renew --dry-run --cert-name domain.tld ` webroot , no hace falta parar nginx para hacer las renovaciones Leer el manual de certot server { listen 80; listen [::]:80; server_name beta.domain.tld; # location / { # root /var/www/beta.domain.tld; # index index.html; # } return 301 https://beta.domain.tld$request_uri; # } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name beta.domain.tld; ssl_certificate /etc/letsencrypt/live/beta.domain.tld/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/beta.domain.tld/privkey.pem; # ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; #add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; location / { root /var/www/beta.domain.tld; index index.html; } } certbot certonly --webroot -w /var/www/domain.tld -d domain.tld -d www.domain.tld -d beta.domain.tld staging --staging - permite mayopr numero de intentos mientras testeamos","title":"LETS ENCRYPT"},{"location":"debian/#monitorizar-red","text":"vnstat - Bandwidth aptitude install vnstat // lista todas las interfaces de red disponibles vnstat --iflist // configura interface vnstat -u -i eth0 // comienza la ejecucion del servicio como demonio /etc/init.d/vnstat start // cambia de due\u00f1o para poder escribir en su propia base de datos chown -R vnstat:vnstat /var/lib/vnstat/ monitorizar (como un usuario normal) // tiempo real vnstat -l // serie historica por horas-dias-meses-semanas vnstat -h|d|w|m // top 10 dias vnstat -t archivo configuracion (para cambiar la interfaz que por defecto es eth0) nano /etc/vnstat.conf crontab -e 0 * * * * node /var/www/vnstat/vnstat.js // ejecutar cada hora vnstat -i eth0 --json d // dentro de vnstat.js nload apt install nload iftop apt install iftop nethogs apt install nethogs tcptrack apt install tcptrack tcptrack -i interface muestra todas las conexiones existentes en tiempo real nethogs apt install nethogs","title":"MONITORIZAR RED"},{"location":"debian/#mysql","text":"","title":"MYSQL"},{"location":"debian/#instalar-mysql-57x","text":"instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // redirige a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // Descomentar esta line para evitar acceso desde el exterior bind-address = 127.0.0.1 service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; truncate table with fk SET FOREIGN_KEY_CHECKS = 0; TRUNCATE table table_name; SET FOREIGN_KEY_CHECKS = 1;","title":"Instalar MYSQL 5.7.X"},{"location":"debian/#instalar-mysql-80x","text":"Aviso sobre el nuevo sistema de autenticacion MySQL 8 uses a new authentication based on improved SHA256-based password methods. It is recommended that all new MySQL Server installations use this method going forward. This new authentication plugin requires new versions of connectors and clients, with support for this new 8 authentication(caching_sha2_password). Currently MySQL 8 Connectors and community drivers built with libmysqlclient21 support this new method. Clients built with older versions of libmysqlclient may not be able to connect to the new server. To retain compatibility with older client software, the default authentication plugin can be set to the legacy value (mysql_native_password) This should only be done if required third-party software has not been updated to work with the new authentication method. The change will be written to the file /etc/mysql/mysql.conf.d/default-auth-override.cnf After installation, the default can be changed by setting the default_authentication_plugin server setting. instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // se ven todos los sitios donde puede estar la configuracion // vamos a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // y debajo de [mysqld] escribimos bind_address = 127.0.0.1 // para prohibir acceso desde el exterior service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; // para apagar mysql password validation UNINSTALL COMPONENT 'file://component_validate_password';","title":"Instalar MYSQL 8.0.X"},{"location":"debian/#redis","text":"","title":"REDIS"},{"location":"debian/#instalar-redis-40x","text":"Instalar apt -t stretch-backports install \"redis-server\" service redis status Configurar nano /etc/redis/redis.conf appendonly yes appendfsync everysec service redis restart","title":"Instalar REDIS 4.0.X"},{"location":"debian/#vps","text":"Benchmark (curl -s wget.racing/nench.sh | bash; curl -s wget.racing/nench.sh | bash) 2>&1 | tee nench.log wget -qO- bench.sh | bash Ram dmidecode -t 17 dd if=/dev/zero of=/dev/null bs=1024M count=200 iperf apt install iperf iperf -c iperf.online.net speedtest curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py chmod +x speedtest-cli http://speedtest.tele2.net/ download wget -O /dev/null http://speedtest.tele2.net/1GB.zip upload curl -T 1GB.zip ftp://speedtest.tele2.net/upload/ hard disk apt install smartmontools // informacion smartctl -a /dev/sda // testear smartctl -t short|long|select /dev/sda // resultados smartctl -a /dev/sda // o solo testear smartctl -l selftest /dev/sdc // informacion hdparm -I /dev/sda // testea hdparm -tT /dev/sda // testea dd if=/dev/zero of=/tmp/output conv=fdatasync bs=384k count=1k; rm -f /tmp/output more benchmarks openssl speed rsa openssl speed -multi numCores rsa2048 7z b SYS arm-XT arreglar el bug de poca velocidad de subida lowendtalk apt install linux-image-4.9.0-6-armmp linux-headers-4.9.0-6-armmp apt purge *armada* reboot modprobe error ufw wget http://last.public.ovh.hdaas.snap.mirrors.ovh.net/ubuntu/pool /main/l/linux-modules-armada375/linux-modules-armada375_4.5.2-4_armhf.deb dpkg -i linux-modules-armada375_4.5.2-4_armhf.deb grub-mkconfig -o /boot/grub/grub.cfg rsync De local a otra remota rsync -aP /home/user/data/ user@destiny.com:/home/user/data # automatizado sin preguntar contrase\u00f1a rsync -arv --delete -e \"sshpass -f '/file/with/passwd' || -p 'password' ssh -p PORT -o StrictHostKeyChecking=no\" --progress /source/data/ user@domain.com:/destination/data De otra remota a local * rsync -charvzP --delete -e \"sshpass -p 'pass' ssh -p port\" --progress user@remote.host:/remote/path /local/path/","title":"VPS"},{"location":"debian/#test-api","text":"siege siege -c 30 -r 1 --no-parser https://api.codetabs.com/v1/ siege -c250 -d10 -t3 https://api.codetabs.com/v1/proxy?quest=http Apache Bench apt-get install apache2-utils - -n numero de peticiones -c concurrencias Mas info ab -n 1000 -c 10 https://jolav.github.io/ \u00a1 Ojo porque ab asume que todas las respuestas son iguales !. Si content-length es distinta lo considera un error y aparece como failed request","title":"TEST API"},{"location":"debian/#openvpn","text":"Script para instalar Crear un Kill Switch // ON-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default deny outgoing ufw allow out on tun0 from any to any ufw enable // OFF-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default allow outgoing ufw enable chmod +x ON-openvpn.sh OFF-openvpn.sh Conectarte a tu openVpn ./on-openvpn.sh ./off-openvpn.sh more","title":"OPENVPN"},{"location":"debian/#flash-firefox","text":"Download from here tar -xzf flash_player_ppapi_linux*.tar.gz cp libpepflashplayer.so /usr/lib/mozilla/plugins cp -r usr/* /usr // restart firefox","title":"FLASH FIREFOX"},{"location":"debian/#virtualbox","text":"Descargar de aqui en el apartado \"All distributions\" el archivo .run https://www.virtualbox.org/wiki/Linux_Downloads Si tras ejecutarlo e instalarlo dice que falta el dkms es ir aqui buscarlo, bajarlo e instalarlo https://tracker.debian.org/pkg/virtualbox Despues de instalarlo a veces sale este error There were problems setting up VirtualBox. To re-start the set-up process, ru /sbin/vboxconfig as root. If your system is using EFI Secure Boot you may need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information. modprobe vboxdrv","title":"VIRTUALBOX"},{"location":"debian/#gre-tunnel","text":"Tutorial patra configurar Hacerlo persistente con systemd apt install iptables iproute2 ps aux | grep gre ip tunnel show Pantalla modprobe ip_gre iptunnel del gre1 # Solo una vez #echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf #sysctl -p iptunnel add gre1 mode gre local IP_PANTALLA remote IP_SERVIDOR ttl 255 ip addr add 192.168.168.1/30 dev gre1 ip link set gre1 up # aqui ping a 192.168.168.2 # BUYVM # iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor # iptables -t nat -A PREROUTING -d IP_PANTALLA -j DNAT --to-destination 192.168.168.2 # iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # If you're wanting to get more specific, you could add: -p tcp --dport 25565 # HETZNER iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.168.2 iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.168.2 Extras keepalive en el servidor crontab -e */1 * * * * ping -c2 192.168.168.1 ps aux | grep gre ip tunnel show Servidor modprobe ip_gre iptunnel del gre1 iptunnel add gre1 mode gre local IP_SERVIDOR remote IP_PANTALLA ttl 255 ip addr add 192.168.168.2/30 dev gre1 ip link set gre1 up # TEST-1 ping a 192.168.168.1 # Solo una vez, esto solo se puede borrar luego manualmente # echo '100 GRETUNNEL1' >> /etc/iproute2/rt_tables ip rule add from 192.168.168.0/30 table GRETUNNEL1 ip route add default via 192.168.168.1 table GRETUNNEL1 # TEST-2 # curl http://www.cpanel.net/showip.cgi --interface 192.168.168.2 # wget http://www.cpanel.net/showip.cgi --bind-address=192.168.168.2 -q -O - Persistente crear en cliente y servidor en /etc/systemd/system un nuevo servicio greTunnel.service [Unit] Description=levantar gre tunnel After=network.target [Service] ExecStart=sh /ruta/hasta/el/script Restart=always User=root Group=root Type=simple [Install] WantedBy=multi-user.target","title":"GRE TUNNEL"},{"location":"expressjs/","text":"EXPRESS 4.16.X USO instalacion npm install -g express - Lo instalamos globalmente npm install -g express-generator - Y el generador de codigo plantilla que nos permite usar el comando express A pelo npm init - te pregunta muchas cosas para generar el package.json Con plantillas express -h Muestra las opciones express --hbs miApp Crea el proyecto miApp con handlebars pej cd miApp & npm install Instala las dependencias api application app Es una instancia de la aplicacion express que se usa normalmente para configurar la aplicacion request req Es una envoltura del objeto request del modulo HTTP usado para extraer informacion sobre la peticion response res Es una envoltura del objeto response del modulo HTTP usado para enviar los datos y cabeceras de la respuesta Application settings: env: production, development ... viewcache view engine: jade, ejs, hbs ... views trustproxy (NGINX) Seguimiento de una peticion en express MAIN FILE app.js o main.js Cosas que se hacen en este fichero: Dependencias - Incluir paquetes de terceros y modulos nuestros como manejadores, utilidades ayudantes y modelos Instanciaciones - configurar las opciones de express como motor de plantillas Configuraciones - ajustes y como conectar las bases de datos Middlewares - Definir middlewares Ruteo - definir rutas Arranque - iniciar la app o exportarla app como un modulo ajustes app.set(nombre, valor) - para definir un valor app.set('port', process.env.PORT || 3000); app.get(nombre) - para conseguir un valor app.enable() - app.disable() - app.enabled() - app.disabled() - env - almacena el modo de entorno actual para ese proceso de node.js. Se toma de process.env.NODE_ENV o se pone development por defecto. Opciones {development, test, stage, preview, production} view cache - ponerlo a true para produccion view engine - view engine views - la ruta absoluta al directorio con las plantillas app.set('views', path.join(__dirname, 'templates')) trust proxy - ponerlo a true se esta detras de un proxy como nginx. Por defecto esta desactivado, para activarlo app.set('trust proxy', true); app.enable('trust proxy'); jsonp callback name - vale para hacer llamadas ajax desde otros dominios usando CORS app.set('jsonp callback name', 'cb'); json replacer - json spaces - son dos parametros que se aplican a todas las funciones JSON.stringify(). replacer es un filtro spaces es valor de indentacion app.set('json replacer', function(key, value){ if (key === 'discount') return undefined; else return value; }); app.set('json spaces', 4); case sensitive routing - por defecto disabled, asi /nombre y /Nombres es la misma ruta strict routing - por defeto disabled, asi /users y /users/ son la misma ruta x-powered-by - establece la opcion de la respuesta x-powered-by con el valor Express. Por seguridad lo mejor es desactivarla app.set('x-powered-by', false) // o app.disable('x-powered-by') etag - dejarlo como esta es lo mejor query parser - para parsear las query-string enviadas en la URL. Por defecto extended (usa el modulo qs), true (qs), false (lo desactiva), simple (usa el modulo del nucleo querystring) app.set('query parser', 'simple'); app.set('query parser', false); app.set('query parser', customQueryParsingFunction); subdomain offset - Para aplicaciones desplegadas en varios subdominios contenido estatico Usar directorio de contenido estatico Para servir contenido estatico se usa el middleware express.static incorporado en express. var publicPath = path.resolve(__dirname, 'public'); app.use(express.static(publicPath)); Ya puedes cargar archivos del directorio public El nombre del directorio public no es parte de la url http://localhost:3000/css/style.css http://localhost:3000/public/css/style.css NO Usar multiples directorios de contenido estatico Express busca los archivos en el orden en el que se declaran los directorios estaticos app.use(express.static('public')); app.use(express.static('files')); Prefijo de ruta virtual app.use('/static', express.static('public')); Ahora para cargar los archivos : http://localhost:3000/static/css/style.css TEMPLATES REQUEST (Peticion) Request API req.query - Esta propiedad es un objeto que tiene una propiedad para cada query string en la ruta. Si no hay query string es un objeto vacio {}. // GET /search?q=jolav req.query.q // => \"jolav\" // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order // => \"desc\" req.query.shoe.color // => \"blue\" req.query.shoe.type // => \"converse\" req.params - Esta propiedad es un objeto con propiedades mapeadas a la ruta \"parametros\". Ejemmplo una ruta /usuario/:nombre, la propiedad 'nombre' esta disponoble en req.params.nombre. Por defecto el objeto es {} // GET /user/jolav on route /user/:name req.params.name // => \"jolav\" // GET /file/js/react.js on royte /file/* req.params[0] // => \"js/react.js\" req.body - Contiene pares clave-valor de datos enviados en el body de la peticion. Por defecto es undefined y se llena cuando usas un middleware body-parsing como por ejemplo body-parser o multer req.route - Contiene la ruta actual como una string app.get('/user/:id?', function userIdHandler(req, res) { console.log(req.route); res.send('GET'); }); { path: '/user/:id?', stack: [ { handle: [Function: userIdHandler], name: 'userIdHandler', params: undefined, path: undefined, keys: [], regexp: /^\\/?$/i, method: 'get' } ], methods: { get: true } } req.cookies - Al usar middleware cookie-parser esta propiedad es un objeto que contiene las cookies enviadas con la peticion. Si no hay cookies por defecto es {} req.headers - req.xhr - Es una propiedad booleana que es true si el campo de la cabecera X-Requested-With header de la peticion es \u201cXMLHttpRequest\u201d req.hostname - Contiene el hostname sacado de la cabecera Host HTTP Header de la peticion. Vamos, de que pagina web viene la peticion // Host: \"example.com:3000\" req.hostname // => \"example.com\" req.originalUrl - req.path - req.baseUrl - // GET /search?q=something req.originalUrl // => \"/search?q=something\" // example.com/users?sort=desc req.path // => \"/users\" // GET 'http://www.example.com/admin/new' app.use('/admin', function(req, res, next) { console.log(req.originalUrl); // '/admin/new' console.log(req.baseUrl); // '/admin' console.log(req.path); // '/new' next(); }); req.protocol - Contiene el protocolo de la peticion como string (http o https) RESPONSE (Respuesta) Response API res.headersSent - Propiedad booleana que indica si la aplicacion ya ha enviado cabeceras http para la respuesta (vamos, si ya ha enviado alguna respuesta) app.get('/', function (req, res) { console.log(res.headersSent); // false res.send('OK'); console.log(res.headersSent); // true }); res.cookie(name, value [, options]) - Establece el nombre de la cookie a value (que puede ser una string o un objeto convertido en JSON). Las options es un objeto que puede tener las siguientes propiedades (domain, encode, expires, httpOnly, maxAge, path, secure, signed ,sameSite) res.download(path [, filename] [, options] [, fn]) - Transfiere el archivo en la ruta (path) como un adjunto. Lo normal es que el navegador del cliente pregunte para permitir la descarga res.download('/report-12345.pdf', 'report.pdf', function(err){ if (err) { // Handle error, response may be partially-sent, check res.headersSent } else { // decrement a download credit, etc. } }); res.end([data] [, encoding]) - Finaliza el proceso de respuesta. Se usa para terminar la respuesta sin enviar ningun dato. Si necesitas respondee con datos usas metodos como res.send() o res.json() res.render(view, [locals], callback) - Renderiza una vista y envia el HTML renderizado como string al cliente res.set(field, [value]) - Determina el valor de la cabecera de respuesta http de nombre field a value. Para establecer multiples campos a la vez pasa un objeto como parametro res.set('Content-Type', 'text/plain'); res.set({ 'Content-Type': 'text/plain', 'Content-Length': '123', 'ETag': '12345' }); res.setHeader('Content-Type', 'application/json'); // res.header() is an alias of res.set() method from Express framework. // The only difference is res.setHeader() allows you only to set a // singular header and res.header() will allow you to set multiple headers // res.setHeader() is a native method of Node.js res.status(code) - Establece el estatus HTTP para la respuesta. Se puede encadenar res.status(200).send(JSON.stringify(data, null, 3)); // same as res.status(200).json(data); res.send([status], body) - Envia la respuesta HTTP. El parametro del body puede ser una objeto Buffer, una cadena, un objeto o un array res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('

        some html

        '); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' }); res.sendFile(path [, options] [, fn]) - Envia el fichero que se encuentra el la ruta dada (path). Establece la cabecera de respuesta HTTP Content-Type segun la extension del archivo enviado. Salvo que la option root este especificada es el objeto de opciones el path debe ser ruta absoluta al archivo app.get('/file/:name', function (req, res, next) { const options = { root: __dirname + '/public/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; const fileName = req.params.name; res.sendFile(fileName, options, function (err) { if (err) { next(err); } else { console.log('Sent:', fileName); } }); }) res.json([status], json) - Envia una respuesta JSON ( con el apropiado content-type) que es el parametro convertido a JSON usando JSON.stringify() res.jsonp([status], jsonp) - Envia una respuesta JSON con soporte para JSONP. Este metodo es identico a res.json() salvo que a\u00f1ade soporte para el callback de JSONP res.redirect([status], path) - Redirige a la URL marcada en path con un HTTP status code igual a status, que si no se especifica por defecto es \"302\" res.location(path) - Establece la cabecera HTTP header Location a path res.redirect('/foo/bar'); res.redirect('http://example.com'); res.redirect(301, 'http://example.com'); res.redirect('../login'); MIDDLEWARE https://expressjs.com/en/resources/middleware.html Definicion Se usan para gestionar las peticiones HTTP hechas al servidor, manejarlas y responderlas. Son callbacks que se ejecutan cuando ocurre una peticion HTTP. La mayoria son de dise\u00f1o propio para cubrir nuestras necesidades pero tambien los hay para cosas comunes como logueos, servir ficheros estaticos, parseos y muchas mas cosas. orden - Los middlewares se ejecutan en el mismo orden en el que se cargan Que puede hacer un middleware ejecutar codigo hacer cambios en los objetos request y response terminar el ciclo request-response llamar al siguiente middleware Si el middleware en curso no termina el ciclo request-response debe llamar a next() para pasar el control al siguiente middleware o la peticion se quedara colgada. Cada funcion middleware tiene tres argumentos: req : objeto que contiene toda la informacion de la peticion HTTP res : objeto que contiene toda la informacion de la respuesta HTTP next : es el siguiente middleware definido en el orden de middlewares Crear un middleware var express = require('express'); var app = express(); // Lo definimos var myLogger = function (req, res, next) { console.log('LOGGED'); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(myLogger); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3000); Otro ejemplo middleware pero este manipula la peticion var express = require('express'); var app = express(); // Lo definimos var requestTime = function (req, res, next) { req.requestTime = Date.now(); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(requestTime); app.get('/', function (req, res) { var responseText = 'Hello World!
        '; responseText += 'Requested at: ' + req.requestTime + ''; res.send(responseText); }); app.listen(3000); Limitar un middleware a una cierta rutas app.use(/ruta, middlewareParaEsaRuta); Para cada ciclo request-response de una aplicacion Express Se ejecutan los middlewares de arriba a abajo Para no terminar el ciclo un middleware debe pasar el control al siguiente mediante un next(); next('route'); se salta el resto de middlewares del stack de rutas Para terminar un ciclo debemos usar res.end o usar res.send() \u00f3 res.sendFile() que internamente llaman a res.end Tipos A nivel de aplicacion const app = express(); app.use() app.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] A nivel de router const router = express.Router(); router.use() router.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] Manejo de error Tienen un argumento mas (err) app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Error : something broke!'); }); Incorporados de serie express.static - sirve recursos estaticos como archivos html, imagenes y cosas asi. express.json``- parsea peticiones entrantes con JSON . express.urlencoded` - parsea peticiones entrantes con URLEncoded Terceros npm install middleware; const middleware = require('middleware'); app.use(middleware()); Esenciales compression - gzips los datos transferidos. Debe ponerse my arriba para que comprima los datos de otros middlewares y rutas npm install compression var compression = require('compression'); app.use(compression()); express-static contenido estatico morgan - antiguo logger. Lleva registro de todas las peticiones y otra informacion importante npm install morgan var logger = require('morgan'); app.use(logger(\"common | dev | short | tiny | y mas\")); // usar dev cors - soporte cors para express cors = require('cors'); app.use(cors()); Si no usamos el middleware poner antes de las rutas este codigo para a\u00f1adir las cabeceras app.use(function(req, res, next) { res.header(\"Access-Control-Allow-Origin\", \"*\"); res.header(\"Access-Control-Allow-Headers\", \"Origin, X-Requested-With Content-Type, Accept\"); next(); }); helmet - middlewares de seguridad var helmet = require('helmet'); app.use(helmet()); body-parser - permite procesar los datos que vienen y convertirlos en objetos javascript/node usables. npm install body-parser var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); errorhandler - se usa para manejo basico de errores en desarrollo y prototipado npm install errorhandler var errorHandler = require('errorhandler'); if (app.get('env') === 'development') { app.use(errorhandler()); } connect-busboy - para usar el parseador de formularios busboy npm install connect-busboy var busboy = require('connect-busboy'); app.use('/upload', busboy({immediate: true })); cookie-parser - permite acceder los valores de las cookies del usuario del objeto req.cookie npm install cookie-parser var cookieParser = require('cookie-parser'); app.use(cookieParser()); method-override - permite al servidor soportar metodos http que el cliente no soporte. npm install method-override var methodOverride = require('method-override'); app.use(methodOverride(\"loQueToque\")); serve-index - como un ls en la terminal npm install serve-index var serveIndex = require('serve-index'); app.use('/shared', serveIndex( path.join('public','shared'), {'icons': true} )); express-session - permite al servidor usar sesiones web. Necesita tener activo antes a cookie-parser. npm install express-session response-time - a\u00f1ade la cabecera \"X-Response-Time\" con un tiempo en ms con un numero de 3 digitos por defecto desde el momento en el que la peticion entro en este middleware. npm install response-time var responseTime = require('response-time'); app.use(responseTime(4)); // cambio a 4 digitos csurf - para prevenir CSRF npm install csurf var csrf = require('csurf'); app.use(csrf()); serve-favicon - para configurar el favicon que querramos npm install serve-favicon var favicon = require('serve-favicon'); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname + '/public', 'favicon.ico'))); passport y express-session - autenticacion var passport = require('passport'); var session = require('express-session'); // required for passport app.use(session({ secret: 'kk', saveUninitialized: true, resave: true})); app.use(passport.initialize()); app.use(passport.session()); // persistent login sessions vhost - para usar diferentes rutas basadas en dominios. Por ejemplo tenemos dos apps con express (api y web) para organizar el codigo para diferentes rutas basadas en los dominios api.dominio.com y web.dominio.com npm install vhost var api = express() var web = express() app.use(vhost('www.dominio.com', web)) app.use(vhost('api.dominio.com', api)) connect-timeout - establece un temporizador npm install connect-timeout var timeout = require('connect-timeout'); cookie-session - almacen de sesion de cookies raw-body - para peticiones como buffers express-validator - para sanear y validar datos que se reciben oauth2-server - autenticacion connect-redis - almacen de la sesion en redis SESIONES + COOKIES Actualizacion 04-07-2019 Ya no hacen falta ni cookie-parser , ni body-parser OJO con los dominios desarrollando en local, si expressjs se levanta en localhost, poner el navegador tambien en localhost y no con 127.0.0.1 o las cookies no se podran leer (aunque si funcionan) app.use(express.json()); // to support JSON-encoded bodies app.use(express.urlencoded({ // to support URL-encoded bodies extended: true })); app.set('trust proxy', 1); // trust first proxy app.use(session({ secret: \"process.env.secretSession\", name: 'alpha', saveUninitialized: false, resave: false, cookie: { httpOnly: false, // true to production //secure: true // comment for localhost, only works for https secure: false, path: \"/\" }, })); ROUTING El ruteo determina como responde una aplicacion a una peticion de un cliente que contiene una URI (o ruta) y un metodo HTTP (GET, POST ...) Cada ruta puede tener una o mas funciones manejadoras que se ejecutan cuando la ruta coincide. Las rutas se pueden hacer con expresiones regulares protocolo hostname port path querystring fragment http:// localhost :3000 /about ?test=1 #history http:// www.bing.com /search ?q=grunt&first https:// google.com / #q=express app.METHOD app.METHOD(path, [handler], handler); path es la ruta en el servidor que pueden ser cadenas, patrones de cadenas o expresiones regulares handler es la funcion que se ejecuta cuando la ruta coincide. Cuando hay varios manejadores para evitar que se ejecuten todos hay que invocar next('route') y saltara a la siguiente METHOD get, leer post, crear put, actualizar delete, borrar hay otros cuantos all, para todos // Ejemplos app.get('/', function (req, res) { // GET method route res.send('GET request to the homepage'); }); app.post('/', function (req, res) { // POST method route res.send('POST request to the homepage'); }); parametros en la ruta La ruta puede contener parametros que se capturan en req.params Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { \"userId\": \"34\", \"bookId\": \"8989\" } multiples manejadores de ruta Se puede establecer m\u00faltiples callbacks (manejadores) que se comportan como middlewares para gestionar una petici\u00f3n. La unica excepcion es que podrian invocar next(\"route\") para evitar los restantes manejadores de esa ruta Los manejadores de ruta pueden ser una funcion, un array de funciones o una combinacion de ambos // varias funciones independientes app.get('/example/b', function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from B!'); }); // array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } var cb2 = function (req, res) { res.send('Hello from C!'); } app.get('/example/c', [cb0, cb1, cb2]); // mix de funciones independientes y array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } app.get('/example/d', [cb0, cb1], function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from D!'); }); app.route() cadena de manejadores de ruta app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); }); clase express.Router La clase express.Router se usa para crear manejadores modulares Creamos un archivo perfil.js en el subdirectorio para rutas /routes var express = require('express'); var perfil = express.Router(); // middleware especifico para esta ruta si nos hace falta, es opcional perfil.use (function(req, res, next) { console.log('Hora = ', Date.now()); next(); }); perfil.get(\"/\", function(req, res, next) { res.send(\"En ruta /\"); }); perfil.get(\"/username\", function(req, res, next) { res.send(\"En /username\"); }); module.exports = perfil; Cargamos el modulo de router en la aplicacion en app.js // en app.js con esto creamos dos rutas \"/profile\" y \"/profile/:username\" var perfiles = require('./routes/perfil.js'); app.use('/perfiles', perfiles); Ahora la app ya atiende a las rutas /perfil y /perfil/:username Cada router puede cargar otros router hasta cargar todos en pej index.js y al cargar en app,js /controller/index.js ya estaran todas las rutas ERRORES El middleware de manejo de errores se define el ultimo despues de todos los app.use() y manejo de rutas. En desarrollo if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } En produccion app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); Se produce un error en express cuando llamamos un next(\"algo ha pasado\") Se saltara los middleware que haya hasta llegar al primer middleware que maneje errores Express no maneja errores producidos por la palabra clave throw y tiene protecciones para estas excepciones. La app retirnara un error 500 y esa peticion fallara pero la app continuara ejecutandose. Sin embargo los errores de sintaxis cascan el programa app.use(function(req, res, next) { if (req.url === \"/\") { next(); } else if (req.url === \"/throw\") { throw new Error(\"Gimme that error\"); } else { next(\"You didn't visit the root!\"); } }); app.use(function(req, res) { res.send(\"Welcome to the homepage.\"); }); app.use(function(err, req, res, next) { console.error(err); res.status(500); next(err); }); app.use(function(err, req, res, next) { res.send(\"Got an error: \" + err); }); APIs RESTful API CRUD api crear -> POST leer -> GET actualizar -> PUT borrar -> DELETE Versiones Patron para mantener la retrocompatibilidad api1.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"Sample response for /timezone\"); }); api.get(\"/all_timezones\", function(req, res) { res.send(\"Sample response for /all_timezones\"); }); module.exports = api; api2.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"API 2: super cool new response for /timezone\"); }); module.exports = api; app.js var express = require(\"express\"); var apiVersion1 = require(\"./api1.js\"); var apiVersion2 = require(\"./api2.js\"); var app = express(); app.use(\"/v1\", apiVersion1); app.use(\"/v2\", apiVersion2); app.listen(3000, function() { console.log(\"App started on port 3000\"); }); SEGURIDAD Seguridad en express Cross-site request forgery npm install --save csurf - Se evita al usar el middleware csurf Debe ir precedido por cookie-parser y express-session var cookieParser = require('cookie-parser'), var session = require('express-session'); var csrf = require(\"csurf\"); app.use(cookieParser('FE28D342-4040-4D0E-B080-B85E85DAF7FD')); app.use(session({ secret: 'BD564488-5105-4202-8927-5A5C9AE9154E', resave: true, saveUninitialized: true })); app.use(csrf()); app.use(function (request, response, next) { response.locals.csrftoken = request.csrfToken(); next(); }); Permisos en procesos No correr servicios como root. Los servicios se pueden cambiar de usuario en ejecucion usando GID (group ID) y UID (user ID) var app = express(); http.createServer(app).listen(app.get('port'), function(){ console.log(\"Express server listening on port \" + app.get('port')); process.setgid(parseInt(process.env.GID, 10)); process.setuid(parseInt(process.env.UID, 10)); }); HTTP Security Headess Instalar middleware helmet que es un conjunto de middlewares de seguridad npm install --save helmet var helmet = require('helmet'); app.use(helmet()); Input Validation Chequear manualmente los datos con expresiones regulares de las rutas que aceptan datos externos Deben tambien controlarse el mapeo de objetos de los datos La validacion en el navegador es solo por criterios de usabilidad, no aporta proteccion a la aplicacion web npm install --save express-validator var validator = require('express-validator'); // lo aplico despues del body-parser app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); app.use(validator()); Ahora en los manejadores tenemos acceso a req.assert y req.validationErrors() app.post('/login', function(req, res){ req.assert('password', 'Password is required').notEmpty(); req.assert('email', 'A valid email is required').notEmpty().isEmail(); var errors = req.validationErrors(); if (errors) { res.render('index', {errors: errors}); } else { res.render('login', {email: request.email}); } }); Seguridad de los paquetes npm npm install -g nsp nsp check --output summary app.disable('x-powered-by');","title":"Expressjs"},{"location":"expressjs/#express-416x","text":"","title":"EXPRESS 4.16.X"},{"location":"expressjs/#uso","text":"","title":"USO"},{"location":"expressjs/#instalacion","text":"npm install -g express - Lo instalamos globalmente npm install -g express-generator - Y el generador de codigo plantilla que nos permite usar el comando express A pelo npm init - te pregunta muchas cosas para generar el package.json Con plantillas express -h Muestra las opciones express --hbs miApp Crea el proyecto miApp con handlebars pej cd miApp & npm install Instala las dependencias","title":"instalacion"},{"location":"expressjs/#api","text":"application app Es una instancia de la aplicacion express que se usa normalmente para configurar la aplicacion request req Es una envoltura del objeto request del modulo HTTP usado para extraer informacion sobre la peticion response res Es una envoltura del objeto response del modulo HTTP usado para enviar los datos y cabeceras de la respuesta Application settings: env: production, development ... viewcache view engine: jade, ejs, hbs ... views trustproxy (NGINX) Seguimiento de una peticion en express","title":"api"},{"location":"expressjs/#main-file","text":"app.js o main.js Cosas que se hacen en este fichero: Dependencias - Incluir paquetes de terceros y modulos nuestros como manejadores, utilidades ayudantes y modelos Instanciaciones - configurar las opciones de express como motor de plantillas Configuraciones - ajustes y como conectar las bases de datos Middlewares - Definir middlewares Ruteo - definir rutas Arranque - iniciar la app o exportarla app como un modulo","title":"MAIN FILE"},{"location":"expressjs/#ajustes","text":"app.set(nombre, valor) - para definir un valor app.set('port', process.env.PORT || 3000); app.get(nombre) - para conseguir un valor app.enable() - app.disable() - app.enabled() - app.disabled() - env - almacena el modo de entorno actual para ese proceso de node.js. Se toma de process.env.NODE_ENV o se pone development por defecto. Opciones {development, test, stage, preview, production} view cache - ponerlo a true para produccion view engine - view engine views - la ruta absoluta al directorio con las plantillas app.set('views', path.join(__dirname, 'templates')) trust proxy - ponerlo a true se esta detras de un proxy como nginx. Por defecto esta desactivado, para activarlo app.set('trust proxy', true); app.enable('trust proxy'); jsonp callback name - vale para hacer llamadas ajax desde otros dominios usando CORS app.set('jsonp callback name', 'cb'); json replacer - json spaces - son dos parametros que se aplican a todas las funciones JSON.stringify(). replacer es un filtro spaces es valor de indentacion app.set('json replacer', function(key, value){ if (key === 'discount') return undefined; else return value; }); app.set('json spaces', 4); case sensitive routing - por defecto disabled, asi /nombre y /Nombres es la misma ruta strict routing - por defeto disabled, asi /users y /users/ son la misma ruta x-powered-by - establece la opcion de la respuesta x-powered-by con el valor Express. Por seguridad lo mejor es desactivarla app.set('x-powered-by', false) // o app.disable('x-powered-by') etag - dejarlo como esta es lo mejor query parser - para parsear las query-string enviadas en la URL. Por defecto extended (usa el modulo qs), true (qs), false (lo desactiva), simple (usa el modulo del nucleo querystring) app.set('query parser', 'simple'); app.set('query parser', false); app.set('query parser', customQueryParsingFunction); subdomain offset - Para aplicaciones desplegadas en varios subdominios","title":"ajustes"},{"location":"expressjs/#contenido-estatico","text":"Usar directorio de contenido estatico Para servir contenido estatico se usa el middleware express.static incorporado en express. var publicPath = path.resolve(__dirname, 'public'); app.use(express.static(publicPath)); Ya puedes cargar archivos del directorio public El nombre del directorio public no es parte de la url http://localhost:3000/css/style.css http://localhost:3000/public/css/style.css NO Usar multiples directorios de contenido estatico Express busca los archivos en el orden en el que se declaran los directorios estaticos app.use(express.static('public')); app.use(express.static('files')); Prefijo de ruta virtual app.use('/static', express.static('public')); Ahora para cargar los archivos : http://localhost:3000/static/css/style.css","title":"contenido estatico"},{"location":"expressjs/#templates","text":"","title":"TEMPLATES"},{"location":"expressjs/#request-peticion","text":"Request API req.query - Esta propiedad es un objeto que tiene una propiedad para cada query string en la ruta. Si no hay query string es un objeto vacio {}. // GET /search?q=jolav req.query.q // => \"jolav\" // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order // => \"desc\" req.query.shoe.color // => \"blue\" req.query.shoe.type // => \"converse\" req.params - Esta propiedad es un objeto con propiedades mapeadas a la ruta \"parametros\". Ejemmplo una ruta /usuario/:nombre, la propiedad 'nombre' esta disponoble en req.params.nombre. Por defecto el objeto es {} // GET /user/jolav on route /user/:name req.params.name // => \"jolav\" // GET /file/js/react.js on royte /file/* req.params[0] // => \"js/react.js\" req.body - Contiene pares clave-valor de datos enviados en el body de la peticion. Por defecto es undefined y se llena cuando usas un middleware body-parsing como por ejemplo body-parser o multer req.route - Contiene la ruta actual como una string app.get('/user/:id?', function userIdHandler(req, res) { console.log(req.route); res.send('GET'); }); { path: '/user/:id?', stack: [ { handle: [Function: userIdHandler], name: 'userIdHandler', params: undefined, path: undefined, keys: [], regexp: /^\\/?$/i, method: 'get' } ], methods: { get: true } } req.cookies - Al usar middleware cookie-parser esta propiedad es un objeto que contiene las cookies enviadas con la peticion. Si no hay cookies por defecto es {} req.headers - req.xhr - Es una propiedad booleana que es true si el campo de la cabecera X-Requested-With header de la peticion es \u201cXMLHttpRequest\u201d req.hostname - Contiene el hostname sacado de la cabecera Host HTTP Header de la peticion. Vamos, de que pagina web viene la peticion // Host: \"example.com:3000\" req.hostname // => \"example.com\" req.originalUrl - req.path - req.baseUrl - // GET /search?q=something req.originalUrl // => \"/search?q=something\" // example.com/users?sort=desc req.path // => \"/users\" // GET 'http://www.example.com/admin/new' app.use('/admin', function(req, res, next) { console.log(req.originalUrl); // '/admin/new' console.log(req.baseUrl); // '/admin' console.log(req.path); // '/new' next(); }); req.protocol - Contiene el protocolo de la peticion como string (http o https)","title":"REQUEST (Peticion)"},{"location":"expressjs/#response-respuesta","text":"Response API res.headersSent - Propiedad booleana que indica si la aplicacion ya ha enviado cabeceras http para la respuesta (vamos, si ya ha enviado alguna respuesta) app.get('/', function (req, res) { console.log(res.headersSent); // false res.send('OK'); console.log(res.headersSent); // true }); res.cookie(name, value [, options]) - Establece el nombre de la cookie a value (que puede ser una string o un objeto convertido en JSON). Las options es un objeto que puede tener las siguientes propiedades (domain, encode, expires, httpOnly, maxAge, path, secure, signed ,sameSite) res.download(path [, filename] [, options] [, fn]) - Transfiere el archivo en la ruta (path) como un adjunto. Lo normal es que el navegador del cliente pregunte para permitir la descarga res.download('/report-12345.pdf', 'report.pdf', function(err){ if (err) { // Handle error, response may be partially-sent, check res.headersSent } else { // decrement a download credit, etc. } }); res.end([data] [, encoding]) - Finaliza el proceso de respuesta. Se usa para terminar la respuesta sin enviar ningun dato. Si necesitas respondee con datos usas metodos como res.send() o res.json() res.render(view, [locals], callback) - Renderiza una vista y envia el HTML renderizado como string al cliente res.set(field, [value]) - Determina el valor de la cabecera de respuesta http de nombre field a value. Para establecer multiples campos a la vez pasa un objeto como parametro res.set('Content-Type', 'text/plain'); res.set({ 'Content-Type': 'text/plain', 'Content-Length': '123', 'ETag': '12345' }); res.setHeader('Content-Type', 'application/json'); // res.header() is an alias of res.set() method from Express framework. // The only difference is res.setHeader() allows you only to set a // singular header and res.header() will allow you to set multiple headers // res.setHeader() is a native method of Node.js res.status(code) - Establece el estatus HTTP para la respuesta. Se puede encadenar res.status(200).send(JSON.stringify(data, null, 3)); // same as res.status(200).json(data); res.send([status], body) - Envia la respuesta HTTP. El parametro del body puede ser una objeto Buffer, una cadena, un objeto o un array res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('

        some html

        '); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' }); res.sendFile(path [, options] [, fn]) - Envia el fichero que se encuentra el la ruta dada (path). Establece la cabecera de respuesta HTTP Content-Type segun la extension del archivo enviado. Salvo que la option root este especificada es el objeto de opciones el path debe ser ruta absoluta al archivo app.get('/file/:name', function (req, res, next) { const options = { root: __dirname + '/public/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; const fileName = req.params.name; res.sendFile(fileName, options, function (err) { if (err) { next(err); } else { console.log('Sent:', fileName); } }); }) res.json([status], json) - Envia una respuesta JSON ( con el apropiado content-type) que es el parametro convertido a JSON usando JSON.stringify() res.jsonp([status], jsonp) - Envia una respuesta JSON con soporte para JSONP. Este metodo es identico a res.json() salvo que a\u00f1ade soporte para el callback de JSONP res.redirect([status], path) - Redirige a la URL marcada en path con un HTTP status code igual a status, que si no se especifica por defecto es \"302\" res.location(path) - Establece la cabecera HTTP header Location a path res.redirect('/foo/bar'); res.redirect('http://example.com'); res.redirect(301, 'http://example.com'); res.redirect('../login');","title":"RESPONSE (Respuesta)"},{"location":"expressjs/#middleware","text":"https://expressjs.com/en/resources/middleware.html","title":"MIDDLEWARE"},{"location":"expressjs/#definicion","text":"Se usan para gestionar las peticiones HTTP hechas al servidor, manejarlas y responderlas. Son callbacks que se ejecutan cuando ocurre una peticion HTTP. La mayoria son de dise\u00f1o propio para cubrir nuestras necesidades pero tambien los hay para cosas comunes como logueos, servir ficheros estaticos, parseos y muchas mas cosas. orden - Los middlewares se ejecutan en el mismo orden en el que se cargan Que puede hacer un middleware ejecutar codigo hacer cambios en los objetos request y response terminar el ciclo request-response llamar al siguiente middleware Si el middleware en curso no termina el ciclo request-response debe llamar a next() para pasar el control al siguiente middleware o la peticion se quedara colgada. Cada funcion middleware tiene tres argumentos: req : objeto que contiene toda la informacion de la peticion HTTP res : objeto que contiene toda la informacion de la respuesta HTTP next : es el siguiente middleware definido en el orden de middlewares Crear un middleware var express = require('express'); var app = express(); // Lo definimos var myLogger = function (req, res, next) { console.log('LOGGED'); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(myLogger); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3000); Otro ejemplo middleware pero este manipula la peticion var express = require('express'); var app = express(); // Lo definimos var requestTime = function (req, res, next) { req.requestTime = Date.now(); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(requestTime); app.get('/', function (req, res) { var responseText = 'Hello World!
        '; responseText += 'Requested at: ' + req.requestTime + ''; res.send(responseText); }); app.listen(3000); Limitar un middleware a una cierta rutas app.use(/ruta, middlewareParaEsaRuta); Para cada ciclo request-response de una aplicacion Express Se ejecutan los middlewares de arriba a abajo Para no terminar el ciclo un middleware debe pasar el control al siguiente mediante un next(); next('route'); se salta el resto de middlewares del stack de rutas Para terminar un ciclo debemos usar res.end o usar res.send() \u00f3 res.sendFile() que internamente llaman a res.end","title":"Definicion"},{"location":"expressjs/#tipos","text":"A nivel de aplicacion const app = express(); app.use() app.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] A nivel de router const router = express.Router(); router.use() router.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] Manejo de error Tienen un argumento mas (err) app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Error : something broke!'); }); Incorporados de serie express.static - sirve recursos estaticos como archivos html, imagenes y cosas asi. express.json``- parsea peticiones entrantes con JSON . express.urlencoded` - parsea peticiones entrantes con URLEncoded Terceros npm install middleware; const middleware = require('middleware'); app.use(middleware());","title":"Tipos"},{"location":"expressjs/#esenciales","text":"compression - gzips los datos transferidos. Debe ponerse my arriba para que comprima los datos de otros middlewares y rutas npm install compression var compression = require('compression'); app.use(compression()); express-static contenido estatico morgan - antiguo logger. Lleva registro de todas las peticiones y otra informacion importante npm install morgan var logger = require('morgan'); app.use(logger(\"common | dev | short | tiny | y mas\")); // usar dev cors - soporte cors para express cors = require('cors'); app.use(cors()); Si no usamos el middleware poner antes de las rutas este codigo para a\u00f1adir las cabeceras app.use(function(req, res, next) { res.header(\"Access-Control-Allow-Origin\", \"*\"); res.header(\"Access-Control-Allow-Headers\", \"Origin, X-Requested-With Content-Type, Accept\"); next(); }); helmet - middlewares de seguridad var helmet = require('helmet'); app.use(helmet()); body-parser - permite procesar los datos que vienen y convertirlos en objetos javascript/node usables. npm install body-parser var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); errorhandler - se usa para manejo basico de errores en desarrollo y prototipado npm install errorhandler var errorHandler = require('errorhandler'); if (app.get('env') === 'development') { app.use(errorhandler()); } connect-busboy - para usar el parseador de formularios busboy npm install connect-busboy var busboy = require('connect-busboy'); app.use('/upload', busboy({immediate: true })); cookie-parser - permite acceder los valores de las cookies del usuario del objeto req.cookie npm install cookie-parser var cookieParser = require('cookie-parser'); app.use(cookieParser()); method-override - permite al servidor soportar metodos http que el cliente no soporte. npm install method-override var methodOverride = require('method-override'); app.use(methodOverride(\"loQueToque\")); serve-index - como un ls en la terminal npm install serve-index var serveIndex = require('serve-index'); app.use('/shared', serveIndex( path.join('public','shared'), {'icons': true} )); express-session - permite al servidor usar sesiones web. Necesita tener activo antes a cookie-parser. npm install express-session response-time - a\u00f1ade la cabecera \"X-Response-Time\" con un tiempo en ms con un numero de 3 digitos por defecto desde el momento en el que la peticion entro en este middleware. npm install response-time var responseTime = require('response-time'); app.use(responseTime(4)); // cambio a 4 digitos csurf - para prevenir CSRF npm install csurf var csrf = require('csurf'); app.use(csrf()); serve-favicon - para configurar el favicon que querramos npm install serve-favicon var favicon = require('serve-favicon'); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname + '/public', 'favicon.ico'))); passport y express-session - autenticacion var passport = require('passport'); var session = require('express-session'); // required for passport app.use(session({ secret: 'kk', saveUninitialized: true, resave: true})); app.use(passport.initialize()); app.use(passport.session()); // persistent login sessions vhost - para usar diferentes rutas basadas en dominios. Por ejemplo tenemos dos apps con express (api y web) para organizar el codigo para diferentes rutas basadas en los dominios api.dominio.com y web.dominio.com npm install vhost var api = express() var web = express() app.use(vhost('www.dominio.com', web)) app.use(vhost('api.dominio.com', api)) connect-timeout - establece un temporizador npm install connect-timeout var timeout = require('connect-timeout'); cookie-session - almacen de sesion de cookies raw-body - para peticiones como buffers express-validator - para sanear y validar datos que se reciben oauth2-server - autenticacion connect-redis - almacen de la sesion en redis","title":"Esenciales"},{"location":"expressjs/#sesiones-cookies","text":"Actualizacion 04-07-2019 Ya no hacen falta ni cookie-parser , ni body-parser OJO con los dominios desarrollando en local, si expressjs se levanta en localhost, poner el navegador tambien en localhost y no con 127.0.0.1 o las cookies no se podran leer (aunque si funcionan) app.use(express.json()); // to support JSON-encoded bodies app.use(express.urlencoded({ // to support URL-encoded bodies extended: true })); app.set('trust proxy', 1); // trust first proxy app.use(session({ secret: \"process.env.secretSession\", name: 'alpha', saveUninitialized: false, resave: false, cookie: { httpOnly: false, // true to production //secure: true // comment for localhost, only works for https secure: false, path: \"/\" }, }));","title":"SESIONES + COOKIES"},{"location":"expressjs/#routing","text":"El ruteo determina como responde una aplicacion a una peticion de un cliente que contiene una URI (o ruta) y un metodo HTTP (GET, POST ...) Cada ruta puede tener una o mas funciones manejadoras que se ejecutan cuando la ruta coincide. Las rutas se pueden hacer con expresiones regulares protocolo hostname port path querystring fragment http:// localhost :3000 /about ?test=1 #history http:// www.bing.com /search ?q=grunt&first https:// google.com / #q=express","title":"ROUTING"},{"location":"expressjs/#appmethod","text":"app.METHOD(path, [handler], handler); path es la ruta en el servidor que pueden ser cadenas, patrones de cadenas o expresiones regulares handler es la funcion que se ejecuta cuando la ruta coincide. Cuando hay varios manejadores para evitar que se ejecuten todos hay que invocar next('route') y saltara a la siguiente METHOD get, leer post, crear put, actualizar delete, borrar hay otros cuantos all, para todos // Ejemplos app.get('/', function (req, res) { // GET method route res.send('GET request to the homepage'); }); app.post('/', function (req, res) { // POST method route res.send('POST request to the homepage'); }); parametros en la ruta La ruta puede contener parametros que se capturan en req.params Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { \"userId\": \"34\", \"bookId\": \"8989\" } multiples manejadores de ruta Se puede establecer m\u00faltiples callbacks (manejadores) que se comportan como middlewares para gestionar una petici\u00f3n. La unica excepcion es que podrian invocar next(\"route\") para evitar los restantes manejadores de esa ruta Los manejadores de ruta pueden ser una funcion, un array de funciones o una combinacion de ambos // varias funciones independientes app.get('/example/b', function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from B!'); }); // array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } var cb2 = function (req, res) { res.send('Hello from C!'); } app.get('/example/c', [cb0, cb1, cb2]); // mix de funciones independientes y array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } app.get('/example/d', [cb0, cb1], function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from D!'); });","title":"app.METHOD"},{"location":"expressjs/#approute","text":"cadena de manejadores de ruta app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); });","title":"app.route()"},{"location":"expressjs/#clase-expressrouter","text":"La clase express.Router se usa para crear manejadores modulares Creamos un archivo perfil.js en el subdirectorio para rutas /routes var express = require('express'); var perfil = express.Router(); // middleware especifico para esta ruta si nos hace falta, es opcional perfil.use (function(req, res, next) { console.log('Hora = ', Date.now()); next(); }); perfil.get(\"/\", function(req, res, next) { res.send(\"En ruta /\"); }); perfil.get(\"/username\", function(req, res, next) { res.send(\"En /username\"); }); module.exports = perfil; Cargamos el modulo de router en la aplicacion en app.js // en app.js con esto creamos dos rutas \"/profile\" y \"/profile/:username\" var perfiles = require('./routes/perfil.js'); app.use('/perfiles', perfiles); Ahora la app ya atiende a las rutas /perfil y /perfil/:username Cada router puede cargar otros router hasta cargar todos en pej index.js y al cargar en app,js /controller/index.js ya estaran todas las rutas","title":"clase express.Router"},{"location":"expressjs/#errores","text":"El middleware de manejo de errores se define el ultimo despues de todos los app.use() y manejo de rutas. En desarrollo if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } En produccion app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); Se produce un error en express cuando llamamos un next(\"algo ha pasado\") Se saltara los middleware que haya hasta llegar al primer middleware que maneje errores Express no maneja errores producidos por la palabra clave throw y tiene protecciones para estas excepciones. La app retirnara un error 500 y esa peticion fallara pero la app continuara ejecutandose. Sin embargo los errores de sintaxis cascan el programa app.use(function(req, res, next) { if (req.url === \"/\") { next(); } else if (req.url === \"/throw\") { throw new Error(\"Gimme that error\"); } else { next(\"You didn't visit the root!\"); } }); app.use(function(req, res) { res.send(\"Welcome to the homepage.\"); }); app.use(function(err, req, res, next) { console.error(err); res.status(500); next(err); }); app.use(function(err, req, res, next) { res.send(\"Got an error: \" + err); });","title":"ERRORES"},{"location":"expressjs/#apis","text":"RESTful API CRUD api crear -> POST leer -> GET actualizar -> PUT borrar -> DELETE Versiones Patron para mantener la retrocompatibilidad api1.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"Sample response for /timezone\"); }); api.get(\"/all_timezones\", function(req, res) { res.send(\"Sample response for /all_timezones\"); }); module.exports = api; api2.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"API 2: super cool new response for /timezone\"); }); module.exports = api; app.js var express = require(\"express\"); var apiVersion1 = require(\"./api1.js\"); var apiVersion2 = require(\"./api2.js\"); var app = express(); app.use(\"/v1\", apiVersion1); app.use(\"/v2\", apiVersion2); app.listen(3000, function() { console.log(\"App started on port 3000\"); });","title":"APIs"},{"location":"expressjs/#seguridad","text":"Seguridad en express Cross-site request forgery npm install --save csurf - Se evita al usar el middleware csurf Debe ir precedido por cookie-parser y express-session var cookieParser = require('cookie-parser'), var session = require('express-session'); var csrf = require(\"csurf\"); app.use(cookieParser('FE28D342-4040-4D0E-B080-B85E85DAF7FD')); app.use(session({ secret: 'BD564488-5105-4202-8927-5A5C9AE9154E', resave: true, saveUninitialized: true })); app.use(csrf()); app.use(function (request, response, next) { response.locals.csrftoken = request.csrfToken(); next(); }); Permisos en procesos No correr servicios como root. Los servicios se pueden cambiar de usuario en ejecucion usando GID (group ID) y UID (user ID) var app = express(); http.createServer(app).listen(app.get('port'), function(){ console.log(\"Express server listening on port \" + app.get('port')); process.setgid(parseInt(process.env.GID, 10)); process.setuid(parseInt(process.env.UID, 10)); }); HTTP Security Headess Instalar middleware helmet que es un conjunto de middlewares de seguridad npm install --save helmet var helmet = require('helmet'); app.use(helmet()); Input Validation Chequear manualmente los datos con expresiones regulares de las rutas que aceptan datos externos Deben tambien controlarse el mapeo de objetos de los datos La validacion en el navegador es solo por criterios de usabilidad, no aporta proteccion a la aplicacion web npm install --save express-validator var validator = require('express-validator'); // lo aplico despues del body-parser app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); app.use(validator()); Ahora en los manejadores tenemos acceso a req.assert y req.validationErrors() app.post('/login', function(req, res){ req.assert('password', 'Password is required').notEmpty(); req.assert('email', 'A valid email is required').notEmpty().isEmail(); var errors = req.validationErrors(); if (errors) { res.render('index', {errors: errors}); } else { res.render('login', {email: request.email}); } }); Seguridad de los paquetes npm npm install -g nsp nsp check --output summary app.disable('x-powered-by');","title":"SEGURIDAD"},{"location":"frontend/","text":"FRONT END IMAGENES IMAGENES tynypng - Comprimir imagenes shrinktheweb - Capturar instantaneas de paginas web ICONOS SoftIcons Material design Iconfinder COLORES Color-hex - Para elegir colores SPRITES css sprites - Generador de sprites y su CSS EDITORES ONLINE Luna pic Resize Image IMAGENES GRATUITAS Pixabay Pexels FUENTES GOOGLE FONTS se pueden importar desde el HTML o desde el CSS @import url('https://fonts.googleapis.com/css?family=name:400,500'); Lato Roboto Oxygen Fira Sans IBM Plex Sans Exo Titillium Web Rambla Open Sans Ovo Varela Varela Round PT Sans Audiowide Orbitron Alegreya Patrick Hand SC Indie Flower Chewy Righteous Pacifico Press Start 2P Luckiest Guy Bungee SEGURIDAD Y ESTADISTICAS STATS Pingdom - Mide la velocidad de carga de las paginas WebPageTets - Mide la velocidad de carga de las paginas GT Metrix - Mide la velocidad de carga de las paginas Google PageSpeed - Optimiza la velocidad de carga de las paginas SECURITY CertBot - Para manejar lor certificados lets encrypt Secarma - Prueba la seguridad de las cabeceras del servidor MXToolbox - Todo sobre DNS SSL Labs - Testea la seguridad del SSL del servidor Scan My Server - Testeo completo sobre las vulnerabilidades del servidor y la pagina UTILS XML Sitemaps - Generador de sitemap.xml FUENTES DE INFORMACION APIs LIST List of public APIs - Github repo con lista de APIs publicas Programmableweb - Pagina con listado de APIs GOVs data Data Gov - Datos del Gobierno USA EU Open Data Portal - Datos de la CEE Spain Gov Data - Datos del Gobierno Espa\u00f1ol FOOD Nutritionix - Api completa sobre comida STOCK MARKET IEX Trading - Api en tiempo real Alphavantage - API en tiempo real Quandl - Bases de datos financieras y economicas LIVE-SERVER // se recarga al cambiar archivos css (que por defecto no lo hace) live-server --no-css-inject // por efecto abre en 127.0.0.1 , para cambiarlo live-server --no-css-inject --host=localhost","title":"Front End"},{"location":"frontend/#front-end","text":"","title":"FRONT END"},{"location":"frontend/#imagenes","text":"IMAGENES tynypng - Comprimir imagenes shrinktheweb - Capturar instantaneas de paginas web ICONOS SoftIcons Material design Iconfinder COLORES Color-hex - Para elegir colores SPRITES css sprites - Generador de sprites y su CSS EDITORES ONLINE Luna pic Resize Image IMAGENES GRATUITAS Pixabay Pexels","title":"IMAGENES"},{"location":"frontend/#fuentes","text":"GOOGLE FONTS se pueden importar desde el HTML o desde el CSS @import url('https://fonts.googleapis.com/css?family=name:400,500'); Lato Roboto Oxygen Fira Sans IBM Plex Sans Exo Titillium Web Rambla Open Sans Ovo Varela Varela Round PT Sans Audiowide Orbitron Alegreya Patrick Hand SC Indie Flower Chewy Righteous Pacifico Press Start 2P Luckiest Guy Bungee","title":"FUENTES"},{"location":"frontend/#seguridad-y-estadisticas","text":"STATS Pingdom - Mide la velocidad de carga de las paginas WebPageTets - Mide la velocidad de carga de las paginas GT Metrix - Mide la velocidad de carga de las paginas Google PageSpeed - Optimiza la velocidad de carga de las paginas SECURITY CertBot - Para manejar lor certificados lets encrypt Secarma - Prueba la seguridad de las cabeceras del servidor MXToolbox - Todo sobre DNS SSL Labs - Testea la seguridad del SSL del servidor Scan My Server - Testeo completo sobre las vulnerabilidades del servidor y la pagina UTILS XML Sitemaps - Generador de sitemap.xml","title":"SEGURIDAD Y ESTADISTICAS"},{"location":"frontend/#fuentes-de-informacion","text":"APIs LIST List of public APIs - Github repo con lista de APIs publicas Programmableweb - Pagina con listado de APIs GOVs data Data Gov - Datos del Gobierno USA EU Open Data Portal - Datos de la CEE Spain Gov Data - Datos del Gobierno Espa\u00f1ol FOOD Nutritionix - Api completa sobre comida STOCK MARKET IEX Trading - Api en tiempo real Alphavantage - API en tiempo real Quandl - Bases de datos financieras y economicas","title":"FUENTES DE INFORMACION"},{"location":"frontend/#live-server","text":"// se recarga al cambiar archivos css (que por defecto no lo hace) live-server --no-css-inject // por efecto abre en 127.0.0.1 , para cambiarlo live-server --no-css-inject --host=localhost","title":"LIVE-SERVER"},{"location":"golang-bases-de-datos/","text":"GOLANG para BASES DE DATOS MYSQL driver go-sql-driver go get -u github.com/go-sql-driver/mysql Crear conexion a la BBDD package store import ( \"database/sql\" \"fmt\" // mysql driver _ \"github.com/go-sql-driver/mysql\" ) type configDB struct { DatabaseType string `json:\"databaseType\"` Host string `json:\"host\"` Port int `json:\"port\"` DB string `json:\"db\"` User string `json:\"user\"` Password string `json:\"password\"` } // DB ... type DB struct { *sql.DB } // NewDB ... func NewDB(mode string) (*DB, error) { var c configDB loadConfigJSON(&c) setDBConnConfig(mode, &c) connPath := fmt.Sprintf(\"%s:%s@tcp(%s:%d)/%s?parseTime=true\", c.User, c.Password, c.Host, c.Port, c.DB, ) //fmt.Println(\"CONNPATH => \", connPath) db, err := sql.Open(c.DatabaseType, connPath) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return &DB{db}, nil } // lo llamo desde otro paquete package login import ( store \"casServer/login/store\" ) var loginDB *store.DB func init() { db, err := store.NewDB(checkAppConfMode()) if err != nil { log.Fatal(\"Error connecting DataBase => \", err) } loginDB = db //users, _ := loginDB.AccountList() //fmt.Println(len(users)) } Select func (loginDB *DB) Account(name string) (*User, error) { //fmt.Println(\"SEARCHING ...\", name) u := new(User) query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, usersTable, ) //fmt.Println(query) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB %s\\n\", err) return u, err } defer stmt.Close() err = stmt.QueryRow(name).Scan( &u.NickID, &u.Nick, &u.PassHashed, &u.Email, &u.Verified, &u.Logo, &u.SecretQuest, &u.SecretHashed, &u.CreatedAt, &u.LastSeen, &u.Online) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", u) return u, nil } log.Printf(\"ERROR 2 DB %s\\n\", err) return nil, err } return u, nil } func (loginDB *DB) AccountList() ([]*User, error) { query := fmt.Sprintf(` SELECT nickID FROM %s `, usersTable, ) stmt, err := loginDB.Prepare(query) if err != nil { return nil, err } defer stmt.Close() rows, err := stmt.Query() if err != nil { return nil, err } defer rows.Close() users := make([]*User, 0) for rows.Next() { user := new(User) err := rows.Scan( &user.NickID, ) if err != nil { return nil, err } users = append(users, user) } return users, nil } func (loginDB *DB) UserSession(usernameID string) (*Session, error) { s := NewSession() query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, sessionsTable, ) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 3 DB SESSIONS %s\\n\", err) return s, err } defer stmt.Close() err = stmt.QueryRow(usernameID).Scan( &s.NickID, &s.SessionID, &s.Expires, ) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", s) return s, nil } log.Printf(\"ERROR 4 DB SESSIONS %s\\n\", err) return nil, err } return s, nil } Insert func (loginDB *DB) NewAccount(u *User) error { //fmt.Println(\"USER => \", u) query := fmt.Sprintf(` INSERT INTO %s ( nickID, nick, passHashed, email, verified, logo, secretQuest, secretHashed, createdAt, lastSeen, online ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, usersTable, ) stmt, err := loginDB.Prepare(query) //fmt.Println(query) if err != nil { log.Printf(\"ERROR 3 DB USERS %s -> %s\\n\", u.Nick, err) return err } defer stmt.Close() _, err = stmt.Exec( u.NickID, u.Nick, u.PassHashed, u.Email, u.Verified, u.Logo, u.SecretQuest, u.SecretHashed, u.CreatedAt, u.LastSeen, u.Online, ) if err != nil { log.Printf(\"ERROR 4 DB USERS %s -> %s\\n\", u.Nick, err) return err } return nil } func (loginDB *DB) SaveSession(s *Session) error { query := fmt.Sprintf(` INSERT INTO %s ( nickID, sessionID, expires ) values (?, ?, ?) ON DUPLICATE KEY UPDATE sessionID=? , expires= ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } defer stmt.Close() _, err = stmt.Exec( s.NickID, s.SessionID, s.Expires, s.SessionID, s.Expires, ) if err != nil { log.Printf(\"ERROR 2 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } return nil } Update Delete func (loginDB *DB) DeleteSession(usernameID string) error { query := fmt.Sprintf(` DELETE FROM %s WHERE nickID = ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 5 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } defer stmt.Close() _, err = stmt.Exec( usernameID, ) if err != nil { log.Printf(\"ERROR 6 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } return nil }","title":"Golang Bases de Datos"},{"location":"golang-bases-de-datos/#golang-para-bases-de-datos","text":"","title":"GOLANG para BASES DE DATOS"},{"location":"golang-bases-de-datos/#mysql","text":"","title":"MYSQL"},{"location":"golang-bases-de-datos/#driver","text":"go-sql-driver go get -u github.com/go-sql-driver/mysql","title":"driver"},{"location":"golang-bases-de-datos/#crear-conexion-a-la-bbdd","text":"package store import ( \"database/sql\" \"fmt\" // mysql driver _ \"github.com/go-sql-driver/mysql\" ) type configDB struct { DatabaseType string `json:\"databaseType\"` Host string `json:\"host\"` Port int `json:\"port\"` DB string `json:\"db\"` User string `json:\"user\"` Password string `json:\"password\"` } // DB ... type DB struct { *sql.DB } // NewDB ... func NewDB(mode string) (*DB, error) { var c configDB loadConfigJSON(&c) setDBConnConfig(mode, &c) connPath := fmt.Sprintf(\"%s:%s@tcp(%s:%d)/%s?parseTime=true\", c.User, c.Password, c.Host, c.Port, c.DB, ) //fmt.Println(\"CONNPATH => \", connPath) db, err := sql.Open(c.DatabaseType, connPath) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return &DB{db}, nil } // lo llamo desde otro paquete package login import ( store \"casServer/login/store\" ) var loginDB *store.DB func init() { db, err := store.NewDB(checkAppConfMode()) if err != nil { log.Fatal(\"Error connecting DataBase => \", err) } loginDB = db //users, _ := loginDB.AccountList() //fmt.Println(len(users)) }","title":"Crear conexion a la BBDD"},{"location":"golang-bases-de-datos/#select","text":"func (loginDB *DB) Account(name string) (*User, error) { //fmt.Println(\"SEARCHING ...\", name) u := new(User) query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, usersTable, ) //fmt.Println(query) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB %s\\n\", err) return u, err } defer stmt.Close() err = stmt.QueryRow(name).Scan( &u.NickID, &u.Nick, &u.PassHashed, &u.Email, &u.Verified, &u.Logo, &u.SecretQuest, &u.SecretHashed, &u.CreatedAt, &u.LastSeen, &u.Online) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", u) return u, nil } log.Printf(\"ERROR 2 DB %s\\n\", err) return nil, err } return u, nil } func (loginDB *DB) AccountList() ([]*User, error) { query := fmt.Sprintf(` SELECT nickID FROM %s `, usersTable, ) stmt, err := loginDB.Prepare(query) if err != nil { return nil, err } defer stmt.Close() rows, err := stmt.Query() if err != nil { return nil, err } defer rows.Close() users := make([]*User, 0) for rows.Next() { user := new(User) err := rows.Scan( &user.NickID, ) if err != nil { return nil, err } users = append(users, user) } return users, nil } func (loginDB *DB) UserSession(usernameID string) (*Session, error) { s := NewSession() query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, sessionsTable, ) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 3 DB SESSIONS %s\\n\", err) return s, err } defer stmt.Close() err = stmt.QueryRow(usernameID).Scan( &s.NickID, &s.SessionID, &s.Expires, ) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", s) return s, nil } log.Printf(\"ERROR 4 DB SESSIONS %s\\n\", err) return nil, err } return s, nil }","title":"Select"},{"location":"golang-bases-de-datos/#insert","text":"func (loginDB *DB) NewAccount(u *User) error { //fmt.Println(\"USER => \", u) query := fmt.Sprintf(` INSERT INTO %s ( nickID, nick, passHashed, email, verified, logo, secretQuest, secretHashed, createdAt, lastSeen, online ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, usersTable, ) stmt, err := loginDB.Prepare(query) //fmt.Println(query) if err != nil { log.Printf(\"ERROR 3 DB USERS %s -> %s\\n\", u.Nick, err) return err } defer stmt.Close() _, err = stmt.Exec( u.NickID, u.Nick, u.PassHashed, u.Email, u.Verified, u.Logo, u.SecretQuest, u.SecretHashed, u.CreatedAt, u.LastSeen, u.Online, ) if err != nil { log.Printf(\"ERROR 4 DB USERS %s -> %s\\n\", u.Nick, err) return err } return nil } func (loginDB *DB) SaveSession(s *Session) error { query := fmt.Sprintf(` INSERT INTO %s ( nickID, sessionID, expires ) values (?, ?, ?) ON DUPLICATE KEY UPDATE sessionID=? , expires= ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } defer stmt.Close() _, err = stmt.Exec( s.NickID, s.SessionID, s.Expires, s.SessionID, s.Expires, ) if err != nil { log.Printf(\"ERROR 2 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } return nil }","title":"Insert"},{"location":"golang-bases-de-datos/#update","text":"","title":"Update"},{"location":"golang-bases-de-datos/#delete","text":"func (loginDB *DB) DeleteSession(usernameID string) error { query := fmt.Sprintf(` DELETE FROM %s WHERE nickID = ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 5 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } defer stmt.Close() _, err = stmt.Exec( usernameID, ) if err != nil { log.Printf(\"ERROR 6 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } return nil }","title":"Delete"},{"location":"golang-para-web/","text":"GOLANG PARA DESARROLLO WEB NET/HTTP import net/http Static // sirve el directorio entero func main() { dir := http.Dir(\"./files\") http.ListenAndServe(\":8080\", http.FileServer(dir)) http.HandleFunc(\"/\", readme) } // ServeFile sirve un archivo o un directorio como 3er argumento func main() { http.HandleFunc(\"/\", public) http.ListenAndServe(\":8080\", nil) } func public(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, \"./files/hola.html\") // http.ServeFile(w, r, \"./files/\") } // sirve el directorio ./files en la ruta /static/ // ./files puede estar en cualquier sitio del sistema de archivos // no solo en el dir de la aplicacion func main() { dir := http.Dir(\"./files/\") handler := http.StripPrefix(\"/static/\", http.FileServer(dir)) http.Handle(\"/static/\", handler) http.HandleFunc(\"/\", homePage) http.ListenAndServe(\":8080\", nil) } Handler - Handlers son cualquier struct que tiene un metodo ServeHTTP(w http.ResponseWriter, r *http.Request) con dos parametros: una interface HTTPResponseWriter y un puntero a una Request struct. - Handler functions son funciones que se comportan como handlers. Tienen la misma firma que el metodo ServeHTTP y se utiizan para procesar peticiones (Requests) - Handlers y handler functions se pueden encadenar para permitir el procesado en partes de peticiones mediante la separacion de asuntos. - Multiplexers(routers) tambien son handlers. ServeMux es un router de peticiones HTTP. Acepta peticiones HTTP y las redirige al handler adecuado segun la URL de la peticion. DefaultServeMux es una instancia de ServeMux que se usa como router por defecto Handler // multi handler and chain handler package main import ( \"fmt\" \"net/http\" ) type helloHandler struct{} func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"Hello!\") } type worldHandler struct{} func (h *worldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"World!\") } func log(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ fmt.Printf(\"Handler called - %T\\n\", h) h.ServeHTTP(w, r) }) } func protect(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ // some code to make sure the user is authorized h.ServeHTTP(w, r) }) } func main() { hello := helloHandler{} world := worldHandler{} server := http.Server{ Addr: \"127.0.0.1:8080\", } http.Handle(\"/hello\", protect(log(&hello))) http.Handle(\"/world\", &world) server.ListenAndServe() } HandleFunc package main import ( \"fmt\" \"net/http\" \"reflect\" \"runtime\" ) func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"Hello!\") } func world(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"World!\") } func log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name() fmt.Println(\"Handler function called - \" + name) h(w, r) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/hello\", log(hello)) http.HandleFunc(\"/world\", world) server.ListenAndServe() } Request URL https://golang.org/src/net/url/url.go type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string RawPath string // encoded path hint ForceQuery bool // append a query ('?') even if RawQuery is empty RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } algunos metodos // EscapedPath returns the escaped form of u.Path. func (u *URL) EscapedPath() string {} // IsAbs reports whether the URL is absolute. func (u *URL) IsAbs() bool {} // Query parses RawQuery and returns the corresponding values. func (u *URL) Query() Values {} type Values map[string][]string Headers type Header func (h Header) Add(key, value string) func (h Header) Del(key string) func (h Header) Get(key string) string func (h Header) Set(key, value string) func (h Header) Write(w io.Writer) error func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error func headers(w http.ResponseWriter, r *http.Request) { h := r.Header // h := r.Header[\"Accept-Encoding\"] // devuelve un map de strings // h := r.Header.Get(\"Accept-Encoding\") // devuelve string fmt.Fprintln(w, h) } http.HandleFunc(\"/headers\", headers) Body func body(w http.ResponseWriter, r *http.Request) { len := r.ContentLength body := make([]byte, len) r.Body.Read(body) fmt.Fprintln(w, string(body)) } http.HandleFunc(\"/body\", body) ResponseWriter La interface ResponseWriter tiene tres metodos: - Write - coge un []bytes y lo escribe en el body de la respuesta HTTP. Si la cabecera no especifica content-type usa los los primeros 512 bytes de datos para detectar el tipo de contenido - WriteHeader - envia un numero entero que representa el codigo de estado de la respuesta HTTP. Despues de usar este metodo no se puede escribir ni modificar nada en la cabecera. Si no se use este metodo por defecto cuando se llama a Write se envia el codigo 200 OK Es muy util para enviar codigos de errores - Header - devuelve un map de campos de la cabecera que se pueden modificar y que seran enviados en la respuesta al cliente type post struct { User string Langs []string } func writeExample(w http.ResponseWriter, r *http.Request) { str := ` Write Example

        Hello World

        ` w.Write([]byte(str)) } func writeHeaderExample(w http.ResponseWriter, r *http.Request) { w.WriteHeader(501) fmt.Fprintln(w, \"Not implemented yet\") } func headerExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Location\", \"https://jolav.github.io\") w.WriteHeader(302) } func jsonExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"application/json\") post := &post{ User: \"jolav\", Langs: []string{\"Go\", \"HTML\", \"Javascript\"}, } json, _ := json.Marshal(post) w.Write(json) } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/write\", writeExample) http.HandleFunc(\"/writeheader\", writeHeaderExample) http.HandleFunc(\"/redirect\", headerExample) http.HandleFunc(\"/json\", jsonExample) server.ListenAndServe() } Middleware type Middleware []http.Handler // Adds a handler to the middleware func (m *Middleware) Add(handler http.Handler) { *m = append(*m, handler) } func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http. \u27a5Request) { // Process the middleware } Cookies https://golang.org/src/net/http/cookie.go type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } Si no se usa el campo Expires la cookie es de sesion o temporal y se eliminan del navegador cuando este se cierra. De lo contrario la cookie es persistente y dura hasta que expire o se elimine. Usar MaxAge en lugar de Expires que esta deprecada package main import ( \"encoding/base64\" \"fmt\" \"net/http\" \"time\" ) func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: \"first cookie\", Value: \"Valor de la primera galleta\", HttpOnly: true, } c2 := http.Cookie{ Name: \"second cookie\", Value: \"Valor de la segunda galleta\", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) } func getCookie(w http.ResponseWriter, r *http.Request) { c1, err := r.Cookie(\"first cookie\") if err != nil { fmt.Fprintln(w, \"Cannot get the first cookie\") } cs := r.Cookies() fmt.Fprintln(w, c1) fmt.Fprintln(w, cs) } func setMessage(w http.ResponseWriter, r *http.Request) { msg := []byte(\"Hello World!\") c := http.Cookie{ Name: \"flash\", Value: base64.URLEncoding.EncodeToString(msg), } http.SetCookie(w, &c) } func showMessage(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie(\"flash\") if err != nil { if err == http.ErrNoCookie { fmt.Fprintln(w, \"No message found\") } } else { rc := http.Cookie{ Name: \"flash\", MaxAge: -1, Expires: time.Unix(1, 0), } http.SetCookie(w, &rc) val, _ := base64.URLEncoding.DecodeString(c.Value) fmt.Fprintln(w, string(val)) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/setCookie\", setCookie) http.HandleFunc(\"/getCookie\", getCookie) http.HandleFunc(\"/setMessage\", setMessage) http.HandleFunc(\"/showMessage\", showMessage) server.ListenAndServe() } Sessions Forms 1\u00ba - Parseamos la peticion con ParseForm o ParseMultipartForm 2\u00ba - Accedemos al formulario // formulario para process1
        // formulario para process2 y process3
        package main import ( \"fmt\" \"io/ioutil\" \"net/http\" ) func process1(w http.ResponseWriter, r *http.Request) { r.ParseForm() fmt.Fprintln(w, r.Form[\"campo\"][0]) fmt.Prinltln(w, r.Form.Get(\"campo\")) // fmt.Fprintln(w, r.PostForm) } func process2(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile(\"uploaded\") if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func process3(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(1024) fileHeader := r.MultipartForm.File[\"uploaded\"][0] file, err := fileHeader.Open() if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/process1\", process1) http.HandleFunc(\"/process2\", process2) http.HandleFunc(\"/process3\", process3) server.ListenAndServe() } Cliente HTTP type Client func (c *Client) Do(req *Request) (*Response, error) func (c *Client) Get(url string) (resp *Response, err error) func (c *Client) Head(url string) (resp *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) Ejemplo Hacer peticiones get Poner en el main o donde sea para asegurarse que tiene un tiempo maximo de espera y no se queda colgado esperando hasta el infinito (que es el valor por defecto) https://reddit.com/r/golang/comments/45mzie/dont_use_gos_default_http_client/ http.DefaultClient.Timeout = 10 * time.Second func getHttpRequest() { url := \"https://codetabs.com/tools/geoip/geoip.html\" resp, err := http.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&geo) if err != nil { panic(err) } aux.SendDataToClient(w, r, geo) } ServeMux func mainNormal() { // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) http.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) http.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) http.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) http.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) http.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) // any /voting/* will redirect to voting.Voting http.HandleFunc(\"/voting/\", voting.Router) // any /pintelest/* will redirect to voting.Voting http.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", } server.ListenAndServe() } func mainMux() { mux := http.NewServeMux() // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) mux.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) mux.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) mux.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) mux.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) mux.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) mux.HandleFunc(\"/voting/\", voting.Router) //mux.HandleFunc(\"/voting/p/\", nodePintelest) // any /pintelest/* will redirect to nodePintelest mux.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", Handler: mux, } server.ListenAndServe() } // http://codepodu.com/subdomains-with-golang/ type Subdomains map[string]http.Handler func (subdomains Subdomains) ServeHTTP(w http.ResponseWriter, r *http.Request) { domainParts := strings.Split(r.Host, \".\") if mux := subdomains[domainParts[0]]; mux != nil { // Let the appropriate mux serve the request mux.ServeHTTP(w, r) } else { // Handle 404 http.Error(w, \"Not found\", 404) } } type Mux struct { http.Handler } func (mux Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) } func adminHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerOne , Hello, %q\", r.URL.Path[1:]) } func adminHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerOne , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func main() { adminMux := http.NewServeMux() adminMux.HandleFunc(\"/admin/pathone\", adminHandlerOne) adminMux.HandleFunc(\"/admin/pathtwo\", adminHandlerTwo) analyticsMux := http.NewServeMux() analyticsMux.HandleFunc(\"/analytics/pathone\", analyticsHandlerOne) analyticsMux.HandleFunc(\"/analytics/pathtwo\", analyticsHandlerTwo) subdomains := make(Subdomains) subdomains[\"admin\"] = adminMux subdomains[\"analytics\"] = analyticsMux http.ListenAndServe(\":8080\", subdomains) } HTML/TEMPLATE import html/template Para usarlo hay que importar el paquete html/template crear la plantilla t, _ := template.ParseFiles(\"index.html\") asignar valor a variables de plantilla template_value := \"Hola\" servir la pagina t.Execute(w, template_values) index.html Hello World Hello {{ . }} pagina.go package main import ( \"html/template\" \"net/http\" ) func handler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles(\"index.html\") name := \"World\" t.Execute(w, name) } func main() { http.HandleFunc(\"/\", handler) http.ListenAndServe(\":8080\", nil) } Fields {{}} cualquier cosa a ser renderizada debe ir entre dobles parentesis {{.}} abreviatura para el objeto actual {{ .FieldName}} campo FieldName del objecto actual Arrays and slices type Friend struct { Fname string } type Person struct { UserName string Emails []string Friends []*Friend } func main() { f1 := Friend{Fname: \"minux.ma\"} f2 := Friend{Fname: \"xushiwei\"} t := template.New(\"fieldname example\") t, _ = t.Parse(`hello {{.UserName}}! {{range .Emails}} an email {{.}} {{end}} {{with .Friends}} {{range .}} my friend name is {{.Fname}} {{end}} {{end}} `) p := Person{UserName: \"Astaxie\", Emails: []string{\"astaxie@beego.me\", \"astaxie@gmail.com\"}, Friends: []*Friend{&f1, &f2}} t.Execute(os.Stdout, p) } Arrays and slices index const tmpl = ` {{range $index, $link := .}} {{$index}}: {{$link.Name}} {{end}} ` type Link struct { Name string Href string } func main() { // arrays var la [2]Link la[0] = Link{\"Google\", \"https://www.google.com/\"} la[1] = Link{\"Facebook\", \"https://www.facebook.com/\"} t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, la) // slices var ls []Link ls = append(ls, Link{\"Google\", \"https://www.google.com/\"}) ls = append(ls, Link{\"Facebook\", \"https://www.facebook.com/\"}) t.Execute(os.Stdout, ls) } Maps const tmpl = ` {{range $name, $href := .}} {{$name}} {{end}} ` func main() { // map var m = map[string]string{ \"Google\": \"https://www.google.com/\", \"Facebook\": \"https://www.facebook.com/\", } t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, m) } Conditions {{if}} {{else}} : Solo para valores booleanos, no hace comparaciones {{if ``}} Will not print. {{end}} {{if `anything`}} Will print. {{end}} {{if `anything`}} Print IF part. {{else}} Print ELSE part. {{end}} Pipelines {{ . | html}} Por ejemplo usamos esto para coger el objto actual '.' y aplicarle escape a HTML al objeto Variables Pasar variables a templates // usando anonymous structs var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") templates.ExecuteTemplate(w, \"page.html\", struct { PageTitle string Message string User string }{\"Template example: struct\", \"Hello\", \"World\"}) } // usando Maps var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") m := make(map[string]interface{}) m[\"PageTitle\"] = \"Template example: map\" m[\"Message\"] = \"Hello\" m[\"User\"] = \"World\" templates.ExecuteTemplate(w, \"page.html\", m) } // mapa m := map[string]interface{}{ \"imgs\": imgs, // {{range .imgs.Image}}{{.}}{{end}} \"user\": p, //{{.user.Name}} } // struct , Images []Image type Data struct { I Images P Profile } var d Data d.I = imgs // {{range .I.Image}}{{.}}{{end}} d.P = p // {{.P.Name}}*/ t.Execute(w, &m) Funciones Predefinidas Por ejemplo print equivale a fmt.Sprintf func main() { texto := \"{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}} {{end}}!\\n\" t := template.New(\"test\") t = template.Must(t.Parse(texto)) t.Execute(os.Stdout, nil) // Resultado -> hello Mary! De Dise\u00f1o const tmpl = ` hello {{gettext .}} hello {{. | gettext}} ` var funcMap = template.FuncMap{ \"gettext\": gettext, } func gettext(s string) string { if s == \"world\" { return \"otraCosa\" } return s } func main() { t, _ := template.New(\"foo\").Funcs(funcMap).Parse(tmpl) s := \"world\" t.Execute(os.Stdout, s) } Must Es una funcion del paquete template para validar plantillas Nested templates Se puede declarar una plantilla: {{ define \"sub-plantilla\"}} contenido que sea {{ end}} Luego esa plantilla se inserta {{ template \"sub-plantilla\" }} base.html {{define \"base\"}} {{template \"title\" .}} {{template \"content\" .}} {{end}} index.html {{template \"base\" .}} {{define \"title\"}}my title{{end}} {{define \"content\"}}
        hello {{.}}
        {{end}} nestedTemplates.go func main() { // cannot put base.html before index.html will give empty output // t, _ := template.ParseFiles(\"base.html\", \"index.html\") t, _ := template.ParseFiles(\"index.html\", \"base.html\") name := \"world\" t.Execute(os.Stdout, name) } Pasar vars a js Pasar variables golang a cliente js // voting.go func guest(w http.ResponseWriter, r *http.Request) { var data aPoll data = aPoll{Question: \"Texto de la cuestion\"} tmpl[\"guest.html\"].ExecuteTemplate(w, \"guest.html\", data) } var voting = (function () { function init () { console.log(\"Data from golang\", golang); } return { init: init }; }()); NET/URL A\u00f1adir parametros a URL // sobre una URL existente values := r.URL.Query() values.Add(\"nombreNuevoParamatro\", valor) values.Get(\"nombreDelValor\", valor) r.URL.RawQuery = values.Encode() fmt.Println(r.URL.String()) fmt.Println(values[\"nombreNuevoParametro\"]) // construyendo una URL urlData, err := url.Parse(\"https://apisquesea.com/custom/v1?q=\") params := url.Values{} params.Add(\"q\", r.URL.Query().Get(\"q\")) params.Add(\"cx\", c.APIImage.CseID) params.Add(\"key\", c.APIImage.Key) params.Add(\"num\", r.URL.Query().Get(\"num\")) params.Add(\"offset\", r.URL.Query().Get(\"offset\")) urlData.RawQuery = params.Encode() URL parsing UTILIDADES fresh https://github.com/pilu/fresh - Especie de nodemon para golang. archivo de configuracion que se ejecuta con fresh -c ruta/al/archivo root: . tmp_path: ./tmp build_name: runner-build build_log: runner-build-errors.log valid_ext: .go, .tpl, .tmpl, .html, .css, .js ignored: assets, tmp, pintelest build_delay: 600 colors: 1 log_color_main: cyan log_color_build: yellow log_color_runner: green log_color_watcher: magenta log_color_app:","title":"Golang para web"},{"location":"golang-para-web/#golang-para-desarrollo-web","text":"","title":"GOLANG PARA DESARROLLO WEB"},{"location":"golang-para-web/#nethttp","text":"import net/http","title":"NET/HTTP"},{"location":"golang-para-web/#static","text":"// sirve el directorio entero func main() { dir := http.Dir(\"./files\") http.ListenAndServe(\":8080\", http.FileServer(dir)) http.HandleFunc(\"/\", readme) } // ServeFile sirve un archivo o un directorio como 3er argumento func main() { http.HandleFunc(\"/\", public) http.ListenAndServe(\":8080\", nil) } func public(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, \"./files/hola.html\") // http.ServeFile(w, r, \"./files/\") } // sirve el directorio ./files en la ruta /static/ // ./files puede estar en cualquier sitio del sistema de archivos // no solo en el dir de la aplicacion func main() { dir := http.Dir(\"./files/\") handler := http.StripPrefix(\"/static/\", http.FileServer(dir)) http.Handle(\"/static/\", handler) http.HandleFunc(\"/\", homePage) http.ListenAndServe(\":8080\", nil) }","title":"Static"},{"location":"golang-para-web/#handler","text":"- Handlers son cualquier struct que tiene un metodo ServeHTTP(w http.ResponseWriter, r *http.Request) con dos parametros: una interface HTTPResponseWriter y un puntero a una Request struct. - Handler functions son funciones que se comportan como handlers. Tienen la misma firma que el metodo ServeHTTP y se utiizan para procesar peticiones (Requests) - Handlers y handler functions se pueden encadenar para permitir el procesado en partes de peticiones mediante la separacion de asuntos. - Multiplexers(routers) tambien son handlers. ServeMux es un router de peticiones HTTP. Acepta peticiones HTTP y las redirige al handler adecuado segun la URL de la peticion. DefaultServeMux es una instancia de ServeMux que se usa como router por defecto Handler // multi handler and chain handler package main import ( \"fmt\" \"net/http\" ) type helloHandler struct{} func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"Hello!\") } type worldHandler struct{} func (h *worldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"World!\") } func log(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ fmt.Printf(\"Handler called - %T\\n\", h) h.ServeHTTP(w, r) }) } func protect(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ // some code to make sure the user is authorized h.ServeHTTP(w, r) }) } func main() { hello := helloHandler{} world := worldHandler{} server := http.Server{ Addr: \"127.0.0.1:8080\", } http.Handle(\"/hello\", protect(log(&hello))) http.Handle(\"/world\", &world) server.ListenAndServe() } HandleFunc package main import ( \"fmt\" \"net/http\" \"reflect\" \"runtime\" ) func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"Hello!\") } func world(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"World!\") } func log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name() fmt.Println(\"Handler function called - \" + name) h(w, r) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/hello\", log(hello)) http.HandleFunc(\"/world\", world) server.ListenAndServe() }","title":"Handler"},{"location":"golang-para-web/#request","text":"URL https://golang.org/src/net/url/url.go type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string RawPath string // encoded path hint ForceQuery bool // append a query ('?') even if RawQuery is empty RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } algunos metodos // EscapedPath returns the escaped form of u.Path. func (u *URL) EscapedPath() string {} // IsAbs reports whether the URL is absolute. func (u *URL) IsAbs() bool {} // Query parses RawQuery and returns the corresponding values. func (u *URL) Query() Values {} type Values map[string][]string Headers type Header func (h Header) Add(key, value string) func (h Header) Del(key string) func (h Header) Get(key string) string func (h Header) Set(key, value string) func (h Header) Write(w io.Writer) error func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error func headers(w http.ResponseWriter, r *http.Request) { h := r.Header // h := r.Header[\"Accept-Encoding\"] // devuelve un map de strings // h := r.Header.Get(\"Accept-Encoding\") // devuelve string fmt.Fprintln(w, h) } http.HandleFunc(\"/headers\", headers) Body func body(w http.ResponseWriter, r *http.Request) { len := r.ContentLength body := make([]byte, len) r.Body.Read(body) fmt.Fprintln(w, string(body)) } http.HandleFunc(\"/body\", body)","title":"Request"},{"location":"golang-para-web/#responsewriter","text":"La interface ResponseWriter tiene tres metodos: - Write - coge un []bytes y lo escribe en el body de la respuesta HTTP. Si la cabecera no especifica content-type usa los los primeros 512 bytes de datos para detectar el tipo de contenido - WriteHeader - envia un numero entero que representa el codigo de estado de la respuesta HTTP. Despues de usar este metodo no se puede escribir ni modificar nada en la cabecera. Si no se use este metodo por defecto cuando se llama a Write se envia el codigo 200 OK Es muy util para enviar codigos de errores - Header - devuelve un map de campos de la cabecera que se pueden modificar y que seran enviados en la respuesta al cliente type post struct { User string Langs []string } func writeExample(w http.ResponseWriter, r *http.Request) { str := ` Write Example

        Hello World

        ` w.Write([]byte(str)) } func writeHeaderExample(w http.ResponseWriter, r *http.Request) { w.WriteHeader(501) fmt.Fprintln(w, \"Not implemented yet\") } func headerExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Location\", \"https://jolav.github.io\") w.WriteHeader(302) } func jsonExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"application/json\") post := &post{ User: \"jolav\", Langs: []string{\"Go\", \"HTML\", \"Javascript\"}, } json, _ := json.Marshal(post) w.Write(json) } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/write\", writeExample) http.HandleFunc(\"/writeheader\", writeHeaderExample) http.HandleFunc(\"/redirect\", headerExample) http.HandleFunc(\"/json\", jsonExample) server.ListenAndServe() }","title":"ResponseWriter"},{"location":"golang-para-web/#middleware","text":"type Middleware []http.Handler // Adds a handler to the middleware func (m *Middleware) Add(handler http.Handler) { *m = append(*m, handler) } func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http. \u27a5Request) { // Process the middleware }","title":"Middleware"},{"location":"golang-para-web/#cookies","text":"https://golang.org/src/net/http/cookie.go type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } Si no se usa el campo Expires la cookie es de sesion o temporal y se eliminan del navegador cuando este se cierra. De lo contrario la cookie es persistente y dura hasta que expire o se elimine. Usar MaxAge en lugar de Expires que esta deprecada package main import ( \"encoding/base64\" \"fmt\" \"net/http\" \"time\" ) func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: \"first cookie\", Value: \"Valor de la primera galleta\", HttpOnly: true, } c2 := http.Cookie{ Name: \"second cookie\", Value: \"Valor de la segunda galleta\", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) } func getCookie(w http.ResponseWriter, r *http.Request) { c1, err := r.Cookie(\"first cookie\") if err != nil { fmt.Fprintln(w, \"Cannot get the first cookie\") } cs := r.Cookies() fmt.Fprintln(w, c1) fmt.Fprintln(w, cs) } func setMessage(w http.ResponseWriter, r *http.Request) { msg := []byte(\"Hello World!\") c := http.Cookie{ Name: \"flash\", Value: base64.URLEncoding.EncodeToString(msg), } http.SetCookie(w, &c) } func showMessage(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie(\"flash\") if err != nil { if err == http.ErrNoCookie { fmt.Fprintln(w, \"No message found\") } } else { rc := http.Cookie{ Name: \"flash\", MaxAge: -1, Expires: time.Unix(1, 0), } http.SetCookie(w, &rc) val, _ := base64.URLEncoding.DecodeString(c.Value) fmt.Fprintln(w, string(val)) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/setCookie\", setCookie) http.HandleFunc(\"/getCookie\", getCookie) http.HandleFunc(\"/setMessage\", setMessage) http.HandleFunc(\"/showMessage\", showMessage) server.ListenAndServe() }","title":"Cookies"},{"location":"golang-para-web/#sessions","text":"","title":"Sessions"},{"location":"golang-para-web/#forms","text":"1\u00ba - Parseamos la peticion con ParseForm o ParseMultipartForm 2\u00ba - Accedemos al formulario // formulario para process1
        // formulario para process2 y process3
        package main import ( \"fmt\" \"io/ioutil\" \"net/http\" ) func process1(w http.ResponseWriter, r *http.Request) { r.ParseForm() fmt.Fprintln(w, r.Form[\"campo\"][0]) fmt.Prinltln(w, r.Form.Get(\"campo\")) // fmt.Fprintln(w, r.PostForm) } func process2(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile(\"uploaded\") if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func process3(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(1024) fileHeader := r.MultipartForm.File[\"uploaded\"][0] file, err := fileHeader.Open() if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/process1\", process1) http.HandleFunc(\"/process2\", process2) http.HandleFunc(\"/process3\", process3) server.ListenAndServe() }","title":"Forms"},{"location":"golang-para-web/#cliente-http","text":"type Client func (c *Client) Do(req *Request) (*Response, error) func (c *Client) Get(url string) (resp *Response, err error) func (c *Client) Head(url string) (resp *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) Ejemplo Hacer peticiones get Poner en el main o donde sea para asegurarse que tiene un tiempo maximo de espera y no se queda colgado esperando hasta el infinito (que es el valor por defecto) https://reddit.com/r/golang/comments/45mzie/dont_use_gos_default_http_client/ http.DefaultClient.Timeout = 10 * time.Second func getHttpRequest() { url := \"https://codetabs.com/tools/geoip/geoip.html\" resp, err := http.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&geo) if err != nil { panic(err) } aux.SendDataToClient(w, r, geo) }","title":"Cliente HTTP"},{"location":"golang-para-web/#servemux","text":"func mainNormal() { // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) http.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) http.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) http.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) http.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) http.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) // any /voting/* will redirect to voting.Voting http.HandleFunc(\"/voting/\", voting.Router) // any /pintelest/* will redirect to voting.Voting http.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", } server.ListenAndServe() } func mainMux() { mux := http.NewServeMux() // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) mux.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) mux.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) mux.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) mux.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) mux.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) mux.HandleFunc(\"/voting/\", voting.Router) //mux.HandleFunc(\"/voting/p/\", nodePintelest) // any /pintelest/* will redirect to nodePintelest mux.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", Handler: mux, } server.ListenAndServe() } // http://codepodu.com/subdomains-with-golang/ type Subdomains map[string]http.Handler func (subdomains Subdomains) ServeHTTP(w http.ResponseWriter, r *http.Request) { domainParts := strings.Split(r.Host, \".\") if mux := subdomains[domainParts[0]]; mux != nil { // Let the appropriate mux serve the request mux.ServeHTTP(w, r) } else { // Handle 404 http.Error(w, \"Not found\", 404) } } type Mux struct { http.Handler } func (mux Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) } func adminHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerOne , Hello, %q\", r.URL.Path[1:]) } func adminHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerOne , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func main() { adminMux := http.NewServeMux() adminMux.HandleFunc(\"/admin/pathone\", adminHandlerOne) adminMux.HandleFunc(\"/admin/pathtwo\", adminHandlerTwo) analyticsMux := http.NewServeMux() analyticsMux.HandleFunc(\"/analytics/pathone\", analyticsHandlerOne) analyticsMux.HandleFunc(\"/analytics/pathtwo\", analyticsHandlerTwo) subdomains := make(Subdomains) subdomains[\"admin\"] = adminMux subdomains[\"analytics\"] = analyticsMux http.ListenAndServe(\":8080\", subdomains) }","title":"ServeMux"},{"location":"golang-para-web/#htmltemplate","text":"import html/template Para usarlo hay que importar el paquete html/template crear la plantilla t, _ := template.ParseFiles(\"index.html\") asignar valor a variables de plantilla template_value := \"Hola\" servir la pagina t.Execute(w, template_values) index.html Hello World Hello {{ . }} pagina.go package main import ( \"html/template\" \"net/http\" ) func handler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles(\"index.html\") name := \"World\" t.Execute(w, name) } func main() { http.HandleFunc(\"/\", handler) http.ListenAndServe(\":8080\", nil) }","title":"HTML/TEMPLATE"},{"location":"golang-para-web/#fields","text":"{{}} cualquier cosa a ser renderizada debe ir entre dobles parentesis {{.}} abreviatura para el objeto actual {{ .FieldName}} campo FieldName del objecto actual Arrays and slices type Friend struct { Fname string } type Person struct { UserName string Emails []string Friends []*Friend } func main() { f1 := Friend{Fname: \"minux.ma\"} f2 := Friend{Fname: \"xushiwei\"} t := template.New(\"fieldname example\") t, _ = t.Parse(`hello {{.UserName}}! {{range .Emails}} an email {{.}} {{end}} {{with .Friends}} {{range .}} my friend name is {{.Fname}} {{end}} {{end}} `) p := Person{UserName: \"Astaxie\", Emails: []string{\"astaxie@beego.me\", \"astaxie@gmail.com\"}, Friends: []*Friend{&f1, &f2}} t.Execute(os.Stdout, p) } Arrays and slices index const tmpl = ` {{range $index, $link := .}} {{$index}}: {{$link.Name}} {{end}} ` type Link struct { Name string Href string } func main() { // arrays var la [2]Link la[0] = Link{\"Google\", \"https://www.google.com/\"} la[1] = Link{\"Facebook\", \"https://www.facebook.com/\"} t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, la) // slices var ls []Link ls = append(ls, Link{\"Google\", \"https://www.google.com/\"}) ls = append(ls, Link{\"Facebook\", \"https://www.facebook.com/\"}) t.Execute(os.Stdout, ls) } Maps const tmpl = ` {{range $name, $href := .}} {{$name}} {{end}} ` func main() { // map var m = map[string]string{ \"Google\": \"https://www.google.com/\", \"Facebook\": \"https://www.facebook.com/\", } t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, m) }","title":"Fields"},{"location":"golang-para-web/#conditions","text":"{{if}} {{else}} : Solo para valores booleanos, no hace comparaciones {{if ``}} Will not print. {{end}} {{if `anything`}} Will print. {{end}} {{if `anything`}} Print IF part. {{else}} Print ELSE part. {{end}}","title":"Conditions"},{"location":"golang-para-web/#pipelines","text":"{{ . | html}} Por ejemplo usamos esto para coger el objto actual '.' y aplicarle escape a HTML al objeto","title":"Pipelines"},{"location":"golang-para-web/#variables","text":"Pasar variables a templates // usando anonymous structs var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") templates.ExecuteTemplate(w, \"page.html\", struct { PageTitle string Message string User string }{\"Template example: struct\", \"Hello\", \"World\"}) } // usando Maps var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") m := make(map[string]interface{}) m[\"PageTitle\"] = \"Template example: map\" m[\"Message\"] = \"Hello\" m[\"User\"] = \"World\" templates.ExecuteTemplate(w, \"page.html\", m) } // mapa m := map[string]interface{}{ \"imgs\": imgs, // {{range .imgs.Image}}{{.}}{{end}} \"user\": p, //{{.user.Name}} } // struct , Images []Image type Data struct { I Images P Profile } var d Data d.I = imgs // {{range .I.Image}}{{.}}{{end}} d.P = p // {{.P.Name}}*/ t.Execute(w, &m)","title":"Variables"},{"location":"golang-para-web/#funciones","text":"","title":"Funciones"},{"location":"golang-para-web/#predefinidas","text":"Por ejemplo print equivale a fmt.Sprintf func main() { texto := \"{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}} {{end}}!\\n\" t := template.New(\"test\") t = template.Must(t.Parse(texto)) t.Execute(os.Stdout, nil) // Resultado -> hello Mary!","title":"Predefinidas"},{"location":"golang-para-web/#de-diseno","text":"const tmpl = ` hello {{gettext .}} hello {{. | gettext}} ` var funcMap = template.FuncMap{ \"gettext\": gettext, } func gettext(s string) string { if s == \"world\" { return \"otraCosa\" } return s } func main() { t, _ := template.New(\"foo\").Funcs(funcMap).Parse(tmpl) s := \"world\" t.Execute(os.Stdout, s) }","title":"De Dise\u00f1o"},{"location":"golang-para-web/#must","text":"Es una funcion del paquete template para validar plantillas","title":"Must"},{"location":"golang-para-web/#nested-templates","text":"Se puede declarar una plantilla: {{ define \"sub-plantilla\"}} contenido que sea {{ end}} Luego esa plantilla se inserta {{ template \"sub-plantilla\" }} base.html {{define \"base\"}} {{template \"title\" .}} {{template \"content\" .}} {{end}} index.html {{template \"base\" .}} {{define \"title\"}}my title{{end}} {{define \"content\"}}
        hello {{.}}
        {{end}} nestedTemplates.go func main() { // cannot put base.html before index.html will give empty output // t, _ := template.ParseFiles(\"base.html\", \"index.html\") t, _ := template.ParseFiles(\"index.html\", \"base.html\") name := \"world\" t.Execute(os.Stdout, name) }","title":"Nested templates"},{"location":"golang-para-web/#pasar-vars-a-js","text":"Pasar variables golang a cliente js // voting.go func guest(w http.ResponseWriter, r *http.Request) { var data aPoll data = aPoll{Question: \"Texto de la cuestion\"} tmpl[\"guest.html\"].ExecuteTemplate(w, \"guest.html\", data) } var voting = (function () { function init () { console.log(\"Data from golang\", golang); } return { init: init }; }());","title":"Pasar vars a js"},{"location":"golang-para-web/#neturl","text":"","title":"NET/URL"},{"location":"golang-para-web/#anadir-parametros-a-url","text":"// sobre una URL existente values := r.URL.Query() values.Add(\"nombreNuevoParamatro\", valor) values.Get(\"nombreDelValor\", valor) r.URL.RawQuery = values.Encode() fmt.Println(r.URL.String()) fmt.Println(values[\"nombreNuevoParametro\"]) // construyendo una URL urlData, err := url.Parse(\"https://apisquesea.com/custom/v1?q=\") params := url.Values{} params.Add(\"q\", r.URL.Query().Get(\"q\")) params.Add(\"cx\", c.APIImage.CseID) params.Add(\"key\", c.APIImage.Key) params.Add(\"num\", r.URL.Query().Get(\"num\")) params.Add(\"offset\", r.URL.Query().Get(\"offset\")) urlData.RawQuery = params.Encode() URL parsing","title":"A\u00f1adir parametros a URL"},{"location":"golang-para-web/#utilidades","text":"","title":"UTILIDADES"},{"location":"golang-para-web/#fresh","text":"https://github.com/pilu/fresh - Especie de nodemon para golang. archivo de configuracion que se ejecuta con fresh -c ruta/al/archivo root: . tmp_path: ./tmp build_name: runner-build build_log: runner-build-errors.log valid_ext: .go, .tpl, .tmpl, .html, .css, .js ignored: assets, tmp, pintelest build_delay: 600 colors: 1 log_color_main: cyan log_color_build: yellow log_color_runner: green log_color_watcher: magenta log_color_app:","title":"fresh"},{"location":"golang-snippets/","text":"GOLANG SNIPPETS SEND/RECEIVE DATA SendJSONToClient import ( \"encoding/json\" \"log\" \"net/http\" ) // SendJSONToClient ... func SendJSONToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) } SendXMLToClient import ( \"encoding/xml\" \"log\" \"net/http\" ) // SendXMLToClient ... func SendXMLToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/xml\") var dataXML = []byte(``) dataXML, err := xml.Marshal(&d) if err != nil { log.Printf(\"ERROR Parsing into XML %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataXML) } SendErrorToClient import ( \"encoding/json\" \"log\" \"net/http\" ) // SendErrorToClient ... func SendErrorToClient(w http.ResponseWriter, d interface{}) { w.WriteHeader(http.StatusBadRequest) w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) } DoGetRequest import ( \"encoding/json\" \"io/ioutil\" \"log\" \"net/http\" \"time\" ) // DoGetRequest ... func DoGetRequest(w http.ResponseWriter, url string, d interface{}) { var netClient = &http.Client{ Timeout: time.Second * 10, } resp, err := netClient.Get(url) if err != nil { log.Fatal(err) } if resp.StatusCode != 200 { log.Fatal(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // body is a string, for use we must Unmarshal over a struct err = json.Unmarshal(body, &d) if err != nil { log.Fatalln(err) } } DoGetConcurrentRequest import ( \"encoding/json\" \"fmt\" \"io/ioutil\" \"log\" \"net/http\" ) func fillDefaultStocks(links []string) { ch := make(chan []byte) for _, link := range links { go doGetConcurrentRequest(link, ch) } for range links { json.Unmarshal(<-ch, &stocks) } } func doGetConcurrentRequest(url string, ch chan<- []byte) { resp, err := http.Get(url) if err != nil { msg := fmt.Sprintf(\"ERROR 1 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } if resp.StatusCode != 200 { msg := fmt.Sprintf(\"ERROR 2 Status Code %d\", resp.StatusCode) log.Printf(msg) ch <- []byte(msg) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { msg := fmt.Sprintf(\"ERROR 3 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } ch <- body } DoPostRequest func sendRequest(data []byte, a app) { server, _ := os.Hostname() server = strings.ToLower(server) contentType := \"application/x-www-form-urlencoded\" //; param=value\" host := \"https://\" + a.Conf.Host + a.Conf.PathToAPI var client = &http.Client{ Timeout: time.Second * 3, } params := url.Values{ //\"server\": {server}, \"test\": {a.Conf.Valid}, \"data\": {string(data)}, } params.Add(\"server\", server) query := bytes.NewBufferString(params.Encode()) resp, err := http.NewRequest(\"POST\", host, query) resp.Header.Add(\"Content-Type\", contentType) resp.Header.Add(\"Accept-Charset\", \"utf-8\") if err != nil { log.Fatal(\"Error preparing POST request => \", err) } r, err := client.Do(resp) if err != nil { log.Fatal(\"Error sending POST request => \", err) } if r.StatusCode != 200 { log.Fatal(\"Error received from server => \", r.Status, \" \", err) } } GetInterfacesTypes import \"fmt\" // GetInterfacesTypes ... func GetInterfacesTypes(f interface{}) { switch vf := f.(type) { case map[string]interface{}: //fmt.Println(\"is a map:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } case []interface{}: //fmt.Println(\"is an array:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) if k == 4 { fmt.Println(`ALELUYA==>`, vv) } default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } } } IsJSON import \"encoding/json\" // IsJSON ... func IsJSON(str string) bool { var js json.RawMessage return json.Unmarshal([]byte(str), &js) == nil } ERRORCHECK Check import \"log\" // Check ... func Check(err error) { if err != nil { log.Fatal(err) } } FILES ReadFile import ( \"log\" \"os\" ) // ReadFile ... func ReadFile(filePath string) string { file, err := os.Open(filePath) defer file.Close() stat, err := file.Stat() if err != nil { log.Fatal(err) } bs := make([]byte, stat.Size()) _, err = file.Read(bs) if err != nil { log.Fatal(err) } data := string(bs) return data } ReadFileLineByLine import ( \"bufio\" \"fmt\" \"log\" \"os\" ) // ReadFileLineByLine ... func ReadFileLineByLine(filePath string) { file, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { log.Fatal(err) } } WriteFile import ( \"log\" \"os\" ) // WriteFile ... func WriteFile(filePath string, content string) { file, err := os.Create(filePath) if err != nil { log.Fatal(err) } defer file.Close() file.WriteString(content) } LoadJSONfromFileDecoder import ( \"encoding/json\" \"log\" \"os\" ) // LoadJSONfromFileDecoder ... func LoadJSONfromFileDecoder(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() decoder := json.NewDecoder(file) err = decoder.Decode(&data) if err != nil { log.Fatalln(\"Cannot get configuration from file\", err) } } LoadJSONfromFileMarshall import ( \"encoding/json\" \"io/ioutil\" \"log\" \"os\" ) // LoadJSONfromFileMarshall ... func LoadJSONfromFileMarshall(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() body, err := ioutil.ReadAll(file) // get file content if err != nil { log.Fatalln(err) } err = json.Unmarshal(body, &data) if err != nil { log.Fatalln(err) } } WriteJSONtoFile import ( \"encoding/json\" \"os\" ) // WriteJSONtoFile ... func WriteJSONtoFile(filePath string, d interface{}) { f, err := os.Create(filePath) if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&d) } DownloadFile import ( \"io\" \"net/http\" \"os\" ) // DownloadFile ... func DownloadFile(filePath string, url string) (err error) { // Create the file out, err := os.Create(filePath) if err != nil { return err } defer out.Close() // Get the data resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil } SendFileFromServerToClient import ( \"fmt\" \"io\" \"net\" \"net/http\" \"time\" ) func Index(w http.ResponseWriter, r *http.Request) { url := \"http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png\" timeout := time.Duration(5) * time.Second transport := &http.Transport{ ResponseHeaderTimeout: timeout, Dial: func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) }, DisableKeepAlives: true, } client := &http.Client{ Transport: transport, } resp, err := client.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() //copy the relevant headers. If you want to preserve the downloaded // file name, extract it with go's url parser. w.Header().Set(\"Content-Disposition\", \"attachment; filename=Wiki.png\") w.Header().Set(\"Content-Type\", r.Header.Get(\"Content-Type\")) w.Header().Set(\"Content-Length\", r.Header.Get(\"Content-Length\")) //stream the body to the client without fully loading it into memory io.Copy(w, resp.Body) } func main() { http.HandleFunc(\"/\", Index) err := http.ListenAndServe(\":8000\", nil) if err != nil { fmt.Println(err) } } ParseCSVFile // file.csv \"AAPL\",\"Apple Inc\",\"4.10%\" \"AMZN\",\"Amazon.com Inc\",\"3.49%\" \"MSFT\",\"Microsoft Corp\",\"3.23%\" \"GOOGL\",\"Alphabet Inc\",\"3.09%\" import ( \"bufio\" \"encoding/csv\" \"encoding/json\" \"fmt\" \"io\" \"os\" ) type stock struct { Symbol string `json:\"symbol\"` } func main() { csvFile, _ := os.Open(\"sp.csv\") reader := csv.NewReader(bufio.NewReader(csvFile)) var stocks []stock for { line, error := reader.Read() if error == io.EOF { break } aux := stock{ Symbol: line[0], } stocks = append(stocks, aux) } //stocksJSON, _ := json.Marshal(stocks) //fmt.Println(string(stocksJSON)) f, err := os.Create(\"spList.json\") if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&stocks) fmt.Println(`END`) } // result [ { \"symbol\": \"AAPL\" }, { \"symbol\": \"AMZN\" }, { \"symbol\": \"MSFT\" }, { \"symbol\": \"GOOGL\" } ] HTTP SERVER Lectura Request Handling in Go type Handler interface { ServeHttp( ResponseWriter, *Request ) } Wrapper Es muy sencillo pero luego complica para testearlo mux.HandleFunc(\"/path\", func(w http.ResponseWriter, r *http.Request) { nombreFuncion(w, r, loQueQueramosPasar) }) Handle + HandleFunc package main import ( \"fmt\" \"net/http\" \"time\" ) func timeHandler1(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(time.RFC1123) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } func timeHandler2(format string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) }) } /* lo mismo pero con conversion implicita al tipo HandlerFunc func timeHandler2(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } } */ func hiHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { mux := http.NewServeMux() // Creamos un closure con las variables que queremos usar th2 := timeHandler2(time.RFC3339) mux.HandleFunc(\"/time/1\", timeHandler1) mux.Handle(\"/time/2\", th2) mux.HandleFunc(\"/hello\", hiHandler) //http.HandleFunc(\"/time/1\", timeHandler1) //http.Handle(\"/time/2\", th2) //http.HandleFunc(\"/hello\", hiHandler) http.ListenAndServe(\":3000\", mux /*nil*/) } Handler type specificHandler struct { Thing string } func(h *specificHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) { w.Write(h.Thing) } func main() { http.Handle(\"/something\", &specificHandler{Thing: \"Hello world!\"}) http.ListenAndServe(\":8080\", nil) } package main import ( \"fmt\" \"net/http\" \"time\" ) type timeHandler struct { format string } func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(th.format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } type hiHandler struct{} func (ti *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { /mux := http.NewServeMux() th1 := &timeHandler{format: time.RFC1123} th2 := &timeHandler{format: time.RFC3339} hi := &hiHandler{} mux.Handle(\"/time/1\", th1) mux.Handle(\"/time/2\", th2) mux.Handle(\"/hello\", hi) //http.Handle(\"/time/1\", th1) //http.Handle(\"/time/2\", th2) //http.Handle(\"/hello\", hi) http.ListenAndServe(\":3000\", /*nil*/ mux) } Ejemplo Completo package main import ( \"errors\" \"fmt\" \"log\" \"net/http\" \"os\" \"time\" _ \"github.com/go-sql-driver/mysql\" ) type app struct { Config struct { Mode string `json:\"mode\"` Port int `json:\"port\"` Valid string `json:\"valid\"` ErrorsLogFile string `json:\"errorsLogFile\"` HitsLogFile string `json:\"hitsLogFile\"` } `json:\"config\"` Mysql struct { User string `json:\"user\"` Password string `json:\"password\"` DB string `json:\"db\"` Host string `json:\"host\"` Port int `json:\"port\"` TableBW string `json:\"tableBw\"` TableHits string `json:\"tableHits\"` } } type requestError struct { Error error `json:\"-\"` Message string `json:\"message\"` StatusCode int `json:\"-\"` } func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != a.Config.Valid { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } updateBw(w, r, a) } func main() { var a app loadConfigJSON(&a) checkMode(&a) // Custom Log File if a.Config.Mode == \"production\" { var f = a.Config.ErrorsLogFile mylog, err := os.OpenFile(f, os.O_WRONLY|os.O_CREATE|os.O_APPEND , 0644) if err != nil { log.Printf(\"ERROR opening log file %s\\n\", err) } defer mylog.Close() // defer must be in main log.SetOutput(mylog) } mux := http.NewServeMux() mux.Handle(\"/savebw/\", &a) mux.Handle(\"/saveHits/\", checkValid( func(w http.ResponseWriter, r *http.Request) { updateHits(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/get/\", checkValid( func(w http.ResponseWriter, r *http.Request) { getStats(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/\", badRequest) server := http.Server{ Addr: fmt.Sprintf(\"localhost:%d\", a.Config.Port), Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, MaxHeaderBytes: 1 << 20, } log.Printf(\"Server up listening %s in mode %s\", server.Addr , a.Config.Mode) server.ListenAndServe() } func checkValid(next http.HandlerFunc, test string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != test { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } next.ServeHTTP(w, r) } } func badRequest(w http.ResponseWriter, r *http.Request) { re := &requestError{ Error: errors.New(\"Unexistent Endpoint\"), Message: \"Bad Request\", StatusCode: 400, } sendErrorToClient(w, re) } MIDDLEWARES RateLimit import \"net/http\" // ExceedLimit ... func ExceedLimit(ip string) bool { // ToDO return false } // RateLimit ... func RateLimit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if ExceedLimit(GetIP(r)) { http.Error(w, \"Too many requests\", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } NETWORK GetIP import ( \"net\" \"net/http\" ) // GetIP returns string with IP func GetIP(r *http.Request) string { ip := r.Header.Get(\"X-Forwarded-For\") if len(ip) > 0 { return ip } ip, _, _ = net.SplitHostPort(r.RemoteAddr) return ip } IsValidURL import \"net/url\" // IsValidURL ... func IsValidURL(rawurl string) bool { _, err := url.ParseRequestURI(rawurl) if err != nil { return false } return true } ExistsURL import \"net/http\" func ExistsURL(myurl string) bool { resp, err := http.Head(myurl) if err != nil { return false } if resp.StatusCode != http.StatusOK { return false } return true } GetLanguage import ( \"net/http\" \"strings\" ) // GetLanguage ... func GetLanguage(r *http.Request) string { lang := r.Header.Get(\"Accept-Language\") if lang != \"\" { // curl request doesnt have Accept-Language lang = lang[0:strings.Index(lang, \",\")] } return lang } RemoveProtocolFromURL // RemoveProtocolFromURL ... func RemoveProtocolFromURL(url string) string { if strings.HasPrefix(url, \"https://\") { return url[8:] } if strings.HasPrefix(url, \"https:/\") { return url[7:] } if strings.HasPrefix(url, \"http://\") { return url[7:] } if strings.HasPrefix(url, \"http:/\") { return url[6:] } return url } RemoveProtocolAndWWWFromURL // RemoveProtocolAndWWWFromURL ... func RemoveProtocolAndWWWFromURL(url string) string { if strings.HasPrefix(url, \"https://www.\") { return url[12:] } if strings.HasPrefix(url, \"https:/www.\") { return url[11:] } if strings.HasPrefix(url, \"http://www.\") { return url[11:] } if strings.HasPrefix(url, \"http:/www.\") { return url[10:] } return RemoveProtocolFromURL(url) } NUMBERS GetRandomInt import ( \"math/rand\" \"time\" ) // GetRandomInt [min, max] both included func GetRandomInt(min, max int) int { r := rand.New(rand.NewSource(time.Now().UnixNano())) //rand.Seed(time.Now().UnixNano()) // return rand.Intn(max-min+1) + min return r.Intn(max-min+1) + min } GetRandomFloat64 import ( \"math/rand\" \"time\" ) // GetRandomFloat64 [min, max] both included func GetRandomFloat64(min, max float64) float64 { rand.Seed(time.Now().UnixNano()) return (rand.Float64() * (max - min)) + (min) } ToFixedFloat64 import \"math\" // ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat64(untruncated float64, precision int) float64 { coef := math.Pow10(precision) truncated := float64(int(untruncated*coef)) / coef return truncated } ToFixedFloat32 import \"math\" // ToFixedFloat32 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat32(untruncated float32, precision int) float32 { coef := float32(math.Pow10(precision)) truncated := float32(int(untruncated*coef)) / coef return truncated } RoundFloat64 // RoundFloat64 -> rounds float64 into integer func RoundFloat64(num float64) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) } RoundFloat32 // RoundFloat32 -> rounds float32 into integer func RoundFloat32(num float32) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) } ReverseSliceInt // ReverseSliceInt [0,1,2,3,4,5] ==> [5,4,3,2,1,0] func ReverseSliceInt(reverse []int) []int { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse } TransposeMatrixInt // TransposeMatrixInt rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixInt(matrix [][]int) [][]int { result := make([][]int, len(matrix[0])) for i := range result { result[i] = make([]int, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result } SliceContainsInt // SliceContainsInt ... returns true/false func SliceContainsInt(num int, slice []int) bool { for _, v := range slice { if v == num { return true } } return false } ArabicToRomanNumbers import \"math\" // ArabicToRomanNumbers converts arabic int to roman numeral (string) func ArabicToRomanNumbers(n int) string { var rom string hundreds := []string{ \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\"} tens := []string{ \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\"} units := []string{ \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\"} t := int(math.Floor(float64(n / 1000))) h := int(math.Floor(float64(n % 1000 / 100))) d := int(math.Floor(float64(n % 100 / 10))) u := int(math.Floor(float64(n % 10))) for i := 0; i < t; i++ { rom += \"M\" } if h > 0 { rom += hundreds[h-1] } if d > 0 { rom += tens[d-1] } if u > 0 { rom += units[u-1] } return rom } STRINGS RemoveAllWhitespaces import \"strings\" // RemoveAllWhitespaces ... func RemoveAllWhitespaces(str string) string { return strings.Replace(str, \" \", \"\", -1) } ReplaceAllWhitespacesByChar import \"strings\" // ReplaceAllWhitespacesByChar ... func ReplaceAllWhitespacesByChar(str string, otherChar string) string { return strings.Replace(str, \" \", otherChar, -1) } ReverseSliceString // ReverseSliceString [\"H\",\"O\",\"L\",\"A\"] ==> [\"A\",\"L\",\"O\",\"H\"] func ReverseSliceString(reverse []string) []string { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse } TransposeMatrixString // TransposeMatrixString rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixString(matrix [][]string) [][]string { result := make([][]string, len(matrix[0])) for i := range result { result[i] = make([]string, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result } SliceContainsString // SliceContainsString ... returns true/false func SliceContainsString(str string, slice []string) bool { for _, v := range slice { if v == str { return true } } return false } FixBadEncodedStrings // FixBadEncodedStrings ... func FixBadEncodedStrings(bad string) string { //bad := \"Kl\u00c3\u00a4der\" var good []byte for _, c := range bad { good = append(good, byte(c)) } //fmt.Println(string(good)) return string(good) } OS execCommand import ( \"fmt\" \"os/exec\" ) func main() { command := []string{\"vnstat\", \"-i\", ifinterface, \"--json\"} ///fmt.Println(\"Command =>\", command) chunk, err := execCommand(command) if err != nil { log.Fatal(err) } //fmt.Println(`CHUNK =>`, string(chunk)) } func execCommand(args []string) (err error) { _, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { fmt.Println(err) return err } return err } func execCommand(args []string) (c []byte, err error) { c, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { return nil, err } return c, err } func execCommand(comm string) { _, err := exec.Command(\"sh\", \"-c\", comm).CombinedOutput() if err != nil { log.Fatal(err) } } TIME ParseStringToTime import \"time\" // ParseStringToTime ... func ParseStringToTime(start string) time.Time { layout1 := \"2006-01-02\" // Layout numbers? layout2 := \"2006-01-02T15:04:05\" t, err := time.Parse(layout1, start) if err != nil { t, err = time.Parse(layout2, start) } return t } GetTimestampFromDate import ( \"strconv\" \"strings\" \"time\" ) // GetTimestampFromDateString ...(yyyy-mm-dd) func GetTimestampFromDateString(date string) float64 { var t int64 params := strings.Split(date, \"-\") day, _ := strconv.Atoi(params[2]) month, _ := strconv.Atoi(params[1]) year, _ := strconv.Atoi(params[0]) auxT := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) t = int64(auxT.UnixNano() / int64(time.Millisecond)) return float64(t) } OnceADayTask import \"time\" func onceADayTask() { t := time.Now() n := time.Date(t.Year(),t.Month(),t.Day(),3,10,10,0,t.Location()) d := n.Sub(t) if d < 0 { n = n.Add(24 * time.Hour) d = n.Sub(t) } for { time.Sleep(d) d = 24 * time.Hour doSomeTask() } } SetInterval import ( \"fmt\" \"net/http\" \"time\" ) type updates []struct { Symbol string `json:\"symbol\"` Price float64 `json:\"price\"` } func initUpdateIntervals() { var u updates var w http.ResponseWriter ticker := time.NewTicker(time.Millisecond * 1000) go func() { for _ = range ticker.C { u = updates{} lib.MakeGetRequest(w, url, &u) for _, v := range u { if v.Symbol != \"\" { stocks[v.Symbol].PriceNow = v.Price } } t := time.Now() hour, min, sec := t.Clock() fmt.Println(`TICK`, hour, min, sec) if hour == 6 && min == 1 { if sec > 0 && sec < 6 { go dailyWork() } } } }() } ticker := time.NewTicker(2 * time.Second) quit := make(chan struct{}) go func() { for { select { case <-ticker.C: fmt.Println(\"Se ejecuta cada X * time.Second\") case <-quit: ticker.Stop() return } } }() func interval() { ticker := time.NewTicker(time.Millisecond * 2000) for _ = range ticker.C { fmt.Println(\"Hi Every 2 secs\") } } LOGS Custom Logs // main.go /////// Custom Error Log File + Custom Info Log File ///////// iLog := createCustomInfoLogFile2(a.Conf.InfoLogFile) mylog := createCustomErrorLogFile(a.Conf.ErrorsLogFile) defer mylog.Close() ////////////////////////////////////////////////////////////// // ya por donde queramos func createCustomErrorLogFile(f string) *os.File { mylog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Error log file %s\\n\", err) } log.SetOutput(mylog) return mylog } func createCustomInfoLogFile2(f string) *log.Logger { infoLog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Info log file %s\\n\", err) } var iLog *log.Logger iLog = log.New(infoLog, \"INFO :\\t\", log.Ldate|log.Ltime) return iLog } PrettyPrint Structs func prettyPrintStruct(s interface{}) { result, _ := json.MarshalIndent(s, \"\", \"\\t\") fmt.Print(string(result), \"\\n\") } FLAGS Binarios con versiones package main import ( \"flag\" \"fmt\" \"os\" ) var version = \"0.0.0\" var when = \"undefined\" func main() { checkFlags() fmt.Println(\"Continue...\") } func checkFlags() { versionFlag := flag.Bool(\"v\", false, \"Show current version and exit\") flag.Parse() switch { case *versionFlag: fmt.Printf(\"Version:\\t: %s\\n\", version) fmt.Printf(\"Date :\\t: %s\\n\", when) os.Exit(0) } } /* go build -ldflags=\" -X 'main.version=v0.2.0' -X 'main.when=$(date -u +%F_%T)'\" go build -ldflags=\"-X 'main.when=$(date -u +%F_%T)'\" luego podemos hacer ./binary -v */ ORGANIZACION DE CODIGO Compartir structs entre paquetes // main.go package main import ( s \"pruebas/secondarypkg\" \"time\" ) func main() { p := &s.Placeholder{ Name: \"FooBar\", Date: time.Now().String(), } s.Foo(p) } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func Foo(p *Placeholder) { fmt.Println(p.Date, p.Name) } // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func (p *Placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) *Placeholder { return &Placeholder{ Name: name, Date: date, } } Lo mismo usando interfaces // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type PlaceHolder interface { Foo() } type placeholder struct { Name string Date string } func (p *placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) PlaceHolder { return &placeholder{ Name: name, Date: date, } }","title":"Golang snippets"},{"location":"golang-snippets/#golang-snippets","text":"","title":"GOLANG SNIPPETS"},{"location":"golang-snippets/#sendreceive-data","text":"","title":"SEND/RECEIVE DATA"},{"location":"golang-snippets/#sendjsontoclient","text":"import ( \"encoding/json\" \"log\" \"net/http\" ) // SendJSONToClient ... func SendJSONToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) }","title":"SendJSONToClient"},{"location":"golang-snippets/#sendxmltoclient","text":"import ( \"encoding/xml\" \"log\" \"net/http\" ) // SendXMLToClient ... func SendXMLToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/xml\") var dataXML = []byte(``) dataXML, err := xml.Marshal(&d) if err != nil { log.Printf(\"ERROR Parsing into XML %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataXML) }","title":"SendXMLToClient"},{"location":"golang-snippets/#senderrortoclient","text":"import ( \"encoding/json\" \"log\" \"net/http\" ) // SendErrorToClient ... func SendErrorToClient(w http.ResponseWriter, d interface{}) { w.WriteHeader(http.StatusBadRequest) w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) }","title":"SendErrorToClient"},{"location":"golang-snippets/#dogetrequest","text":"import ( \"encoding/json\" \"io/ioutil\" \"log\" \"net/http\" \"time\" ) // DoGetRequest ... func DoGetRequest(w http.ResponseWriter, url string, d interface{}) { var netClient = &http.Client{ Timeout: time.Second * 10, } resp, err := netClient.Get(url) if err != nil { log.Fatal(err) } if resp.StatusCode != 200 { log.Fatal(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // body is a string, for use we must Unmarshal over a struct err = json.Unmarshal(body, &d) if err != nil { log.Fatalln(err) } }","title":"DoGetRequest"},{"location":"golang-snippets/#dogetconcurrentrequest","text":"import ( \"encoding/json\" \"fmt\" \"io/ioutil\" \"log\" \"net/http\" ) func fillDefaultStocks(links []string) { ch := make(chan []byte) for _, link := range links { go doGetConcurrentRequest(link, ch) } for range links { json.Unmarshal(<-ch, &stocks) } } func doGetConcurrentRequest(url string, ch chan<- []byte) { resp, err := http.Get(url) if err != nil { msg := fmt.Sprintf(\"ERROR 1 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } if resp.StatusCode != 200 { msg := fmt.Sprintf(\"ERROR 2 Status Code %d\", resp.StatusCode) log.Printf(msg) ch <- []byte(msg) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { msg := fmt.Sprintf(\"ERROR 3 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } ch <- body }","title":"DoGetConcurrentRequest"},{"location":"golang-snippets/#dopostrequest","text":"func sendRequest(data []byte, a app) { server, _ := os.Hostname() server = strings.ToLower(server) contentType := \"application/x-www-form-urlencoded\" //; param=value\" host := \"https://\" + a.Conf.Host + a.Conf.PathToAPI var client = &http.Client{ Timeout: time.Second * 3, } params := url.Values{ //\"server\": {server}, \"test\": {a.Conf.Valid}, \"data\": {string(data)}, } params.Add(\"server\", server) query := bytes.NewBufferString(params.Encode()) resp, err := http.NewRequest(\"POST\", host, query) resp.Header.Add(\"Content-Type\", contentType) resp.Header.Add(\"Accept-Charset\", \"utf-8\") if err != nil { log.Fatal(\"Error preparing POST request => \", err) } r, err := client.Do(resp) if err != nil { log.Fatal(\"Error sending POST request => \", err) } if r.StatusCode != 200 { log.Fatal(\"Error received from server => \", r.Status, \" \", err) } }","title":"DoPostRequest"},{"location":"golang-snippets/#getinterfacestypes","text":"import \"fmt\" // GetInterfacesTypes ... func GetInterfacesTypes(f interface{}) { switch vf := f.(type) { case map[string]interface{}: //fmt.Println(\"is a map:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } case []interface{}: //fmt.Println(\"is an array:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) if k == 4 { fmt.Println(`ALELUYA==>`, vv) } default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } } }","title":"GetInterfacesTypes"},{"location":"golang-snippets/#isjson","text":"import \"encoding/json\" // IsJSON ... func IsJSON(str string) bool { var js json.RawMessage return json.Unmarshal([]byte(str), &js) == nil }","title":"IsJSON"},{"location":"golang-snippets/#errorcheck","text":"","title":"ERRORCHECK"},{"location":"golang-snippets/#check","text":"import \"log\" // Check ... func Check(err error) { if err != nil { log.Fatal(err) } }","title":"Check"},{"location":"golang-snippets/#files","text":"","title":"FILES"},{"location":"golang-snippets/#readfile","text":"import ( \"log\" \"os\" ) // ReadFile ... func ReadFile(filePath string) string { file, err := os.Open(filePath) defer file.Close() stat, err := file.Stat() if err != nil { log.Fatal(err) } bs := make([]byte, stat.Size()) _, err = file.Read(bs) if err != nil { log.Fatal(err) } data := string(bs) return data }","title":"ReadFile"},{"location":"golang-snippets/#readfilelinebyline","text":"import ( \"bufio\" \"fmt\" \"log\" \"os\" ) // ReadFileLineByLine ... func ReadFileLineByLine(filePath string) { file, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { log.Fatal(err) } }","title":"ReadFileLineByLine"},{"location":"golang-snippets/#writefile","text":"import ( \"log\" \"os\" ) // WriteFile ... func WriteFile(filePath string, content string) { file, err := os.Create(filePath) if err != nil { log.Fatal(err) } defer file.Close() file.WriteString(content) }","title":"WriteFile"},{"location":"golang-snippets/#loadjsonfromfiledecoder","text":"import ( \"encoding/json\" \"log\" \"os\" ) // LoadJSONfromFileDecoder ... func LoadJSONfromFileDecoder(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() decoder := json.NewDecoder(file) err = decoder.Decode(&data) if err != nil { log.Fatalln(\"Cannot get configuration from file\", err) } }","title":"LoadJSONfromFileDecoder"},{"location":"golang-snippets/#loadjsonfromfilemarshall","text":"import ( \"encoding/json\" \"io/ioutil\" \"log\" \"os\" ) // LoadJSONfromFileMarshall ... func LoadJSONfromFileMarshall(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() body, err := ioutil.ReadAll(file) // get file content if err != nil { log.Fatalln(err) } err = json.Unmarshal(body, &data) if err != nil { log.Fatalln(err) } }","title":"LoadJSONfromFileMarshall"},{"location":"golang-snippets/#writejsontofile","text":"import ( \"encoding/json\" \"os\" ) // WriteJSONtoFile ... func WriteJSONtoFile(filePath string, d interface{}) { f, err := os.Create(filePath) if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&d) }","title":"WriteJSONtoFile"},{"location":"golang-snippets/#downloadfile","text":"import ( \"io\" \"net/http\" \"os\" ) // DownloadFile ... func DownloadFile(filePath string, url string) (err error) { // Create the file out, err := os.Create(filePath) if err != nil { return err } defer out.Close() // Get the data resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil }","title":"DownloadFile"},{"location":"golang-snippets/#sendfilefromservertoclient","text":"import ( \"fmt\" \"io\" \"net\" \"net/http\" \"time\" ) func Index(w http.ResponseWriter, r *http.Request) { url := \"http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png\" timeout := time.Duration(5) * time.Second transport := &http.Transport{ ResponseHeaderTimeout: timeout, Dial: func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) }, DisableKeepAlives: true, } client := &http.Client{ Transport: transport, } resp, err := client.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() //copy the relevant headers. If you want to preserve the downloaded // file name, extract it with go's url parser. w.Header().Set(\"Content-Disposition\", \"attachment; filename=Wiki.png\") w.Header().Set(\"Content-Type\", r.Header.Get(\"Content-Type\")) w.Header().Set(\"Content-Length\", r.Header.Get(\"Content-Length\")) //stream the body to the client without fully loading it into memory io.Copy(w, resp.Body) } func main() { http.HandleFunc(\"/\", Index) err := http.ListenAndServe(\":8000\", nil) if err != nil { fmt.Println(err) } }","title":"SendFileFromServerToClient"},{"location":"golang-snippets/#parsecsvfile","text":"// file.csv \"AAPL\",\"Apple Inc\",\"4.10%\" \"AMZN\",\"Amazon.com Inc\",\"3.49%\" \"MSFT\",\"Microsoft Corp\",\"3.23%\" \"GOOGL\",\"Alphabet Inc\",\"3.09%\" import ( \"bufio\" \"encoding/csv\" \"encoding/json\" \"fmt\" \"io\" \"os\" ) type stock struct { Symbol string `json:\"symbol\"` } func main() { csvFile, _ := os.Open(\"sp.csv\") reader := csv.NewReader(bufio.NewReader(csvFile)) var stocks []stock for { line, error := reader.Read() if error == io.EOF { break } aux := stock{ Symbol: line[0], } stocks = append(stocks, aux) } //stocksJSON, _ := json.Marshal(stocks) //fmt.Println(string(stocksJSON)) f, err := os.Create(\"spList.json\") if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&stocks) fmt.Println(`END`) } // result [ { \"symbol\": \"AAPL\" }, { \"symbol\": \"AMZN\" }, { \"symbol\": \"MSFT\" }, { \"symbol\": \"GOOGL\" } ]","title":"ParseCSVFile"},{"location":"golang-snippets/#http-server","text":"Lectura Request Handling in Go type Handler interface { ServeHttp( ResponseWriter, *Request ) }","title":"HTTP SERVER"},{"location":"golang-snippets/#wrapper","text":"Es muy sencillo pero luego complica para testearlo mux.HandleFunc(\"/path\", func(w http.ResponseWriter, r *http.Request) { nombreFuncion(w, r, loQueQueramosPasar) })","title":"Wrapper"},{"location":"golang-snippets/#handle-handlefunc","text":"package main import ( \"fmt\" \"net/http\" \"time\" ) func timeHandler1(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(time.RFC1123) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } func timeHandler2(format string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) }) } /* lo mismo pero con conversion implicita al tipo HandlerFunc func timeHandler2(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } } */ func hiHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { mux := http.NewServeMux() // Creamos un closure con las variables que queremos usar th2 := timeHandler2(time.RFC3339) mux.HandleFunc(\"/time/1\", timeHandler1) mux.Handle(\"/time/2\", th2) mux.HandleFunc(\"/hello\", hiHandler) //http.HandleFunc(\"/time/1\", timeHandler1) //http.Handle(\"/time/2\", th2) //http.HandleFunc(\"/hello\", hiHandler) http.ListenAndServe(\":3000\", mux /*nil*/) }","title":"Handle + HandleFunc"},{"location":"golang-snippets/#handler","text":"type specificHandler struct { Thing string } func(h *specificHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) { w.Write(h.Thing) } func main() { http.Handle(\"/something\", &specificHandler{Thing: \"Hello world!\"}) http.ListenAndServe(\":8080\", nil) } package main import ( \"fmt\" \"net/http\" \"time\" ) type timeHandler struct { format string } func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(th.format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } type hiHandler struct{} func (ti *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { /mux := http.NewServeMux() th1 := &timeHandler{format: time.RFC1123} th2 := &timeHandler{format: time.RFC3339} hi := &hiHandler{} mux.Handle(\"/time/1\", th1) mux.Handle(\"/time/2\", th2) mux.Handle(\"/hello\", hi) //http.Handle(\"/time/1\", th1) //http.Handle(\"/time/2\", th2) //http.Handle(\"/hello\", hi) http.ListenAndServe(\":3000\", /*nil*/ mux) }","title":"Handler"},{"location":"golang-snippets/#ejemplo-completo","text":"package main import ( \"errors\" \"fmt\" \"log\" \"net/http\" \"os\" \"time\" _ \"github.com/go-sql-driver/mysql\" ) type app struct { Config struct { Mode string `json:\"mode\"` Port int `json:\"port\"` Valid string `json:\"valid\"` ErrorsLogFile string `json:\"errorsLogFile\"` HitsLogFile string `json:\"hitsLogFile\"` } `json:\"config\"` Mysql struct { User string `json:\"user\"` Password string `json:\"password\"` DB string `json:\"db\"` Host string `json:\"host\"` Port int `json:\"port\"` TableBW string `json:\"tableBw\"` TableHits string `json:\"tableHits\"` } } type requestError struct { Error error `json:\"-\"` Message string `json:\"message\"` StatusCode int `json:\"-\"` } func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != a.Config.Valid { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } updateBw(w, r, a) } func main() { var a app loadConfigJSON(&a) checkMode(&a) // Custom Log File if a.Config.Mode == \"production\" { var f = a.Config.ErrorsLogFile mylog, err := os.OpenFile(f, os.O_WRONLY|os.O_CREATE|os.O_APPEND , 0644) if err != nil { log.Printf(\"ERROR opening log file %s\\n\", err) } defer mylog.Close() // defer must be in main log.SetOutput(mylog) } mux := http.NewServeMux() mux.Handle(\"/savebw/\", &a) mux.Handle(\"/saveHits/\", checkValid( func(w http.ResponseWriter, r *http.Request) { updateHits(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/get/\", checkValid( func(w http.ResponseWriter, r *http.Request) { getStats(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/\", badRequest) server := http.Server{ Addr: fmt.Sprintf(\"localhost:%d\", a.Config.Port), Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, MaxHeaderBytes: 1 << 20, } log.Printf(\"Server up listening %s in mode %s\", server.Addr , a.Config.Mode) server.ListenAndServe() } func checkValid(next http.HandlerFunc, test string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != test { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } next.ServeHTTP(w, r) } } func badRequest(w http.ResponseWriter, r *http.Request) { re := &requestError{ Error: errors.New(\"Unexistent Endpoint\"), Message: \"Bad Request\", StatusCode: 400, } sendErrorToClient(w, re) }","title":"Ejemplo Completo"},{"location":"golang-snippets/#middlewares","text":"","title":"MIDDLEWARES"},{"location":"golang-snippets/#ratelimit","text":"import \"net/http\" // ExceedLimit ... func ExceedLimit(ip string) bool { // ToDO return false } // RateLimit ... func RateLimit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if ExceedLimit(GetIP(r)) { http.Error(w, \"Too many requests\", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) }","title":"RateLimit"},{"location":"golang-snippets/#network","text":"","title":"NETWORK"},{"location":"golang-snippets/#getip","text":"import ( \"net\" \"net/http\" ) // GetIP returns string with IP func GetIP(r *http.Request) string { ip := r.Header.Get(\"X-Forwarded-For\") if len(ip) > 0 { return ip } ip, _, _ = net.SplitHostPort(r.RemoteAddr) return ip }","title":"GetIP"},{"location":"golang-snippets/#isvalidurl","text":"import \"net/url\" // IsValidURL ... func IsValidURL(rawurl string) bool { _, err := url.ParseRequestURI(rawurl) if err != nil { return false } return true }","title":"IsValidURL"},{"location":"golang-snippets/#existsurl","text":"import \"net/http\" func ExistsURL(myurl string) bool { resp, err := http.Head(myurl) if err != nil { return false } if resp.StatusCode != http.StatusOK { return false } return true }","title":"ExistsURL"},{"location":"golang-snippets/#getlanguage","text":"import ( \"net/http\" \"strings\" ) // GetLanguage ... func GetLanguage(r *http.Request) string { lang := r.Header.Get(\"Accept-Language\") if lang != \"\" { // curl request doesnt have Accept-Language lang = lang[0:strings.Index(lang, \",\")] } return lang }","title":"GetLanguage"},{"location":"golang-snippets/#removeprotocolfromurl","text":"// RemoveProtocolFromURL ... func RemoveProtocolFromURL(url string) string { if strings.HasPrefix(url, \"https://\") { return url[8:] } if strings.HasPrefix(url, \"https:/\") { return url[7:] } if strings.HasPrefix(url, \"http://\") { return url[7:] } if strings.HasPrefix(url, \"http:/\") { return url[6:] } return url }","title":"RemoveProtocolFromURL"},{"location":"golang-snippets/#removeprotocolandwwwfromurl","text":"// RemoveProtocolAndWWWFromURL ... func RemoveProtocolAndWWWFromURL(url string) string { if strings.HasPrefix(url, \"https://www.\") { return url[12:] } if strings.HasPrefix(url, \"https:/www.\") { return url[11:] } if strings.HasPrefix(url, \"http://www.\") { return url[11:] } if strings.HasPrefix(url, \"http:/www.\") { return url[10:] } return RemoveProtocolFromURL(url) }","title":"RemoveProtocolAndWWWFromURL"},{"location":"golang-snippets/#numbers","text":"","title":"NUMBERS"},{"location":"golang-snippets/#getrandomint","text":"import ( \"math/rand\" \"time\" ) // GetRandomInt [min, max] both included func GetRandomInt(min, max int) int { r := rand.New(rand.NewSource(time.Now().UnixNano())) //rand.Seed(time.Now().UnixNano()) // return rand.Intn(max-min+1) + min return r.Intn(max-min+1) + min }","title":"GetRandomInt"},{"location":"golang-snippets/#getrandomfloat64","text":"import ( \"math/rand\" \"time\" ) // GetRandomFloat64 [min, max] both included func GetRandomFloat64(min, max float64) float64 { rand.Seed(time.Now().UnixNano()) return (rand.Float64() * (max - min)) + (min) }","title":"GetRandomFloat64"},{"location":"golang-snippets/#tofixedfloat64","text":"import \"math\" // ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat64(untruncated float64, precision int) float64 { coef := math.Pow10(precision) truncated := float64(int(untruncated*coef)) / coef return truncated }","title":"ToFixedFloat64"},{"location":"golang-snippets/#tofixedfloat32","text":"import \"math\" // ToFixedFloat32 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat32(untruncated float32, precision int) float32 { coef := float32(math.Pow10(precision)) truncated := float32(int(untruncated*coef)) / coef return truncated }","title":"ToFixedFloat32"},{"location":"golang-snippets/#roundfloat64","text":"// RoundFloat64 -> rounds float64 into integer func RoundFloat64(num float64) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) }","title":"RoundFloat64"},{"location":"golang-snippets/#roundfloat32","text":"// RoundFloat32 -> rounds float32 into integer func RoundFloat32(num float32) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) }","title":"RoundFloat32"},{"location":"golang-snippets/#reversesliceint","text":"// ReverseSliceInt [0,1,2,3,4,5] ==> [5,4,3,2,1,0] func ReverseSliceInt(reverse []int) []int { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse }","title":"ReverseSliceInt"},{"location":"golang-snippets/#transposematrixint","text":"// TransposeMatrixInt rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixInt(matrix [][]int) [][]int { result := make([][]int, len(matrix[0])) for i := range result { result[i] = make([]int, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result }","title":"TransposeMatrixInt"},{"location":"golang-snippets/#slicecontainsint","text":"// SliceContainsInt ... returns true/false func SliceContainsInt(num int, slice []int) bool { for _, v := range slice { if v == num { return true } } return false }","title":"SliceContainsInt"},{"location":"golang-snippets/#arabictoromannumbers","text":"import \"math\" // ArabicToRomanNumbers converts arabic int to roman numeral (string) func ArabicToRomanNumbers(n int) string { var rom string hundreds := []string{ \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\"} tens := []string{ \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\"} units := []string{ \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\"} t := int(math.Floor(float64(n / 1000))) h := int(math.Floor(float64(n % 1000 / 100))) d := int(math.Floor(float64(n % 100 / 10))) u := int(math.Floor(float64(n % 10))) for i := 0; i < t; i++ { rom += \"M\" } if h > 0 { rom += hundreds[h-1] } if d > 0 { rom += tens[d-1] } if u > 0 { rom += units[u-1] } return rom }","title":"ArabicToRomanNumbers"},{"location":"golang-snippets/#strings","text":"","title":"STRINGS"},{"location":"golang-snippets/#removeallwhitespaces","text":"import \"strings\" // RemoveAllWhitespaces ... func RemoveAllWhitespaces(str string) string { return strings.Replace(str, \" \", \"\", -1) }","title":"RemoveAllWhitespaces"},{"location":"golang-snippets/#replaceallwhitespacesbychar","text":"import \"strings\" // ReplaceAllWhitespacesByChar ... func ReplaceAllWhitespacesByChar(str string, otherChar string) string { return strings.Replace(str, \" \", otherChar, -1) }","title":"ReplaceAllWhitespacesByChar"},{"location":"golang-snippets/#reverseslicestring","text":"// ReverseSliceString [\"H\",\"O\",\"L\",\"A\"] ==> [\"A\",\"L\",\"O\",\"H\"] func ReverseSliceString(reverse []string) []string { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse }","title":"ReverseSliceString"},{"location":"golang-snippets/#transposematrixstring","text":"// TransposeMatrixString rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixString(matrix [][]string) [][]string { result := make([][]string, len(matrix[0])) for i := range result { result[i] = make([]string, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result }","title":"TransposeMatrixString"},{"location":"golang-snippets/#slicecontainsstring","text":"// SliceContainsString ... returns true/false func SliceContainsString(str string, slice []string) bool { for _, v := range slice { if v == str { return true } } return false }","title":"SliceContainsString"},{"location":"golang-snippets/#fixbadencodedstrings","text":"// FixBadEncodedStrings ... func FixBadEncodedStrings(bad string) string { //bad := \"Kl\u00c3\u00a4der\" var good []byte for _, c := range bad { good = append(good, byte(c)) } //fmt.Println(string(good)) return string(good) }","title":"FixBadEncodedStrings"},{"location":"golang-snippets/#os","text":"","title":"OS"},{"location":"golang-snippets/#execcommand","text":"import ( \"fmt\" \"os/exec\" ) func main() { command := []string{\"vnstat\", \"-i\", ifinterface, \"--json\"} ///fmt.Println(\"Command =>\", command) chunk, err := execCommand(command) if err != nil { log.Fatal(err) } //fmt.Println(`CHUNK =>`, string(chunk)) } func execCommand(args []string) (err error) { _, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { fmt.Println(err) return err } return err } func execCommand(args []string) (c []byte, err error) { c, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { return nil, err } return c, err } func execCommand(comm string) { _, err := exec.Command(\"sh\", \"-c\", comm).CombinedOutput() if err != nil { log.Fatal(err) } }","title":"execCommand"},{"location":"golang-snippets/#time","text":"","title":"TIME"},{"location":"golang-snippets/#parsestringtotime","text":"import \"time\" // ParseStringToTime ... func ParseStringToTime(start string) time.Time { layout1 := \"2006-01-02\" // Layout numbers? layout2 := \"2006-01-02T15:04:05\" t, err := time.Parse(layout1, start) if err != nil { t, err = time.Parse(layout2, start) } return t }","title":"ParseStringToTime"},{"location":"golang-snippets/#gettimestampfromdate","text":"import ( \"strconv\" \"strings\" \"time\" ) // GetTimestampFromDateString ...(yyyy-mm-dd) func GetTimestampFromDateString(date string) float64 { var t int64 params := strings.Split(date, \"-\") day, _ := strconv.Atoi(params[2]) month, _ := strconv.Atoi(params[1]) year, _ := strconv.Atoi(params[0]) auxT := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) t = int64(auxT.UnixNano() / int64(time.Millisecond)) return float64(t) }","title":"GetTimestampFromDate"},{"location":"golang-snippets/#onceadaytask","text":"import \"time\" func onceADayTask() { t := time.Now() n := time.Date(t.Year(),t.Month(),t.Day(),3,10,10,0,t.Location()) d := n.Sub(t) if d < 0 { n = n.Add(24 * time.Hour) d = n.Sub(t) } for { time.Sleep(d) d = 24 * time.Hour doSomeTask() } }","title":"OnceADayTask"},{"location":"golang-snippets/#setinterval","text":"import ( \"fmt\" \"net/http\" \"time\" ) type updates []struct { Symbol string `json:\"symbol\"` Price float64 `json:\"price\"` } func initUpdateIntervals() { var u updates var w http.ResponseWriter ticker := time.NewTicker(time.Millisecond * 1000) go func() { for _ = range ticker.C { u = updates{} lib.MakeGetRequest(w, url, &u) for _, v := range u { if v.Symbol != \"\" { stocks[v.Symbol].PriceNow = v.Price } } t := time.Now() hour, min, sec := t.Clock() fmt.Println(`TICK`, hour, min, sec) if hour == 6 && min == 1 { if sec > 0 && sec < 6 { go dailyWork() } } } }() } ticker := time.NewTicker(2 * time.Second) quit := make(chan struct{}) go func() { for { select { case <-ticker.C: fmt.Println(\"Se ejecuta cada X * time.Second\") case <-quit: ticker.Stop() return } } }() func interval() { ticker := time.NewTicker(time.Millisecond * 2000) for _ = range ticker.C { fmt.Println(\"Hi Every 2 secs\") } }","title":"SetInterval"},{"location":"golang-snippets/#logs","text":"","title":"LOGS"},{"location":"golang-snippets/#custom-logs","text":"// main.go /////// Custom Error Log File + Custom Info Log File ///////// iLog := createCustomInfoLogFile2(a.Conf.InfoLogFile) mylog := createCustomErrorLogFile(a.Conf.ErrorsLogFile) defer mylog.Close() ////////////////////////////////////////////////////////////// // ya por donde queramos func createCustomErrorLogFile(f string) *os.File { mylog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Error log file %s\\n\", err) } log.SetOutput(mylog) return mylog } func createCustomInfoLogFile2(f string) *log.Logger { infoLog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Info log file %s\\n\", err) } var iLog *log.Logger iLog = log.New(infoLog, \"INFO :\\t\", log.Ldate|log.Ltime) return iLog }","title":"Custom Logs"},{"location":"golang-snippets/#prettyprint-structs","text":"func prettyPrintStruct(s interface{}) { result, _ := json.MarshalIndent(s, \"\", \"\\t\") fmt.Print(string(result), \"\\n\") }","title":"PrettyPrint Structs"},{"location":"golang-snippets/#flags","text":"","title":"FLAGS"},{"location":"golang-snippets/#binarios-con-versiones","text":"package main import ( \"flag\" \"fmt\" \"os\" ) var version = \"0.0.0\" var when = \"undefined\" func main() { checkFlags() fmt.Println(\"Continue...\") } func checkFlags() { versionFlag := flag.Bool(\"v\", false, \"Show current version and exit\") flag.Parse() switch { case *versionFlag: fmt.Printf(\"Version:\\t: %s\\n\", version) fmt.Printf(\"Date :\\t: %s\\n\", when) os.Exit(0) } } /* go build -ldflags=\" -X 'main.version=v0.2.0' -X 'main.when=$(date -u +%F_%T)'\" go build -ldflags=\"-X 'main.when=$(date -u +%F_%T)'\" luego podemos hacer ./binary -v */","title":"Binarios con versiones"},{"location":"golang-snippets/#organizacion-de-codigo","text":"","title":"ORGANIZACION DE CODIGO"},{"location":"golang-snippets/#compartir-structs-entre-paquetes","text":"// main.go package main import ( s \"pruebas/secondarypkg\" \"time\" ) func main() { p := &s.Placeholder{ Name: \"FooBar\", Date: time.Now().String(), } s.Foo(p) } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func Foo(p *Placeholder) { fmt.Println(p.Date, p.Name) } // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func (p *Placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) *Placeholder { return &Placeholder{ Name: name, Date: date, } } Lo mismo usando interfaces // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type PlaceHolder interface { Foo() } type placeholder struct { Name string Date string } func (p *placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) PlaceHolder { return &placeholder{ Name: name, Date: date, } }","title":"Compartir structs entre paquetes"},{"location":"golang/","text":"GOLANG 1.21.X INSTALACION descargarlo de aqui Como root tar -C /usr/local -xzf go-file.tar.gz // como usuario nano $HOME/.bashrc nano $HOME/.profile // a\u00f1adir a cada uno # Golang conf export PATH=$PATH:/usr/local/go/bin export GOPATH=$HOME/path/to/golang/code export PATH=$PATH:$GOPATH/bin // La siguiente linea hay veces que es necesaria export GOBIN=$PATH:$GOPATH/bin Para recargar la configuracion source ~/.profile Carpetas que se crean: bin - Contiene los binarios compilados. Podemos a\u00f1adir la carpeta bin al path del sistema para hacer los binarios compilados ejecutables desde cualquier sitio pkg - contiene los versiones compiladas de las librerias disponibles para que el compilador las pueda enlazar sin tener que recompilarlas src - contiene todo el codigo organizado por rutas de import VS Code Go: Install/Update Tools ENLACES UTILES Go Interfaces Tipos de funcion Modulos Ejemplos - gobyexample Ejemplos - rosettacode GO MODULES en VSCODE GO MODULES en VSCODE Blogs Jacob Martin - Articulos y tutoriales Dave Cheney Alex Edwards Desarrollo Web Writing Web Applications - Tutorial basico de la wiki de golang.org Ejemplos Golang para web - gowebexamples Librerias database/sql go-sql-driver/mysql gorilla-websocket gobwas-ws Utilidades curl-to-Go - Herramienta online que convierte comandos curl en codigo Go JSON-to-Go - Herramienta online que convierte JSON en structs para Go Despliegue y seguridad GO TOOL go [arguments] The commands are: bug start a bug report build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages or modules mod module maintenance run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages Use \"go help \" for more information about a command. Additional help topics: buildmode build modes c calling between Go and C cache build and test caching environment environment variables filetype file types go.mod the go.mod file gopath GOPATH environment variable gopath-get legacy GOPATH go get goproxy module proxy protocol importpath import path syntax modules modules, module versions, and more module-get module-aware go get packages package lists and patterns testflag testing flags testfunc testing functions Use \"go help \" for more information about that topic. install // descarga el codigo y todas sus dependencias. Lo compila e instala el // binario en el directorio $GOPATH/bin go install github.com/ruta/codigo // instalar la ultima version go install ruta/codigo@latest build // -o nombre para el ejecutable go build -o nombreEjecutable program.go // -s -w eliminan el debug y hacen mas peque\u00f1o el binario go build -ldflags \"-s -w\" // para incluir la fecha en el binario go build -ldflags=\"-X 'main.releaseDate=$(date -u +%F_%T)'\" GOOS - sistema operativo para el que compilamos GOARCH - procesador para el que se compila GOOS=darwin GOARCH=386 go build GOOS=linux GOARCH=amd64 go build -o geoip // -o fuerza el nombre del binario al del parametro GOOS= GOARCH= windows 386 windows amd64 linux 386 linux amd64 linux arm linux arm64 android arm darwin 386 darwin amd64 darwin arm darwin arm64 Lista de combinaciones validas de sistema operativo y arquitectura Usando cgo Ejemplo : usar libreria de C bearlibterminal con bindings para Go. Descargar aqui libBearLibTerminal.so (de linuxx64) va a /usr/lib en gopath (mi caso $HOME/.golang/src/bearlibterminal) ponemos BearLibTerminal.go (los bindings a go) y BearLibTerminal.h (las cabeceras de C) Ahora ya podemos importar la libreria y usarla import ( blt \"bearlibterminal\" ) Para Compilar a Windows usr/bin/ld: cannot find -l // o mingw-64, no tengo claro como van todas esos paquetes tan // similares apt-get install gcc-mingw-w64-x86-64 gcc-multilib cd /usr/x86_64-w64-mingw32/lib // poner ahi todas las librerias para windows *.dll y *.lib GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build main.go OPERADORES Aritmeticos + Suma - Resta * Multiplicacion / Division % Modulo, lo que sobra de la division entera ++ Incremento -- Decremento Asignacion = x = y += x = x + y -= x = x - y *= x = x * y /= x = x / y %= x = x % y Comparacion == igual != no igual > mayor que < menor que >= mayor o igual que <= menor o igual que Logicos && AND || OR ! NOT Punteros & devuelve la direccion de una variable * puntero a una variable VARIABLES Una variable puede contener cualquier tipo, incluso una funcion func main() { accion := func() { fmt.Println(\"Hola\") } accion() } TypeOf(variable) Para averiguar de que tipo es una variable import (\"reflect\") fmt.Println(\"....\", reflect.TypeOf(variable)) Declaracion Declaracion de variables var ( name string age int location string ) var ( name, location string age int ) var name string Inicializacion de variables var ( name string = \"jolav\" age int = 100 ) var ( // inferred typing name = \"jolav\" age = 32 ) var name, location, age = \"jolav\", \"casa\", 100 Sentencia de asignacion := Dentro de una funcion podemos usar := en lugar de var func main() { name, location := \"jolav\", \"casa\" age := 100 } new Pone a cero el valor del tipo y devuelve un puntero a el. x := new(int) make Necesario para slices maps y channels Zero Values Cuando se declaran variables sin un valor explicito se les asigna el valor zero int - 0 float - 0.0 string - \"\" boolean - false pointers - nil map - nil slices - nil array - array listo para usar con sus elementos a zero value que sea functions - nil interfaces - nil channels -nil type package tempconv import \"fmt\" type Celsius float64 type Fahrenheit float64 const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 ) func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) } Alcance El alcance es la region del programa donde una variable definida existe Tipos de variables segun donde se declaren: local variables - dentro de una funcion o un bloque. Fuera de ese entorno no existen package variables - fuera de todas las funciones o bloques. Accesibles desde cualquier parte del paquete formal parameters - en la definicion de los parametros de una funcion. Se tratan como locales para esa funcion y tienen preferencia sobre las globales Cuando coinciden dentro de una funcion o bloque una local y una global prevalece la local Conversion de tipos Go no tiene conversion implicita de tipos T(v) - Convierte el valor v al tipo T i := 42 f := float64(i) u := uint(f) strconv Type Assertion func diffArray(s1, s2 interface{}) []string { var aux1 []int fmt.Println(reflect.TypeOf(s1)) var a1, a2 []string if reflect.TypeOf(s1) == reflect.TypeOf(aux1) { // s1,s2 son []int a1, a2 = convertIntToString(s1.([]int), s2.([]int)) // pasamos s1,s2 como []int y usando type assertion } else { a1, a2 = s1.([]string), s2.([]string) } // aqui ya a1,a2 son []string func diffTwoArrays() { diffArray([]int{1, 2, 3, 5}, []int{1, 2, 3, 4, 5})) diffArray([]string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"}, []string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"}) } Punteros Punteros vs Valor Un puntero contiene la direccion de memoria de un valor Todo en Go se pasa por valor, pero ... Cuando se declara una variable de tipo de referencia se crea un valor llamado header value que contiene un puntero a la estructura de datos subyacente necesaria para segun cada tipo de referencia. Cada tipo de referencia contiene campos unicos para gestionar la estructura de datos subyacente propia. El header value contiene un puntero, por lo tanto puedes pasar una copia de cualquier tipo de referencia y compartir la estructura subyacente intrinsicamente al compartir el puntero. int - valor float - valor string - variable de tipo de referencia, pero funciona como valor boolean - valor arrays - valor slices - variable de tipo de referencia maps - variable de tipo de referencia functions - variable de tipo de referencia interfaces - variable de tipo de referencia channels - variable de tipo de referencia Punteros Por defecto Go pasa los argumentos por valor (crea una copia) Para pasarlos por referencia hay que pasar punteros o usar estructuras de datos que usan valores por referencia como slices y maps. & - para conseguir el puntero de un valor lo ponemos delante de su nombre * - para desreferenciar un puntero y que nos de acceso a su valor Si p es un puntero a x &x --> p = &x p es el puntero de x (contiene la direccion de memoria de x) *p --> *p = x *p es el valor de x i := 42 p := &i // P es un puntero a i fmt.Println(*p) // 42 , lee i a traves del puntero p *p = 21 // establece i a traves del puntero p func main() { v := *getPointer() fmt.Println(\"Value is\", v) // Value is 100 m := getPointer() fmt.Println(\"Memory is\", m) // Memory is 0xc00018c020 } func getPointer() (myPointer *int) { a := 100 return &a } func main() { x := 5 zero(&x) fmt.Println(x) // x is 0 } func zero(x *int) { *x = 0 } func main() { var i int = 7 var p *int p = &i fmt.Println(\"i : \" , i) fmt.Println(\"memory address of i : \", &i) fmt.Println(\"p : \" , p) fmt.Println(\"*p : \" , *p) } [output] i : 7 memory address of i : 0x10328000 p : 0x10328000 *p : 7 new new - coge un tipo como argumento, asigna suficiente memoria para ese tipo de dato y devuelve un puntero que apunta a esa memoria. Luego el GC (garbage collector lo limpia todo) func zero(x *int) { *x = 5 } func main() { x := new(int) zero(x) fmt.Println(*x) // x is 5 } Mutabilidad Solo las constantes son inmutables. Sin embargo como los argumentos se pasan por valor, una funcion que recibe y modifica un argumento no muta el valor original Ejemplo func addOne(x int) { x++ } func main() { x := 0 addOne(x) fmt.Println(x) // x da 0 } // Si usamos punteros func addOne(x *int) { *x++ } func main() { x := 0 addOne(&x) fmt.Println(x) // x da 1 } LECTURA FUNDAMENTAL, stackoverflow pointer vs values type data struct { val int } func myfunc() data { // devuelve una copia del struct return data{val: 1} } func myfunc() *data { // devuelve un puntero al struct creado dentro de la funcion return &data{} } func myfunc(d *data) { // recibe un struct ya existente y sobreescribe su valor d.val = 1 } DATOS BASICOS Numeros Cuando se definen numeros de forma literal se puede usar guion bajo _ para hacerlos mas legibles const segundosEnUnA\u00f1o = 31_557_600 Integers Los enteros son numeros sin decimal int - positivos y negativos uint - unsigned, solo los positivos byte - alias de uint8 (0-255) rune - alias de int32 Numeros de Punto Flotante Son numeros reales (con parte decimal) float32 - conocido como simple precision float64 - conocido como doble precision Numeros Complejos complex64 - parte real float32 + partes imaginarias complex128 - parte real float64 + partes imaginarias Booleanos && - and || - or ! - not Cadenas Estan hechas de bytes (uno por caracter) La diferencia entre comillas simples o dobles es que en estas no pueden contener nuevas lineas y se permiten escapar caracteres especiales len(string) - longitud de la cadena \"Hola mundo\"[1] - acceder a caracteres de la cadena \"Hello, \" + World\" Constantes Se declaran como variables pero con la palabra clave const . No se pueden declarar usando := Solo pueden ser caracteres, string, booleano o valores numericos. const PI = 3.14 Iota iota info Es un identificador usado en declaraciones de constantes para indicar que son autoincrementables. . Se resetea a cero cuando aparece la palabra reservada const const ( // iota is reset to 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) ESTRUCTURAS DE CONTROL for for init; condition; post { } // for normal sum := 0 for i := 0; i < 10; i++ { sum = sum + i } for condition { } // for sin declaraciones pre/post que funciona como un while. Podemos // tambien quitar hasta los punto y coma sum := 1 for ; sum < 1000; { for sum < 1000 { sum = sum + sum } for {} // for infinito for { ..codigo } if if answer != 42 { return \"Wrong answer\" } if err := foo(); err != nil { panic(err) } if { // codigo } else { // codigo } switch switch en golang Solo se pueden comparar valores del mismo tipo declaracion default para ejecutarse si todas las demas fallan en la declaracion se puede usar una expression (pej calcular un valor) case 300 - 150: Se puede tener multiples valores un solo caso case 6, 7: fallthroguh se ejecutan todas las declaraciones que cumplen la condicion break sale del switch, por defecto en cada opcion es automatico el break t := time.Now() switch { case t.Hour() < 12: fmt.Println(\"Good morning!\") case t.Hour() < 17: fmt.Println(\"Good afternoon.\") default: fmt.Println(\"Good evening.\") } switch os := runtime.GOOS; os { case \"darwin\": fmt.Println(\"OS X.\") case \"linux\": fmt.Println(\"Linux.\") default: // freebsd, openbsd,plan9, windows... fmt.Printf(\"%s.\\n\", os) } range Para iterar sobre array , slice , string , map o leer de un channel El valor que nos da range es una copia del valor del elemento original y por tanto si se modifica no afecta al original for k,v := range zoo { v.age = 10 // no modifica el original zoo[k].age = 999 // SI modifica el original } slice var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key, value := range pow { fmt.Println(\"Posicion\", key, \"valor\", value) } Podemos omitir el index o el value usando _ for i, _ := range pow for _, value := range pow Podemos omitir tambien el valor omitiendo por completo , value var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key := range pow { fmt.Println(\"Posicion\", key) } for _, value := range pow { fmt.Println(\"valor\", value) } map El primer parametro no es un entero autoincrementable sino la clave del map for key, value := range cities break Paras la iteracion en cualquier momento continue Omites una iteracion ARRAYS tipo [n]T - es un array de n elementos de tipo T No se pueden redimensionar Se pueden inicializar al declararlos a := [2]string{\"hello\", \"world!\"} a := [...]string{\"hello\", \"world!\"} usando una ellipsis para indicar un numero variable de elementos que en este caso son dos a := [5]int{1: 10, 2: 20} - inicializando solo algunos valores Mostrar arrays fmt.Printf(\"%q\\n\", a) // [\"hello\" \"world!\"] len(array) MultiDimensionales var a [4][2]int array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} SLICES tipo []T - es un slice de elementos de tipo T Crear un slice : Los slice hay que crearlos antes de usarlos slice literal mySlice := []int{2, 3, 5, 7, 11, 13} make - crea un slice vacio de una longitud y (opcional una capacidad) cities := make([]string, len, cap) Recortando un slice s[a:b] - selecciona elementos desde la pos a (inclusive) hasta b (exclusive) s[:b] - un indice a que no se declara es un 0 implicito s[a:] - un indice b que no se declara es implicito un len(s) A\u00f1adiendo a un slice cities = append(cities, \"San Diego\") cities = append(cities, \"San Diego\", \"Mountain View\") otherCities := []string{\"Santa Monica\", \"Venice\"} cities = append(cities, otherCities...) Copiar un slice copy(destino, origen) Length len(slice) Nil slices Declaracion var z []int - El valor cero de un slice es nil. Un slice nil tiene una longitud de cero Inicializacion z := make([]int, 0) z := []int{} Las tres formas son lo mismo BiDimensional // allocate composed 2d array a := make([][]int, row) for i := range a { a[i] = make([]int, col) } // allocate composed 2d array a := make([][]int, row) e := make([]int, row * col) for i := range a { a[i] = e[i*col:(i+1)*col] } // otra posibilidad func get(r, c int) int { return e[r*cols+c] } MAPS tipo map[a]b - es un map de claves tipo a con valores tipo b Formado por pares clave/valor Crear un map : Los map hay que crearlos antes de usarlos map literal amigos := map[string]int{\"Juan\":50, \"Elena\":21, \"Carlos\":41,} make - creas un nil map vacio amigos := make(map[string]int) Si lo declaramos pero no lo inicializamos, al intentar a\u00f1adir elementos no compilara amigos := map[string]int{} - declarado pero no inicializado Modificando maps m[key] = elem - Insertando o actualizando un valor elem = m[key] - Devuelve el elemento delete(m, key) - Borrando un elemento elem, ok = m[key] - Testea si existe un valor con una clave determinada elements := map[string]map[string]string{ \"H\": map[string]string{ \"name\":\"Hydrogen\", \"state\":\"gas\", }, \"He\": map[string]string{ \"name\":\"Helium\", \"state\":\"gas\", }, \"Li\": map[string]string{ \"name\":\"Lithium\", \"state\":\"solid\", }, } if el, ok := elements[\"Li\"]; ok { fmt.Println(el[\"name\"], el[\"state\"]) } STRUCTS Es una coleccion de campos/propiedades Solo los campos exportados (primera letra mayuscula) son accesibles de fuera del paquete Inicializacion type Circle struct { x, y, r float64 } var c Circle - crea una variable local Circle que pone por defecto los valores a cero (0 para int, 0.0 para float. \"\" para string, nil para punteros) c := new(Circle) - asigna memoria para todos los campos, los inicializa a cero y devuelve un puntero a la struct (*Circle), los punteros se usan mucho en structs paa que las funciones puedan modificar los datos. c := Circle{x: 0, y: 0, r: 5} c := Circle{0, 0, 5} c := &Circle{0, 0, 5} c := Circle{x: 1} c := Circle{} type Circle struct { x, y, r float64 } func main() { fmt.Println(c.x, c.y, c.r) c.x = 10 c.y = 5 } // todo en uno var addCases = []struct { in string want string }{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // mas claro type addCases2 []struct { in string want string } ac := addCases2{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // para verlos for i, v := range addCases { fmt.Println(i, v.in) } for i, v := range ac { fmt.Println(i, v) } // con nombres fmt.Printf(\"%+v\\n\", struct) // bien formateado s, _ := json.MarshalIndent(g, \"\", \"\\t\") fmt.Print(string(s)) func show() { fmt.Println(t[0].hola) fmt.Println(test2[1].hola2) } type test []struct { hola string } var t = test{ {\"prueba1\"}, {\"prueba2\"}, } var test2 = []struct { hola2 string }{ {\"prueba3\"}, {\"prueba4\"}, } Metodos Un metodo es una funcion con el primer argumento implicito llamado receptor. func (ReceiverType r) func_name (parameters) (results) El receptor (receiver) del metodo esta entre la palabra clave function y el nombre del metodo func (u User) Greeting() string - nos permite llamarla con u.Greeting() Organizacion del codigo package models // list of packages to import // list of constants // list of variables // Main type(s) for the file, // try to keep the lowest amount of structs per file when possible. // List of functions // List of methods Alias Para definir metodos en un tipo que no es tuyo se usan alias import \"strings\" type MyStr string func (s MyStr) Uppercase() string { return strings.ToUpper(string(s)) } func main() { fmt.Println(MyStr(\"test\").Uppercase()) } Usar punteros en los receptores Los metodos se pueden asociar a un nombre o a puntero. Ventajas de usar punteros: evitar copiar el valor con cada llamada al metodo (pasarlo por referencia) para poder modificar el valor que pasamos type User struct { name string email string } func (u user) notify() { fmt.Printf(\"Mandar correo a %s<%s>\\n\", u.name, u.email) } // sin el puntero del receptor el correo no se cambiaria. func (u *user) changeEmail(email string) { u.email = email } SUGERENCIA Despu\u00e9s de declarar un nuevo tipo, trate de responder a esta pregunta antes de declarar m\u00e9todos para el tipo: \u00bf A\u00f1adir o quitar algo de un valor de este tipo necesita crear un nuevo valor o mutar el existente ? - Si la respuesta es crear un nuevo valor, usa receptores de valor en sus m\u00e9todos. - Si la respuesta es mutar el valor, usa receptores de puntero. Esto tambi\u00e9n se aplica a la forma en que los valores de este tipo deben pasarse a otras partes de su programa. Es importante ser consistente. La idea es no centrarse en lo que el m\u00e9todo est\u00e1 haciendo con el valor, sino centrarse en cu\u00e1l es la naturaleza del valor. Composicion type User struct { Id int Name, Location string } type Player struct { User GameId int } Podemos acceder a la Struct de User: a := new(Player) a.User.Name a.Name INTERFACES Explicacion de interfaces Mas Explicacion de interfaces Mas aun sobre interfaces Es un conjunto de metodos Es un tipo de datos package main import \"fmt\" type cat struct { name string } func (c *cat) born() { fmt.Println(c.name, \"is born Miaouu\") } type dog struct { name string } func (d *dog) born() { fmt.Println(d.name, \"is born Wharff\") } type animal interface { born() } func born(a animal) { a.born() } func main() { Jasper := &cat{\"JASPER\"} Lucy := &dog{\"Lucy\"} Max := new(dog) Max.name = \"Max\" Max.born() // call born function born(Jasper) born(Lucy) born(Max) } package main import \"fmt\" type Human struct { name string age int phone string } type Student struct { Human //an anonymous field of type Human school string loan float32 } // A human likes to stay... err... *say* hi func (h *Human) SayHi() { fmt.Printf(\"Hi, I am %s you can call me on %s\\n\", h.name, h.phone) } // A human can sing a song, preferrably to a familiar tune! func (h *Human) Sing(lyrics string) { fmt.Println(\"La la, la la la, la la la la la...\", lyrics) } // A Human man likes to guzzle his beer! func (h *Human) Guzzle(beerStein string) { fmt.Println(\"Guzzle Guzzle Guzzle...\", beerStein) } // A Student borrows some money func (s *Student) BorrowMoney(amount float32) { s.loan += amount // (again and again and...) } func Prestar(y YoungChap, amount float32) { y.BorrowMoney(amount) } // INTERFACES type Men interface { SayHi() Sing(lyrics string) Guzzle(beerStein string) } type YoungChap interface { SayHi() Sing(song string) BorrowMoney(amount float32) } func main() { mike := Student{Human{\"Mike\", 25, \"222-222-XXX\"}, \"MIT\", 150.50} mike.BorrowMoney(10) mike.BorrowMoney(10) Prestar(&mike, 100) fmt.Println(\"Debe ..\", mike.loan) } interfaces vacias 1- Todo tiene un type , puedes definir un nuevo type por ejemplo T que tiene tres metodos A , B y C 2- El conjunto de metodos especificos de un type se llama interface type . En nuestro ejemplo T_interface = (A, B, C) 3- Puedes crear un nuevo interface type definiendo los metodos que tiene. Pro ejemplo creo MyInterface = (A) 4- Cuando especificas una variable de tipo interface type le puedes asignar solo los tipos que esten en una interface que sea un superset de tu interface, vamos que todos los metodos de MyInterface deben estar en T_interface Conclusion : Todos los tipos de variables satisfacen la empty interface . Por tanto una funcion que tiene una interface{} como argumento admite cualquier valor sea el que sea. Pero dentro de la funcion el runtime de Go convierte ese valor a un valor interface{} func DoSomething(v interface{}) { // la funcion acepta cualquier valor una vez dentro // v es del tipo interface{} } EL valor de una interfaz son dos word de datos: - una word es un puntero a una tabla de metodos para el valor del type subyacente - la otra word es un puntero a los datos actuales de ese valor FUNCIONES Call Stack func main() { fmt.Println(f1()) } func f1() int { return f2() } func f2() int { return 1 } Argumentos Argumentos que reciben. Las funciones pueden recibir 0 o mas argumentos todos tipados despues del nombre de la variable. func add(x int, y int) int { return x + y } func add(x, y int) int { // int afecta a todos los parametros (x, y) return x + y } // ... funciones que aceptan un numero variable de parametros func add(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { // pasamos los parametros que queramos fmt.Println(add(1,2,3)) xs := []int{1,2,3} fmt.Println(add(xs...)) // tambien podemos pasar un slice } Retorno de parametros, puede devolver cualquier numero de ellos return region, continente // devuelve mas de un valor // Si los parametros de retorno estan nombrados vale con solo return func location(name, city string) (region, continent string) { ..codigo return // devuelve region y continent } Closures func generadorPares() func() uint { i := uint(0) return func() (ret uint) { ret = i i = i + 2 return } } func main() { nextPar := generadorPares() fmt.Println(nextPar()) // 0 fmt.Println(nextPar()) // 2 fmt.Println(nextPar()) // 4 } Recursion func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) } type function package main import \"fmt\" type test_int func(int) bool // isOdd takes an ints and returns a bool set to true if the // int parameter is odd, or false if not. // isOdd is of type func(int) bool which is what test_int // is declared to be. func isOdd(integer int) bool { if integer%2 == 0 { return false } return true } // Same comment for isEven func isEven(integer int) bool { if integer%2 == 0 { return true } return false } // We could've written: // func filter(slice []int, f func(int) bool) []int func filter(slice []int, f test_int) []int { var result []int for _, value := range slice { if f(value) { result = append(result, value) } } return result } func main(){ slice := []int {1, 2, 3, 4, 5, 7} fmt.Println(\"slice = \", slice) odd := filter(slice, isOdd) fmt.Println(\"Odd elements of slice are: \", odd) even := filter(slice, isEven) fmt.Println(\"Even elements of slice are: \", even) } defer Aplaza la ejecucion de una funcion hasta que termina la funcion en la que se encuentra. Lo tipico es cerrar archivos o desbloquear un mutex(mutual exclusion, para asegurar que solo una goroutine puede acceder a la vez a una variable) func main() { defer fmt.Println(\"world\") fmt.Println(\"hello\") } Se usa para liberar recursos cuando se pueda f, _ := os.Open(filename) defer f.Close() panic, recover panic(\"valor de panic\") - crea un runtime error . recover() - detiene el panic y devuelve el valor que fue pasado con la llamada a panic Un panic generalmente indica un error de programacion o una condicion excepcional de la que no hay forma facil de recuperarse func main() { defer func() { str := recover() fmt.Println(str) }() panic(\"PANIC\") } CONCURRENCIA goroutines go f(x) comienza la ejecucion de una nueva goroutine que es una funcion capaz de ejecutarse concurrentemente con otras funciones. // sin wait, el programa main puede acabar antes de que las goroutines // hagan lo que tengan que hacer func parallelLetFreq() { var wg sync.WaitGroup wg.Add(3) // suma 3 a las goroutines a esperar go count(\"1\", &wg) go count(\"2\", &wg) go count(\"3\", &wg) wg.Wait() // espera a todas las goroutines (3 en este caso) } func count(n int, wg *sync.WaitGroup) { defer wg.Done() // al terminar la funcion terminar goroutine fmt.Println(\"Number --> \", n)) } channels channels - son un conducto a traves del cual puedes recibir y enviar datos con el operador <- ch <- data - Envia data al canal ch data := <-ch - Recibe informacion del canal ch y lo asigna a data ch := make(chan int) - Los canales hay que crearlos antes de usarlos Por defecto los envios y recepciones esperan hasta que el otro lado este listo. Esto permite a las goroutines sincronizarse sin bloqueos especificos o condiciones func sum(a []int, c chan int) { sum := 0 for _, v := range a { sum += v } c <- sum // send sum to c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) } Buffered channels ch := make(chan int, 100) - Ponemos un buffer a los canales indicando su longitud como segundo argumento en el make para inicializar el canal Enviar datos aun canal con buffer se bloquea si el buffer esta lleno Recibir datos de un canal con buffer se bloquea si el buffer esta vacio func main() { c := make(chan int, 2) c <- 1; c <- 2; c <- 3 fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } // fatal error: all goroutines are asleep - deadlock! Sin embargo el siguiente funcionaria. Al a\u00f1adir el valor extra desde una goroutine no se bloquea el hilo principal pues aunque la goroutine se llama antes que el canal se vacie esta esperara hasta que haya espacio en el canal. func main() { c := make(chan int, 2) c <- 1; c <- 2 c3 := func() { c <- 3 } go c3() fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } Close close(ch) - Solo un emisor puede cerrar un canal. Enviar a un canal cerrado causa un panic. No son como ficheros que hace falta cerrarlos. Solo se cierran para avisar al receptor de que no llegaran mas datos y para terminar los loop range v, ok := <-ch - Un emisor puede cerrar un canal para indicar que no se enviara nada mas. Los receptores pueden testear cuando un canal ha sido cerrado asignando un segundo parametro a la expresion receptora ok sera falso cuando no haya mas valores que recibir y el canal este cerrado. for i := range ch - recibe valores del canal hasta que se cierre Select Es como switch pero con canales 1A - 89 1B - 103 MODULES go mod init nombreModulo go mod init github.com/jolav/nombreModulo // listar todos los modulos con sus dependencias go list -m all go list all ./... // chechear paquetes con actualizaciones go list -m -u all go list -m -u -json all // actualizar // cambiar manualmenrte el archivo go.mod o // actualiza todas salvo nueva version mayor, go get -v -u ./... // para versiones especificas o nueva version mayor go get -v -u github.com/user/repo@v1.1.1 //despues para asegurar que el el codigo que tenemos en el modulo coincide // con el archivo gp.mod ejecutamos go mod tidy PAQUETES Un programa Go esta hecho con paquetes. Los programas empiezan ejecutando la funcion main dentro del paquete main . Por convencion el nombre del paquete es la ultima palabra de la ruta del import. El paquete \"math/rand\" comprende archivos que comienzan con la sentencia package rand Paquetes que no son de la libreria estandar se importan usando una URL web, pero antes hay que descargarlos con go get go get github.com/creador/ruta/al/paquete import \"github.com/creador/ruta/al/paquete\" Despues de importar un paquete podemos usar los nombres que el exporta (sean variables, metodos o funciones) desde fuera de el paquete. Los nombres exportados en Go comienzan por letra mayuscula package main import ( \"fmt\" \"math\" ) func main() { fmt.Println(math.Pi) fmt.Println(math.pi) } // cannot refer to unexported name math.pi Otras formas de importar paquetes \u00ecmport alias \"fmt\" - Crea un alias de fmt. Ahora es alias.LoQueSea en lugar de fmt.LoQueSea import . \"fmt\" - Permite acceder al contenido directamente sin tener que ir precedido de fmt import _ \"fmt\" - Elimina las advertencia del compilado sobre ese paquete si no se usa y ejecuta si hay las funciones de inicializacion ( func init() {} ), El resto del paquete permanece inaccesible. Crear paquetes Los nombres de paquetes coinciden con la carpeta donde estan. Esto se puede cambiar pero no merece la pena Por convencion el nombre del paquete es la ultima palabra de la ruta del import. ~/src/proyectoX/main.go package main import \"fmt\" import \"proyectoX/utilidades\" // la ruta es a partir de srcs func main() { // llamada a utilidades.Media(xs) } ~/src/proyectoX/utilidades/media.go package utilidades func Media() { // codigo que sea } Desinstalar paquetes go clean -i ruta/paquete... - teoricamente borras los pkg y bin, los src hay que borrarlos manualmente Actualizar go get -u all - Actualiza todos go get -u full/package/name - Actualizar solo ese paquete EJECUCION El programa se inicia por la funcion main del package main Antes se ejecutan las funciones init de ese fichero Los paquetes importados \"_ import \"ruta/paquete\" hacen que el compilador acepte un paquete que no se usa y ademas ejecutan la o las funciones init de ese paquete TESTING El compilador ignora todos los archivos que terminan en _test.go ~/src/proyectoX/utilidades/media_test.go package utilidades import \"testing\" type testpair struct { values []float64 average float64 } var tests = []testpair{ {[]float64{1, 2}, 1.5}, {[]float64{1, 1, 1, 1, 1, 1}, 1}, {[]float64{-1, 1}, 0}, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Media(pair.values) if v != pair.average { t.Error( \"For\", pair.values, \"expected\", pair.average, \"got\", v, ) } } } go test ERRORS Errores en Go Los captura un tipo interfaz predefinido cuyo unico metodo Error devuelve una cadena type error interface { Error() string } Forma estandard de tratar los errores. log.Fatal(err) - manda el error a la terminal y detiene el programa f, err := os.Open(\"filename.ext\") if err != nil { log.Fatal(err) } Podemos aligerar la repeticion un poco usando: func check(e error) { if e != nil { panic(e) } } // y ahora ya solo ponemos check(err) LIBRERIA ESTANDAR FMT import \"fmt\" fmt.Print() - imprime fmt.Println() - imprime y salta de linea fmt.Printf() - imprime con un determinado formato type point struct { x, y int } p := point{1, 2} fmt.Printf(\"%v\\n\", p) // {1 2} // en una struct, `%+v` incluye los nombres de los campos de la struct fmt.Printf(\"%+v\\n\", p) // {x:1 y:2} // Imprimir el tipo de un valor fmt.Printf(\"%T\\n\", p) // main.point // `%d` para enteros standard fmt.Printf(\"%d\\n\", 123) // 123 // Imprime el caracter que corresponde al entero fmt.Printf(\"%c\\n\", 65) // a // Imprime floats fmt.Printf(\"%f\\n\", 78.9) // 78.90000 // Imprime string basicas `%s`. fmt.Printf(\"%s\\n\", \"\\\"string\\\"\") // \"string\" // Imprimir Booleano fmt.Printf(\"%t\\n\", a ==b) // true o false // Imprime un puntero`%p`. fmt.Printf(\"%p\\n\", &p) // 0x42135100 fmt.Sprint() - devuelve el resultado a una string fmt.Sprintln() - devuelve el resultado con salto de linea a una string fmt.Sprintf() - devuelve el resultado con un determinado formato a una string // las Sxxx() son como las normales en vez de imprimir el resultado // lo devuelven como un string s := fmt.Sprintf(\"Hi, my name is %s and I'm %d years old.\", \"Bob\", 23) // s vale \"Hi, my name is Bob and I'm 23 years old.\" fmt.Scan() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea cuentan como espacio fmt.Scanln() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea acaban con la lectura de datos verbos - General %v - valor en formato por defecto. En structs %+v a\u00f1ade los nombres de los campos %T - tipo del valor %#v - representacion del tipo del valor con sintaxis de golang - Booleano %t - booleano, devuelve palabra true o false - Integer %b - devuelve en base 2 %c - devuelve caracter representado por el correspondiente codigo Unicode %d - devuelve en base 10 %U - formato Unicode - Floating point f% - notacion decimal sin exponentes e% - notacion decimal con exponentes - Strings y []byte %s - cadenas normales %q - para escapar comillas dobles %x - convierte a base hexadecimal STRINGS import \"strings\" strings.Contains(\"test\", \"es\") = true - Contiene \"test\" a \"es\" strings.Count(\"test\", \"t\") = 2 - Cuantas \"t\" hay en \"test\" strings.HasPrefix(\"test\", \"te\") = true - Comienza \"test\" por \"te\" strings.HasSuffix(\"test\", \"st\") = True - Acaba \"test\" en \"st\" strings.Index(\"test\", \"e\") = 1 - Posicion de string \"e\" dentro de string \"test\", si no esta devuelve -1 strings.Join([]string{\"a\",\"b\"}, \"-\") = \"a-b\" - Coge una lista de strings y las junta en una separadas por otra string (\"-\" en el ejemplo) strings.Repeat(\"a\", 5) = aaaaa - Repite una string n veces strings.Replace(\"aaaa\", \"a\", \"b\", 2) = \"bbaa\" - reemplaza en una cadena una parte por otra n veces (o todas las que se pueda si pasamos -1) strings.Split(\"a-b-c-d-e\", \"-\") = []string{\"a\",\"b\",\"c\",\"d\",\"e\"} - Parte una string en un array de strings usando otra string como separador strings.ToLower(\"test\") = \"TEST \"- convierte la cadena a minusculas strings.ToUpper(\"TEST\") = \"test\" - convierte la cadena a mayusculas strings.Fields(\"cadena que sea) = como split usando espacios en blanco. es equivalente a si usaramos strings.Split(text, \" \") strings.Trim(\"cadena\",\"loquecorta\") = elimina en cadena todas las loquecorta pero solo del comienzo y del final strings.Trim(\" !!! Achtung! Achtung! !!! \", \"! \") == [\"Achtung! Achtung\"] Convertir string en slice of bytes y viceversa arr := []byte(\"test\") str := string([]byte{'t','e','s','t'}) Fuera del paquete string len(\"aquiunacadena\") - nos da la longitud de la string \"cadena\"[3] - nos da el codigo ASCII del caracter de indice 3, \"e\" = 101 string(cadena[n]) - nos da el caracter de la cadena en la posicion n STRCONV import \"strconv\" - conversiones entre numeros y strings s := strconv.Itoa(-42) - int to string i, err := strconv.Atoi(\"-42\") - string to int b, err := strconv.ParseBool(\"true\") - string to boolean f, err := strconv.ParseFloat(\"3.1415\", 64) - string to float i, err := strconv.ParseInt(\"-42\", 10, 64) - string to int u, err := strconv.ParseUint(\"42\", 10, 64) - string to uint s := strconv.FormatBool(true) - boolean value to string s := strconv.FormatFloat(3.1415, 'E', -1, 64) - float to string s := strconv.FormatInt(-42, 16) - int to string s := strconv.FormatUint(42, 16) - uint to string APPEND Trucos con slices func append(slice []T, elements...T) []T. IO import \"io\" Tiene dos interfaces principales Reader soporta leer a a traves del metodo Read Writer soporta escribir a traves del metodo Write IO/IOUTIL import io/ioutil leer y escribir un archivo De esta forma cargamos todo el archivo en memoria de golpe. Mas control a traves de un File struct del paquete OS data := []byte(\"Hello World!\\n\") // write err := ioutil.WriteFile(\"data1\", data, 0644) if err != nil { panic(err) } //read read, err := ioutil.ReadFile(\"data1\") if err != nil { return } fmt.Print(string(read1)) Limitar tama\u00f1o io defer resp.Body.Close() limitReader := &io.LimitedReader{R: resp.Body, N: 2e6} // (2mb) body, err := ioutil.ReadAll(limitReader) OS import \"os\" Saber donde estamos os.Getwd() leer escribir un archivo // Una forma file, err := os.Open(\"test.txt\") if err != nil { // handle the error here } defer file.Close() stat, err := file.Stat() // get the file size if err != nil { return } bs := make([]byte, stat.Size()) // read the file _, err = file.Read(bs) if err != nil { return } str := string(bs) fmt.Println(str) // otra forma data := []byte(\"Hello World!\\n\") // write to file and read from file using the File struct file1, _ := os.Create(\"data2\") defer file1.Close() bytes, _ := file1.Write(data) fmt.Printf(\"Wrote %d bytes to file\\n\", bytes) file2, _ := os.Open(\"data2\") defer file2.Close() read2 := make([]byte, len(data)) bytes, _ = file2.Read(read2) fmt.Printf(\"Read %d bytes from file\\n\", bytes) fmt.Println(string(read2)) crear un archivo func main() { file, err := os.Create(\"test.txt\") if err != nil { return } defer file.Close() file.WriteString(\"test\") } Leer el contenido de un directorio Readdir - coge un argumento que es el numero de entradas que devuelve. Con -1 devuelve todas func main() { dir, err := os.Open(\".\") if err != nil { return } defer dir.Close() fileInfos, err := dir.Readdir(-1) if err != nil { return } for _, fi := range fileInfos { fmt.Println(fi.Name()) } } Walk - para recorrer recursivamente un directorio. Pertenece al paquete path/filepath Command line arguments el primer valor del slice de argumentos es el nombre del comando path incluido argsWithProg := os.Args - slice completo con comando nombre path incluido argsWithoutProg := os.Args[1:] - slice solo de argumentos arg := os.Args[x] - devuelve argumento de posicion X environment variables os.Setenv(\"nombreVariable\", \"valor\") - establece un par clave/valor para una variable de entorno os.Getenv(\"nombreVariable\") - devuelve el valor de esa clave // os.Environ es una lista de todas las variables de entorno for _, e := range os.Environ() { pair := strings.Split(e, \"=\") fmt.Println(pair[0], \"-->\", pair[1]) } PATH/FILEPATH import path/filepath Recorrer recursivamente un directorio Walk func main() { filepath.Walk(\".\", func(path string, info os.FileInfo, err error) error { fmt.Println(path) return nil }) } REGEXP import \"regexp\" // Comprueba si es una cadena patron := \"loquequeremoscomprobar\" match, _ := regexp.MatchString(\"p([a-z]+)ch\", patron) fmt.Println(match) // o compilamos primero una struct optimizada para regexp patron := \"loquequeremoscomprobar\" r, _ := regexp.Compile(\"p([a-z]+)ch\") fmt.Println(r.MatchString(patron)) // Por ejemplo cambiar en la cadena s los guiones bajos por guiones r := regexp.MustCompile(\"_\") s = r.ReplaceAllString(s, `-`) JSON import \"encoding/json\" Golang JSON dataJson, err := json.Marshal(structObject) - Go struct data to JSON data dataJson, err:= json.MarshalIndent(strObj, \"\", \" \") - bien preformateado err := json.Unmarshal(dataJson, &structObject) - JSON data to Go struct data urlDir := \"https://domain.tld/api/que/queramos\" resp, err := http.Get(urlDir) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } body = body[5 : len(body)-6] // quitar mis pegatinas de
         var s structObject err = json.Unmarshal(body, &s) fmt.Println(s) Convertir json to go struct JSON-to-Go online json:\"-\" ignora ese campo tanto al convertir a json o al convertir desde json json:\"nombreCampo,omitempy - no se incluye el campo al convertir a json si ese campo ya tiene un valor por defecto. Decoder Ademas de Unmarshal/Marshal existe Decoder/Encoder , que se debe usar si los datos vienen de una stream io.Reader como por ejemplo el Body de una http.Request. Si los datos estan en una string o en memoria mejor usar Unmarshal type configuration struct { lo que sea } file, _ := os.Open(\"conf.json\") defer file.Close() decoder := json.NewDecoder(file) conf := configuration{} err := decoder.Decode(&conf) if err != nil { fmt.Println(\"Error:\", err) } fmt.Println(conf) Parsing Interfaces An\u00e1lisis de una interfaz Si realmente no tienes ni idea de c\u00f3mo podr\u00eda ser tu JSON, se puede analizar en una interfaz gen\u00e9rica{}. Una interfaz vac\u00eda es una forma de definir una variable en Go como \"esto podr\u00eda ser cualquier cosa\". En tiempo de ejecuci\u00f3n, Go asignar\u00e1 la memoria adecuada para que se ajuste a lo que decida almacenar en ella. Esto es lo que parece: var parsed interface{} err := json.Unmarshal(data, &parsed) En realidad, el uso de parsed es un poco laborioso, ya que Go no puede usarlo sin saber de qu\u00e9 tipo es. switch parsed.(type) { case int: someGreatIntFunction(parsed.(int)) case map: someMapThing(parsed.(map)) default: panic(\"JSON type not understood\") } Tambi\u00e9n puedes hacer aserciones de tipo similares en l\u00ednea: intVal, ok := parsed.(int) if !ok { panic(\"JSON value must be an int\") } Afortunadamente, sin embargo, es raro no tener idea de lo que puede ser un valor. Si, por ejemplo, sabe que su valor JSON es un objeto, puedes analizarlo en una interfaz de map[string]interface{}. Esto te da la ventaja de poder referirte a claves espec\u00edficas. Un ejemplo: var parsed map[string]interface{} data := []byte(` { \"id\": \"k34rAT4\", \"age\": 24 } `) err := json.Unmarshal(data, &parsed) A continuaci\u00f3n, puedes referirte a las teclas espec\u00edficas sin ning\u00fan problema: parsed[\"id\"] Sin embargo, todav\u00eda tienes interfaces como valor de su map, por lo que debes hacer type assertions para utilizarlas: idString := parsed[\"id\"].(string) Go utiliza estos seis tipos para todos los valores analizados en las interfaces: bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null Es decir, tus n\u00fameros siempre ser\u00e1n de tipo float64, y necesitar\u00e1n ser casteados a int, por ejemplo. Si tiene una necesidad de obtener enteros directamente, puedes usar el m\u00e9todo UseNumber. Lo que te da un objeto que puede convertirse en un float64 o en un int a tu discreci\u00f3n. De manera similar, todos los objetos decodificados en una interfaz ser\u00e1n map[string]interface{}, y necesitar\u00e1n ser mapeados manualmente a cualquier estructura aue quieras usar. Sobre JSON TIME import \"time\" now := time.Now() - nos da la hora actual 2012-10-31 15:50:13.793654 +0000 UTC then := time.Date(2015, 10, 10, 18, 30, 08, 0, time.UTC) - Creamos un struct de tiempo asociado a una localizacion (time zone) then.Year() then.Month() then.Day() then.Hour() then.Minute() then.Second() then.Nanosecond() then.Location() then.Weekday() then.Before(now) then.After(now) then.Equal(now) diff := now.Sub(then) - metodo Sub devuelve duracion del intervalo entre dos tiempos diff.Hours() diff.Minutes() diff.Seconds() diff.Nanoseconds() // avanzar o retroceder en el tiempo then.Add(diff) then.Add(-diff) // sumar tiempo tiempoQueSea.Add( 1000 * time.Hours) String to Time // pasar una fecha a string segun un determinado formato layout := \"2006-01-02 15:04:05\" t, err := time.Parse(layout1, start) if err != nil { fmt.Prinltln(err) } // Hora actual a string con determinado formato horaActual = time.Now().Format(layout) Time to String myString = myTime.String() Timestamp Unix epoch now := time.Now() secs := now.Unix() nanos := now.UnixNano() millis := nanos / 1000000 time.Unix(secs, 0) time.Unix(0, nanos) Intervalos timers - para hacer algo una vez dentro de un tiempo timer1 := time.NewTimer(time.Second * 2) <-timer1.C fmt.Println(\"Timer 1 expired\") timer2 := time.NewTimer(time.Second) go func() { <-timer2.C fmt.Println(\"Timer 2 expired\") }() stop2 := timer2.Stop() if stop2 { fmt.Println(\"Timer 2 stopped\") } // Timer 1 expired // Timer 2 stopped // Timer 2 expired NUNCA APARECE, se cancela antes tickers - para hacer algo repetidamente a intervalos regulares ticker := time.NewTicker(time.Millisecond * 500) go func() { for t := range ticker.C { fmt.Println(\"Tick at\", t) } }() time.Sleep(time.Millisecond * 1600) ticker.Stop() fmt.Println(\"Ticker stopped\") MATH import \"math\" math.Floor(x float64) float64 - devuelve el entero (int) mas grande poisble menor o igual que x math.Pow(x,y float64) float64 - x elevado a y MATH/RAND import \"math/rand\" rand.Intn(10) - genera un numero aleatorio entero >= 0 y < 10 rand.Float64() - genera un numero aleatorio >= 0.0 y < 1.0 (rand.Float64()*5)+5 - genera entre >= 5.0 y < 10.0 s1 := rand.NewSource(time.Now().UnixNano()) - semilla para que no sea siempre igual r1 := rand.New(s1) - para ir cambiando la semilla rand.Seed(time.Now().UTC().UnixNano()) - otra forma de cambiar la semilla para que no siempre sea igual func init() { //fmt.Println(`Init from package tracker`) r = rand.New(rand.NewSource(time.Now().UnixNano())) } var r *rand.Rand func createRandomString() string { const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\" result := \"\" for i := 0; i < lenID; i++ { result += string(chars[r.Intn(len(chars))]) } return result } DATABASE/SQL database/sql FLAG import \"flag\" Para enviar argumentos a un comando Ejemplos SORT import sort Contiene funciones para ordenar datos arbitrario de slices de ints y floats y structs definidas por el usuario s = []strings sort.strings(s) - De menor a mayor alfabeticamente n = []ints || float32 || float64 sort.Ints(n) - Ordena los numeros de menor a mayor sort.IntsAreSorted(n) - booleano que devuelve si estan ordenados custom sorting package main import \"sort\" import \"fmt\" // If I have an array/slice of structs in Go and want to sort them // using the sort package it seems to me that I need to implement // the whole sort interface which contains 3 methods: // https://golang.org/pkg/sort/#Interface type ByLength []string func (s ByLength) Len() int { return len(s) } func (s ByLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s ByLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) } func main() { fruits := []string{\"peach\", \"banana\", \"kiwi\"} sort.Sort(ByLength(fruits)) fmt.Println(fruits) }","title":"Golang"},{"location":"golang/#golang-121x","text":"","title":"GOLANG 1.21.X"},{"location":"golang/#instalacion","text":"descargarlo de aqui Como root tar -C /usr/local -xzf go-file.tar.gz // como usuario nano $HOME/.bashrc nano $HOME/.profile // a\u00f1adir a cada uno # Golang conf export PATH=$PATH:/usr/local/go/bin export GOPATH=$HOME/path/to/golang/code export PATH=$PATH:$GOPATH/bin // La siguiente linea hay veces que es necesaria export GOBIN=$PATH:$GOPATH/bin Para recargar la configuracion source ~/.profile Carpetas que se crean: bin - Contiene los binarios compilados. Podemos a\u00f1adir la carpeta bin al path del sistema para hacer los binarios compilados ejecutables desde cualquier sitio pkg - contiene los versiones compiladas de las librerias disponibles para que el compilador las pueda enlazar sin tener que recompilarlas src - contiene todo el codigo organizado por rutas de import VS Code Go: Install/Update Tools","title":"INSTALACION"},{"location":"golang/#enlaces-utiles","text":"Go Interfaces Tipos de funcion Modulos Ejemplos - gobyexample Ejemplos - rosettacode GO MODULES en VSCODE GO MODULES en VSCODE Blogs Jacob Martin - Articulos y tutoriales Dave Cheney Alex Edwards Desarrollo Web Writing Web Applications - Tutorial basico de la wiki de golang.org Ejemplos Golang para web - gowebexamples Librerias database/sql go-sql-driver/mysql gorilla-websocket gobwas-ws Utilidades curl-to-Go - Herramienta online que convierte comandos curl en codigo Go JSON-to-Go - Herramienta online que convierte JSON en structs para Go Despliegue y seguridad","title":"ENLACES UTILES"},{"location":"golang/#go-tool","text":"go  [arguments] The commands are: bug start a bug report build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages or modules mod module maintenance run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages Use \"go help \" for more information about a command. Additional help topics: buildmode build modes c calling between Go and C cache build and test caching environment environment variables filetype file types go.mod the go.mod file gopath GOPATH environment variable gopath-get legacy GOPATH go get goproxy module proxy protocol importpath import path syntax modules modules, module versions, and more module-get module-aware go get packages package lists and patterns testflag testing flags testfunc testing functions Use \"go help \" for more information about that topic.","title":"GO TOOL"},{"location":"golang/#install","text":"// descarga el codigo y todas sus dependencias. Lo compila e instala el // binario en el directorio $GOPATH/bin go install github.com/ruta/codigo // instalar la ultima version go install ruta/codigo@latest","title":"install"},{"location":"golang/#build","text":"// -o nombre para el ejecutable go build -o nombreEjecutable program.go // -s -w eliminan el debug y hacen mas peque\u00f1o el binario go build -ldflags \"-s -w\" // para incluir la fecha en el binario go build -ldflags=\"-X 'main.releaseDate=$(date -u +%F_%T)'\" GOOS - sistema operativo para el que compilamos GOARCH - procesador para el que se compila GOOS=darwin GOARCH=386 go build GOOS=linux GOARCH=amd64 go build -o geoip // -o fuerza el nombre del binario al del parametro GOOS= GOARCH= windows 386 windows amd64 linux 386 linux amd64 linux arm linux arm64 android arm darwin 386 darwin amd64 darwin arm darwin arm64 Lista de combinaciones validas de sistema operativo y arquitectura Usando cgo Ejemplo : usar libreria de C bearlibterminal con bindings para Go. Descargar aqui libBearLibTerminal.so (de linuxx64) va a /usr/lib en gopath (mi caso $HOME/.golang/src/bearlibterminal) ponemos BearLibTerminal.go (los bindings a go) y BearLibTerminal.h (las cabeceras de C) Ahora ya podemos importar la libreria y usarla import ( blt \"bearlibterminal\" ) Para Compilar a Windows usr/bin/ld: cannot find -l // o mingw-64, no tengo claro como van todas esos paquetes tan // similares apt-get install gcc-mingw-w64-x86-64 gcc-multilib cd /usr/x86_64-w64-mingw32/lib // poner ahi todas las librerias para windows *.dll y *.lib GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build main.go","title":"build"},{"location":"golang/#operadores","text":"Aritmeticos + Suma - Resta * Multiplicacion / Division % Modulo, lo que sobra de la division entera ++ Incremento -- Decremento Asignacion = x = y += x = x + y -= x = x - y *= x = x * y /= x = x / y %= x = x % y Comparacion == igual != no igual > mayor que < menor que >= mayor o igual que <= menor o igual que Logicos && AND || OR ! NOT Punteros & devuelve la direccion de una variable * puntero a una variable","title":"OPERADORES"},{"location":"golang/#variables","text":"Una variable puede contener cualquier tipo, incluso una funcion func main() { accion := func() { fmt.Println(\"Hola\") } accion() } TypeOf(variable) Para averiguar de que tipo es una variable import (\"reflect\") fmt.Println(\"....\", reflect.TypeOf(variable))","title":"VARIABLES"},{"location":"golang/#declaracion","text":"Declaracion de variables var ( name string age int location string ) var ( name, location string age int ) var name string Inicializacion de variables var ( name string = \"jolav\" age int = 100 ) var ( // inferred typing name = \"jolav\" age = 32 ) var name, location, age = \"jolav\", \"casa\", 100 Sentencia de asignacion := Dentro de una funcion podemos usar := en lugar de var func main() { name, location := \"jolav\", \"casa\" age := 100 } new Pone a cero el valor del tipo y devuelve un puntero a el. x := new(int) make Necesario para slices maps y channels Zero Values Cuando se declaran variables sin un valor explicito se les asigna el valor zero int - 0 float - 0.0 string - \"\" boolean - false pointers - nil map - nil slices - nil array - array listo para usar con sus elementos a zero value que sea functions - nil interfaces - nil channels -nil type package tempconv import \"fmt\" type Celsius float64 type Fahrenheit float64 const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 ) func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }","title":"Declaracion"},{"location":"golang/#alcance","text":"El alcance es la region del programa donde una variable definida existe Tipos de variables segun donde se declaren: local variables - dentro de una funcion o un bloque. Fuera de ese entorno no existen package variables - fuera de todas las funciones o bloques. Accesibles desde cualquier parte del paquete formal parameters - en la definicion de los parametros de una funcion. Se tratan como locales para esa funcion y tienen preferencia sobre las globales Cuando coinciden dentro de una funcion o bloque una local y una global prevalece la local","title":"Alcance"},{"location":"golang/#conversion-de-tipos","text":"Go no tiene conversion implicita de tipos T(v) - Convierte el valor v al tipo T i := 42 f := float64(i) u := uint(f) strconv Type Assertion func diffArray(s1, s2 interface{}) []string { var aux1 []int fmt.Println(reflect.TypeOf(s1)) var a1, a2 []string if reflect.TypeOf(s1) == reflect.TypeOf(aux1) { // s1,s2 son []int a1, a2 = convertIntToString(s1.([]int), s2.([]int)) // pasamos s1,s2 como []int y usando type assertion } else { a1, a2 = s1.([]string), s2.([]string) } // aqui ya a1,a2 son []string func diffTwoArrays() { diffArray([]int{1, 2, 3, 5}, []int{1, 2, 3, 4, 5})) diffArray([]string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"}, []string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"}) }","title":"Conversion de tipos"},{"location":"golang/#punteros","text":"Punteros vs Valor Un puntero contiene la direccion de memoria de un valor Todo en Go se pasa por valor, pero ... Cuando se declara una variable de tipo de referencia se crea un valor llamado header value que contiene un puntero a la estructura de datos subyacente necesaria para segun cada tipo de referencia. Cada tipo de referencia contiene campos unicos para gestionar la estructura de datos subyacente propia. El header value contiene un puntero, por lo tanto puedes pasar una copia de cualquier tipo de referencia y compartir la estructura subyacente intrinsicamente al compartir el puntero. int - valor float - valor string - variable de tipo de referencia, pero funciona como valor boolean - valor arrays - valor slices - variable de tipo de referencia maps - variable de tipo de referencia functions - variable de tipo de referencia interfaces - variable de tipo de referencia channels - variable de tipo de referencia Punteros Por defecto Go pasa los argumentos por valor (crea una copia) Para pasarlos por referencia hay que pasar punteros o usar estructuras de datos que usan valores por referencia como slices y maps. & - para conseguir el puntero de un valor lo ponemos delante de su nombre * - para desreferenciar un puntero y que nos de acceso a su valor Si p es un puntero a x &x --> p = &x p es el puntero de x (contiene la direccion de memoria de x) *p --> *p = x *p es el valor de x i := 42 p := &i // P es un puntero a i fmt.Println(*p) // 42 , lee i a traves del puntero p *p = 21 // establece i a traves del puntero p func main() { v := *getPointer() fmt.Println(\"Value is\", v) // Value is 100 m := getPointer() fmt.Println(\"Memory is\", m) // Memory is 0xc00018c020 } func getPointer() (myPointer *int) { a := 100 return &a } func main() { x := 5 zero(&x) fmt.Println(x) // x is 0 } func zero(x *int) { *x = 0 } func main() { var i int = 7 var p *int p = &i fmt.Println(\"i : \" , i) fmt.Println(\"memory address of i : \", &i) fmt.Println(\"p : \" , p) fmt.Println(\"*p : \" , *p) } [output] i : 7 memory address of i : 0x10328000 p : 0x10328000 *p : 7 new new - coge un tipo como argumento, asigna suficiente memoria para ese tipo de dato y devuelve un puntero que apunta a esa memoria. Luego el GC (garbage collector lo limpia todo) func zero(x *int) { *x = 5 } func main() { x := new(int) zero(x) fmt.Println(*x) // x is 5 } Mutabilidad Solo las constantes son inmutables. Sin embargo como los argumentos se pasan por valor, una funcion que recibe y modifica un argumento no muta el valor original Ejemplo func addOne(x int) { x++ } func main() { x := 0 addOne(x) fmt.Println(x) // x da 0 } // Si usamos punteros func addOne(x *int) { *x++ } func main() { x := 0 addOne(&x) fmt.Println(x) // x da 1 } LECTURA FUNDAMENTAL, stackoverflow pointer vs values type data struct { val int } func myfunc() data { // devuelve una copia del struct return data{val: 1} } func myfunc() *data { // devuelve un puntero al struct creado dentro de la funcion return &data{} } func myfunc(d *data) { // recibe un struct ya existente y sobreescribe su valor d.val = 1 }","title":"Punteros"},{"location":"golang/#datos-basicos","text":"","title":"DATOS BASICOS"},{"location":"golang/#numeros","text":"Cuando se definen numeros de forma literal se puede usar guion bajo _ para hacerlos mas legibles const segundosEnUnA\u00f1o = 31_557_600 Integers Los enteros son numeros sin decimal int - positivos y negativos uint - unsigned, solo los positivos byte - alias de uint8 (0-255) rune - alias de int32 Numeros de Punto Flotante Son numeros reales (con parte decimal) float32 - conocido como simple precision float64 - conocido como doble precision Numeros Complejos complex64 - parte real float32 + partes imaginarias complex128 - parte real float64 + partes imaginarias","title":"Numeros"},{"location":"golang/#booleanos","text":"&& - and || - or ! - not","title":"Booleanos"},{"location":"golang/#cadenas","text":"Estan hechas de bytes (uno por caracter) La diferencia entre comillas simples o dobles es que en estas no pueden contener nuevas lineas y se permiten escapar caracteres especiales len(string) - longitud de la cadena \"Hola mundo\"[1] - acceder a caracteres de la cadena \"Hello, \" + World\"","title":"Cadenas"},{"location":"golang/#constantes","text":"Se declaran como variables pero con la palabra clave const . No se pueden declarar usando := Solo pueden ser caracteres, string, booleano o valores numericos. const PI = 3.14","title":"Constantes"},{"location":"golang/#iota","text":"iota info Es un identificador usado en declaraciones de constantes para indicar que son autoincrementables. . Se resetea a cero cuando aparece la palabra reservada const const ( // iota is reset to 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 )","title":"Iota"},{"location":"golang/#estructuras-de-control","text":"","title":"ESTRUCTURAS DE CONTROL"},{"location":"golang/#for","text":"for init; condition; post { } // for normal sum := 0 for i := 0; i < 10; i++ { sum = sum + i } for condition { } // for sin declaraciones pre/post que funciona como un while. Podemos // tambien quitar hasta los punto y coma sum := 1 for ; sum < 1000; { for sum < 1000 { sum = sum + sum } for {} // for infinito for { ..codigo }","title":"for"},{"location":"golang/#if","text":"if answer != 42 { return \"Wrong answer\" } if err := foo(); err != nil { panic(err) } if { // codigo } else { // codigo }","title":"if"},{"location":"golang/#switch","text":"switch en golang Solo se pueden comparar valores del mismo tipo declaracion default para ejecutarse si todas las demas fallan en la declaracion se puede usar una expression (pej calcular un valor) case 300 - 150: Se puede tener multiples valores un solo caso case 6, 7: fallthroguh se ejecutan todas las declaraciones que cumplen la condicion break sale del switch, por defecto en cada opcion es automatico el break t := time.Now() switch { case t.Hour() < 12: fmt.Println(\"Good morning!\") case t.Hour() < 17: fmt.Println(\"Good afternoon.\") default: fmt.Println(\"Good evening.\") } switch os := runtime.GOOS; os { case \"darwin\": fmt.Println(\"OS X.\") case \"linux\": fmt.Println(\"Linux.\") default: // freebsd, openbsd,plan9, windows... fmt.Printf(\"%s.\\n\", os) }","title":"switch"},{"location":"golang/#range","text":"Para iterar sobre array , slice , string , map o leer de un channel El valor que nos da range es una copia del valor del elemento original y por tanto si se modifica no afecta al original for k,v := range zoo { v.age = 10 // no modifica el original zoo[k].age = 999 // SI modifica el original } slice var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key, value := range pow { fmt.Println(\"Posicion\", key, \"valor\", value) } Podemos omitir el index o el value usando _ for i, _ := range pow for _, value := range pow Podemos omitir tambien el valor omitiendo por completo , value var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key := range pow { fmt.Println(\"Posicion\", key) } for _, value := range pow { fmt.Println(\"valor\", value) } map El primer parametro no es un entero autoincrementable sino la clave del map for key, value := range cities break Paras la iteracion en cualquier momento continue Omites una iteracion","title":"range"},{"location":"golang/#arrays","text":"tipo [n]T - es un array de n elementos de tipo T No se pueden redimensionar Se pueden inicializar al declararlos a := [2]string{\"hello\", \"world!\"} a := [...]string{\"hello\", \"world!\"} usando una ellipsis para indicar un numero variable de elementos que en este caso son dos a := [5]int{1: 10, 2: 20} - inicializando solo algunos valores Mostrar arrays fmt.Printf(\"%q\\n\", a) // [\"hello\" \"world!\"] len(array) MultiDimensionales var a [4][2]int array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}","title":"ARRAYS"},{"location":"golang/#slices","text":"tipo []T - es un slice de elementos de tipo T Crear un slice : Los slice hay que crearlos antes de usarlos slice literal mySlice := []int{2, 3, 5, 7, 11, 13} make - crea un slice vacio de una longitud y (opcional una capacidad) cities := make([]string, len, cap) Recortando un slice s[a:b] - selecciona elementos desde la pos a (inclusive) hasta b (exclusive) s[:b] - un indice a que no se declara es un 0 implicito s[a:] - un indice b que no se declara es implicito un len(s) A\u00f1adiendo a un slice cities = append(cities, \"San Diego\") cities = append(cities, \"San Diego\", \"Mountain View\") otherCities := []string{\"Santa Monica\", \"Venice\"} cities = append(cities, otherCities...) Copiar un slice copy(destino, origen) Length len(slice) Nil slices Declaracion var z []int - El valor cero de un slice es nil. Un slice nil tiene una longitud de cero Inicializacion z := make([]int, 0) z := []int{} Las tres formas son lo mismo BiDimensional // allocate composed 2d array a := make([][]int, row) for i := range a { a[i] = make([]int, col) } // allocate composed 2d array a := make([][]int, row) e := make([]int, row * col) for i := range a { a[i] = e[i*col:(i+1)*col] } // otra posibilidad func get(r, c int) int { return e[r*cols+c] }","title":"SLICES"},{"location":"golang/#maps","text":"tipo map[a]b - es un map de claves tipo a con valores tipo b Formado por pares clave/valor Crear un map : Los map hay que crearlos antes de usarlos map literal amigos := map[string]int{\"Juan\":50, \"Elena\":21, \"Carlos\":41,} make - creas un nil map vacio amigos := make(map[string]int) Si lo declaramos pero no lo inicializamos, al intentar a\u00f1adir elementos no compilara amigos := map[string]int{} - declarado pero no inicializado Modificando maps m[key] = elem - Insertando o actualizando un valor elem = m[key] - Devuelve el elemento delete(m, key) - Borrando un elemento elem, ok = m[key] - Testea si existe un valor con una clave determinada elements := map[string]map[string]string{ \"H\": map[string]string{ \"name\":\"Hydrogen\", \"state\":\"gas\", }, \"He\": map[string]string{ \"name\":\"Helium\", \"state\":\"gas\", }, \"Li\": map[string]string{ \"name\":\"Lithium\", \"state\":\"solid\", }, } if el, ok := elements[\"Li\"]; ok { fmt.Println(el[\"name\"], el[\"state\"]) }","title":"MAPS"},{"location":"golang/#structs","text":"Es una coleccion de campos/propiedades Solo los campos exportados (primera letra mayuscula) son accesibles de fuera del paquete","title":"STRUCTS"},{"location":"golang/#inicializacion","text":"type Circle struct { x, y, r float64 } var c Circle - crea una variable local Circle que pone por defecto los valores a cero (0 para int, 0.0 para float. \"\" para string, nil para punteros) c := new(Circle) - asigna memoria para todos los campos, los inicializa a cero y devuelve un puntero a la struct (*Circle), los punteros se usan mucho en structs paa que las funciones puedan modificar los datos. c := Circle{x: 0, y: 0, r: 5} c := Circle{0, 0, 5} c := &Circle{0, 0, 5} c := Circle{x: 1} c := Circle{} type Circle struct { x, y, r float64 } func main() { fmt.Println(c.x, c.y, c.r) c.x = 10 c.y = 5 } // todo en uno var addCases = []struct { in string want string }{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // mas claro type addCases2 []struct { in string want string } ac := addCases2{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // para verlos for i, v := range addCases { fmt.Println(i, v.in) } for i, v := range ac { fmt.Println(i, v) } // con nombres fmt.Printf(\"%+v\\n\", struct) // bien formateado s, _ := json.MarshalIndent(g, \"\", \"\\t\") fmt.Print(string(s)) func show() { fmt.Println(t[0].hola) fmt.Println(test2[1].hola2) } type test []struct { hola string } var t = test{ {\"prueba1\"}, {\"prueba2\"}, } var test2 = []struct { hola2 string }{ {\"prueba3\"}, {\"prueba4\"}, }","title":"Inicializacion"},{"location":"golang/#metodos","text":"Un metodo es una funcion con el primer argumento implicito llamado receptor. func (ReceiverType r) func_name (parameters) (results) El receptor (receiver) del metodo esta entre la palabra clave function y el nombre del metodo func (u User) Greeting() string - nos permite llamarla con u.Greeting() Organizacion del codigo package models // list of packages to import // list of constants // list of variables // Main type(s) for the file, // try to keep the lowest amount of structs per file when possible. // List of functions // List of methods Alias Para definir metodos en un tipo que no es tuyo se usan alias import \"strings\" type MyStr string func (s MyStr) Uppercase() string { return strings.ToUpper(string(s)) } func main() { fmt.Println(MyStr(\"test\").Uppercase()) } Usar punteros en los receptores Los metodos se pueden asociar a un nombre o a puntero. Ventajas de usar punteros: evitar copiar el valor con cada llamada al metodo (pasarlo por referencia) para poder modificar el valor que pasamos type User struct { name string email string } func (u user) notify() { fmt.Printf(\"Mandar correo a %s<%s>\\n\", u.name, u.email) } // sin el puntero del receptor el correo no se cambiaria. func (u *user) changeEmail(email string) { u.email = email } SUGERENCIA Despu\u00e9s de declarar un nuevo tipo, trate de responder a esta pregunta antes de declarar m\u00e9todos para el tipo: \u00bf A\u00f1adir o quitar algo de un valor de este tipo necesita crear un nuevo valor o mutar el existente ? - Si la respuesta es crear un nuevo valor, usa receptores de valor en sus m\u00e9todos. - Si la respuesta es mutar el valor, usa receptores de puntero. Esto tambi\u00e9n se aplica a la forma en que los valores de este tipo deben pasarse a otras partes de su programa. Es importante ser consistente. La idea es no centrarse en lo que el m\u00e9todo est\u00e1 haciendo con el valor, sino centrarse en cu\u00e1l es la naturaleza del valor.","title":"Metodos"},{"location":"golang/#composicion","text":"type User struct { Id int Name, Location string } type Player struct { User GameId int } Podemos acceder a la Struct de User: a := new(Player) a.User.Name a.Name","title":"Composicion"},{"location":"golang/#interfaces","text":"Explicacion de interfaces Mas Explicacion de interfaces Mas aun sobre interfaces Es un conjunto de metodos Es un tipo de datos package main import \"fmt\" type cat struct { name string } func (c *cat) born() { fmt.Println(c.name, \"is born Miaouu\") } type dog struct { name string } func (d *dog) born() { fmt.Println(d.name, \"is born Wharff\") } type animal interface { born() } func born(a animal) { a.born() } func main() { Jasper := &cat{\"JASPER\"} Lucy := &dog{\"Lucy\"} Max := new(dog) Max.name = \"Max\" Max.born() // call born function born(Jasper) born(Lucy) born(Max) } package main import \"fmt\" type Human struct { name string age int phone string } type Student struct { Human //an anonymous field of type Human school string loan float32 } // A human likes to stay... err... *say* hi func (h *Human) SayHi() { fmt.Printf(\"Hi, I am %s you can call me on %s\\n\", h.name, h.phone) } // A human can sing a song, preferrably to a familiar tune! func (h *Human) Sing(lyrics string) { fmt.Println(\"La la, la la la, la la la la la...\", lyrics) } // A Human man likes to guzzle his beer! func (h *Human) Guzzle(beerStein string) { fmt.Println(\"Guzzle Guzzle Guzzle...\", beerStein) } // A Student borrows some money func (s *Student) BorrowMoney(amount float32) { s.loan += amount // (again and again and...) } func Prestar(y YoungChap, amount float32) { y.BorrowMoney(amount) } // INTERFACES type Men interface { SayHi() Sing(lyrics string) Guzzle(beerStein string) } type YoungChap interface { SayHi() Sing(song string) BorrowMoney(amount float32) } func main() { mike := Student{Human{\"Mike\", 25, \"222-222-XXX\"}, \"MIT\", 150.50} mike.BorrowMoney(10) mike.BorrowMoney(10) Prestar(&mike, 100) fmt.Println(\"Debe ..\", mike.loan) } interfaces vacias 1- Todo tiene un type , puedes definir un nuevo type por ejemplo T que tiene tres metodos A , B y C 2- El conjunto de metodos especificos de un type se llama interface type . En nuestro ejemplo T_interface = (A, B, C) 3- Puedes crear un nuevo interface type definiendo los metodos que tiene. Pro ejemplo creo MyInterface = (A) 4- Cuando especificas una variable de tipo interface type le puedes asignar solo los tipos que esten en una interface que sea un superset de tu interface, vamos que todos los metodos de MyInterface deben estar en T_interface Conclusion : Todos los tipos de variables satisfacen la empty interface . Por tanto una funcion que tiene una interface{} como argumento admite cualquier valor sea el que sea. Pero dentro de la funcion el runtime de Go convierte ese valor a un valor interface{} func DoSomething(v interface{}) { // la funcion acepta cualquier valor una vez dentro // v es del tipo interface{} } EL valor de una interfaz son dos word de datos: - una word es un puntero a una tabla de metodos para el valor del type subyacente - la otra word es un puntero a los datos actuales de ese valor","title":"INTERFACES"},{"location":"golang/#funciones","text":"Call Stack func main() { fmt.Println(f1()) } func f1() int { return f2() } func f2() int { return 1 } Argumentos Argumentos que reciben. Las funciones pueden recibir 0 o mas argumentos todos tipados despues del nombre de la variable. func add(x int, y int) int { return x + y } func add(x, y int) int { // int afecta a todos los parametros (x, y) return x + y } // ... funciones que aceptan un numero variable de parametros func add(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { // pasamos los parametros que queramos fmt.Println(add(1,2,3)) xs := []int{1,2,3} fmt.Println(add(xs...)) // tambien podemos pasar un slice } Retorno de parametros, puede devolver cualquier numero de ellos return region, continente // devuelve mas de un valor // Si los parametros de retorno estan nombrados vale con solo return func location(name, city string) (region, continent string) { ..codigo return // devuelve region y continent } Closures func generadorPares() func() uint { i := uint(0) return func() (ret uint) { ret = i i = i + 2 return } } func main() { nextPar := generadorPares() fmt.Println(nextPar()) // 0 fmt.Println(nextPar()) // 2 fmt.Println(nextPar()) // 4 } Recursion func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) }","title":"FUNCIONES"},{"location":"golang/#type-function","text":"package main import \"fmt\" type test_int func(int) bool // isOdd takes an ints and returns a bool set to true if the // int parameter is odd, or false if not. // isOdd is of type func(int) bool which is what test_int // is declared to be. func isOdd(integer int) bool { if integer%2 == 0 { return false } return true } // Same comment for isEven func isEven(integer int) bool { if integer%2 == 0 { return true } return false } // We could've written: // func filter(slice []int, f func(int) bool) []int func filter(slice []int, f test_int) []int { var result []int for _, value := range slice { if f(value) { result = append(result, value) } } return result } func main(){ slice := []int {1, 2, 3, 4, 5, 7} fmt.Println(\"slice = \", slice) odd := filter(slice, isOdd) fmt.Println(\"Odd elements of slice are: \", odd) even := filter(slice, isEven) fmt.Println(\"Even elements of slice are: \", even) }","title":"type function"},{"location":"golang/#defer","text":"Aplaza la ejecucion de una funcion hasta que termina la funcion en la que se encuentra. Lo tipico es cerrar archivos o desbloquear un mutex(mutual exclusion, para asegurar que solo una goroutine puede acceder a la vez a una variable) func main() { defer fmt.Println(\"world\") fmt.Println(\"hello\") } Se usa para liberar recursos cuando se pueda f, _ := os.Open(filename) defer f.Close()","title":"defer"},{"location":"golang/#panic-recover","text":"panic(\"valor de panic\") - crea un runtime error . recover() - detiene el panic y devuelve el valor que fue pasado con la llamada a panic Un panic generalmente indica un error de programacion o una condicion excepcional de la que no hay forma facil de recuperarse func main() { defer func() { str := recover() fmt.Println(str) }() panic(\"PANIC\") }","title":"panic, recover"},{"location":"golang/#concurrencia","text":"","title":"CONCURRENCIA"},{"location":"golang/#goroutines","text":"go f(x) comienza la ejecucion de una nueva goroutine que es una funcion capaz de ejecutarse concurrentemente con otras funciones. // sin wait, el programa main puede acabar antes de que las goroutines // hagan lo que tengan que hacer func parallelLetFreq() { var wg sync.WaitGroup wg.Add(3) // suma 3 a las goroutines a esperar go count(\"1\", &wg) go count(\"2\", &wg) go count(\"3\", &wg) wg.Wait() // espera a todas las goroutines (3 en este caso) } func count(n int, wg *sync.WaitGroup) { defer wg.Done() // al terminar la funcion terminar goroutine fmt.Println(\"Number --> \", n)) }","title":"goroutines"},{"location":"golang/#channels","text":"channels - son un conducto a traves del cual puedes recibir y enviar datos con el operador <- ch <- data - Envia data al canal ch data := <-ch - Recibe informacion del canal ch y lo asigna a data ch := make(chan int) - Los canales hay que crearlos antes de usarlos Por defecto los envios y recepciones esperan hasta que el otro lado este listo. Esto permite a las goroutines sincronizarse sin bloqueos especificos o condiciones func sum(a []int, c chan int) { sum := 0 for _, v := range a { sum += v } c <- sum // send sum to c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) } Buffered channels ch := make(chan int, 100) - Ponemos un buffer a los canales indicando su longitud como segundo argumento en el make para inicializar el canal Enviar datos aun canal con buffer se bloquea si el buffer esta lleno Recibir datos de un canal con buffer se bloquea si el buffer esta vacio func main() { c := make(chan int, 2) c <- 1; c <- 2; c <- 3 fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } // fatal error: all goroutines are asleep - deadlock! Sin embargo el siguiente funcionaria. Al a\u00f1adir el valor extra desde una goroutine no se bloquea el hilo principal pues aunque la goroutine se llama antes que el canal se vacie esta esperara hasta que haya espacio en el canal. func main() { c := make(chan int, 2) c <- 1; c <- 2 c3 := func() { c <- 3 } go c3() fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } Close close(ch) - Solo un emisor puede cerrar un canal. Enviar a un canal cerrado causa un panic. No son como ficheros que hace falta cerrarlos. Solo se cierran para avisar al receptor de que no llegaran mas datos y para terminar los loop range v, ok := <-ch - Un emisor puede cerrar un canal para indicar que no se enviara nada mas. Los receptores pueden testear cuando un canal ha sido cerrado asignando un segundo parametro a la expresion receptora ok sera falso cuando no haya mas valores que recibir y el canal este cerrado. for i := range ch - recibe valores del canal hasta que se cierre Select Es como switch pero con canales 1A - 89 1B - 103","title":"channels"},{"location":"golang/#modules","text":"go mod init nombreModulo go mod init github.com/jolav/nombreModulo // listar todos los modulos con sus dependencias go list -m all go list all ./... // chechear paquetes con actualizaciones go list -m -u all go list -m -u -json all // actualizar // cambiar manualmenrte el archivo go.mod o // actualiza todas salvo nueva version mayor, go get -v -u ./... // para versiones especificas o nueva version mayor go get -v -u github.com/user/repo@v1.1.1 //despues para asegurar que el el codigo que tenemos en el modulo coincide // con el archivo gp.mod ejecutamos go mod tidy","title":"MODULES"},{"location":"golang/#paquetes","text":"Un programa Go esta hecho con paquetes. Los programas empiezan ejecutando la funcion main dentro del paquete main . Por convencion el nombre del paquete es la ultima palabra de la ruta del import. El paquete \"math/rand\" comprende archivos que comienzan con la sentencia package rand Paquetes que no son de la libreria estandar se importan usando una URL web, pero antes hay que descargarlos con go get go get github.com/creador/ruta/al/paquete import \"github.com/creador/ruta/al/paquete\" Despues de importar un paquete podemos usar los nombres que el exporta (sean variables, metodos o funciones) desde fuera de el paquete. Los nombres exportados en Go comienzan por letra mayuscula package main import ( \"fmt\" \"math\" ) func main() { fmt.Println(math.Pi) fmt.Println(math.pi) } // cannot refer to unexported name math.pi Otras formas de importar paquetes \u00ecmport alias \"fmt\" - Crea un alias de fmt. Ahora es alias.LoQueSea en lugar de fmt.LoQueSea import . \"fmt\" - Permite acceder al contenido directamente sin tener que ir precedido de fmt import _ \"fmt\" - Elimina las advertencia del compilado sobre ese paquete si no se usa y ejecuta si hay las funciones de inicializacion ( func init() {} ), El resto del paquete permanece inaccesible.","title":"PAQUETES"},{"location":"golang/#crear-paquetes","text":"Los nombres de paquetes coinciden con la carpeta donde estan. Esto se puede cambiar pero no merece la pena Por convencion el nombre del paquete es la ultima palabra de la ruta del import. ~/src/proyectoX/main.go package main import \"fmt\" import \"proyectoX/utilidades\" // la ruta es a partir de srcs func main() { // llamada a utilidades.Media(xs) } ~/src/proyectoX/utilidades/media.go package utilidades func Media() { // codigo que sea }","title":"Crear paquetes"},{"location":"golang/#desinstalar-paquetes","text":"go clean -i ruta/paquete... - teoricamente borras los pkg y bin, los src hay que borrarlos manualmente","title":"Desinstalar paquetes"},{"location":"golang/#actualizar","text":"go get -u all - Actualiza todos go get -u full/package/name - Actualizar solo ese paquete","title":"Actualizar"},{"location":"golang/#ejecucion","text":"El programa se inicia por la funcion main del package main Antes se ejecutan las funciones init de ese fichero Los paquetes importados \"_ import \"ruta/paquete\" hacen que el compilador acepte un paquete que no se usa y ademas ejecutan la o las funciones init de ese paquete","title":"EJECUCION"},{"location":"golang/#testing","text":"El compilador ignora todos los archivos que terminan en _test.go ~/src/proyectoX/utilidades/media_test.go package utilidades import \"testing\" type testpair struct { values []float64 average float64 } var tests = []testpair{ {[]float64{1, 2}, 1.5}, {[]float64{1, 1, 1, 1, 1, 1}, 1}, {[]float64{-1, 1}, 0}, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Media(pair.values) if v != pair.average { t.Error( \"For\", pair.values, \"expected\", pair.average, \"got\", v, ) } } } go test","title":"TESTING"},{"location":"golang/#errors","text":"Errores en Go Los captura un tipo interfaz predefinido cuyo unico metodo Error devuelve una cadena type error interface { Error() string } Forma estandard de tratar los errores. log.Fatal(err) - manda el error a la terminal y detiene el programa f, err := os.Open(\"filename.ext\") if err != nil { log.Fatal(err) } Podemos aligerar la repeticion un poco usando: func check(e error) { if e != nil { panic(e) } } // y ahora ya solo ponemos check(err)","title":"ERRORS"},{"location":"golang/#libreria-estandar","text":"","title":"LIBRERIA ESTANDAR"},{"location":"golang/#fmt","text":"import \"fmt\" fmt.Print() - imprime fmt.Println() - imprime y salta de linea fmt.Printf() - imprime con un determinado formato type point struct { x, y int } p := point{1, 2} fmt.Printf(\"%v\\n\", p) // {1 2} // en una struct, `%+v` incluye los nombres de los campos de la struct fmt.Printf(\"%+v\\n\", p) // {x:1 y:2} // Imprimir el tipo de un valor fmt.Printf(\"%T\\n\", p) // main.point // `%d` para enteros standard fmt.Printf(\"%d\\n\", 123) // 123 // Imprime el caracter que corresponde al entero fmt.Printf(\"%c\\n\", 65) // a // Imprime floats fmt.Printf(\"%f\\n\", 78.9) // 78.90000 // Imprime string basicas `%s`. fmt.Printf(\"%s\\n\", \"\\\"string\\\"\") // \"string\" // Imprimir Booleano fmt.Printf(\"%t\\n\", a ==b) // true o false // Imprime un puntero`%p`. fmt.Printf(\"%p\\n\", &p) // 0x42135100 fmt.Sprint() - devuelve el resultado a una string fmt.Sprintln() - devuelve el resultado con salto de linea a una string fmt.Sprintf() - devuelve el resultado con un determinado formato a una string // las Sxxx() son como las normales en vez de imprimir el resultado // lo devuelven como un string s := fmt.Sprintf(\"Hi, my name is %s and I'm %d years old.\", \"Bob\", 23) // s vale \"Hi, my name is Bob and I'm 23 years old.\" fmt.Scan() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea cuentan como espacio fmt.Scanln() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea acaban con la lectura de datos verbos - General %v - valor en formato por defecto. En structs %+v a\u00f1ade los nombres de los campos %T - tipo del valor %#v - representacion del tipo del valor con sintaxis de golang - Booleano %t - booleano, devuelve palabra true o false - Integer %b - devuelve en base 2 %c - devuelve caracter representado por el correspondiente codigo Unicode %d - devuelve en base 10 %U - formato Unicode - Floating point f% - notacion decimal sin exponentes e% - notacion decimal con exponentes - Strings y []byte %s - cadenas normales %q - para escapar comillas dobles %x - convierte a base hexadecimal","title":"FMT"},{"location":"golang/#strings","text":"import \"strings\" strings.Contains(\"test\", \"es\") = true - Contiene \"test\" a \"es\" strings.Count(\"test\", \"t\") = 2 - Cuantas \"t\" hay en \"test\" strings.HasPrefix(\"test\", \"te\") = true - Comienza \"test\" por \"te\" strings.HasSuffix(\"test\", \"st\") = True - Acaba \"test\" en \"st\" strings.Index(\"test\", \"e\") = 1 - Posicion de string \"e\" dentro de string \"test\", si no esta devuelve -1 strings.Join([]string{\"a\",\"b\"}, \"-\") = \"a-b\" - Coge una lista de strings y las junta en una separadas por otra string (\"-\" en el ejemplo) strings.Repeat(\"a\", 5) = aaaaa - Repite una string n veces strings.Replace(\"aaaa\", \"a\", \"b\", 2) = \"bbaa\" - reemplaza en una cadena una parte por otra n veces (o todas las que se pueda si pasamos -1) strings.Split(\"a-b-c-d-e\", \"-\") = []string{\"a\",\"b\",\"c\",\"d\",\"e\"} - Parte una string en un array de strings usando otra string como separador strings.ToLower(\"test\") = \"TEST \"- convierte la cadena a minusculas strings.ToUpper(\"TEST\") = \"test\" - convierte la cadena a mayusculas strings.Fields(\"cadena que sea) = como split usando espacios en blanco. es equivalente a si usaramos strings.Split(text, \" \") strings.Trim(\"cadena\",\"loquecorta\") = elimina en cadena todas las loquecorta pero solo del comienzo y del final strings.Trim(\" !!! Achtung! Achtung! !!! \", \"! \") == [\"Achtung! Achtung\"] Convertir string en slice of bytes y viceversa arr := []byte(\"test\") str := string([]byte{'t','e','s','t'}) Fuera del paquete string len(\"aquiunacadena\") - nos da la longitud de la string \"cadena\"[3] - nos da el codigo ASCII del caracter de indice 3, \"e\" = 101 string(cadena[n]) - nos da el caracter de la cadena en la posicion n","title":"STRINGS"},{"location":"golang/#strconv","text":"import \"strconv\" - conversiones entre numeros y strings s := strconv.Itoa(-42) - int to string i, err := strconv.Atoi(\"-42\") - string to int b, err := strconv.ParseBool(\"true\") - string to boolean f, err := strconv.ParseFloat(\"3.1415\", 64) - string to float i, err := strconv.ParseInt(\"-42\", 10, 64) - string to int u, err := strconv.ParseUint(\"42\", 10, 64) - string to uint s := strconv.FormatBool(true) - boolean value to string s := strconv.FormatFloat(3.1415, 'E', -1, 64) - float to string s := strconv.FormatInt(-42, 16) - int to string s := strconv.FormatUint(42, 16) - uint to string","title":"STRCONV"},{"location":"golang/#append","text":"Trucos con slices func append(slice []T, elements...T) []T.","title":"APPEND"},{"location":"golang/#io","text":"import \"io\" Tiene dos interfaces principales Reader soporta leer a a traves del metodo Read Writer soporta escribir a traves del metodo Write","title":"IO"},{"location":"golang/#ioioutil","text":"import io/ioutil leer y escribir un archivo De esta forma cargamos todo el archivo en memoria de golpe. Mas control a traves de un File struct del paquete OS data := []byte(\"Hello World!\\n\") // write err := ioutil.WriteFile(\"data1\", data, 0644) if err != nil { panic(err) } //read read, err := ioutil.ReadFile(\"data1\") if err != nil { return } fmt.Print(string(read1)) Limitar tama\u00f1o io defer resp.Body.Close() limitReader := &io.LimitedReader{R: resp.Body, N: 2e6} // (2mb) body, err := ioutil.ReadAll(limitReader)","title":"IO/IOUTIL"},{"location":"golang/#os","text":"import \"os\" Saber donde estamos os.Getwd() leer escribir un archivo // Una forma file, err := os.Open(\"test.txt\") if err != nil { // handle the error here } defer file.Close() stat, err := file.Stat() // get the file size if err != nil { return } bs := make([]byte, stat.Size()) // read the file _, err = file.Read(bs) if err != nil { return } str := string(bs) fmt.Println(str) // otra forma data := []byte(\"Hello World!\\n\") // write to file and read from file using the File struct file1, _ := os.Create(\"data2\") defer file1.Close() bytes, _ := file1.Write(data) fmt.Printf(\"Wrote %d bytes to file\\n\", bytes) file2, _ := os.Open(\"data2\") defer file2.Close() read2 := make([]byte, len(data)) bytes, _ = file2.Read(read2) fmt.Printf(\"Read %d bytes from file\\n\", bytes) fmt.Println(string(read2)) crear un archivo func main() { file, err := os.Create(\"test.txt\") if err != nil { return } defer file.Close() file.WriteString(\"test\") } Leer el contenido de un directorio Readdir - coge un argumento que es el numero de entradas que devuelve. Con -1 devuelve todas func main() { dir, err := os.Open(\".\") if err != nil { return } defer dir.Close() fileInfos, err := dir.Readdir(-1) if err != nil { return } for _, fi := range fileInfos { fmt.Println(fi.Name()) } } Walk - para recorrer recursivamente un directorio. Pertenece al paquete path/filepath Command line arguments el primer valor del slice de argumentos es el nombre del comando path incluido argsWithProg := os.Args - slice completo con comando nombre path incluido argsWithoutProg := os.Args[1:] - slice solo de argumentos arg := os.Args[x] - devuelve argumento de posicion X environment variables os.Setenv(\"nombreVariable\", \"valor\") - establece un par clave/valor para una variable de entorno os.Getenv(\"nombreVariable\") - devuelve el valor de esa clave // os.Environ es una lista de todas las variables de entorno for _, e := range os.Environ() { pair := strings.Split(e, \"=\") fmt.Println(pair[0], \"-->\", pair[1]) }","title":"OS"},{"location":"golang/#pathfilepath","text":"import path/filepath Recorrer recursivamente un directorio Walk func main() { filepath.Walk(\".\", func(path string, info os.FileInfo, err error) error { fmt.Println(path) return nil }) }","title":"PATH/FILEPATH"},{"location":"golang/#regexp","text":"import \"regexp\" // Comprueba si es una cadena patron := \"loquequeremoscomprobar\" match, _ := regexp.MatchString(\"p([a-z]+)ch\", patron) fmt.Println(match) // o compilamos primero una struct optimizada para regexp patron := \"loquequeremoscomprobar\" r, _ := regexp.Compile(\"p([a-z]+)ch\") fmt.Println(r.MatchString(patron)) // Por ejemplo cambiar en la cadena s los guiones bajos por guiones r := regexp.MustCompile(\"_\") s = r.ReplaceAllString(s, `-`)","title":"REGEXP"},{"location":"golang/#json","text":"import \"encoding/json\" Golang JSON dataJson, err := json.Marshal(structObject) - Go struct data to JSON data dataJson, err:= json.MarshalIndent(strObj, \"\", \" \") - bien preformateado err := json.Unmarshal(dataJson, &structObject) - JSON data to Go struct data urlDir := \"https://domain.tld/api/que/queramos\" resp, err := http.Get(urlDir) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } body = body[5 : len(body)-6] // quitar mis pegatinas de 
         var s structObject err = json.Unmarshal(body, &s) fmt.Println(s) Convertir json to go struct JSON-to-Go online json:\"-\" ignora ese campo tanto al convertir a json o al convertir desde json json:\"nombreCampo,omitempy - no se incluye el campo al convertir a json si ese campo ya tiene un valor por defecto. Decoder Ademas de Unmarshal/Marshal existe Decoder/Encoder , que se debe usar si los datos vienen de una stream io.Reader como por ejemplo el Body de una http.Request. Si los datos estan en una string o en memoria mejor usar Unmarshal type configuration struct { lo que sea } file, _ := os.Open(\"conf.json\") defer file.Close() decoder := json.NewDecoder(file) conf := configuration{} err := decoder.Decode(&conf) if err != nil { fmt.Println(\"Error:\", err) } fmt.Println(conf) Parsing Interfaces An\u00e1lisis de una interfaz Si realmente no tienes ni idea de c\u00f3mo podr\u00eda ser tu JSON, se puede analizar en una interfaz gen\u00e9rica{}. Una interfaz vac\u00eda es una forma de definir una variable en Go como \"esto podr\u00eda ser cualquier cosa\". En tiempo de ejecuci\u00f3n, Go asignar\u00e1 la memoria adecuada para que se ajuste a lo que decida almacenar en ella. Esto es lo que parece: var parsed interface{} err := json.Unmarshal(data, &parsed) En realidad, el uso de parsed es un poco laborioso, ya que Go no puede usarlo sin saber de qu\u00e9 tipo es. switch parsed.(type) { case int: someGreatIntFunction(parsed.(int)) case map: someMapThing(parsed.(map)) default: panic(\"JSON type not understood\") } Tambi\u00e9n puedes hacer aserciones de tipo similares en l\u00ednea: intVal, ok := parsed.(int) if !ok { panic(\"JSON value must be an int\") } Afortunadamente, sin embargo, es raro no tener idea de lo que puede ser un valor. Si, por ejemplo, sabe que su valor JSON es un objeto, puedes analizarlo en una interfaz de map[string]interface{}. Esto te da la ventaja de poder referirte a claves espec\u00edficas. Un ejemplo: var parsed map[string]interface{} data := []byte(` { \"id\": \"k34rAT4\", \"age\": 24 } `) err := json.Unmarshal(data, &parsed) A continuaci\u00f3n, puedes referirte a las teclas espec\u00edficas sin ning\u00fan problema: parsed[\"id\"] Sin embargo, todav\u00eda tienes interfaces como valor de su map, por lo que debes hacer type assertions para utilizarlas: idString := parsed[\"id\"].(string) Go utiliza estos seis tipos para todos los valores analizados en las interfaces: bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null Es decir, tus n\u00fameros siempre ser\u00e1n de tipo float64, y necesitar\u00e1n ser casteados a int, por ejemplo. Si tiene una necesidad de obtener enteros directamente, puedes usar el m\u00e9todo UseNumber. Lo que te da un objeto que puede convertirse en un float64 o en un int a tu discreci\u00f3n. De manera similar, todos los objetos decodificados en una interfaz ser\u00e1n map[string]interface{}, y necesitar\u00e1n ser mapeados manualmente a cualquier estructura aue quieras usar. Sobre JSON","title":"JSON"},{"location":"golang/#time","text":"import \"time\" now := time.Now() - nos da la hora actual 2012-10-31 15:50:13.793654 +0000 UTC then := time.Date(2015, 10, 10, 18, 30, 08, 0, time.UTC) - Creamos un struct de tiempo asociado a una localizacion (time zone) then.Year() then.Month() then.Day() then.Hour() then.Minute() then.Second() then.Nanosecond() then.Location() then.Weekday() then.Before(now) then.After(now) then.Equal(now) diff := now.Sub(then) - metodo Sub devuelve duracion del intervalo entre dos tiempos diff.Hours() diff.Minutes() diff.Seconds() diff.Nanoseconds() // avanzar o retroceder en el tiempo then.Add(diff) then.Add(-diff) // sumar tiempo tiempoQueSea.Add( 1000 * time.Hours) String to Time // pasar una fecha a string segun un determinado formato layout := \"2006-01-02 15:04:05\" t, err := time.Parse(layout1, start) if err != nil { fmt.Prinltln(err) } // Hora actual a string con determinado formato horaActual = time.Now().Format(layout) Time to String myString = myTime.String() Timestamp Unix epoch now := time.Now() secs := now.Unix() nanos := now.UnixNano() millis := nanos / 1000000 time.Unix(secs, 0) time.Unix(0, nanos) Intervalos timers - para hacer algo una vez dentro de un tiempo timer1 := time.NewTimer(time.Second * 2) <-timer1.C fmt.Println(\"Timer 1 expired\") timer2 := time.NewTimer(time.Second) go func() { <-timer2.C fmt.Println(\"Timer 2 expired\") }() stop2 := timer2.Stop() if stop2 { fmt.Println(\"Timer 2 stopped\") } // Timer 1 expired // Timer 2 stopped // Timer 2 expired NUNCA APARECE, se cancela antes tickers - para hacer algo repetidamente a intervalos regulares ticker := time.NewTicker(time.Millisecond * 500) go func() { for t := range ticker.C { fmt.Println(\"Tick at\", t) } }() time.Sleep(time.Millisecond * 1600) ticker.Stop() fmt.Println(\"Ticker stopped\")","title":"TIME"},{"location":"golang/#math","text":"import \"math\" math.Floor(x float64) float64 - devuelve el entero (int) mas grande poisble menor o igual que x math.Pow(x,y float64) float64 - x elevado a y","title":"MATH"},{"location":"golang/#mathrand","text":"import \"math/rand\" rand.Intn(10) - genera un numero aleatorio entero >= 0 y < 10 rand.Float64() - genera un numero aleatorio >= 0.0 y < 1.0 (rand.Float64()*5)+5 - genera entre >= 5.0 y < 10.0 s1 := rand.NewSource(time.Now().UnixNano()) - semilla para que no sea siempre igual r1 := rand.New(s1) - para ir cambiando la semilla rand.Seed(time.Now().UTC().UnixNano()) - otra forma de cambiar la semilla para que no siempre sea igual func init() { //fmt.Println(`Init from package tracker`) r = rand.New(rand.NewSource(time.Now().UnixNano())) } var r *rand.Rand func createRandomString() string { const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\" result := \"\" for i := 0; i < lenID; i++ { result += string(chars[r.Intn(len(chars))]) } return result }","title":"MATH/RAND"},{"location":"golang/#databasesql","text":"database/sql","title":"DATABASE/SQL"},{"location":"golang/#flag","text":"import \"flag\" Para enviar argumentos a un comando Ejemplos","title":"FLAG"},{"location":"golang/#sort","text":"import sort Contiene funciones para ordenar datos arbitrario de slices de ints y floats y structs definidas por el usuario s = []strings sort.strings(s) - De menor a mayor alfabeticamente n = []ints || float32 || float64 sort.Ints(n) - Ordena los numeros de menor a mayor sort.IntsAreSorted(n) - booleano que devuelve si estan ordenados custom sorting package main import \"sort\" import \"fmt\" // If I have an array/slice of structs in Go and want to sort them // using the sort package it seems to me that I need to implement // the whole sort interface which contains 3 methods: // https://golang.org/pkg/sort/#Interface type ByLength []string func (s ByLength) Len() int { return len(s) } func (s ByLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s ByLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) } func main() { fruits := []string{\"peach\", \"banana\", \"kiwi\"} sort.Sort(ByLength(fruits)) fmt.Println(fruits) }","title":"SORT"},{"location":"html/","text":"HTML FLEXBOX Buena Guia para usar Flexbox Patrones para Flexbox CSS GRID Aprender aqui gridbyexample.com SNIPPETS Plantilla    Title                   Validacion con HTML5 sin submit 
        document.getElementById('addUser').addEventListener('click', addNewUser); function addNewUser (ev) { ev.preventDefault(); const f = document.getElementsByTagName('form')[0]; if (f.checkValidity()) { const newUsername = document.getElementById('newUsername').value; const params = `username=${newUsername}`; makeAjaxRequest(addNewUserUrl, 'POST', params, null, function (data) { showUsersList(data); }); } else { alert(document.getElementById('newUsername').validationMessage); } } Disparar evento click con ENTER
        Button
        function init () { const button = document.getElementById('button'); button.addEventListener('click', action); const input = document.getElementById('inputText'); input.addEventListener('keyup', testEnter); } function testEnter (ev) { ev.preventDefault(); if (ev.keyCode === 13) { document.getElementById('button').click(); } } HTML5 ESTRUCTURA Titulo Block Elements Elementos que siempre empiezan en una nueva linea Inline Elements Elementos que aparecen a continuacion en la misma linea del anterior Caracteres de escape TEXTO white space collapsing : Dos o mas espacios o lineas juntos el navegador solo mostrara uno Elementos para estructurar la pagina

        paragraph

        headings bold italic superscript subscript
        line breaks
        horizontal rules Elementos semanticos contenido importante enfasis
        citar parrafos
        citas cortas dentro de un parrafo abreviaturas o acronimos referencia a algo (libro, peli ...) la primera explicacion de un termino en el documento
        para contener detalles de contacto de alguien
        mostrar contenido que ha sido insertado en el documento mostrar contenido que ha sido borrado en el documento indicar que algo ya no es relevante LISTAS Ordenadas
        1. primero
        2. segundo
        3. tercero
        primero segundo tercero Desordenadas
        • primero
        • segundo
        • tercero
        primero segundo tercero Listas de deficiones
        concepto 1
        definicion de concepto 1
        concepto 2
        definicion de concepto 2
        concepto 3
        definicion de concepto 3
        concepto 1 definicion de concepto 1 concepto 2 definicion de concepto 2 concepto 3 definicion de concepto 3 ENLACES A paginas externas href como url absoluta A paginas del mismo sitio Contacto href como url relativa A direcciones de correo Mandar correo A una nueva pesta\u00f1a Movie Database A una parte de la misma pagina

        Bla bla bla

        \u00f3

        Bla bla bla

        ... ... Subir A una parte de otra pagina Enlace IMAGENES Ponerlas todas en una carpeta /imagenes Salvarlas a resolucion de 72 ppi(pixels per inch), los monitores no dan mas y asi ahorramos peso en la imagen \"lo CODIGO VIEJO -Altura ,anchura y alineamiento de la imagen es mejor hacerlo por CSS \"loquesea\" \"alt\"
        se usa para tener juntas y asociar las imagenes con sus pies de fotos
        Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
        \"loquesea\"
        Pie de foto
        TABLAS para crear la tabla fila CODIGO VIEJO (Ahora por CSS) width spacing bgcolor border
        celda Extiende el texto a dos columnas Extiende el texto a dos filas es una celda pero cabecera de la fila o columna scope=\"row\" scope=\"col\" atributo que indica si es fila o columna
        Sabado Domingo
        Cervezas 4 2
        Cervezas 3 3
        Total 7 5
        FORMULARIOS action method id size CODIGO VIEJO no deberia usarse, para el tama\u00f1o del cuadro. Usar CSS type=\"text\" crea una entrada de texto de una sola linea type=\"password\" como text pero los caracteres no se ven al teclearlos name nombre de la variable, el valor sera lo introducido en el formulario maxlength limitar los caracteres, p ej mes 2 caracteres type=\"submit\" boton que envia el formulario, el value es el texto que sale en el boton placeholder en cualquier input de texto es el valor que saldra por defecto hasta que el usuario lo pinche encima
        Usuario Contrase\u00f1a
        textarea cols y rows son las dos CODIGO VIEJO, mejor con CSS Escribir Aqui... radio button Puedes elegir una opcion Elige una opcion Opcion 1 Opcion 2 Opcion 3

        Elige una opcion
        Opcion 1 Opcion 2 Opcion 3

        checkbox Pues elegir cero, una o mas opciones de las disponibles Elige una opcion Opcion 1 Opcion 2 Opcion 3

        Elige una opcion
        Opcion 1 Opcion 2 Opcion 3

        select : drop down list Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3

        Opcion a elegir ?

        multiple select box Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3 Opcion 4 Opcion 5

        Opcion a elegir ?

        file input box Subir un archivo

        Subir un archivo


        image button Texto de lo que sea

        Texto de lo que sea

        button and hidden controls Add
        labeling form controls uso de etiquetas para accesibilidad grouping form elements Detalles contacto Email: Movil: Telefono fijo:
        Detalles contacto

        Validacion Usuario Contrase\u00f1a
        Usuario
        Contrase\u00f1a
        Fecha Elige Fecha Correo Correo URL URL Telefono Telefono Numero Numero Range Numero Color Color Search Search VIDEO Y AUDIO Video Para poner diferentes formatos usamos Audio Para poner diferentes formatos usamos LAYOUT old Layout new Layout header, footer, nav, article, aside, section hgroup, figure, figcaption
        se usa para tener juntas y asociar las imagenes con sus pies de fotos
        Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
        \"Bok
        Bok Choi
        div
        queda para todo lo que no sea claramente algo de lo anterior y para tener juntos elementos relacionados o envolver partes de la pagina

        Yoko's Kitchen

        Convertir bloque en enlace Envolvemos el elemento a converir en enlace con
        \"Bok
        Bok Choi

        Japanese Vegetarian

        Five week course in London

        A five week introduction to traditional Japanese vegetarian meals, teaching you a selection of rice and noodle dishes.

        ","title":"HTML"},{"location":"html/#html","text":"","title":"HTML"},{"location":"html/#flexbox","text":"Buena Guia para usar Flexbox Patrones para Flexbox","title":"FLEXBOX"},{"location":"html/#css-grid","text":"Aprender aqui gridbyexample.com","title":"CSS GRID"},{"location":"html/#snippets","text":"","title":"SNIPPETS"},{"location":"html/#plantilla","text":" Title ","title":"Plantilla"},{"location":"html/#validacion-con-html5-sin-submit","text":"
        document.getElementById('addUser').addEventListener('click', addNewUser); function addNewUser (ev) { ev.preventDefault(); const f = document.getElementsByTagName('form')[0]; if (f.checkValidity()) { const newUsername = document.getElementById('newUsername').value; const params = `username=${newUsername}`; makeAjaxRequest(addNewUserUrl, 'POST', params, null, function (data) { showUsersList(data); }); } else { alert(document.getElementById('newUsername').validationMessage); } }","title":"Validacion con HTML5 sin submit"},{"location":"html/#disparar-evento-click-con-enter","text":"
        Button
        function init () { const button = document.getElementById('button'); button.addEventListener('click', action); const input = document.getElementById('inputText'); input.addEventListener('keyup', testEnter); } function testEnter (ev) { ev.preventDefault(); if (ev.keyCode === 13) { document.getElementById('button').click(); } }","title":"Disparar evento click con ENTER"},{"location":"html/#html5","text":"","title":"HTML5"},{"location":"html/#estructura","text":" Titulo Block Elements Elementos que siempre empiezan en una nueva linea Inline Elements Elementos que aparecen a continuacion en la misma linea del anterior Caracteres de escape","title":"ESTRUCTURA"},{"location":"html/#texto","text":"white space collapsing : Dos o mas espacios o lineas juntos el navegador solo mostrara uno Elementos para estructurar la pagina

        paragraph

        headings bold italic superscript subscript
        line breaks
        horizontal rules Elementos semanticos contenido importante enfasis
        citar parrafos
        citas cortas dentro de un parrafo abreviaturas o acronimos referencia a algo (libro, peli ...) la primera explicacion de un termino en el documento
        para contener detalles de contacto de alguien
        mostrar contenido que ha sido insertado en el documento mostrar contenido que ha sido borrado en el documento indicar que algo ya no es relevante","title":"TEXTO"},{"location":"html/#listas","text":"Ordenadas
        1. primero
        2. segundo
        3. tercero
        primero segundo tercero Desordenadas
        • primero
        • segundo
        • tercero
        primero segundo tercero Listas de deficiones
        concepto 1
        definicion de concepto 1
        concepto 2
        definicion de concepto 2
        concepto 3
        definicion de concepto 3
        concepto 1 definicion de concepto 1 concepto 2 definicion de concepto 2 concepto 3 definicion de concepto 3","title":"LISTAS"},{"location":"html/#enlaces","text":"A paginas externas href como url absoluta A paginas del mismo sitio Contacto href como url relativa A direcciones de correo Mandar correo A una nueva pesta\u00f1a Movie Database A una parte de la misma pagina

        Bla bla bla

        \u00f3

        Bla bla bla

        ... ... Subir A una parte de otra pagina Enlace","title":"ENLACES"},{"location":"html/#imagenes","text":"Ponerlas todas en una carpeta /imagenes Salvarlas a resolucion de 72 ppi(pixels per inch), los monitores no dan mas y asi ahorramos peso en la imagen \"lo CODIGO VIEJO -Altura ,anchura y alineamiento de la imagen es mejor hacerlo por CSS \"loquesea\" \"alt\"
        se usa para tener juntas y asociar las imagenes con sus pies de fotos
        Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
        \"loquesea\"
        Pie de foto
        ","title":"IMAGENES"},{"location":"html/#tablas","text":" para crear la tabla fila CODIGO VIEJO (Ahora por CSS) width spacing bgcolor border
        celda Extiende el texto a dos columnas Extiende el texto a dos filas es una celda pero cabecera de la fila o columna scope=\"row\" scope=\"col\" atributo que indica si es fila o columna
        Sabado Domingo
        Cervezas 4 2
        Cervezas 3 3
        Total 7 5
        ","title":"TABLAS"},{"location":"html/#formularios","text":"action method id size CODIGO VIEJO no deberia usarse, para el tama\u00f1o del cuadro. Usar CSS type=\"text\" crea una entrada de texto de una sola linea type=\"password\" como text pero los caracteres no se ven al teclearlos name nombre de la variable, el valor sera lo introducido en el formulario maxlength limitar los caracteres, p ej mes 2 caracteres type=\"submit\" boton que envia el formulario, el value es el texto que sale en el boton placeholder en cualquier input de texto es el valor que saldra por defecto hasta que el usuario lo pinche encima
        Usuario Contrase\u00f1a
        textarea cols y rows son las dos CODIGO VIEJO, mejor con CSS Escribir Aqui... radio button Puedes elegir una opcion Elige una opcion Opcion 1 Opcion 2 Opcion 3

        Elige una opcion
        Opcion 1 Opcion 2 Opcion 3

        checkbox Pues elegir cero, una o mas opciones de las disponibles Elige una opcion Opcion 1 Opcion 2 Opcion 3

        Elige una opcion
        Opcion 1 Opcion 2 Opcion 3

        select : drop down list Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3

        Opcion a elegir ?

        multiple select box Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3 Opcion 4 Opcion 5

        Opcion a elegir ?

        file input box Subir un archivo

        Subir un archivo


        image button Texto de lo que sea

        Texto de lo que sea

        button and hidden controls Add
        labeling form controls uso de etiquetas para accesibilidad grouping form elements Detalles contacto Email: Movil: Telefono fijo:
        Detalles contacto

        Validacion Usuario Contrase\u00f1a
        Usuario
        Contrase\u00f1a
        Fecha Elige Fecha Correo Correo URL URL Telefono Telefono Numero Numero Range Numero Color Color Search Search ","title":"FORMULARIOS"},{"location":"html/#video-y-audio","text":"","title":"VIDEO Y AUDIO"},{"location":"html/#video","text":" Para poner diferentes formatos usamos ","title":"Video"},{"location":"html/#audio","text":" Para poner diferentes formatos usamos ","title":"Audio"},{"location":"html/#layout","text":"old Layout new Layout header, footer, nav, article, aside, section hgroup, figure, figcaption
        se usa para tener juntas y asociar las imagenes con sus pies de fotos
        Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
        \"Bok
        Bok Choi
        div
        queda para todo lo que no sea claramente algo de lo anterior y para tener juntos elementos relacionados o envolver partes de la pagina

        Yoko's Kitchen

        Convertir bloque en enlace Envolvemos el elemento a converir en enlace con
        \"Bok
        Bok Choi

        Japanese Vegetarian

        Five week course in London

        A five week introduction to traditional Japanese vegetarian meals, teaching you a selection of rice and noodle dishes.

        ","title":"LAYOUT"},{"location":"javascript-apis/","text":"JAVASCRIPT APIs Para ver si un navegador tiene una funcionalidad if (navigator.geolocation) { // codigo } else { // codigo } Modernizr puede ayudar if (Modernizr.awesomeNewFeature) { showOffAwesomeNewFeature(); } else { getTheOldLameExperience(); } LIBRERIA STANDARD Math Math es un Objeto Global que actua sobre numeros Propiedades Math.PI - Devuelve pi 3.14159265359 Math.E - constante de Euler Math.LN2 - logaritmo natural de 2 Math.LN10 - logaritmo natural de 10 Math.LOG2E - logaritmo en base 2 de e Math.LOG10E - logaritmo en base 10 de e Math.SQRT1_2 - raiz cuadrada de medio (1/2) Math.SQRT2 - raiz cuadrada de 2 Metodos Math.abs(num) - Devuelve el valor absoluto de num Math.round(num) - Redondea num al entero mas cercano Math.sqrt(num) - Devuelve la raiz cuadrada del numero positivo num Math.ceil(num) - Redondea al entero mas cercano por arriba Math.floor(num) - Redondea al entero mas cercano por abajo Math.random() - Genera un numero aleatorio entre 0 (inclusivo) y 1 (no inclusivo) Math.pow(num, pot) - Devuelve num elevado a la pot Math.max(num1, num2, num3) - devuelve el mayor numero Math.min(num1, num2, num3) - devuelve el menor numero Math.acos(x) - Math.asin(x) - Math.atan(x) - Math.atan2(x) - Math.cos(x) - Math.sin(x) - Math.tan(x) - // Crea un numero aleatorio entre min y max ambos inclusivo Math.floor(Math.random() * (max - min + 1) + min); Date Crear Objeto Date var d = new Date(); var d = new Date(millis); var d = new Date(dateString); var d = new Date(year, month, day, hours, minutes, seconds, millis); Metodos Date.now() - devuelve el numero de Milisegundos desde el 1 ene 1970 Date.parse() - parsea la fecha y devuelve el numero de Milisegundos desde el 1 ene 1970 .getDate() , .setDate() - Dia del mes (1-31) .getDay() - Dia de la semana (0-6) .getFullYear() , .setFullYear() - a\u00f1o (4 digitos) .getHours() , .setHours() - Hora (0-23) .getMilliseconds() , .setMilliseconds() - Milisegundos (0-999) .getMinutes() , .setMinutes() - Minutos (0-59) .getMonth() , .setMonth() - Mes (0-11) .getSeconds() , .setSeconds() - Segundos (0-59) .getTime() , .setTime() - Milisegundos desde 1 Enero 1970 00:00:00 y negativo para cualquier tiempo anterior a esa fecha .getTimezoneOffset() - Minutos de diferencia horaria entre UTC y la hora local Version para UTC .getUTCDate() , .setUTCDate() - Dia del mes (1-31) .toDateString() - Fecha del tipo Mon Jan 17 1982 .toTimeString() - Hora del tipo 19:45:15 GMT+0300 (CEST) .toString() - Devuelve una string con la fecha especificada .toISOString() - Devuelve una string con la fecha especificada usando el standard ISO .date.toJSON() - Devuelve una string con la fecha especificada formateado en JSON. .toLocaleDateString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toLocaleTimeString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toLocaleString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toUTCString() - Devuelve una string con la fecha especificada segun la hora universal .valueOf() - Devuelve el valor primitico de un objeto Date JSON JSON.stringify JSON.stringify(value, replacer?, space?) convierte el valor value a una cadena en formato JSON. replacer es opcional y se usa para cambiar value antes de stringify function replacer(key, value) { if (typeof value === 'number') { value = 2 * value; } return value; } JSON.stringify({ a: 5, b: [ 2, 8 ] }, replacer) // '{\"a\":10,\"b\":[4,16]} JSON.parse JSON.parse(text, reviver?) convierte los datos JSON en text y devuelve un valor javascript reviver es opcional y se puede usar para transformar los datos ya parseados STRICT MODE Variables han de ser definidas explicitamente No se puede borrar una variable u objeto usando delete No se puede definir la misma propiedad dos veces No permite los nombres de parametros duplicados En una funcion si no se conoce this en lugar de usar el objeto global window sera undefined Las variables instanciadas dentro del contexto de eval() s\u00f3lo son v\u00e1lidas en ese contexto. La sentencia with(){} ya no se usa js Envolvemos todo la parte del codigo js en una IIFEs (function() { 'use strict'; /* code here */ .. codigo }()); node.js a\u00f1adimos al comienzo del archivo /*jslint node: true */ 'use strict'; WEB STORAGE Objeto Storage Los navegadores guardan sobre 8mb por dominio en un objecto storage Los datos se guardan como propiedades (clave/calor) del objeto storage Acceso a los datos se hace de manera sincrona Los navegadores usan politica del mismo origen, vamos que los datos solo son accesibles por otras paginas del mismo dominio Para ello las 4 partes del URL deben coincidir Protocolo \u00a1 ojo que https es distinto a http ! Subdominio, maps.google.com no puede acceder a datos guardados de www.google.com Dominio debe coincidir Puerto, este tambien debe coincidr Propiedades .length - numero de claves Metodos .setItem('clave', 'valor') - Crea una nueva pareja clave/valor .getItem('clave') - Devuelve el valor de la clave \"clave\" .removeItem('clave') - Elimina la clave/valor para esa clave .clear() - Limpia toda la informacion del objeto storage sessionStorage Cambios frecuentes cada vez que el usuario visita el sitio, (datos de localizacion, logueos) Es personal y privado, no debe ser visto por otros usuarios del dispositivo localStorage Solo cambia en los intervalos establecidos (horarios, listas de precios) y es util almacenarlo offline Cosas que el usuario use de nuevo si vuelve al sitio (guardar preferencias y ajustes) localStorage.setItem(\"username\", \"marijn\"); console.log(localStorage.getItem(\"username\")); // \u2192 marijn localStorage.removeItem(\"username\"); Un valor en localStorage dura hasta que se sobreescribe, se elimina o el usuario limpia sus datos locales Cada pagina tiene su propio almacen que solo puede interactuar con scripts de la misma pagina Ejemplo var basicRecipes = [{ title: 'Cookies', ingredients: ['Cup shortening', 'Peanut Butter', 'Milk', 'Eggs'] }, { title: 'Spaghetti', ingredients: ['Noodles', 'Tomato Sauce', 'Meatballs', 'Onion'] }, { title: 'Rice Pudding', ingredients: ['White Rice', 'Milk', 'Sugar', 'Salt'] }]; // Estas dos hacen lo mismo localStorage.setItem('basicRecipes', JSON.stringify(basicRecipes)); localStorage.basicRecipes = JSON.stringify(basicRecipes); // Dos formas de hacer lo mismo tambien var sol = JSON.parse(localStorage.getItem('basicRecipes')); console.log(sol[0].title); console.log((JSON.parse(localStorage.basicRecipes))[0]); // Esto borra toda la localStorage localStorage.clear() IndexedDB Web SQL Deprecada, pero aun se usa No funciona ni en chrome ni en IE GEOLOCATION Metodos objeto navigation.geolocation getCurrentPosition(exito, error, conf) - exito - funcion para procesar la ubicacion recibida en el objeto Position error -funcion para procesar los errores retornados en el objeto PositionError conf - objeto para configurar como la informacion sera adquirida watchPosition(exito, error, conf) - igual que el anterior excepto que inicia un proceso de vigilancia para detectar nuevas ubicaciones que nos enviara cada cierto tiempo clearWatch(id) - El metodo watchPosition() retorna un valor que puede ser almacenado en una variable para luego ser usado como id aqui y detener la vigilancia Propiedades objeto Position .coords.latitude - Devuelve latitud en grados decimales .coords.longitude - Devuelve longitud en grados decimales .coords.accuracy - Precision de latitud y longitud en metros .coords.altitude - Devuelve metros sobre el nivel del mar .coords.altitudeAccuracy - Precision de la altitud en metros .coords.heading - Devuelve grados respecto al norte .coords.speed - Devuelve velocidad en m/s .coords.timestamp - Devuelve tiempo desde que se creo (en forma de Date ) Propiedades objeto PositionError PositionError.code - Devuelve un numero de error con los valores: Permiso denegado No disponeble Ha expirado el tiempo PositionError.message - Devuelve un mensaje (pero no para el usuario) var elMap = document.getElementById('loc'); var msg = 'Sorry, we were unable to get your location.'; if (Modernizr.geolocation) { navigator.geolocation.getCurrentPosition(success, fail); elMap.textContent = 'Checking location...'; } else { elMap.textContent = msg; } function success(position) { msg = '

        Longitude: '; msg += position.coords.longitude + '

        '; msg += '

        Latitude: '; msg += position.coords.latitude + '

        '; elMap.innerHTML = msg; } function fail(msg) { elMap.textContent = msg; console.log(msg.code); } HISTORY Objeto history Propiedades .length - numero de articulos en el objeto historia Metodos history.back() - Retrocedes en la historia a la anterior posicion history.forward() - Saltas adelante a la siguiente posicion history.go(n) - Te lleva a la pagina n respecto de tu posicion que es la 0. Por ejemplo -2 echa dos para atras y 1 salta uno hacia adelante history.pushState() - A\u00f1ade un elemento a la historia history.replaceState() - Cambia el actual elemento de la historia por el que pasamos ahora Eventos window.onpopstate - Usado para manejar los movimientos de usuario de adelante atras GOOGLE MAPS API Key Se consigue aqui Ajustes Crear un mapa El evento onload llama a la funcion loadScript() LoadScript() crea un elemento
        requestAnimationFrame(funcion) - Sincroniza la animacion con la ventana del navegador y el monitor. hay que llamarlo para cada ciclo del bucle cancelAnimationFrame(variable) - Podemos asignar el valor de arriba a una variable y con ese metodo cancelamos el proceso Hay que concentrar el codigo del juego en un objeto global unico var onoff; function gameLoop() { // haces lo que sea onoff = requestAnimationFrame(gameLoop); } // en otro sitio para parar el bucle cancelAnimationFrame(onoff); function gameLoop () { setTimeout(function () { if (running) { update(); render(); } onoff = requestAnimationFrame(gameLoop); // console.log('gameLoop sigue ... ', onoff) if (cancel) { cancelAnimationFrame(onoff); setScoreToZeros(); } }, 1000 / fps); } var mijuego = { lienzo: { ctx: '', offsetx: 0, offsety: 0 }, nave: { x: 300, y: 200, movex: 0, movey: 0, speed: 1 }, iniciar: function(){ var elem = document.getElementById('lienzo'); mijuego.lienzo.ctx = elem.getContext('2d'); mijuego.lienzo.offsetx = elem.offsetLeft; mijuego.lienzo.offsety = elem.offsetTop; document.addEventListener('click', function(e){ mijuego.control(e); }); mijuego.bucle(); }, bucle: function(){ if(mijuego.nave.speed){ mijuego.procesar(); mijuego.detectar(); mijuego.dibujar(); // requestAnimationFrame(function(){ mijuego.bucle() }); webkitRequestAnimationFrame(function(){ mijuego.bucle() }); }else{ mijuego.lienzo.ctx.font = \"bold 36px verdana, sans-serif\"; mijuego.lienzo.ctx.fillText('JUEGO FINALIZADO', 112, 210); } }, control: function(e){ var distancex = e.clientX - (mijuego.lienzo.offsetx + mijuego.nave.x); var distancey = e.clientY - (mijuego.lienzo.offsety + mijuego.nave.y); var ang = Math.atan2(distancex, distancey); mijuego.nave.movex = Math.sin(ang); mijuego.nave.movey = Math.cos(ang); mijuego.nave.speed += 1; }, dibujar: function(){ mijuego.lienzo.ctx.clearRect(0, 0, 600, 400); mijuego.lienzo.ctx.beginPath(); mijuego.lienzo.ctx.arc(mijuego.nave.x, mijuego.nave.y, 20, 0, Math.PI/180*360, false); mijuego.lienzo.ctx.fill(); }, procesar: function(){ mijuego.nave.x += mijuego.nave.movex * mijuego.nave.speed; mijuego.nave.y += mijuego.nave.movey * mijuego.nave.speed; }, detectar: function(){ if(mijuego.nave.x < 0 || mijuego.nave.x > 600 || mijuego.nave.y < 0 || mijuego.nave.y > 400){ mijuego.nave.speed = 0; } } }; addEventListener('load', function(){ mijuego.iniciar(); }); Procesar Video Coger cada cuadro del video desde el elemento
        ); } } LIFECYCLE METODOS /* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
        {this.props.display}
        ); } } class CounterParent extends React.Component { constructor(props, context) { super(props, context); console.log(\"constructor: Default state time!\"); this.state = { count: 0 }; this.increase = this.increase.bind(this); } getInitialState() { console.log(\"getInitialState: Default state time!\"); return { count: 0 }; } increase() { this.setState({ count: this.state.count + 1 }); } componentWillUpdate(newProps, newState) { console.log(\"componentWillUpdate: Component is about to update!\"); } componentDidUpdate(currentProps, currentState) { console.log(\"componentDidUpdate: Component just updated!\"); } componentWillMount() { console.log(\"componentWillMount: Component is about to mount!\"); } componentDidMount() { console.log(\"componentDidMount: Component just mounted!\"); } componentWillUnmount() { console.log(\"componentWillUnmount: Component is about to be removed from the DOM!\"); } shouldComponentUpdate(newProps, newState) { console.log(\"shouldComponentUpdate: Should component update?\"); if (newState.count < 5) { console.log(\"shouldComponentUpdate: Component should update!\"); return true; } else { ReactDOM.unmountComponentAtNode(destination); console.log(\"shouldComponentUpdate: Component should not update!\"); return false; } } componentWillReceiveProps(newProps) { console.log(\"componentWillReceiveProps: Component will get new props!\"); } render() { const backgroundStyle = { padding: 50, border: \"#333 2px dotted\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; return (
        ); } } console.log(\"defaultProps: Default prop time!\"); CounterParent.defaultProps = { }; const layout = (
        ); ReactDOM.render( layout, destination ); RENDERIZADO CONDICIONAL Variables render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = ; } else { button = ; } return (
        {button}
        ); } If return (

        Hello!

        {unreadMessages.length > 0 &&

        You have {unreadMessages.length} unread messages.

        }
        ); If-else codition ? true : false - return (
        The user is {isLoggedIn ? 'currently' : 'not'} logged in.
        ); return (
        {isLoggedIn ? ( ) : ( )}
        ); EVENTOS Eventos en React son SyntheticEvent que envuelven eventos normales Documentacion en React sobre Eventos del sistema this dentro del manejador de eventos -Fuera de react, el valor de this dentro de una manejador de eventos se refiere al elemento que disparo el evento. -En React, this se refiere al componente donde el manejador de evento vive. Escuchando eventos del DOM class Something extends React.Component { handleMyEvent(e) { // do something } componentDidMount() { window.addEventListener(\"someEvent\", this.handleMyEvent); } componentWillUnmount() { window.removeEventListener(\"someEvent\", this.handleMyEvent); } render() { return (
        Hello!
        ); } }; Synthetic Events /* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
        {this.props.display}
        ); } } class CounterParent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.increase = this.increase.bind(this); } increase(e) { //console.log(e); let currentCount = this.state.count; if (e.shiftKey) { currentCount += 10; } else { currentCount += 1; } this.setState({ count: currentCount }); } render() { const backgroundStyle = { padding: 50, backgroundColor: \"#FFC53A\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; const buttonStyle = { fontSize: \"1em\", width: 30, height: 30, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\", lineHeight: \"3px\" }; return (
        ); } } const layout = (
        ); ReactDOM.render( layout, destination ); Pasar parametros desde los eventos onClick={() => this.functionName(params)} PORTALES Uso // These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = { showModal: false }; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({ showModal: true }); } handleHide() { this.setState({ showModal: false }); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? (
        With a portal, we can render content into a different part of the DOM, as if it were any other React child.
        This is being rendered inside the #modal-container div.
        ) : null; return (
        This div has overflow: hidden. {modal}
        ); } } ReactDOM.render(, appRoot); Burbujas de Eventos // These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = {clicks: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState(prevState => ({ clicks: prevState.clicks + 1 })); } render() { return (

        Number of clicks: {this.state.clicks}

        Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

        ); } } function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
        ); } ReactDOM.render(, appRoot); REACT ROUTER 4.2.0 Basico /* global ReactDOM React */ const destination = document.getElementById('book'); const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; const development = \"/old/apps/book/html\"; const production = \"/old/apps/book\"; class Controller extends React.Component { constructor(props) { super(props); this.state = { data: { }, default: development// production }; } render() { const a = { textAlign: \"center\", fontFamily: \"Indie Flower\" }; return (

        Book Trading Club

        • Index
        • Home
        • About
        ); } } const Index = () => (

        Index

        ); const Home = () => (

        Welcome home

        ); const About = () => (

        About

        ); const layout = ( ); ReactDOM.render( layout, destination ); Ejemplo /* global ReactDOM React lib Home About Index LoginForm SignUpForm ShowBooks MyBooks UserDataForm*/ const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; class Controller extends React.Component { render() { const a = { textAlign: \"center\", }; const gap = { paddingTop: \"75px\", }; const links = { fontFamily: \"arial\", fontSize: \"1em\", }; return (
        {/*

        Index

        Login Signup AllBooks MyBooks UserData */}
        ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> {/**/}
        ); } } const layout = ( ); ReactDOM.render( layout, destination );","title":"Reactjs"},{"location":"reactjs/#reactjs-1620","text":"Instalacion https://unpkg.com/react/ https://unpkg.com/react-dom/ ","title":"REACTJS 16.2.0"},{"location":"reactjs/#jsx","text":"JSX permite mezclar javascript y etiquetas HTML para definer elementos de interfaces de usuario y su funcionalidad","title":"JSX"},{"location":"reactjs/#crear-elemento-jsx","text":"// simple const JSX =

        Hello JSX!

        ; // complejo, todos los elementos son envueltos por un unico elemento padre const JSX = (

        Hello JSX!

        { /* this is a JSX comment */ } { 'this is treated as JavaScript code' }

        Some info

        • An item
        • Another item
        • A third item
        );","title":"Crear elemento JSX"},{"location":"reactjs/#renderizar-elemento-jsx","text":"// ReactDOM.render(componentToRender, targetNode) ReactDOM.render(JSX, document.getElementById('challenge-node'));","title":"Renderizar elemento JSX"},{"location":"reactjs/#sintaxis","text":"Definir una clase HTML en JSX , usa className en lugar de class La convenci\u00f3n de nomenclatura para todos los atributos HTML y referencias de eventos en JSX se convierte en camelCase. Por ejemplo, el evento de clic en JSX es onClick, en lugar de onclick. const JSX = (

        Add a class to this div

        );","title":"Sintaxis"},{"location":"reactjs/#componente","text":"","title":"COMPONENTE"},{"location":"reactjs/#tipos","text":"1.Usar una funcion javascript para crear un componente funcional sin estado // After transpiled,
        will have a CSS class of 'customClass' const MyComponent = function() { return (
        Demo Solution
        ); } 2.Usando sintaxis ES6 class class MyComponent extends React.Component { constructor(props) { super(props); } render() { return (

        Hi

        ); } }","title":"Tipos"},{"location":"reactjs/#props-propiedades","text":"Pasar una propiedad const CurrentDate = (props) => { return (

        The current date is: {props.date}

        ); }; class Calendar extends React.Component { constructor(props) { super(props); } render() { return (

        What date is it?

        ); } }; Pasar un Array como Props const ChildComponent = (props) =>

        {props.colors.join(', ')}

        const List= (props) => { return

        {props.tasks.join(\", \")}

        }; class ToDo extends React.Component { constructor(props) { super(props); } render() { return (

        To Do Lists

        Today

        Tomorrow

        ); } }; Usar default Props -Puedes asignar props por defecto a un componente como una propiedad en el propio componente y React asigna el default prop si es necesario. -React asigna default props si las propiedades no est\u00e1n definidas, pero si pasas nulo como valor de una propiedad, permanecer\u00e1 nulo. -La forma de anular los default props es establecer expl\u00edcitamente los valores de la propiedad para un componente. -Decl\u00e1ralos inmediatamente despu\u00e9s de la declaraci\u00f3n del componente MyComponent.defaultProps = { location: 'San Francisco' } const ShoppingCart = (props) => { return (

        Shopping Cart Component

        ) }; ShoppingCart.defaultProps = { items:0 } // Override Default props const Items = (props) => { return (

        Current Quantity of Items in Cart: {props.quantity}

        ) } Items.defaultProps = { quantity: 0 } class ShoppingCart extends React.Component { constructor(props) { super(props); } render() { return } }; Verificaci\u00f3n de tipos con PropTypes -Establece propTypes cuando sepas de antemano el tipo que tendra la propiedad // require the type function for a prop called handleClick import React, { PropTypes } from 'react'; MyComponent.propTypes = { handleClick: PropTypes.func.isRequired } const Items = (props) => { return

        Current Quantity of Items in Cart: {props.quantity}

        }; Items.propTypes = { quantity: PropTypes.number.isRequired } Items.defaultProps = { quantity: 0 }; class ShoppingCart extends React.Component { constructor(props) { super(props); } render() { return } }; Acceder a Props usando this.props -Pasar una propiedad a un componente de una clase ES6 -Cada vez que se refiera a un componente de la clase dentro de s\u00ed mismo, usa \"this\". -Para acceder a los propiedades dentro de un componente de la clase, pon delante del c\u00f3digo para acceder a \u00e9l \"this\". -Por ejemplo, si un componente de clase ES6 tiene una propiedad llamada data, usa {this.props.data} en JSX. class ReturnTempPassword extends React.Component { constructor(props) { super(props); } render() { return (

        Your temporary password is: {this.props.tempPassword}

        ); } }; class ResetPassword extends React.Component { constructor(props) { super(props); } render() { return (

        Reset Password

        We've generated a new temporary password for you.

        Please reset this password settings ASAP.

        ); } }; Mas props usando componentes de clases es6 class CampSite extends React.Component { constructor(props) { super(props); } render() { return (
        ); } }; // change code below this line const Camper = (props) => { return (

        {props.name}

        ); }; Camper.propTypes = { name: PropTypes.string.isRequired }; Camper.defaultProps = { name: 'CamperBot' };","title":"Props (propiedades)"},{"location":"reactjs/#estilo-css-en-react","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Letter extends React.Component { render() { const letterStyle = { padding: 10, margin: 10, backgroundColor: this.props.bgcolor, color: \"#333\", display: \"inline-block\", fontFamily: \"monospace\", fontSize: 32, textAlign: \"center\" }; return (
        {this.props.children}
        ); } } const layout = (
        A E I O U
        ); ReactDOM.render( layout, destination );","title":"Estilo CSS en React"},{"location":"reactjs/#composicion","text":"Puedes renderizar elementos JSX, componentes funciones sin estado y componentes de clase ES6 dentro de otros componentes","title":"Composicion"},{"location":"reactjs/#composicion-de-componentes","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Card extends React.Component { render() { const cardStyle = { height: 200, width: 150, padding: 0, backgroundColor: \"#FFF\", WebkitFilter: \"drop-shadow(0px 0px 5px #666)\", filter: \"drop-shadow(0px 0px 5px #666)\" }; return (
        ); } } class Square extends React.Component { render() { const squareStyle = { height: 150, backgroundColor: this.props.color }; return (
        ); } } class Label extends React.Component { render() { const labelStyle = { fontFamily: \"sans-serif\", fontWeight: \"bold\", padding: 13, margin: 0 }; return (

        {this.props.color}

        ); } } const layout = (
        ); ReactDOM.render( layout, destination );","title":"Composicion de componentes"},{"location":"reactjs/#transferir-propiedades-con-el-operador-spread","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Display extends React.Component { render() { return (

        {this.props.color}

        {this.props.num}

        {this.props.size}

        ); } } class Label extends React.Component { render() { return ( ); } } class Shirt extends React.Component { render() { return (
        ); } } const layout = (
        ); ReactDOM.render( layout, destination );","title":"Transferir propiedades con el operador spread"},{"location":"reactjs/#estado","text":"","title":"Estado"},{"location":"reactjs/#estado_1","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class LightningCounter extends React.Component { constructor(props, context) { super(props, context); this.state = { strikes: 0 }; this.timerTick = this.timerTick.bind(this); } componentDidMount() { setInterval(this.timerTick, 1000); } timerTick() { this.setState({ strikes: this.state.strikes + 100 }); } render() { const counterStyle = { color: \"#66FFFF\", fontSize: 50 }; const count = this.state.strikes.toLocaleString(); return (

        {count}

        ); } } class LightningCounterDisplay extends React.Component { render() { const commonStyle = { margin: 0, padding: 0 }; const divStyle = { width: 250, textAlign: \"center\", backgroundColor: \"#020202\", padding: 40, fontFamily: \"sans-serif\", color: \"#999999\", borderRadius: 10 }; const textStyles = { emphasis: { fontSize: 38, ...commonStyle }, smallEmphasis: { ...commonStyle }, small: { fontSize: 17, opacity: 0.5, ...commonStyle } } return (

        LIGHTNING STRIKES

        WORLDWIDE

        (since you loaded this example)

        ); } } const layout = (
        ); ReactDOM.render( layout, destination );","title":"Estado"},{"location":"reactjs/#de-los-datos-a-la-ui-interface-de-usuario","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Circle extends React.Component { render() { const circleStyle = { padding: 10, margin: 20, display: \"inline-block\", backgroundColor: this.props.bgColor, borderRadius: \"50%\", width: 100, height: 100, }; return (
        ); } } const colors = [\"#393E41\", \"#E94F37\", \"#1C89BF\", \"#A1D363\", \"#85FFC7\", \"#297373\", \"#FF8552\", \"#A40E4C\"]; const renderData = []; for (let i = 0; i < colors.length; i++) { const color = colors[i]; renderData.push(); } const layout = (
        {renderData}
        ); ReactDOM.render( layout, destination );","title":"De los datos a la UI (interface de usuario)"},{"location":"reactjs/#forceupdate","text":"Si setState no rerenderiza el componete usa forceUpdate() Por defecto, cuando el estado de sus componentes o los props cambian, su componente se volver\u00e1 a renderizar. Sin embargo, si estos cambios son impl\u00edcitos (p.e.: datos profundos dentro de un objeto camabian pero sin cambiar el objeto mismo) o si su render() depende de otros datos, puedes decirle a React que necesita reejecutar render() llamando a forceUpdate().","title":"forceUpdate()"},{"location":"reactjs/#comunicacion-de-datos","text":"Ideas basicas","title":"COMUNICACION DE DATOS"},{"location":"reactjs/#hijos-a-padres","text":"class Container extends React.Component { constructor(props) { super(props); this.state = { input: props.template, }; this.getBackData = this.getBackData.bind(this); } getBackData(data) { this.setState({ input: data }); } render() { return (
        ); } } class Editor extends React.Component { constructor(props) { super(props); this.editing = this.editing.bind(this); } editing(e) { e.preventDefault(); this.props.callback(e.target.value); } render() { return (
        ); } }","title":"Hijos a Padres"},{"location":"reactjs/#lifecycle-metodos","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
        {this.props.display}
        ); } } class CounterParent extends React.Component { constructor(props, context) { super(props, context); console.log(\"constructor: Default state time!\"); this.state = { count: 0 }; this.increase = this.increase.bind(this); } getInitialState() { console.log(\"getInitialState: Default state time!\"); return { count: 0 }; } increase() { this.setState({ count: this.state.count + 1 }); } componentWillUpdate(newProps, newState) { console.log(\"componentWillUpdate: Component is about to update!\"); } componentDidUpdate(currentProps, currentState) { console.log(\"componentDidUpdate: Component just updated!\"); } componentWillMount() { console.log(\"componentWillMount: Component is about to mount!\"); } componentDidMount() { console.log(\"componentDidMount: Component just mounted!\"); } componentWillUnmount() { console.log(\"componentWillUnmount: Component is about to be removed from the DOM!\"); } shouldComponentUpdate(newProps, newState) { console.log(\"shouldComponentUpdate: Should component update?\"); if (newState.count < 5) { console.log(\"shouldComponentUpdate: Component should update!\"); return true; } else { ReactDOM.unmountComponentAtNode(destination); console.log(\"shouldComponentUpdate: Component should not update!\"); return false; } } componentWillReceiveProps(newProps) { console.log(\"componentWillReceiveProps: Component will get new props!\"); } render() { const backgroundStyle = { padding: 50, border: \"#333 2px dotted\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; return (
        ); } } console.log(\"defaultProps: Default prop time!\"); CounterParent.defaultProps = { }; const layout = (
        ); ReactDOM.render( layout, destination );","title":"LIFECYCLE METODOS"},{"location":"reactjs/#renderizado-condicional","text":"","title":"RENDERIZADO CONDICIONAL"},{"location":"reactjs/#variables","text":"render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = ; } else { button = ; } return (
        {button}
        ); }","title":"Variables"},{"location":"reactjs/#if","text":"return (

        Hello!

        {unreadMessages.length > 0 &&

        You have {unreadMessages.length} unread messages.

        }
        );","title":"If"},{"location":"reactjs/#if-else","text":"codition ? true : false - return (
        The user is {isLoggedIn ? 'currently' : 'not'} logged in.
        ); return (
        {isLoggedIn ? ( ) : ( )}
        );","title":"If-else"},{"location":"reactjs/#eventos","text":"Eventos en React son SyntheticEvent que envuelven eventos normales Documentacion en React sobre Eventos del sistema this dentro del manejador de eventos -Fuera de react, el valor de this dentro de una manejador de eventos se refiere al elemento que disparo el evento. -En React, this se refiere al componente donde el manejador de evento vive.","title":"EVENTOS"},{"location":"reactjs/#escuchando-eventos-del-dom","text":"class Something extends React.Component { handleMyEvent(e) { // do something } componentDidMount() { window.addEventListener(\"someEvent\", this.handleMyEvent); } componentWillUnmount() { window.removeEventListener(\"someEvent\", this.handleMyEvent); } render() { return (
        Hello!
        ); } };","title":"Escuchando eventos del DOM"},{"location":"reactjs/#synthetic-events","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
        {this.props.display}
        ); } } class CounterParent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.increase = this.increase.bind(this); } increase(e) { //console.log(e); let currentCount = this.state.count; if (e.shiftKey) { currentCount += 10; } else { currentCount += 1; } this.setState({ count: currentCount }); } render() { const backgroundStyle = { padding: 50, backgroundColor: \"#FFC53A\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; const buttonStyle = { fontSize: \"1em\", width: 30, height: 30, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\", lineHeight: \"3px\" }; return (
        ); } } const layout = (
        ); ReactDOM.render( layout, destination );","title":"Synthetic Events"},{"location":"reactjs/#pasar-parametros-desde-los-eventos","text":"onClick={() => this.functionName(params)}","title":"Pasar parametros desde los eventos"},{"location":"reactjs/#portales","text":"","title":"PORTALES"},{"location":"reactjs/#uso","text":"// These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = { showModal: false }; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({ showModal: true }); } handleHide() { this.setState({ showModal: false }); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? (
        With a portal, we can render content into a different part of the DOM, as if it were any other React child.
        This is being rendered inside the #modal-container div.
        ) : null; return (
        This div has overflow: hidden. {modal}
        ); } } ReactDOM.render(, appRoot);","title":"Uso"},{"location":"reactjs/#burbujas-de-eventos","text":"// These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = {clicks: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState(prevState => ({ clicks: prevState.clicks + 1 })); } render() { return (

        Number of clicks: {this.state.clicks}

        Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

        ); } } function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
        ); } ReactDOM.render(, appRoot);","title":"Burbujas de Eventos"},{"location":"reactjs/#react-router-420","text":"","title":"REACT ROUTER 4.2.0"},{"location":"reactjs/#basico","text":"/* global ReactDOM React */ const destination = document.getElementById('book'); const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; const development = \"/old/apps/book/html\"; const production = \"/old/apps/book\"; class Controller extends React.Component { constructor(props) { super(props); this.state = { data: { }, default: development// production }; } render() { const a = { textAlign: \"center\", fontFamily: \"Indie Flower\" }; return (

        Book Trading Club

        • Index
        • Home
        • About
        ); } } const Index = () => (

        Index

        ); const Home = () => (

        Welcome home

        ); const About = () => (

        About

        ); const layout = ( ); ReactDOM.render( layout, destination );","title":"Basico"},{"location":"reactjs/#ejemplo","text":"/* global ReactDOM React lib Home About Index LoginForm SignUpForm ShowBooks MyBooks UserDataForm*/ const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; class Controller extends React.Component { render() { const a = { textAlign: \"center\", }; const gap = { paddingTop: \"75px\", }; const links = { fontFamily: \"arial\", fontSize: \"1em\", }; return (
        {/*

        Index

        Login Signup AllBooks MyBooks UserData */}
        ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> {/**/}
        ); } } const layout = ( ); ReactDOM.render( layout, destination );","title":"Ejemplo"},{"location":"varios/","text":"MISCELLANEUS IMAGEMAGICK Ejemplos Hacer el fondo transparente convert input.png -transparent red output.png Conversion entre formatos convert image.png image.jpg // bajando la calidad convert image.png -quality 90 image.jpg Convertir color de fondo a transparente o a otro color. convert image.png -background white white.png Montar imagenes montage -label 'FRONT END' frontEnd.png -label 'BACK END' backEnd.png -label 'DATABASE' database.png -label 'UTILS' utils.png -tile 2x2 -geometry 200x200 total.png Recortar los bordes shave Hacer el canvas mayor para encajar la imagen convert input.png -gravity center -background white -extent 500x500 output.png Optimizar imagenes // png convert INPUT.png -strip [-resize WxH] [-alpha Remove] OUTPUT.png //jpg convert INPUT.jpg -sampling-factor 4:2:0 -strip [-resize WxH] [-quality 85] [-interlace JPEG] [-colorspace Gray/sRGB] OUTPUT.jpg Comprimir imagenes // ojo que esto modifica el fichero actual, no crea uno nuevo mogrify -strip -interlace Plane -gaussian-blur 0.05 -quality 40% *.jpg GIT Instalar // Debian backports para pillar la ultima version deb http://ftp.debian.org/debian strecth-backports main aptitude -t strecth-backports install \"package\" // debian aptitude install git git config --global user.name \"John Doe\" git config --global user.email johndoe@example.com git config --list nano ~/.gitconfig Commands git init [project-name] - A\u00f1ade el directorio donde estamos y crea el .git git status - lista todos los archivos nuevos o modificados sin haber sido committed git add [file] - - A\u00f1ade el fichero a la staging area y empieza a seguir los cambios que en el se producen git add . - A\u00f1ade todo en el directorio de forma recursiva a la staging area git reset [file] - Saca al archivo de la staging area git diff - Vemos los cambio del archivo git diff --staged - Vemos los cambio que hemos mandado al staging git commit -m \"mensaje\" - Realiza un commit y le asigna un \"mensaje\" git log - Es un diario con los cambios hechos en commits an la actual rama de .gitignore a github Si a\u00f1adimos algo a .gitignore ya no se commiteara pero tampoco desaparece lo existente en github. Para que se elimine de github ... git rm -r --cached some-directory git commit -m 'Remove the now ignored directory \"some-directory\"' git push origin master - normalmente con git push vale ramas git checkout -b nuevaRama - crea nueva rama de rama nuevaRama git checkout -d nombreRama - delete rama nombreRama git checkout otraRama - cambia a la rama otraRama git push origin nombreRama - push los commits de nombreRama git stash - cambios no committed se arrastran de una rama a otra. Para mantenerlos separados hacemos un stash antes de movernos a otra rama para guardar esos cambios antes de cambiar de rama. git stash apply - cuando vuelves a una rama recuperas los cambios sin hacer commit que se guardaron en esa rama. volver a estado anterior git reset --hard HEAD~5 - elimina los ultimos 5 commits git push origin -f - sincroniza la nueva situacion Volver a un commit anterior sin modificar el head # Paso 1: Encuentra el hash del commit git log # Paso 2: Crea una nueva rama como backup (opcional pero recomendado) git checkout -b nueva-rama # Paso 3: Actualiza el directorio de trabajo al estado del commit # Reemplaza con el hash del commit al que deseas volver git checkout . # Paso 4: A\u00f1ade los cambios al \u00edndice (si es necesario) git add . # Paso 5: Haz un nuevo commit (si es necesario) git commit -m \"Revertir al estado del commit \" # Paso 6: Empuja los cambios al repositorio remoto (si es necesario) git push origin nueva-rama Reducir el tama\u00f1o del directorio .git MKDOCS Instalacion apt-get install python-pip pip list --outdated -lista paquetes que se pueden actualizar pip install mkdocs pip install --upgrade mkdocs -actualizar mkdocs instalar mas temas pip install mkdocs-bootstrap pip install mkdocs-bootswatch pip install mkdocs-material pip install mkdocs-alabaster pip install mkdocs-cinder Configuracion mkdocs new my-project cd my-project $ mkdocs serve Running at: http://127.0.0.1:8000/ Comandos mkdocs build - crea un directorio site con todo el contenido estatico que se subira al servidor mkdocs build --clean - limpia lo que sobra de antes mkdocs build -d ruta/donde/gustes - crea el resultado y con el nombre gustes Ejemplo mkdocs.yml site_name: Chuletas google_analytics: [\"UA-114956807-1\", \"auto\"] repo_url: https://github.com/jolav/chuletas strict: true nav: - 'Menu': 'index.md' - 'HTML': 'html.md' - 'CSS': 'css.md' - 'Front End': 'frontend.md' - 'Javascript': 'javascript.md' - 'Javascript snippets': 'javascript-snippets.md' - 'Reactjs': 'reactjs.md' - 'Vuejs': 'vuejs.md' - 'Nodejs con Expressjs': 'nodejs-expressjs.md' - 'Nodejs snippets': 'nodejs-snippets.md' - 'Nodejs Bases de Datos': 'nodejs-bases-de-datos.md' - 'Golang': 'golang.md' - 'Golang web': 'golang-web.md' - 'Golang snippets': 'golang-snippets.md' - 'Golang Bases de Datos': 'golang-bases-de-datos.md' - 'Debian': 'debian.md' - 'Varios': 'varios.md' #theme: alabaster #theme_dir: \"chuletas-theme\" theme: name: alabaster custom_dir: chuletas-theme site_dir: 'chuletas' docs_dir: 'docs' extra_css: - '_extra/css/extra.css' extra_javascript: - '_extra/js/highlight.pack.js' extra: logo: '_img/chuletas128.png' include_toc: true GLITCH.COM Plantilla package.json { \"name\": \"sp500\", \"version\": \"0.1.11\", \"description\": \"betazone finance sp500 stock real time data\", \"main\": \"sp.js\", \"scripts\": { \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\", \"start\": \"node sp.js\" }, \"engines\": { \"node\": \"8.x\" }, \"author\": \"jolav\", \"license\": \"BSD-3-Clause\", \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/jolav/betazone.git\" }, \"bugs\": { \"url\": \"https://github.com/jolav/betazone/issues\" }, \"homepage\": \"https://github.com/jolav/betazone#readme\", \"dependencies\": { \"express\": \"^4.16.2\", \"dotenv\": \"^5.0.0\", } } EXPRESIONES REGULARES Flags Se a\u00f1aden despues de la expresion regular para indicar algo /expReg/i - ignora mayusculas o minusculas /expReg/g - repetir la busqueda a traves de la cadena entera Basicos . - cualquier cosa \\s - espacio en blanco \\S - cualquiera menos espacio en blanco \\d - numero \\D - no numero \\w - caracter alfanumerico (a-z, A-Z, 0-9) \\W - no caracter alfanumerico \\t - tabulador \\r - retorno de carro \\n - nueva linea Limites ^ - Comienzo de cadena o de multilinea \\A - Comienzo de cadena $ - Fin de cadena o fin de multilinea \\Z - Fin de cadena \\b - Palabra limite , \"\\bcat\\b\" pilla en \"cat in the hat\" pero no en \"locate\" \\B - No es una palabra limite \\< - Comienzo de palabra \\> - Fin de palabra Grupos y rangos Los rangos son inclusive (X|Y) - X o Y, ejemplo \\b(cat|dog)s\\b pilla \"cats\" o \"dogs\" (...) - Grupos [abc] - Rango (\"a\" \u00f3 \"b\" \u00f3 \"c\") [^abc] - No (\"a\" \u00f3 \"b\" \u00f3 \"c\") [a-h] - Minuscula entre la \"a\" y la \"h\" [A-H] - Mayucula entre la \"a\" y la \"h\" [3-6] - Numero entre 3 y 6 ambos inclusive Cuantificadores Por defecto los cuantificadores solo se aplican a un caracter, para aplicarlo a mas usar (...) para especificar la cadena buscada X* - 0 \u00f3 mas repeticiones de X X+ - 1 \u00f3 mas repeticiones de X X? - 0 \u00f3 instancias de X, vamos que es opcional X{m} - exactamente m instancias de X X{m,} - al menos m instancias de X X{m,n} - entre m y n instancias(incluidas) de X Especiales {}[]()^$.|*+?\\ y - entre corchetes deben ser escapados con contrabarra \\ Javascript En Javascript las expresiones regulares han de estar en una sola linea. Los espacios en blanco son significativos Delimitadas por barras / var expreg = /ab+c/; var expreg = new RegExp('/ab+c/'); expreg.test(variableATestarConLaexpresionRegular) // da true o false Metodos regexp.exec(string) Si la expresion regular casa con el string devuelve un array array[0] es la subcadena que casa con la expresion regular array[1] el texto capturado por el primer grupo array[2] el texto capturado por el segundo grupo array[n] el texto capturado por el n grupo Si la expresion regular tiene una bandera g la busqueda empieza en la posicion regexp.lastIndex (inicialmente cero). Si la busqueda es exitosa regexp.lastIndex pasara a ser el siguiente caracter tras la coincidencia. Si falla pasa a 0. Esto permite buscar varias coincidencias en una sola cadena regexp.test(string) Si la expresion regular casa con el string devuelve true, si no false var b = /&.+;/.test('frank & beans'); // b is true string.replace(expreg, nueva) - en la cadena string reemplaza lo que casa con la expresion regular por la string nueva string.match(regexp) - busca la regexp en la cadena string y devuelve las coincidencias en un array var str = \"The rain in SPAIN stays mainly in the plain\"; var res = str.match(/ain/g); console.log(res) // [ 'ain', 'ain', 'ain' ] ExpReg Comunes .replace(/\\s+/g, \"\") - Elimina todos los espacios en blancos .replace(/\\s/g, \"loQueSea\") - Reemplaza todos los espacios en blanco por loQueSea /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/ - direccion de correo valida Aqui","title":"Varios"},{"location":"varios/#miscellaneus","text":"","title":"MISCELLANEUS"},{"location":"varios/#imagemagick","text":"Ejemplos Hacer el fondo transparente convert input.png -transparent red output.png Conversion entre formatos convert image.png image.jpg // bajando la calidad convert image.png -quality 90 image.jpg Convertir color de fondo a transparente o a otro color. convert image.png -background white white.png Montar imagenes montage -label 'FRONT END' frontEnd.png -label 'BACK END' backEnd.png -label 'DATABASE' database.png -label 'UTILS' utils.png -tile 2x2 -geometry 200x200 total.png Recortar los bordes shave Hacer el canvas mayor para encajar la imagen convert input.png -gravity center -background white -extent 500x500 output.png Optimizar imagenes // png convert INPUT.png -strip [-resize WxH] [-alpha Remove] OUTPUT.png //jpg convert INPUT.jpg -sampling-factor 4:2:0 -strip [-resize WxH] [-quality 85] [-interlace JPEG] [-colorspace Gray/sRGB] OUTPUT.jpg Comprimir imagenes // ojo que esto modifica el fichero actual, no crea uno nuevo mogrify -strip -interlace Plane -gaussian-blur 0.05 -quality 40% *.jpg","title":"IMAGEMAGICK"},{"location":"varios/#git","text":"Instalar // Debian backports para pillar la ultima version deb http://ftp.debian.org/debian strecth-backports main aptitude -t strecth-backports install \"package\" // debian aptitude install git git config --global user.name \"John Doe\" git config --global user.email johndoe@example.com git config --list nano ~/.gitconfig Commands git init [project-name] - A\u00f1ade el directorio donde estamos y crea el .git git status - lista todos los archivos nuevos o modificados sin haber sido committed git add [file] - - A\u00f1ade el fichero a la staging area y empieza a seguir los cambios que en el se producen git add . - A\u00f1ade todo en el directorio de forma recursiva a la staging area git reset [file] - Saca al archivo de la staging area git diff - Vemos los cambio del archivo git diff --staged - Vemos los cambio que hemos mandado al staging git commit -m \"mensaje\" - Realiza un commit y le asigna un \"mensaje\" git log - Es un diario con los cambios hechos en commits an la actual rama de .gitignore a github Si a\u00f1adimos algo a .gitignore ya no se commiteara pero tampoco desaparece lo existente en github. Para que se elimine de github ... git rm -r --cached some-directory git commit -m 'Remove the now ignored directory \"some-directory\"' git push origin master - normalmente con git push vale ramas git checkout -b nuevaRama - crea nueva rama de rama nuevaRama git checkout -d nombreRama - delete rama nombreRama git checkout otraRama - cambia a la rama otraRama git push origin nombreRama - push los commits de nombreRama git stash - cambios no committed se arrastran de una rama a otra. Para mantenerlos separados hacemos un stash antes de movernos a otra rama para guardar esos cambios antes de cambiar de rama. git stash apply - cuando vuelves a una rama recuperas los cambios sin hacer commit que se guardaron en esa rama. volver a estado anterior git reset --hard HEAD~5 - elimina los ultimos 5 commits git push origin -f - sincroniza la nueva situacion Volver a un commit anterior sin modificar el head # Paso 1: Encuentra el hash del commit git log # Paso 2: Crea una nueva rama como backup (opcional pero recomendado) git checkout -b nueva-rama # Paso 3: Actualiza el directorio de trabajo al estado del commit # Reemplaza con el hash del commit al que deseas volver git checkout . # Paso 4: A\u00f1ade los cambios al \u00edndice (si es necesario) git add . # Paso 5: Haz un nuevo commit (si es necesario) git commit -m \"Revertir al estado del commit \" # Paso 6: Empuja los cambios al repositorio remoto (si es necesario) git push origin nueva-rama Reducir el tama\u00f1o del directorio .git","title":"GIT"},{"location":"varios/#mkdocs","text":"Instalacion apt-get install python-pip pip list --outdated -lista paquetes que se pueden actualizar pip install mkdocs pip install --upgrade mkdocs -actualizar mkdocs instalar mas temas pip install mkdocs-bootstrap pip install mkdocs-bootswatch pip install mkdocs-material pip install mkdocs-alabaster pip install mkdocs-cinder Configuracion mkdocs new my-project cd my-project $ mkdocs serve Running at: http://127.0.0.1:8000/ Comandos mkdocs build - crea un directorio site con todo el contenido estatico que se subira al servidor mkdocs build --clean - limpia lo que sobra de antes mkdocs build -d ruta/donde/gustes - crea el resultado y con el nombre gustes Ejemplo mkdocs.yml site_name: Chuletas google_analytics: [\"UA-114956807-1\", \"auto\"] repo_url: https://github.com/jolav/chuletas strict: true nav: - 'Menu': 'index.md' - 'HTML': 'html.md' - 'CSS': 'css.md' - 'Front End': 'frontend.md' - 'Javascript': 'javascript.md' - 'Javascript snippets': 'javascript-snippets.md' - 'Reactjs': 'reactjs.md' - 'Vuejs': 'vuejs.md' - 'Nodejs con Expressjs': 'nodejs-expressjs.md' - 'Nodejs snippets': 'nodejs-snippets.md' - 'Nodejs Bases de Datos': 'nodejs-bases-de-datos.md' - 'Golang': 'golang.md' - 'Golang web': 'golang-web.md' - 'Golang snippets': 'golang-snippets.md' - 'Golang Bases de Datos': 'golang-bases-de-datos.md' - 'Debian': 'debian.md' - 'Varios': 'varios.md' #theme: alabaster #theme_dir: \"chuletas-theme\" theme: name: alabaster custom_dir: chuletas-theme site_dir: 'chuletas' docs_dir: 'docs' extra_css: - '_extra/css/extra.css' extra_javascript: - '_extra/js/highlight.pack.js' extra: logo: '_img/chuletas128.png' include_toc: true","title":"MKDOCS"},{"location":"varios/#glitchcom","text":"Plantilla package.json { \"name\": \"sp500\", \"version\": \"0.1.11\", \"description\": \"betazone finance sp500 stock real time data\", \"main\": \"sp.js\", \"scripts\": { \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\", \"start\": \"node sp.js\" }, \"engines\": { \"node\": \"8.x\" }, \"author\": \"jolav\", \"license\": \"BSD-3-Clause\", \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/jolav/betazone.git\" }, \"bugs\": { \"url\": \"https://github.com/jolav/betazone/issues\" }, \"homepage\": \"https://github.com/jolav/betazone#readme\", \"dependencies\": { \"express\": \"^4.16.2\", \"dotenv\": \"^5.0.0\", } }","title":"GLITCH.COM"},{"location":"varios/#expresiones-regulares","text":"Flags Se a\u00f1aden despues de la expresion regular para indicar algo /expReg/i - ignora mayusculas o minusculas /expReg/g - repetir la busqueda a traves de la cadena entera Basicos . - cualquier cosa \\s - espacio en blanco \\S - cualquiera menos espacio en blanco \\d - numero \\D - no numero \\w - caracter alfanumerico (a-z, A-Z, 0-9) \\W - no caracter alfanumerico \\t - tabulador \\r - retorno de carro \\n - nueva linea Limites ^ - Comienzo de cadena o de multilinea \\A - Comienzo de cadena $ - Fin de cadena o fin de multilinea \\Z - Fin de cadena \\b - Palabra limite , \"\\bcat\\b\" pilla en \"cat in the hat\" pero no en \"locate\" \\B - No es una palabra limite \\< - Comienzo de palabra \\> - Fin de palabra Grupos y rangos Los rangos son inclusive (X|Y) - X o Y, ejemplo \\b(cat|dog)s\\b pilla \"cats\" o \"dogs\" (...) - Grupos [abc] - Rango (\"a\" \u00f3 \"b\" \u00f3 \"c\") [^abc] - No (\"a\" \u00f3 \"b\" \u00f3 \"c\") [a-h] - Minuscula entre la \"a\" y la \"h\" [A-H] - Mayucula entre la \"a\" y la \"h\" [3-6] - Numero entre 3 y 6 ambos inclusive Cuantificadores Por defecto los cuantificadores solo se aplican a un caracter, para aplicarlo a mas usar (...) para especificar la cadena buscada X* - 0 \u00f3 mas repeticiones de X X+ - 1 \u00f3 mas repeticiones de X X? - 0 \u00f3 instancias de X, vamos que es opcional X{m} - exactamente m instancias de X X{m,} - al menos m instancias de X X{m,n} - entre m y n instancias(incluidas) de X Especiales {}[]()^$.|*+?\\ y - entre corchetes deben ser escapados con contrabarra \\","title":"EXPRESIONES REGULARES"},{"location":"varios/#javascript","text":"En Javascript las expresiones regulares han de estar en una sola linea. Los espacios en blanco son significativos Delimitadas por barras / var expreg = /ab+c/; var expreg = new RegExp('/ab+c/'); expreg.test(variableATestarConLaexpresionRegular) // da true o false Metodos regexp.exec(string) Si la expresion regular casa con el string devuelve un array array[0] es la subcadena que casa con la expresion regular array[1] el texto capturado por el primer grupo array[2] el texto capturado por el segundo grupo array[n] el texto capturado por el n grupo Si la expresion regular tiene una bandera g la busqueda empieza en la posicion regexp.lastIndex (inicialmente cero). Si la busqueda es exitosa regexp.lastIndex pasara a ser el siguiente caracter tras la coincidencia. Si falla pasa a 0. Esto permite buscar varias coincidencias en una sola cadena regexp.test(string) Si la expresion regular casa con el string devuelve true, si no false var b = /&.+;/.test('frank & beans'); // b is true string.replace(expreg, nueva) - en la cadena string reemplaza lo que casa con la expresion regular por la string nueva string.match(regexp) - busca la regexp en la cadena string y devuelve las coincidencias en un array var str = \"The rain in SPAIN stays mainly in the plain\"; var res = str.match(/ain/g); console.log(res) // [ 'ain', 'ain', 'ain' ]","title":"Javascript"},{"location":"varios/#expreg-comunes","text":".replace(/\\s+/g, \"\") - Elimina todos los espacios en blancos .replace(/\\s/g, \"loQueSea\") - Reemplaza todos los espacios en blanco por loQueSea /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/ - direccion de correo valida Aqui","title":"ExpReg Comunes"}]} \ No newline at end of file +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Volver al inicio . Jolav \u00a9 2024 - Ver el c\u00f3digo en GitHub MENU","title":"Menu"},{"location":"#menu","text":"","title":"MENU"},{"location":"css/","text":"CSS SNIPPETS Alinear imagenes .imgV { vertical-align: middle; } .imgH { display: flex; margin: 0 auto; max-width: 100%; } Enlaces animados y sin subrayar a, a:visited { text-decoration: none; color: #375EAB; } a:hover { color: lightblue; } div:hover { transform: scale(1.2); } Desactivar enlace a.notYet { pointer-events: none; text-decoration: line-through; color: #404040; } hr gradual hr { margin: 10px 10% 10px 10%; border: 0; height: 1px; background: #333; background-image: linear-gradient(to right, #ccc, #888, #ccc); } Problema en Chrome con la lista de puntos ul { text-align: center; /* para evitar los puntos */ display: inline; /* poner los numeros en Chrome de listas ordenadas dentro del texto*/ list-style-position: inside; list-style-type: none; } Fijar pie al final de pantalla html { height: 100%; box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } body { position: relative; margin: 0 auto; /*padding-bottom: 6rem;*/ min-height: 97%; } .footer { position: absolute; right: 0; bottom: 0; left: 0; padding: 1rem; background-color: lightblue; text-align: center; } Tama\u00f1o fuente como navegador html { font-size:16px; } /* Fijando el css en 16px y usando em despues conseguiremos resultados consistentes en firefox y chrome */ body { font-size:0.90em; } CSS3 INTRODUCCION Enlaces a css Externo CSS Externo Si hay multiples hojas de estilo : uno para cada hoja de estilo En la hoja de estilo que se enlaza incluir @import url(\"estilo2.css);\" Interno - NO USAR CSS Interno Selectores Selectores CSS Selectores de atributos Cascada y herencia Cascada - Ultima Regla: la ultima regla aplicada es la que manda - !important a\u00f1adiendo esto despues de la regla asi toma prioridad color: blue !important; - Especificidad : prevalecera la regla del selector que sea mas especifico h3 es mas especifico que * p otro es mas especifico que p p#intro es mas especifico que p Herencia Casi todos los selectores anidados dentro de otros heredan las propiedades asignadas al selector exterior. Por ejemplo un color en body tambien se aplicara al texto de un parrafo. Hay excepciones evidentes como margin-top (un parrafo no tiene el mismo margen superior que el body del documento). Puedes forzar heredar valores de propiedades de los padres usando inherit como valor de la propiedad body { padding: 20px;} .pagina { padding: inherit;} COLOR color - h1 { color: DarkCyan;} /* color name */ h2 { color: #ee3e80;} /* hex code */ p { color: rgb(100,100,90);} /* rgb value */ background color - body { background-color: rgb(150,150,150); } h1 { background-color: DarkCyan; } h2 { background-color: ##ee3e80: } p { background-color: red; } opacity , rgba - p.one { background-color: rgb(0,0,0); opacity: 0.5;} p.two { background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.5);} TEXTO cursor - Controla el tipo de cursor del raton que se muestra auto|crosshair|default|pointer|move|text|wait|help|url(\"cursor.png\") a { cursor: move;} font-family - Familias : serif , sans-serif , cursive , fantasy y monospace font-family: Arial, Verdana, sans-serif font-size - Pixel: Por defecto en los navegadores el texto es de 16px Porcentaje : porcentaje sobre los 16px estandar, p.ej 75% es 12px em : unidad equivalente a la anchura de la m font-face - @font-face { font-family: 'PT Sans'; src: url('_public/fonts/PTSans.ttf') ; font-display: fallback; } @font-face { font-family: 'ChunkFiveRegular'; src: url('fonts/chunkfive.eot'); src: url('fonts/chunkfive.eot?#iefix') format('embedded-opentype'), url('fonts/chunkfive.woff') format('woff'), url('fonts/chunkfive.ttf') format('truetype'), url('fonts/chunkfive.svg#ChunkFiveRegular') format('svg');} font-weight - normal|bold font-style - normal|italic|oblique text-transform - uppercase : convierte el texto a mayusculas lowercase : convierte el texto a minusculas capitalize : pone mayusculas la primera letra de cada palabra h1 { text-transform: uppercase;} text-decoration - none : elimina cualquier decoracion del texto underline : subraya el texto overline : coloca una linea por encima del texto line-through : linea tachando el texto blink : hace que el texto brille y deje brillar a { text-decoration: none;} line-height - distancia entre lineas p { line-height: 1.4em; } letter-spacing , word-spacing - distancia entre letras, distancia entre palabras, por defecto es 0.25em h1, h2 { text-transform: uppercase; letter-spacing: 0.2em; } .credits { font-weight: bold; word-spacing: 1em; } text-align - left : el texto se alinea a la izquierda right : el texto se alinea a la derecha center : el texto se centra justify : Cada linea excepto la ultima ocupa toda la anchura disponible h1 { text-align: left; } vertical-align - Usada con elementos en linea como y es muy similar al atributo align de Valores : baseline , sub , super , top , text-top , middle , bottom , text-bottom #six-months { vertical-align: text-top;} #one-year { vertical-align: baseline;} #two-years { vertical-align: text-bottom;} text-indent - indenta el texto h2 { text-indent: 20px; } text-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado de la sombra color de la sombra p { text-shadow: 2px 2px 1px #222222} :first-letter , :first-line (pseudo-elementos) - Para especificar diferentes valores a la primera letra o primera linea del texto p.intro:first-letter { font-size: 200%;} p.intro:first-line { font-weight: bold;} :link , :visited (pseudo-clases) - Los navegadores muestran los enlaces en azul y subrayados por defecto y cambian el color cuando han sido visitados :link : para poner estilos a enlaces no visitados :visited : para poner estilos a enlaces visitados a:link { color: deeppink; text-decoration: none;} a:visited { color: black;} a:hover { color: deeppink; text-decoration: underline;} a:active { color: darkcyan;} :hover , :active , :focus (pseudo-clases) - :hover : se aplica cuando el raton esta encima (no funciona en tactiles) :active : se aplica cuando se pulsa algo :focus : se aplica cuando el elemento tiene el foco cajetinTexto { padding: 6px 12px 6px 12px; border: 1px solid #665544; color: #ffffff;} boton.submit:hover { background-color: #665544;} boton.submit:active { background-color: chocolate;} cajetinTexto.text { color: #cccccc;} cajetinTexto.text:focus { color: #665544;} BOXES Dimensiones width , height - Por defecto las cajas tienen el tama\u00f1o justo para contener a su elemento. Podemos establecer nosotros ese tama\u00f1o usando pixeles , o porcentajes relativos a la ventana del navegador o a la caja en que ya esta si esta dentro de otra caja, o ems div.box { height: 300px; width: 300px; background-color: #bbbbaa;} min-width , max-width - Minimo y maximo anchura que una caja de un elemento puede tener min-height , max-height - Minimo y maximo anchura que una caja de un elemento puede tener overflow - Indica como actuar si el contenido dentro de la caja es mayor que la caja. hidden : el contenido extra que no cabe sencillamente se esconde scroll : aparece un scroll para acceder a ese contenido extra p.one { overflow: hidden;} p.two { overflow: scroll;} Visibilidad display - Permite convertir un elemento en linea en un bloque o al reves. Tambien vale para esconder un elemento en la pagina inline : convierte un elemento de bloque en un elemento en linea block : convierte un elemento en linea en un elemento de bloque inline-block : permite a un elemento de bloque fluir como un elemento en linea pero manteniendo las caracteristicas de un elemento de bloque none : esconde el elemento de la pagina li { display: inline; margin-right: 10px;} li.coming-soon { display: none;} visibility - Permite esconder cajas pero deja un espacio donde se supone que esta hidden : esconde el elemento visible : muestra el elemento li.coming-soon { visibility: hidden;} box-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado del borde. Con cero la sombra es una linea solida Extension de la sombra, positiva hacia fuera, negativa hacia dentro p { box-shadow: 2px 2px 1px 5px #777777} Bordes border-padding-margin - border-width - espesor de la linea de borde thin|medium|thick . border-top-width , border-right-width , border-bottom-width border-left-width en orden de las agujas del reloj empezando por top p.one { border-width: 2px;} p.two { border-width: thick;} p.three { border-width: 1px 4px 12px 4px;} border-style - define el tipo de borde solid|dotted|dashed|double|groove|ridge|inset|outset|hidden/none . border-top-style ... - Puedes elegir bordes individuales p.one {border-style: dashed;} border-color - elegir color para el borde border-top-color ... - Tambien se puede elegir el color para cada borde p.one { border-color: #0088dd;} p.two { border-color: #bbbbaa blue orange #0088dd;} border-image - Permite usar imagenes como bordes de las cajas border-radius - border-top-right-radius - border-bottom-right-radius - border-bottom-left-radius - border-top-left-radius - p { border-radius: 5px, 10px, 5px, 10px; } p.one { border-radius: 80px 50px; } p.two { border-top-left-radius: 80px 50px;} Margenes margin - Espacio entre el borde y la caja. Lo normal en px aunque tambien se puede en ems o porcentajes. Si dos cajas se solapan usaremos el mayor de los dos margenes y el otro no Tambien individualmente para cada lado margin-top, margin-right ... p.example1 { margin: 10px 2px 10px 5px; p.example2 { margin: 10px;} padding - Espacio entre el borde y el contenido. Lo normal es en px pero se pueden usar ems o porcentajes (% de la ventana del navegador o de la caja donde este contenido el elemento). Existen tambien individualmente para cada lado padding-top, padding-right ... p.example1 { padding: 10px 2px 10px 5px; p.example2 { padding: 10px;} centrando contenido - Para centrar una caja en la pagina ( o centrarla dentro del elemento en el que esta Establecer una width para la caja (sino tomara toda la anchura de la pagina) Poner margin-left: auto y margin-rigth: auto p { width: 300px; padding: 50px; border: 20px solid #0088dd;} p.example { margin: 10px auto 10px auto; LISTAS list-style - Permite declaras las siguientes opciones type, imagen y position en cualquier orden. ul { list-style: inside circle; } list-style-type - Para poner el estilo al marcador de las listas - Listas ordenadas decimal|decimal-leading-zero|lower-alpha|upper-alpha|lower-roman|upper-roman - Listas desordenadas none|disc|circle|square ol { list-style-type: lower-roman;} list-style-imagen - Usar una imagen como marcador de listas. Se puede usar en
          y
        • ul { list-style-image: url(\"images/star.png\");} list-style-position - Por defecto el marcador de lista aparece outside del indentado de la lista. Podemos cambiarlo por inside para que el marcador entre en la caja del texto el cual esta indentado ul.t1 { list-style-position: outside;} ul.t2 { list-style-position: inside;} TABLAS Consejos: Diferenciar cabeceras en negrita, mayusculas o algo mas Oscurecer filas alternativas Columnas con numeros alinearlos a la derecha width : poner la anchura de la tabla padding : de las celdas
          y text-transform : en las cabeceras letter-spacing, font-size : para diferenciar el texto de las cabeceras border-top, border-bottom : para fiferenciar los bordes de la cabecera text-align : para alinear el texto de las celdas a conveniencia background-color : cambiar el color de fondo alternando filas :hover : iluminar la fila con el puntero encima body { font-family: Arial, Verdana, sans-serif; color: #111111;} table { width: 600px;} th, td { padding: 7px 10px 10px 10px;} th { text-transform: uppercase; letter-spacing: 0.1em; font-size: 90%; border-bottom: 2px solid #111111; border-top: 1px solid #999; text-align: left;} tr.even { background-color: #efefef;} tr:hover { background-color: #c3e6e5;} .money { text-align: right;} empty-cells - show|hide|inherit indicar en las celdas vacias si mostramos los bordes o no o hereda el comportamiento de la tabla que le contiene table.one { empty-cells: show;} table.two { empty-cells: hide;} border-spacing ajusta la distancia entre celdas adyacentes, por defecto es minima. Se pone en px. Si pones dos valores son la separacion horizontal y la vertical border-collapse los bordes se juntan en un solo borde table.one { border-spacing: 5px 15px;} table.two { border-collapse: collapse;} FORMULARIOS Dar estilo a entradas de texto input { font-size: 120%; // tama\u00f1o del texto color: #5a5854; // color del texto background-color: #f2f2f2; // color del fondo de la entrada border: 1px solid #bdbdbd; // marca los bordes de la entrada border-radius: 5px; // redondea esos bordes padding: 5px 5px 5px 30px; background-repeat: no-repeat; background-position: 8px 9px; display: block; margin-bottom: 10px;} input:focus { // cambia el color de fondo background-color: #ffffff; border: 1px solid #b1e1e4;} input#email { background-image: url(\"images/email.png\");} input#twitter { background-image: url(\"images/twitter.png\");} input#web { background-image: url(\"images/web.png\");} Dar estilo a botones submit input#submit { color: #444444; // color del texto del boton text-shadow: 0px 1px 1px #ffffff; // apariencia 3d border-bottom: 2px solid #b2b2b2; // para el borde del boton background-color: #b9e4e3; background: -webkit-gradient(linear, left top, left bottom, from(#beeae9), to(#a8cfce)); background: -moz-linear-gradient(top, #beeae9, #a8cfce); background: -o-linear-gradient(top, #beeae9, #a8cfce); background: -ms-linear-gradient(top, #beeae9, #a8cfce);} input#submit:hover { // cambia la apariencia del boton color: #333333; // al pasar por encima border: 1px solid #a4a4a4; border-top: 2px solid #b2b2b2; background-color: #a0dbc4; background: -webkit-gradient(linear, left top, left bottom, from(#a8cfce), to(#beeae9)); background: -moz-linear-gradient(top, #a8cfce, #beeae9); background: -o-linear-gradient(top, #a8cfce, #beeae9); background: -ms-linear-gradient(top, #a8cfce, #beeae9);} Poner estilo a fieldsets y legends fieldset { width: 350px; // controlar el tama\u00f1o del form border: 1px solid #dcdcdc; border-radius: 10px; padding: 20px; text-align: right;} legend { background-color: #efefef; // color de fondo border: 1px solid #dcdcdc; border-radius: 10px; padding: 10px 20px; text-align: left; text-transform: uppercase;} Alinear formularios div { border-bottom: 1px solid #efefef; margin: 10px; padding-bottom: 10px; width: 260px;} .title { float: left; width: 100px; text-align: right; padding-right: 10px;} .radio-buttons label { float: none;} .submit { text-align: right;} LAYOUT Tipos posicionamiento position: static normal o estatico es el usado por defecto. Los elementos de bloque se ponen uno a continuacion de otro ocupando todo el ancho de la ventana del navegador salvo que lo limite con `width. position: relative - Los elementos se posicionan en relacion a donde deberian estar en posicion normal. Los desplazamos dando valor a top, bottom, left, right . Estos valores se ponen en px, porcentajes o ems p.example { position: relative; top: 10px; left: 100px;} position: absolute - El elemento se posiciona de forma absolita respecto a su elemento contenedor y el resto de elementos de la pagina le ignoran h1 { position: absolute; top: 0px; left: 500px; width: 250px;} position: fixed - Como el absoluto pero el elemento ahora es inamovible, su posicion permanece igual independiente del resto de elemntos e incluso si se sube o baja en la ventana del navegador. Util para hacer menus fijos por ejemplo en la parte superior de la ventana h1 { position: fixed; top: 0px; left: 50px; padding: 10px; margin: 0px; width: 100%; background-color: #efefef;} position: inherit , hereda la posicion del padre float: left|right - Desplaza los elementos todo lo que puede hacia la dcha o izda segun la propiedad float . Cualquier otro elemento dentro del elemento contenedor fluira alrededor del elemento que flota blockquote { float: right; width: 275px; font-size: 130%; font-style: italic; font-family: Georgia, Times, serif; margin: 0px 0px 10px 10px; padding: 10px; border-top: 1px solid #665544; border-bottom: 1px solid #665544;} propiedades de apoyo clear: left|right|both|none - indica que ningun otro elemento del mismo contenedot debe tocar el lado indicado de ese elemento .clear { clear: left;} overflow: auto; width:100% - Si todos los elemento de un contenedor son flotantes puede hacer problemas en ciertos navegadores a la hora de mostrar los bordes div { border: 1px solid #665544; overflow: auto; width: 100%;} multicolumna - Crear dise\u00f1os multicolumna con floats. Usar un
          para cada columna y con las siguientes propiedades width , float y margin para cerrar un hueco entre las columnas z-index - Al usar posicionamiento relativo, fijo o absoluto los elementos se pueden solapar. Si es asi el ultimo que aparece en el codigo HTML es el que se ve. Para controlar eso esta la propiedad z-index , se ve el elemento con el mayor valor de esa propiedad h1 { position: fixed; z-index: 10;} Tipos de Layout Anchura fija La anchura se especifica en pixeles (a veces tambien la altura) body { width: 960px; margin: 0 auto;} #content { overflow: auto; height: 100%;} #nav, #feature, #footer { background-color: #efefef; padding: 10px; margin: 10px;} .column1, .column2, .column3 { background-color: #efefef; width: 300px; float: left; margin: 10px;} li { display: inline; padding: 5px;} Liquidos La anchura se especifica en porcentajes. 90% de anchura cada columna se le pone un margin: 1% min-width, max-width para limitar los estiramientos body { width: 90%; margin: 0 auto;} #content {overflow: auto;} #nav, #feature, #footer { margin: 1%;} .column1, .column2, .column3 { width: 31.3%; float: left; margin: 1%;} .column3 {margin-right: 0%;} li { display: inline; padding: 0.5em;} #nav, #footer { background-color: #efefef; padding: 0.5em 0;} #feature, .article { height: 10em; margin-bottom: 1em; background-color: #efefef;} Dise\u00f1o 960px IMAGENES Controlar tama\u00f1o Creas tres clases de imagenes, peque\u00f1as, medianas y grandes. Despues a cada imagen le pones la clase a la que pertenece y asi automaticamente se pone a ese tama\u00f1o img.large { width: 500px; height: 500px;} img.medium { width: 250px; height: 250px;} img.small { width: 100px; height: 100px;} Alinear imagenes Se recomienda usar float en lugar de align . Creamos clases align-left align-right y luego a las imagenes les a\u00f1adimos la clase que nos interese img.align-left { float: left; margin-right: 10px;} img.align-right { float: right; margin-left: 10px;} Centrar imagenes Debemos convertir la imagen en en elemento de bloque y luego usar margin img.align-center { display: block; margin: 0px auto;} background background - Orden de las propiedades: background-color background-image background-repeat background-attachment background-position body { background: #ffffff url(\"images/tulip.gif\") no-repeat top right;} background-image - la imagen se ponde de fondo del elemento al que se lo asignamos p { background-image: url(\"images/pattern.gif\");} background-repeat - repeat la imagen se repite horizontal y verticalmente repeat-x la imagen solo se repite horizontalmente repeat-y la imagen solo se repite verticalmente no-repeat la imagen se muestra solo una vez body { background-image: url(\"images/header.gif\"); background-repeat: repeat-x;} background-attachment - fixed la imagen permanece fija scroll la imagen se mueve con el scroll body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-attachment: fixed;} background-position - Para especificar donde sale una imagen que no se repite. La propiedad tiene dos valores: Si solo se indica uno el segundo valor sera center . Tambien se puede usar px o porcentajes posicion horizontal left|center|right posicion vertical top|center|bottom body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: center top;} body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: 50% 50%;} rollover y sprites Enlaces o botones que tienen un segundo estilo al ponerse el puntero encima y un tercer estilo al pincharlos. Se usan sprites que son una sola imagen con diferentes partes a usar. Add to basket Framing options a.button { height: 36px; background-image: url(\"images/sprite.png\"); text-indent: -9999px; display: inline-block;} a#add-to-basket { width: 174px; background-position: 0px 0px;} a#framing-options { width: 210px; background-position: -175px 0px;} a#add-to-basket:hover { background-position: 0px -40px;} a#framing-options:hover { background-position: -175px -40px;} a#add-to-basket:active { background-position: 0px -80px;} a#framing-options:active { background-position: -175px -80px;} TRANSITION .tecla { color: deepskyblue; background: rgba(0, 0, 0, 0.4); text-shadow: 0 0 1px black; transition: background-color 0.2s; } .pulsada { background-color: orange; transform: scale(1.1, 1.1); }
          Aclap
          function pressKey (e) { var valor = mapa.indexOf(e.key.toUpperCase()); if (valor !== -1) { document.getElementById(valor).addEventListener('transitionend', function () { document.getElementById(valor).classList.remove('pulsada'); }); document.getElementById(valor).classList.add('pulsada'); audio[valor].play(); } }","title":"CSS"},{"location":"css/#css","text":"","title":"CSS"},{"location":"css/#snippets","text":"","title":"SNIPPETS"},{"location":"css/#alinear-imagenes","text":".imgV { vertical-align: middle; } .imgH { display: flex; margin: 0 auto; max-width: 100%; }","title":"Alinear imagenes"},{"location":"css/#enlaces-animados-y-sin-subrayar","text":"a, a:visited { text-decoration: none; color: #375EAB; } a:hover { color: lightblue; } div:hover { transform: scale(1.2); } Desactivar enlace a.notYet { pointer-events: none; text-decoration: line-through; color: #404040; }","title":"Enlaces animados y sin subrayar"},{"location":"css/#hr-gradual","text":"hr { margin: 10px 10% 10px 10%; border: 0; height: 1px; background: #333; background-image: linear-gradient(to right, #ccc, #888, #ccc); }","title":"hr gradual"},{"location":"css/#problema-en-chrome-con-la-lista-de-puntos","text":"ul { text-align: center; /* para evitar los puntos */ display: inline; /* poner los numeros en Chrome de listas ordenadas dentro del texto*/ list-style-position: inside; list-style-type: none; }","title":"Problema en Chrome con la lista de puntos"},{"location":"css/#fijar-pie-al-final-de-pantalla","text":"html { height: 100%; box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } body { position: relative; margin: 0 auto; /*padding-bottom: 6rem;*/ min-height: 97%; } .footer { position: absolute; right: 0; bottom: 0; left: 0; padding: 1rem; background-color: lightblue; text-align: center; }","title":"Fijar pie al final de pantalla"},{"location":"css/#tamano-fuente-como-navegador","text":"html { font-size:16px; } /* Fijando el css en 16px y usando em despues conseguiremos resultados consistentes en firefox y chrome */ body { font-size:0.90em; }","title":"Tama\u00f1o fuente como navegador"},{"location":"css/#css3","text":"","title":"CSS3"},{"location":"css/#introduccion","text":"Enlaces a css Externo CSS Externo Si hay multiples hojas de estilo : uno para cada hoja de estilo En la hoja de estilo que se enlaza incluir @import url(\"estilo2.css);\" Interno - NO USAR CSS Interno ","title":"INTRODUCCION"},{"location":"css/#selectores","text":"Selectores CSS Selectores de atributos","title":"Selectores"},{"location":"css/#cascada-y-herencia","text":"Cascada - Ultima Regla: la ultima regla aplicada es la que manda - !important a\u00f1adiendo esto despues de la regla asi toma prioridad color: blue !important; - Especificidad : prevalecera la regla del selector que sea mas especifico h3 es mas especifico que * p otro es mas especifico que p p#intro es mas especifico que p Herencia Casi todos los selectores anidados dentro de otros heredan las propiedades asignadas al selector exterior. Por ejemplo un color en body tambien se aplicara al texto de un parrafo. Hay excepciones evidentes como margin-top (un parrafo no tiene el mismo margen superior que el body del documento). Puedes forzar heredar valores de propiedades de los padres usando inherit como valor de la propiedad body { padding: 20px;} .pagina { padding: inherit;}","title":"Cascada y herencia"},{"location":"css/#color","text":"color - h1 { color: DarkCyan;} /* color name */ h2 { color: #ee3e80;} /* hex code */ p { color: rgb(100,100,90);} /* rgb value */ background color - body { background-color: rgb(150,150,150); } h1 { background-color: DarkCyan; } h2 { background-color: ##ee3e80: } p { background-color: red; } opacity , rgba - p.one { background-color: rgb(0,0,0); opacity: 0.5;} p.two { background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.5);}","title":"COLOR"},{"location":"css/#texto","text":"cursor - Controla el tipo de cursor del raton que se muestra auto|crosshair|default|pointer|move|text|wait|help|url(\"cursor.png\") a { cursor: move;} font-family - Familias : serif , sans-serif , cursive , fantasy y monospace font-family: Arial, Verdana, sans-serif font-size - Pixel: Por defecto en los navegadores el texto es de 16px Porcentaje : porcentaje sobre los 16px estandar, p.ej 75% es 12px em : unidad equivalente a la anchura de la m font-face - @font-face { font-family: 'PT Sans'; src: url('_public/fonts/PTSans.ttf') ; font-display: fallback; } @font-face { font-family: 'ChunkFiveRegular'; src: url('fonts/chunkfive.eot'); src: url('fonts/chunkfive.eot?#iefix') format('embedded-opentype'), url('fonts/chunkfive.woff') format('woff'), url('fonts/chunkfive.ttf') format('truetype'), url('fonts/chunkfive.svg#ChunkFiveRegular') format('svg');} font-weight - normal|bold font-style - normal|italic|oblique text-transform - uppercase : convierte el texto a mayusculas lowercase : convierte el texto a minusculas capitalize : pone mayusculas la primera letra de cada palabra h1 { text-transform: uppercase;} text-decoration - none : elimina cualquier decoracion del texto underline : subraya el texto overline : coloca una linea por encima del texto line-through : linea tachando el texto blink : hace que el texto brille y deje brillar a { text-decoration: none;} line-height - distancia entre lineas p { line-height: 1.4em; } letter-spacing , word-spacing - distancia entre letras, distancia entre palabras, por defecto es 0.25em h1, h2 { text-transform: uppercase; letter-spacing: 0.2em; } .credits { font-weight: bold; word-spacing: 1em; } text-align - left : el texto se alinea a la izquierda right : el texto se alinea a la derecha center : el texto se centra justify : Cada linea excepto la ultima ocupa toda la anchura disponible h1 { text-align: left; } vertical-align - Usada con elementos en linea como y es muy similar al atributo align de Valores : baseline , sub , super , top , text-top , middle , bottom , text-bottom #six-months { vertical-align: text-top;} #one-year { vertical-align: baseline;} #two-years { vertical-align: text-bottom;} text-indent - indenta el texto h2 { text-indent: 20px; } text-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado de la sombra color de la sombra p { text-shadow: 2px 2px 1px #222222} :first-letter , :first-line (pseudo-elementos) - Para especificar diferentes valores a la primera letra o primera linea del texto p.intro:first-letter { font-size: 200%;} p.intro:first-line { font-weight: bold;} :link , :visited (pseudo-clases) - Los navegadores muestran los enlaces en azul y subrayados por defecto y cambian el color cuando han sido visitados :link : para poner estilos a enlaces no visitados :visited : para poner estilos a enlaces visitados a:link { color: deeppink; text-decoration: none;} a:visited { color: black;} a:hover { color: deeppink; text-decoration: underline;} a:active { color: darkcyan;} :hover , :active , :focus (pseudo-clases) - :hover : se aplica cuando el raton esta encima (no funciona en tactiles) :active : se aplica cuando se pulsa algo :focus : se aplica cuando el elemento tiene el foco cajetinTexto { padding: 6px 12px 6px 12px; border: 1px solid #665544; color: #ffffff;} boton.submit:hover { background-color: #665544;} boton.submit:active { background-color: chocolate;} cajetinTexto.text { color: #cccccc;} cajetinTexto.text:focus { color: #665544;}","title":"TEXTO"},{"location":"css/#boxes","text":"Dimensiones width , height - Por defecto las cajas tienen el tama\u00f1o justo para contener a su elemento. Podemos establecer nosotros ese tama\u00f1o usando pixeles , o porcentajes relativos a la ventana del navegador o a la caja en que ya esta si esta dentro de otra caja, o ems div.box { height: 300px; width: 300px; background-color: #bbbbaa;} min-width , max-width - Minimo y maximo anchura que una caja de un elemento puede tener min-height , max-height - Minimo y maximo anchura que una caja de un elemento puede tener overflow - Indica como actuar si el contenido dentro de la caja es mayor que la caja. hidden : el contenido extra que no cabe sencillamente se esconde scroll : aparece un scroll para acceder a ese contenido extra p.one { overflow: hidden;} p.two { overflow: scroll;} Visibilidad display - Permite convertir un elemento en linea en un bloque o al reves. Tambien vale para esconder un elemento en la pagina inline : convierte un elemento de bloque en un elemento en linea block : convierte un elemento en linea en un elemento de bloque inline-block : permite a un elemento de bloque fluir como un elemento en linea pero manteniendo las caracteristicas de un elemento de bloque none : esconde el elemento de la pagina li { display: inline; margin-right: 10px;} li.coming-soon { display: none;} visibility - Permite esconder cajas pero deja un espacio donde se supone que esta hidden : esconde el elemento visible : muestra el elemento li.coming-soon { visibility: hidden;} box-shadow - distancia a izda o dcha de la sombra distancia arriba o abajo de la sombra (opcional) cantidad de difuminado del borde. Con cero la sombra es una linea solida Extension de la sombra, positiva hacia fuera, negativa hacia dentro p { box-shadow: 2px 2px 1px 5px #777777} Bordes border-padding-margin - border-width - espesor de la linea de borde thin|medium|thick . border-top-width , border-right-width , border-bottom-width border-left-width en orden de las agujas del reloj empezando por top p.one { border-width: 2px;} p.two { border-width: thick;} p.three { border-width: 1px 4px 12px 4px;} border-style - define el tipo de borde solid|dotted|dashed|double|groove|ridge|inset|outset|hidden/none . border-top-style ... - Puedes elegir bordes individuales p.one {border-style: dashed;} border-color - elegir color para el borde border-top-color ... - Tambien se puede elegir el color para cada borde p.one { border-color: #0088dd;} p.two { border-color: #bbbbaa blue orange #0088dd;} border-image - Permite usar imagenes como bordes de las cajas border-radius - border-top-right-radius - border-bottom-right-radius - border-bottom-left-radius - border-top-left-radius - p { border-radius: 5px, 10px, 5px, 10px; } p.one { border-radius: 80px 50px; } p.two { border-top-left-radius: 80px 50px;} Margenes margin - Espacio entre el borde y la caja. Lo normal en px aunque tambien se puede en ems o porcentajes. Si dos cajas se solapan usaremos el mayor de los dos margenes y el otro no Tambien individualmente para cada lado margin-top, margin-right ... p.example1 { margin: 10px 2px 10px 5px; p.example2 { margin: 10px;} padding - Espacio entre el borde y el contenido. Lo normal es en px pero se pueden usar ems o porcentajes (% de la ventana del navegador o de la caja donde este contenido el elemento). Existen tambien individualmente para cada lado padding-top, padding-right ... p.example1 { padding: 10px 2px 10px 5px; p.example2 { padding: 10px;} centrando contenido - Para centrar una caja en la pagina ( o centrarla dentro del elemento en el que esta Establecer una width para la caja (sino tomara toda la anchura de la pagina) Poner margin-left: auto y margin-rigth: auto p { width: 300px; padding: 50px; border: 20px solid #0088dd;} p.example { margin: 10px auto 10px auto;","title":"BOXES"},{"location":"css/#listas","text":"list-style - Permite declaras las siguientes opciones type, imagen y position en cualquier orden. ul { list-style: inside circle; } list-style-type - Para poner el estilo al marcador de las listas - Listas ordenadas decimal|decimal-leading-zero|lower-alpha|upper-alpha|lower-roman|upper-roman - Listas desordenadas none|disc|circle|square ol { list-style-type: lower-roman;} list-style-imagen - Usar una imagen como marcador de listas. Se puede usar en
            y
          • ul { list-style-image: url(\"images/star.png\");} list-style-position - Por defecto el marcador de lista aparece outside del indentado de la lista. Podemos cambiarlo por inside para que el marcador entre en la caja del texto el cual esta indentado ul.t1 { list-style-position: outside;} ul.t2 { list-style-position: inside;}","title":"LISTAS"},{"location":"css/#tablas","text":"Consejos: Diferenciar cabeceras en negrita, mayusculas o algo mas Oscurecer filas alternativas Columnas con numeros alinearlos a la derecha width : poner la anchura de la tabla padding : de las celdas
            y text-transform : en las cabeceras letter-spacing, font-size : para diferenciar el texto de las cabeceras border-top, border-bottom : para fiferenciar los bordes de la cabecera text-align : para alinear el texto de las celdas a conveniencia background-color : cambiar el color de fondo alternando filas :hover : iluminar la fila con el puntero encima body { font-family: Arial, Verdana, sans-serif; color: #111111;} table { width: 600px;} th, td { padding: 7px 10px 10px 10px;} th { text-transform: uppercase; letter-spacing: 0.1em; font-size: 90%; border-bottom: 2px solid #111111; border-top: 1px solid #999; text-align: left;} tr.even { background-color: #efefef;} tr:hover { background-color: #c3e6e5;} .money { text-align: right;} empty-cells - show|hide|inherit indicar en las celdas vacias si mostramos los bordes o no o hereda el comportamiento de la tabla que le contiene table.one { empty-cells: show;} table.two { empty-cells: hide;} border-spacing ajusta la distancia entre celdas adyacentes, por defecto es minima. Se pone en px. Si pones dos valores son la separacion horizontal y la vertical border-collapse los bordes se juntan en un solo borde table.one { border-spacing: 5px 15px;} table.two { border-collapse: collapse;}","title":"TABLAS"},{"location":"css/#formularios","text":"Dar estilo a entradas de texto input { font-size: 120%; // tama\u00f1o del texto color: #5a5854; // color del texto background-color: #f2f2f2; // color del fondo de la entrada border: 1px solid #bdbdbd; // marca los bordes de la entrada border-radius: 5px; // redondea esos bordes padding: 5px 5px 5px 30px; background-repeat: no-repeat; background-position: 8px 9px; display: block; margin-bottom: 10px;} input:focus { // cambia el color de fondo background-color: #ffffff; border: 1px solid #b1e1e4;} input#email { background-image: url(\"images/email.png\");} input#twitter { background-image: url(\"images/twitter.png\");} input#web { background-image: url(\"images/web.png\");} Dar estilo a botones submit input#submit { color: #444444; // color del texto del boton text-shadow: 0px 1px 1px #ffffff; // apariencia 3d border-bottom: 2px solid #b2b2b2; // para el borde del boton background-color: #b9e4e3; background: -webkit-gradient(linear, left top, left bottom, from(#beeae9), to(#a8cfce)); background: -moz-linear-gradient(top, #beeae9, #a8cfce); background: -o-linear-gradient(top, #beeae9, #a8cfce); background: -ms-linear-gradient(top, #beeae9, #a8cfce);} input#submit:hover { // cambia la apariencia del boton color: #333333; // al pasar por encima border: 1px solid #a4a4a4; border-top: 2px solid #b2b2b2; background-color: #a0dbc4; background: -webkit-gradient(linear, left top, left bottom, from(#a8cfce), to(#beeae9)); background: -moz-linear-gradient(top, #a8cfce, #beeae9); background: -o-linear-gradient(top, #a8cfce, #beeae9); background: -ms-linear-gradient(top, #a8cfce, #beeae9);} Poner estilo a fieldsets y legends fieldset { width: 350px; // controlar el tama\u00f1o del form border: 1px solid #dcdcdc; border-radius: 10px; padding: 20px; text-align: right;} legend { background-color: #efefef; // color de fondo border: 1px solid #dcdcdc; border-radius: 10px; padding: 10px 20px; text-align: left; text-transform: uppercase;} Alinear formularios div { border-bottom: 1px solid #efefef; margin: 10px; padding-bottom: 10px; width: 260px;} .title { float: left; width: 100px; text-align: right; padding-right: 10px;} .radio-buttons label { float: none;} .submit { text-align: right;}","title":"FORMULARIOS"},{"location":"css/#layout","text":"Tipos posicionamiento position: static normal o estatico es el usado por defecto. Los elementos de bloque se ponen uno a continuacion de otro ocupando todo el ancho de la ventana del navegador salvo que lo limite con `width. position: relative - Los elementos se posicionan en relacion a donde deberian estar en posicion normal. Los desplazamos dando valor a top, bottom, left, right . Estos valores se ponen en px, porcentajes o ems p.example { position: relative; top: 10px; left: 100px;} position: absolute - El elemento se posiciona de forma absolita respecto a su elemento contenedor y el resto de elementos de la pagina le ignoran h1 { position: absolute; top: 0px; left: 500px; width: 250px;} position: fixed - Como el absoluto pero el elemento ahora es inamovible, su posicion permanece igual independiente del resto de elemntos e incluso si se sube o baja en la ventana del navegador. Util para hacer menus fijos por ejemplo en la parte superior de la ventana h1 { position: fixed; top: 0px; left: 50px; padding: 10px; margin: 0px; width: 100%; background-color: #efefef;} position: inherit , hereda la posicion del padre float: left|right - Desplaza los elementos todo lo que puede hacia la dcha o izda segun la propiedad float . Cualquier otro elemento dentro del elemento contenedor fluira alrededor del elemento que flota blockquote { float: right; width: 275px; font-size: 130%; font-style: italic; font-family: Georgia, Times, serif; margin: 0px 0px 10px 10px; padding: 10px; border-top: 1px solid #665544; border-bottom: 1px solid #665544;} propiedades de apoyo clear: left|right|both|none - indica que ningun otro elemento del mismo contenedot debe tocar el lado indicado de ese elemento .clear { clear: left;} overflow: auto; width:100% - Si todos los elemento de un contenedor son flotantes puede hacer problemas en ciertos navegadores a la hora de mostrar los bordes div { border: 1px solid #665544; overflow: auto; width: 100%;} multicolumna - Crear dise\u00f1os multicolumna con floats. Usar un
            para cada columna y con las siguientes propiedades width , float y margin para cerrar un hueco entre las columnas z-index - Al usar posicionamiento relativo, fijo o absoluto los elementos se pueden solapar. Si es asi el ultimo que aparece en el codigo HTML es el que se ve. Para controlar eso esta la propiedad z-index , se ve el elemento con el mayor valor de esa propiedad h1 { position: fixed; z-index: 10;} Tipos de Layout Anchura fija La anchura se especifica en pixeles (a veces tambien la altura) body { width: 960px; margin: 0 auto;} #content { overflow: auto; height: 100%;} #nav, #feature, #footer { background-color: #efefef; padding: 10px; margin: 10px;} .column1, .column2, .column3 { background-color: #efefef; width: 300px; float: left; margin: 10px;} li { display: inline; padding: 5px;} Liquidos La anchura se especifica en porcentajes. 90% de anchura cada columna se le pone un margin: 1% min-width, max-width para limitar los estiramientos body { width: 90%; margin: 0 auto;} #content {overflow: auto;} #nav, #feature, #footer { margin: 1%;} .column1, .column2, .column3 { width: 31.3%; float: left; margin: 1%;} .column3 {margin-right: 0%;} li { display: inline; padding: 0.5em;} #nav, #footer { background-color: #efefef; padding: 0.5em 0;} #feature, .article { height: 10em; margin-bottom: 1em; background-color: #efefef;} Dise\u00f1o 960px","title":"LAYOUT"},{"location":"css/#imagenes","text":"Controlar tama\u00f1o Creas tres clases de imagenes, peque\u00f1as, medianas y grandes. Despues a cada imagen le pones la clase a la que pertenece y asi automaticamente se pone a ese tama\u00f1o img.large { width: 500px; height: 500px;} img.medium { width: 250px; height: 250px;} img.small { width: 100px; height: 100px;} Alinear imagenes Se recomienda usar float en lugar de align . Creamos clases align-left align-right y luego a las imagenes les a\u00f1adimos la clase que nos interese img.align-left { float: left; margin-right: 10px;} img.align-right { float: right; margin-left: 10px;} Centrar imagenes Debemos convertir la imagen en en elemento de bloque y luego usar margin img.align-center { display: block; margin: 0px auto;} background background - Orden de las propiedades: background-color background-image background-repeat background-attachment background-position body { background: #ffffff url(\"images/tulip.gif\") no-repeat top right;} background-image - la imagen se ponde de fondo del elemento al que se lo asignamos p { background-image: url(\"images/pattern.gif\");} background-repeat - repeat la imagen se repite horizontal y verticalmente repeat-x la imagen solo se repite horizontalmente repeat-y la imagen solo se repite verticalmente no-repeat la imagen se muestra solo una vez body { background-image: url(\"images/header.gif\"); background-repeat: repeat-x;} background-attachment - fixed la imagen permanece fija scroll la imagen se mueve con el scroll body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-attachment: fixed;} background-position - Para especificar donde sale una imagen que no se repite. La propiedad tiene dos valores: Si solo se indica uno el segundo valor sera center . Tambien se puede usar px o porcentajes posicion horizontal left|center|right posicion vertical top|center|bottom body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: center top;} body { background-image: url(\"images/tulip.gif\"); background-repeat: no-repeat; background-position: 50% 50%;} rollover y sprites Enlaces o botones que tienen un segundo estilo al ponerse el puntero encima y un tercer estilo al pincharlos. Se usan sprites que son una sola imagen con diferentes partes a usar. Add to basket Framing options a.button { height: 36px; background-image: url(\"images/sprite.png\"); text-indent: -9999px; display: inline-block;} a#add-to-basket { width: 174px; background-position: 0px 0px;} a#framing-options { width: 210px; background-position: -175px 0px;} a#add-to-basket:hover { background-position: 0px -40px;} a#framing-options:hover { background-position: -175px -40px;} a#add-to-basket:active { background-position: 0px -80px;} a#framing-options:active { background-position: -175px -80px;}","title":"IMAGENES"},{"location":"css/#transition","text":".tecla { color: deepskyblue; background: rgba(0, 0, 0, 0.4); text-shadow: 0 0 1px black; transition: background-color 0.2s; } .pulsada { background-color: orange; transform: scale(1.1, 1.1); }
            Aclap
            function pressKey (e) { var valor = mapa.indexOf(e.key.toUpperCase()); if (valor !== -1) { document.getElementById(valor).addEventListener('transitionend', function () { document.getElementById(valor).classList.remove('pulsada'); }); document.getElementById(valor).classList.add('pulsada'); audio[valor].play(); } }","title":"TRANSITION"},{"location":"debian/","text":"DEBIAN 12 BOOKWORM STABLE Para andar con ojo en las actualizaciones instalar aptitude install apt-listbugs Debian Package Searcher Repositories nano /etc/apt/sources.list ## Debian stable deb https://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware ## Debian security deb https://deb.debian.org/debian-security bookworm-security non-free contrib main non-free-firmware ## Debian updates deb https://deb.debian.org/debian/ bookworm-updates non-free contrib main non-free-firmware ## Debian backports #deb https://deb.debian.org/debian/ bookworm-backports main contrib #non-free non-free-firmware ## Insync deb https://apt.insync.io/debian bookworm non-free contrib ## NodeSource #deb [signed-by=/etc/apt/keyrings/nodesource.gpg] #https://deb.nodesource.com/ node_20.x nodistro main ## Debian Multimedia #deb http://www.deb-multimedia.org/ bookworm main non-free # Chrome deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # Teamviewer #deb [signed-by=/usr/share/keyrings/teamviewer-keyring.gpg] #https://linux.teamviewer.com/deb stable main apt install aptitude htop smartmontools sshpass rsync curl wget nano apt-transport-https iperf zip arc arj bzip2 cabextract lzop nomarch p7zip p7zip-full pax tnef unrar-free unzip unrar deborphan net-tools intel-microcode hdparm ncdu rename iftop dns9utils nethogs tcptrack dnsutils curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg Para instalar Dropbox COMMANDS Add font fc-cache -f -v - tras haber copiado la fuente a /usr/share/fonts gpg gpg -c file.txt - cifra a archivo binario gpg -ca file.txt - cifra a archivo de texto gpg --output output.txt -d file.(gpg or txt) - para descifrar // convertir directorio en un archivo tar czf myfiles.tar.gz mydirectory/ // convertir archivo a un directorio tar xzf myfiles.tar.gz echo RELOADAGENT | gpg-connect-agent - para eliminar de la memoria la clave y que la pida al descomprimir grep Eliminar todas las lineas de una fichero que contienen un determinado 'texto' cat nombreArchivo | grep -v 'texto' > nuevoArchivo Coger solo las lineas de un archivo que contienen un determinado 'texto' grep -i \"texto\" nombreArchivo zip zip -er zipName.zip path/to/folder/ - Comprimir carpeta con contrase\u00f1a dpkg dpkg -i package.deb - apt-get -f install - reparar dependencias incumplidas si las hay dpkg -r onlyThaName - desinstalar debconf-show nombrePaquete - muestra configuracion del paquete instalado dpkg-reconfigure nombrePaquete - para reconfigurar el paquete Tama\u00f1o de ficheros y carpetas ls -lh du -ah /path du -h -d1 | sort -h Lista de directorios (ocultos incluidos) con su tama\u00f1o df -h du -sh * Lista de directorios (no ocultos) con su tama\u00f1o apt install ncdu ncdu Dividir archivo en varios Dividir archivo en trozos de 200mb asegurandoes que el corte no se produce en medio de una linea split -C 200m archivo.txt Limpieza apt-get autoclean && apt-get autoremove && apt-get remove --purge `deborphan` dpkg -l | grep -v ^ii | awk '{print $2}' | sed '1,5d'|xargs dpkg --purge Ver el tama\u00f1o de los logs y limpiar todos excepto los ultimos 3 dias journalctl --disk-usage journalctl --vacuum-time=3d Limpiar caches de imagenes du -sh ~/.cache/thumbnails rm -rf ~/.cache/thumbnails/* Process pgrep processName - buscar proceso ps - listar todos los procesos kill processNumber - matar proceso fg - continuar el proceso que estaba detenido nohup comando & - Ejecuta un comando en segundo plano y sigue ejecutandolo aunque salgamos de esa terminal ulimits error too many open files lsof - para encontrar file descriptors usados lsof -p PID | wc -l - indica cuantos file descriptors (archivos u otros recursos como conexiones http) tiene abiertos el proceso PID lsof -c PROCESS-NAME | wc -l - igual que arriba pero por nombre ulimit -n - muestra el limite de fd que el usuario puede usar ulimit -n 4096 - sube ese limite por ejemplo lo normal es 1024 a 4096 pero solo para esa sesion // Para Hacerlo permamente nano /etc/security/limits.conf userName soft nofile 2000 * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 // Cambiar el limite de fd de un proceso en ejecucion prlimit --pid pidID --nofile=soft:hard prlimit --pid XXXX --nofile=XXXX:XXXX en nginx user www-data; worker_processes 4; pid /run/nginx.pid; worker_rlimit_nofile 50000; events { worker_connections 4000; # multi_accept on; } Buena guia Incrementar limites -> Por usuario nano /etc/security/limits.conf A\u00f1adir al final * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 Guardar el archivo y hacer logout y login de nuevo Si esto no funciona probar con pam-limits nano /etc/pam.d/common-session a\u00f1adir session required pam_limits.so -> Para Todo el Sistema nano /etc/sysctl.conf a\u00f1adir fs.file-max = 2097152 Salimos y ejecutamos sysctl -p -> Verificar que funcionan los nuevos limites cat /proc/sys/fs/file-max Hard Limit ulimit -Hn Soft Limit ulimit -Sn verificar para un usuario su - nombreUsuario -c 'ulimit -aHS' -s '/bin/bash' Verificar para un proceso en ejecucion conseguimos el PID ps aux | grep nombreDelProceso cat /proc/XXX/limits Buscar find /path -name fileName - Buscar archivo find /path -type d -name dirName - Buscar carpeta Crear nuevo usuario useradd -d /home/username -m -s /bin/bash username - Crea un usuario con su carpeta home y consola para usar passwd username - Para crear la contrase\u00f1a del usuario Zona horaria dpkg-reconfigure tzdata - reconfigurar la zona horaria cpulimit apt-get install cpulimit ps aux | grep nombreProceso - nos da el id del proceso cpulimit -p id -l 30 - limita el proceso id al 30% cpulimit -e nombreProceso -l 50 - limita el proceso nombreProceso al 50% A\u00f1adir & para recuperar el control de la consola averiguar la version de debian lsb_release -a dns dig domain.tld @9.9.9.9 cron crontab -e // activar los logs de cron nano /etc/rsyslog.conf // descomentar la linea #cron.* -/var/log/cron service rsyslog restart // ejecutar algo al inicio del servidor crontab -e // como root @reboot cd /home/user/donde-sea && ./programa nmap nmap -Pn X.X.X.X || hostname rename multiple files at once apt install rename // Reemplazar la 1 ocurrencia de abc por xyz rename 's/abc/xyz/' * curl // tiempo en ir, procesar y volver curl -o /dev/null -s -w 'Total: %{time_total}s\\n' https://pagina.web SECURITY SSH aptitude install openssh-server openssh-client nano /etc/ssh/sshd_config // Para quitar acceso como root # Authentication: LoginGraceTime 120 PermitRootLogin without-password // jode mas que poner solo no StrictModes yes // Por seguridad # Para permitir contrase\u00f1as vacias pon yes (NI SE TE OCURRA HACERLO) PermitEmptyPasswords no service ssh restart sshpass -p contrase\u00f1a ssh usuario@dominio Broken pipe Para prevenir desconexiones del tipo broken pipe nano -c /etc/ssh/ssh_config Host * ServerAliveInterval 120 CLAMAV Antivirus para asegurarnos de que no somos conductores de virus entre maquinas windows y por si las moscas ... apt-get install clamav clamav-docs clamav-daemon clamav-freshclam aptitude install arc arj bzip2 cabextract lzop nomarch p7zip pax tnef unrar-free unzip zoo lha unrar - Para que escanee archivos comprimidos nano /etc/clamav/freshclam.conf - El archivo de configuracion por si queremos cambiar algo. service clamav-freshclam restart - hacerlo despues para cargar la nueva configuracion // Para actualizar, como root freshclam // Si esta bloqueado /etc/init.d/clamav-freshclam stop //despues => service clamav-freshclam start // para escanear como usuario normal clamscan -r /ruta/a/escanear RKHUNTER aptitude install rkhunter //para actualizar, como root rkhunter --propupd rkhunter --update //para usar, como root tambien rkhunter --check FAIL2BAN apt-get install fail2ban whois cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local nano /etc/fail2ban/jail.local // Aqui van las IPs que no tendran esas restricciones [DEFAULT] # \"ignoreip\" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1 192.168.1.0/24 bantime = 1800 maxretry = 3 // Correo al que avisar ante sucesos # Destination email address used solely for the interpolations in # jail.{conf,local} configuration files. destemail = root@localhost [webmin] enabled = true port = 10000 filter = webmin-auth banaction = iptables-multiport action = %(action_mwl)s logpath = /var/log/auth.log maxretry = 3 [ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [ssh-ddos] enabled = true port = ssh filter = sshd-ddos logpath = /var/log/auth.log maxretry = 3 service fail2ban restart service fail2ban status Los logs de baneos estan en estos dos archivos /var/log/fail2ban.log /var/log/auth.log manual unban fail2ban-client set ssh unbanip X.X.X.X UFW apt-get install ufw ufw allow ssh/tcp ufw logging on Antes de esto no se podia activar porque nos echa de la sesion de SSH. Ahora si => ufw enable ufw allow smtp/tcp ufw allow http/tcp ufw allow https/tcp ufw allow webmin ufw status - rules list ufw status numbered - numbered rules list ufw delete X - delete rule X bloquear IPs ufw insert 1 deny from X.X.X.X to any nano -c /etc/ufw/before.rules # End required lines -A ufw-before-input -s X.X.X.X -j DROP ufw reload PM2 Instalar npm install pm2 -g npm remove pm2 -g Configuracion DOCS pm2 startup - como usuario y seguir instrucciones para hacer que pm2 se ejecute en los reinicios sin necesitar ser root pm2 unstartup - para desmontar el chiringuito NO SIEMPRE Para ejecutar los procesos como user y no como root chmod -R 777 /home/user/.pm2 Comandos pm2 start app.js pm2 kill // para la ejecucion pero con un reboot se activara de nuevo pm2 list pm2 stop all|number pm2 restart all|number pm2 delete 7 // elimina el proceso especifico con ese id pm2 save // salva la lista de procesos en ese momento pm2 start app.js --name \"my-name\" pm2 restart app --name \"nuevo-nombre\" --update-env // para renombrar pm2 reset app // pone el contador de restarts a cero dev pm2-dev start app.js pm2-dev start app.js --ignore folder1,folder2,file3.txt cluster variables // -i numero de procesos que levanta pm2 start name.js -i max process.env.NODE_APP_INSTANCE; process.env.name process.env.pm_id max-memory-restart pm2 start geoip.js -i max --max-memory-restart 1300M 50M 50K 1G scale // Sumar 3 procesos al actual pm2 scale app +3 // deja 3 procesos activos de todos los que este usando actualmente pm2 scale app 3 cluster logs in the same file // ecosystem.config.js module.exports = { apps: [{ name: 'codetabs', script: 'codetabs.js', ignore_watch: [\"node_modules\", \"tmp\"], output: './../logs/hits.log', error: './../logs/errors.log', env: { NODE_ENV: \"development\", }, env_production: { NODE_ENV: \"production\", }, instances: 8, max_memory_restart: \"1G\", merge_logs: true, log_date_format: 'YYYY-MM-DD HH:mm:ss', }] }; pm2 start ecosystem.config.js --env production NPM sin ser ROOT Como instalar paquetes npm globalmente sin ser root // crear carpeta para los paquetes globales mkdir \"${HOME}/.npm-packages\" // crear .npmrc nano ${HOME}/.npmrc prefix=${HOME}/.npm-packages //editar .bashrc nano ${HOME}/.bashrc NPM_PACKAGES=\"${HOME}/.npm-packages\" PATH=\"$NPM_PACKAGES/bin:$PATH\" unset MANPATH # delete if already modified MANPATH elsewhere export MANPATH=\"$NPM_PACKAGES/share/man:$(manpath)\" // recargar la configuracion para aplicar los cambios source ~/.profile SYSTEMD systemctl status servidorGO - nos da informacion del servicion Crear Servicio nano /etc/systemd/servidorGO.service cp servidorGO.service /etc/systemd/system systemctl enable servidorGO.service service servidorGO.service start Borrar servicio systemctl stop [servicename] systemctl disable [servicename] rm /etc/systemd/system/[servicename] systemctl daemon-reload systemctl reset-failed nombre.service [Unit] Description= Descripcion de la tarea [Service] User=user Group=www-data Restart=on-failure WorkingDirectory=/var/www/path/to/binary/folder ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target Commandos service name status service name start systemctl enable name.service systemctl disable name.service systemctl start name.service systemctl stop name.service systemctl restart name.service systemctl status name.service systemctl reload name.service // Required files /etc/systemd/servidorGO.service /etc/systemd/system/servidorGO.service /etc/systemd/system/multi-user.target.wants/servidorGO.service /sys/fs/cgroup/systemd/system.slice/servidorGO.service Otra opcion ? nano /lib/systemd/system/name.service [Unit] Description= Task description [Service] Type=simple Restart=always RestartSec=5s ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target service name start service name status // para activarlo desde el reinicio del sistema systemctl enable name.service SYSTEMD sin ser ROOT Systemd sin ser ROOT Primero asegurarnos de que este instalado dbus para user apt install dbus-user-session apt install policykit-1 por si da guerra org.freedesktop.policytoolkit1 Creamos carpeta donde guardar los servicios mkdir -p ~/.config/systemd/user En esa carpeta creamos el nombreservicio.service [Unit] Description= Descripcion de la tarea [Service] RestartSec=5s Restart=always WorkingDirectory=/ruta/a/la/carpeta/del/binario ExecStart=/ruta/a/la/carpeta/del/binario/./nombreDelBinario [Install] WantedBy=default.target Ahora hacemos que systemd reconozca los cambios systemctl --user daemon-reload Ya podemos gestionar el servicio systemctl --user start nombreDelServicio systemctl --user stop nombreDelServicio systemctl --user restart nombreDelServicio systemctl --user status nombreDelServicio Para que el servicio se inicie automaticamente cuando el usuario se loguea systemctl --user enable nombreDelServicio // sin el .service al final Para desactivarlo systemctl --user disable nombreDelServicio Hay que hacer que el servicio corra siempre, este o no logueado el due\u00f1o y al inicio del sistema. Para ello como root ejecutamos loginctl enable-linger NOMBREUSUARIO Ya como usuario normal podemos ver el estado de los servicios loginctl user-status NOMBREUSUARIO NGINX Instalacion apt-get install nginx chown -R user:user /var/www - Para darle permisos al usuario para toda esa carpeta mkdir -p /var/www/site1 mkdir -p /var/www/site2 Configuracion nano /etc/nginx/nginx.conf El archivo de configuracion se llama default y esta en la carpeta /etc/nginx/sites-available .Lo borramos o lo renombramos a default.old . La copia de default que esta en /etc/nginx/sites-enabled hay que borrarla Ahora podemos crear nuestro archivo/s de configuracion. nano /etc/nginx/sites-available/domain cp /etc/nginx/sites-available/domain /etc/nginx/sites-enabled/domain service nginx restart nginx -s reload solo para recargar el archivo de configuracion server-side-includes Server Side Includes Directivas y variables ssi on - /etc/nginx/sites-available Para las rutas ojo porque es desde la raiz del servidor web nginx para esa location ocultar la version de nginx nano /etc/nginx/nginx.conf http { server_tokens off; } headers(cabeceras) Ojo, que algunas pueden restringir el comportamiento de las aplicaciones que tengamos # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; add_header Content-Security-Policy \"default-src 'self'\"; En el location block para evitar cualquier indexacion de esa location por parte de los robots de busqueda add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; Limitar tama\u00f1o de los archivos de subida location /count-loc/ { # set client body size to 10M client_max_body_size 10M; } rate Limit nano /etc/nginx/nginx.conf // aqui definimos por ejemplo la zona=one # limit requests limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s; //luego hay que aplicarlo, mejor en location que en server nano /etc/nginx/sites-available/domain location /count-loc/ { # requests limit limit_req zone=one burst=20; } Apply limits per IP geo $limit { default 1; X.X.X.X 0; Y.Y.Y.Y 0; } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=1r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; http2 nano /etc/nginx/nginx.conf // usar solo cifrados muy seguros ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256: RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; // hay que generar una nuevas claves, lo mejor en /etc/nginx/ssl cd /etc/nginx/ssl openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 // http2 solo funciona con https asi que en el bloque de listen 443 listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; // para mejorar rendimiento ssl_session_cache shared:SSL:5m; ssl_session_timeout 1h; cache // en sites-availables bloque propio # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } // luego en el bloque server que queramos a\u00f1adir expires $expires; zonas privadas // crear archivo con la contrase\u00f1a apt-get install apache2-utils cd /etc/nginx htpasswd -c .rethinkdb.pass // will ask for password service nginx restart server { listen 443 ssl; server_name sub.domain.com; location / { ... } location /private/ { auth_basic \"Restricted\"; auth_basic_user_file /etc/nginx/.rethinkdb.pass; ... root or proxy for this location } } custom 404 mkdir /var/www/error => 404.html 404.css , js, png ... server { error_page 404 /404.html; location = /404.html { root /var/www/error; internal; } location = /404.css { root /var/www/error; } location = /caution.png { root /var/www/error; } } En 404.html llamamos a los recursos usando rutas absolutas block domains map $http_referer $bad_referer { default 0; \"~spamdomain1.com\" 1; \"~spamdomain2.com\" 1; \"~spamdomain3.com\" 1; } if ($bad_referer) { return 444; } nginx.conf actualizado 2019-05-08 user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; server_names_hash_bucket_size 64; # 128? # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; # set client body size to 5M # client_max_body_size 2M; # limit requests geo $limit { default 1; X.X.X.X 0; #server1 X.X.X.X 0; #server2 X.X.X:X 0; #server3 X.X.X.X 0; #server4 } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=2r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; limit_req_zone $limit_key zone=five:10m rate=1r/s; limit_req_zone $limit_key zone=six:1000m rate=10r/s; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA +AES256:EECDH+3DES:RSA+3DES:!MD5; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_disable \"msie6\"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml applicati$ ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } dominio-template.conf actualizado 2019-05-08 ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; # server-side-includes ssi on; # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; #add_header Content-Security-Policy \"default-src 'self'\"; #cache # set client body size to 4M # # client_max_body_size 4M; expires $expires; # custom error error_page 404 /404.html; location = /404.html { root /var/www/codetabs/www/_error; internal; } location = /404.css { root /var/www/codetabs/www/_error; } location = /ct24r.png { root /var/www/codetabs/www/_error; } location = /ct64r.png { root /var/www/codetabs/www/_error; } error_page 429 /429.html; location = /429.html { root /var/www/codetabs/www/_error; #internal; } location /_public { # requests limit, ojo que enlentece la carga de la pagina # limit_req zone=one burst=50; alias /var/www/codetabs/www/_public; } SITES/DOMAIN actualizado 2019-05-08 # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } server { listen 80; # Listen to your server ip address server_name 212.24.108.85; # Redirect all traffic comming from your-server-ip to your domain return 301 https://domain.com$request_uri; } server { listen 80; listen [::]:80; server_name domain.com www.domain.com; return 301 https://domain.com$request_uri; server_name *.domain.com; return 301 https://*.domain.com$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name www.domain.com; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; return 301 https://domain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS # add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/html; index index.html; } location /freecodecamp { root /var/www/domain; index index.html; } location /notes { root /var/www/domain; index index.html; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name api.domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS add_header 'Access-Control-Allow-Origin' '*' always; location /github-stars/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3501/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /count-loc/ { # requests limit limit_req zone=three ;#burst=50; # set client body size to 10M client_max_body_size 10M; proxy_pass http://127.0.0.1:3502/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /game/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3503/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name test.domain.com; include /etc/nginx/sites-available/domain.conf; location /admin { # requests limit # limit_req zone=one ;#burst=50; auth_basic \"Area 51\"; auth_basic_user_file /etc/nginx/.admin.pass; root /var/www/domain; index admin.html; } } Subcarpeta con PHP Hracias serversforhackers.com server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS #add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/beta; index index.html; } location ^~ /blog { alias /var/www/wp-domain; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } } location @nested { rewrite /blog/(.*)$ /blog/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } } Dokuwiki # DokuWiki location ^~ /wiki { alias /var/www/dokuwiki; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } # dokuwiki security location ~ /wiki/(conf|bin|inc)/ { deny all; } location ~ /wiki/data/ { internal; } } location @nested { rewrite /wiki/(.*)$ /wiki/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } WEBMIN Instalacion Descarga el .deb de aqui dpkg -i package.deb Si debian protesta de dependencias instala las que pida. Estas son las mas posibles: apt install perl libnet-ssleay-perl openssl libpam-runtime libio-pty-perl python libauthen-pam-perl libio-pty-perl apt-show-versions Para desinstalar paramos service webmin stop y despues /etc/webmin/uninstall.sh Modulos nginx module - https://www.justindhoffman.com/project/nginx-webmin-module webmin -> webmin configuration -> webmin modules Actualizacion Despues de actualizarse hay veces que no arranca /etc/init.d/webmin stop /etc/init.d/webmin start Cambiar el password Para cambiar la contrase\u00f1a desde la consola /usr/share/webmin/changepass.pl /etc/webmin root NEWPASSWORD Lets Encrypt Webmin webmin > webmin Configuration > SSL Encryption > SSL Settings /etc/letsencrypt/live/nombreCert/privkey.pem /etc/letsencrypt/live/nombreCert/cert.pem Apply -> service nginx restart LETS ENCRYPT HTTPS certbot apt-get install certbot - install Create certificate // primero parar nginx service nginx stop // Usar la opcion standalone y creamos todos los dominios juntos // (domain.com www.domain.com sub.domain.com etc) certbot certonly Saving debug log to /var/log/letsencrypt/letsencrypt.log How would you like to authenticate with the ACME CA? ------------------------------------------------------------------------- 1: Place files in webroot directory (webroot) 2: Spin up a temporary webserver (standalone) ------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel):domain.com www.domain.com sub.domain.com Obtaining a new certificate Performing the following challenges: tls-sni-01 challenge for domain.com tls-sni-01 challenge for www.domain.com Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0067_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0067_csr-certbot.pem IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/domain.com/fullchain.pem. Your cert will expire on 2017-11-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run \"certbot renew\" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le Listar certificados certbot certificates - Lista de todos los certificados existentes A\u00f1adir certificado service nginx stop - paramos nginx certbot certonly -d admin.domain.com,api.domain.com,domain.com, sp500.domain.com,www.domain.com,otrosub.domain.com --expand - Eliminar certificado certbot delete - y seleccionamos el que queramos borrar Renovar certbot renew --dry-run - solo testea certbot renew - renueva de verdad certbot renew --force-renew - fuerza la renovacion aunque falte mucho tiempo aun para su caducidad certbot renew --dry-run --cert-name domain.tld ` webroot , no hace falta parar nginx para hacer las renovaciones Leer el manual de certot server { listen 80; listen [::]:80; server_name beta.domain.tld; # location / { # root /var/www/beta.domain.tld; # index index.html; # } return 301 https://beta.domain.tld$request_uri; # } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name beta.domain.tld; ssl_certificate /etc/letsencrypt/live/beta.domain.tld/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/beta.domain.tld/privkey.pem; # ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; #add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; location / { root /var/www/beta.domain.tld; index index.html; } } certbot certonly --webroot -w /var/www/domain.tld -d domain.tld -d www.domain.tld -d beta.domain.tld staging --staging - permite mayopr numero de intentos mientras testeamos MONITORIZAR RED vnstat - Bandwidth aptitude install vnstat // lista todas las interfaces de red disponibles vnstat --iflist // configura interface vnstat -u -i eth0 // comienza la ejecucion del servicio como demonio /etc/init.d/vnstat start // cambia de due\u00f1o para poder escribir en su propia base de datos chown -R vnstat:vnstat /var/lib/vnstat/ monitorizar (como un usuario normal) // tiempo real vnstat -l // serie historica por horas-dias-meses-semanas vnstat -h|d|w|m // top 10 dias vnstat -t archivo configuracion (para cambiar la interfaz que por defecto es eth0) nano /etc/vnstat.conf crontab -e 0 * * * * node /var/www/vnstat/vnstat.js // ejecutar cada hora vnstat -i eth0 --json d // dentro de vnstat.js nload apt install nload iftop apt install iftop nethogs apt install nethogs tcptrack apt install tcptrack tcptrack -i interface muestra todas las conexiones existentes en tiempo real nethogs apt install nethogs MYSQL Instalar MYSQL 5.7.X instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // redirige a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // Descomentar esta line para evitar acceso desde el exterior bind-address = 127.0.0.1 service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; truncate table with fk SET FOREIGN_KEY_CHECKS = 0; TRUNCATE table table_name; SET FOREIGN_KEY_CHECKS = 1; Instalar MYSQL 8.0.X Aviso sobre el nuevo sistema de autenticacion MySQL 8 uses a new authentication based on improved SHA256-based password methods. It is recommended that all new MySQL Server installations use this method going forward. This new authentication plugin requires new versions of connectors and clients, with support for this new 8 authentication(caching_sha2_password). Currently MySQL 8 Connectors and community drivers built with libmysqlclient21 support this new method. Clients built with older versions of libmysqlclient may not be able to connect to the new server. To retain compatibility with older client software, the default authentication plugin can be set to the legacy value (mysql_native_password) This should only be done if required third-party software has not been updated to work with the new authentication method. The change will be written to the file /etc/mysql/mysql.conf.d/default-auth-override.cnf After installation, the default can be changed by setting the default_authentication_plugin server setting. instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // se ven todos los sitios donde puede estar la configuracion // vamos a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // y debajo de [mysqld] escribimos bind_address = 127.0.0.1 // para prohibir acceso desde el exterior service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; // para apagar mysql password validation UNINSTALL COMPONENT 'file://component_validate_password'; REDIS Instalar REDIS 4.0.X Instalar apt -t stretch-backports install \"redis-server\" service redis status Configurar nano /etc/redis/redis.conf appendonly yes appendfsync everysec service redis restart VPS Benchmark (curl -s wget.racing/nench.sh | bash; curl -s wget.racing/nench.sh | bash) 2>&1 | tee nench.log wget -qO- bench.sh | bash Ram dmidecode -t 17 dd if=/dev/zero of=/dev/null bs=1024M count=200 iperf apt install iperf iperf -c iperf.online.net speedtest curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py chmod +x speedtest-cli http://speedtest.tele2.net/ download wget -O /dev/null http://speedtest.tele2.net/1GB.zip upload curl -T 1GB.zip ftp://speedtest.tele2.net/upload/ hard disk apt install smartmontools // informacion smartctl -a /dev/sda // testear smartctl -t short|long|select /dev/sda // resultados smartctl -a /dev/sda // o solo testear smartctl -l selftest /dev/sdc // informacion hdparm -I /dev/sda // testea hdparm -tT /dev/sda // testea dd if=/dev/zero of=/tmp/output conv=fdatasync bs=384k count=1k; rm -f /tmp/output more benchmarks openssl speed rsa openssl speed -multi numCores rsa2048 7z b SYS arm-XT arreglar el bug de poca velocidad de subida lowendtalk apt install linux-image-4.9.0-6-armmp linux-headers-4.9.0-6-armmp apt purge *armada* reboot modprobe error ufw wget http://last.public.ovh.hdaas.snap.mirrors.ovh.net/ubuntu/pool /main/l/linux-modules-armada375/linux-modules-armada375_4.5.2-4_armhf.deb dpkg -i linux-modules-armada375_4.5.2-4_armhf.deb grub-mkconfig -o /boot/grub/grub.cfg rsync De local a otra remota rsync -aP /home/user/data/ user@destiny.com:/home/user/data # automatizado sin preguntar contrase\u00f1a rsync -arv --delete -e \"sshpass -f '/file/with/passwd' || -p 'password' ssh -p PORT -o StrictHostKeyChecking=no\" --progress /source/data/ user@domain.com:/destination/data De otra remota a local * rsync -charvzP --delete -e \"sshpass -p 'pass' ssh -p port\" --progress user@remote.host:/remote/path /local/path/ TEST API siege siege -c 30 -r 1 --no-parser https://api.codetabs.com/v1/ siege -c250 -d10 -t3 https://api.codetabs.com/v1/proxy?quest=http Apache Bench apt-get install apache2-utils - -n numero de peticiones -c concurrencias Mas info ab -n 1000 -c 10 https://jolav.github.io/ \u00a1 Ojo porque ab asume que todas las respuestas son iguales !. Si content-length es distinta lo considera un error y aparece como failed request OPENVPN Script para instalar Crear un Kill Switch // ON-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default deny outgoing ufw allow out on tun0 from any to any ufw enable // OFF-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default allow outgoing ufw enable chmod +x ON-openvpn.sh OFF-openvpn.sh Conectarte a tu openVpn ./on-openvpn.sh ./off-openvpn.sh more FLASH FIREFOX Download from here tar -xzf flash_player_ppapi_linux*.tar.gz cp libpepflashplayer.so /usr/lib/mozilla/plugins cp -r usr/* /usr // restart firefox VIRTUALBOX Descargar de aqui en el apartado \"All distributions\" el archivo .run https://www.virtualbox.org/wiki/Linux_Downloads Si tras ejecutarlo e instalarlo dice que falta el dkms es ir aqui buscarlo, bajarlo e instalarlo https://tracker.debian.org/pkg/virtualbox Despues de instalarlo a veces sale este error There were problems setting up VirtualBox. To re-start the set-up process, ru /sbin/vboxconfig as root. If your system is using EFI Secure Boot you may need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information. modprobe vboxdrv GRE TUNNEL Tutorial patra configurar Hacerlo persistente con systemd apt install iptables iproute2 ps aux | grep gre ip tunnel show Pantalla modprobe ip_gre iptunnel del gre1 # Solo una vez #echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf #sysctl -p iptunnel add gre1 mode gre local IP_PANTALLA remote IP_SERVIDOR ttl 255 ip addr add 192.168.168.1/30 dev gre1 ip link set gre1 up # aqui ping a 192.168.168.2 # BUYVM # iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor # iptables -t nat -A PREROUTING -d IP_PANTALLA -j DNAT --to-destination 192.168.168.2 # iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # If you're wanting to get more specific, you could add: -p tcp --dport 25565 # HETZNER iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.168.2 iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.168.2 Extras keepalive en el servidor crontab -e */1 * * * * ping -c2 192.168.168.1 ps aux | grep gre ip tunnel show Servidor modprobe ip_gre iptunnel del gre1 iptunnel add gre1 mode gre local IP_SERVIDOR remote IP_PANTALLA ttl 255 ip addr add 192.168.168.2/30 dev gre1 ip link set gre1 up # TEST-1 ping a 192.168.168.1 # Solo una vez, esto solo se puede borrar luego manualmente # echo '100 GRETUNNEL1' >> /etc/iproute2/rt_tables ip rule add from 192.168.168.0/30 table GRETUNNEL1 ip route add default via 192.168.168.1 table GRETUNNEL1 # TEST-2 # curl http://www.cpanel.net/showip.cgi --interface 192.168.168.2 # wget http://www.cpanel.net/showip.cgi --bind-address=192.168.168.2 -q -O - Persistente crear en cliente y servidor en /etc/systemd/system un nuevo servicio greTunnel.service [Unit] Description=levantar gre tunnel After=network.target [Service] ExecStart=sh /ruta/hasta/el/script Restart=always User=root Group=root Type=simple [Install] WantedBy=multi-user.target","title":"Debian"},{"location":"debian/#debian-12-bookworm","text":"","title":"DEBIAN 12 BOOKWORM"},{"location":"debian/#stable","text":"Para andar con ojo en las actualizaciones instalar aptitude install apt-listbugs Debian Package Searcher Repositories nano /etc/apt/sources.list ## Debian stable deb https://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware ## Debian security deb https://deb.debian.org/debian-security bookworm-security non-free contrib main non-free-firmware ## Debian updates deb https://deb.debian.org/debian/ bookworm-updates non-free contrib main non-free-firmware ## Debian backports #deb https://deb.debian.org/debian/ bookworm-backports main contrib #non-free non-free-firmware ## Insync deb https://apt.insync.io/debian bookworm non-free contrib ## NodeSource #deb [signed-by=/etc/apt/keyrings/nodesource.gpg] #https://deb.nodesource.com/ node_20.x nodistro main ## Debian Multimedia #deb http://www.deb-multimedia.org/ bookworm main non-free # Chrome deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # Teamviewer #deb [signed-by=/usr/share/keyrings/teamviewer-keyring.gpg] #https://linux.teamviewer.com/deb stable main apt install aptitude htop smartmontools sshpass rsync curl wget nano apt-transport-https iperf zip arc arj bzip2 cabextract lzop nomarch p7zip p7zip-full pax tnef unrar-free unzip unrar deborphan net-tools intel-microcode hdparm ncdu rename iftop dns9utils nethogs tcptrack dnsutils curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg Para instalar Dropbox","title":"STABLE"},{"location":"debian/#commands","text":"Add font fc-cache -f -v - tras haber copiado la fuente a /usr/share/fonts gpg gpg -c file.txt - cifra a archivo binario gpg -ca file.txt - cifra a archivo de texto gpg --output output.txt -d file.(gpg or txt) - para descifrar // convertir directorio en un archivo tar czf myfiles.tar.gz mydirectory/ // convertir archivo a un directorio tar xzf myfiles.tar.gz echo RELOADAGENT | gpg-connect-agent - para eliminar de la memoria la clave y que la pida al descomprimir grep Eliminar todas las lineas de una fichero que contienen un determinado 'texto' cat nombreArchivo | grep -v 'texto' > nuevoArchivo Coger solo las lineas de un archivo que contienen un determinado 'texto' grep -i \"texto\" nombreArchivo zip zip -er zipName.zip path/to/folder/ - Comprimir carpeta con contrase\u00f1a dpkg dpkg -i package.deb - apt-get -f install - reparar dependencias incumplidas si las hay dpkg -r onlyThaName - desinstalar debconf-show nombrePaquete - muestra configuracion del paquete instalado dpkg-reconfigure nombrePaquete - para reconfigurar el paquete Tama\u00f1o de ficheros y carpetas ls -lh du -ah /path du -h -d1 | sort -h Lista de directorios (ocultos incluidos) con su tama\u00f1o df -h du -sh * Lista de directorios (no ocultos) con su tama\u00f1o apt install ncdu ncdu Dividir archivo en varios Dividir archivo en trozos de 200mb asegurandoes que el corte no se produce en medio de una linea split -C 200m archivo.txt Limpieza apt-get autoclean && apt-get autoremove && apt-get remove --purge `deborphan` dpkg -l | grep -v ^ii | awk '{print $2}' | sed '1,5d'|xargs dpkg --purge Ver el tama\u00f1o de los logs y limpiar todos excepto los ultimos 3 dias journalctl --disk-usage journalctl --vacuum-time=3d Limpiar caches de imagenes du -sh ~/.cache/thumbnails rm -rf ~/.cache/thumbnails/* Process pgrep processName - buscar proceso ps - listar todos los procesos kill processNumber - matar proceso fg - continuar el proceso que estaba detenido nohup comando & - Ejecuta un comando en segundo plano y sigue ejecutandolo aunque salgamos de esa terminal ulimits error too many open files lsof - para encontrar file descriptors usados lsof -p PID | wc -l - indica cuantos file descriptors (archivos u otros recursos como conexiones http) tiene abiertos el proceso PID lsof -c PROCESS-NAME | wc -l - igual que arriba pero por nombre ulimit -n - muestra el limite de fd que el usuario puede usar ulimit -n 4096 - sube ese limite por ejemplo lo normal es 1024 a 4096 pero solo para esa sesion // Para Hacerlo permamente nano /etc/security/limits.conf userName soft nofile 2000 * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 // Cambiar el limite de fd de un proceso en ejecucion prlimit --pid pidID --nofile=soft:hard prlimit --pid XXXX --nofile=XXXX:XXXX en nginx user www-data; worker_processes 4; pid /run/nginx.pid; worker_rlimit_nofile 50000; events { worker_connections 4000; # multi_accept on; } Buena guia Incrementar limites -> Por usuario nano /etc/security/limits.conf A\u00f1adir al final * hard nofile 500000 * soft nofile 500000 root hard nofile 500000 root soft nofile 500000 Guardar el archivo y hacer logout y login de nuevo Si esto no funciona probar con pam-limits nano /etc/pam.d/common-session a\u00f1adir session required pam_limits.so -> Para Todo el Sistema nano /etc/sysctl.conf a\u00f1adir fs.file-max = 2097152 Salimos y ejecutamos sysctl -p -> Verificar que funcionan los nuevos limites cat /proc/sys/fs/file-max Hard Limit ulimit -Hn Soft Limit ulimit -Sn verificar para un usuario su - nombreUsuario -c 'ulimit -aHS' -s '/bin/bash' Verificar para un proceso en ejecucion conseguimos el PID ps aux | grep nombreDelProceso cat /proc/XXX/limits Buscar find /path -name fileName - Buscar archivo find /path -type d -name dirName - Buscar carpeta Crear nuevo usuario useradd -d /home/username -m -s /bin/bash username - Crea un usuario con su carpeta home y consola para usar passwd username - Para crear la contrase\u00f1a del usuario Zona horaria dpkg-reconfigure tzdata - reconfigurar la zona horaria cpulimit apt-get install cpulimit ps aux | grep nombreProceso - nos da el id del proceso cpulimit -p id -l 30 - limita el proceso id al 30% cpulimit -e nombreProceso -l 50 - limita el proceso nombreProceso al 50% A\u00f1adir & para recuperar el control de la consola averiguar la version de debian lsb_release -a dns dig domain.tld @9.9.9.9 cron crontab -e // activar los logs de cron nano /etc/rsyslog.conf // descomentar la linea #cron.* -/var/log/cron service rsyslog restart // ejecutar algo al inicio del servidor crontab -e // como root @reboot cd /home/user/donde-sea && ./programa nmap nmap -Pn X.X.X.X || hostname rename multiple files at once apt install rename // Reemplazar la 1 ocurrencia de abc por xyz rename 's/abc/xyz/' * curl // tiempo en ir, procesar y volver curl -o /dev/null -s -w 'Total: %{time_total}s\\n' https://pagina.web","title":"COMMANDS"},{"location":"debian/#security","text":"","title":"SECURITY"},{"location":"debian/#ssh","text":"aptitude install openssh-server openssh-client nano /etc/ssh/sshd_config // Para quitar acceso como root # Authentication: LoginGraceTime 120 PermitRootLogin without-password // jode mas que poner solo no StrictModes yes // Por seguridad # Para permitir contrase\u00f1as vacias pon yes (NI SE TE OCURRA HACERLO) PermitEmptyPasswords no service ssh restart sshpass -p contrase\u00f1a ssh usuario@dominio Broken pipe Para prevenir desconexiones del tipo broken pipe nano -c /etc/ssh/ssh_config Host * ServerAliveInterval 120","title":"SSH"},{"location":"debian/#clamav","text":"Antivirus para asegurarnos de que no somos conductores de virus entre maquinas windows y por si las moscas ... apt-get install clamav clamav-docs clamav-daemon clamav-freshclam aptitude install arc arj bzip2 cabextract lzop nomarch p7zip pax tnef unrar-free unzip zoo lha unrar - Para que escanee archivos comprimidos nano /etc/clamav/freshclam.conf - El archivo de configuracion por si queremos cambiar algo. service clamav-freshclam restart - hacerlo despues para cargar la nueva configuracion // Para actualizar, como root freshclam // Si esta bloqueado /etc/init.d/clamav-freshclam stop //despues => service clamav-freshclam start // para escanear como usuario normal clamscan -r /ruta/a/escanear","title":"CLAMAV"},{"location":"debian/#rkhunter","text":"aptitude install rkhunter //para actualizar, como root rkhunter --propupd rkhunter --update //para usar, como root tambien rkhunter --check","title":"RKHUNTER"},{"location":"debian/#fail2ban","text":"apt-get install fail2ban whois cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local nano /etc/fail2ban/jail.local // Aqui van las IPs que no tendran esas restricciones [DEFAULT] # \"ignoreip\" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1 192.168.1.0/24 bantime = 1800 maxretry = 3 // Correo al que avisar ante sucesos # Destination email address used solely for the interpolations in # jail.{conf,local} configuration files. destemail = root@localhost [webmin] enabled = true port = 10000 filter = webmin-auth banaction = iptables-multiport action = %(action_mwl)s logpath = /var/log/auth.log maxretry = 3 [ssh] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [ssh-ddos] enabled = true port = ssh filter = sshd-ddos logpath = /var/log/auth.log maxretry = 3 service fail2ban restart service fail2ban status Los logs de baneos estan en estos dos archivos /var/log/fail2ban.log /var/log/auth.log manual unban fail2ban-client set ssh unbanip X.X.X.X","title":"FAIL2BAN"},{"location":"debian/#ufw","text":"apt-get install ufw ufw allow ssh/tcp ufw logging on Antes de esto no se podia activar porque nos echa de la sesion de SSH. Ahora si => ufw enable ufw allow smtp/tcp ufw allow http/tcp ufw allow https/tcp ufw allow webmin ufw status - rules list ufw status numbered - numbered rules list ufw delete X - delete rule X bloquear IPs ufw insert 1 deny from X.X.X.X to any nano -c /etc/ufw/before.rules # End required lines -A ufw-before-input -s X.X.X.X -j DROP ufw reload","title":"UFW"},{"location":"debian/#pm2","text":"Instalar npm install pm2 -g npm remove pm2 -g Configuracion DOCS pm2 startup - como usuario y seguir instrucciones para hacer que pm2 se ejecute en los reinicios sin necesitar ser root pm2 unstartup - para desmontar el chiringuito NO SIEMPRE Para ejecutar los procesos como user y no como root chmod -R 777 /home/user/.pm2 Comandos pm2 start app.js pm2 kill // para la ejecucion pero con un reboot se activara de nuevo pm2 list pm2 stop all|number pm2 restart all|number pm2 delete 7 // elimina el proceso especifico con ese id pm2 save // salva la lista de procesos en ese momento pm2 start app.js --name \"my-name\" pm2 restart app --name \"nuevo-nombre\" --update-env // para renombrar pm2 reset app // pone el contador de restarts a cero dev pm2-dev start app.js pm2-dev start app.js --ignore folder1,folder2,file3.txt cluster variables // -i numero de procesos que levanta pm2 start name.js -i max process.env.NODE_APP_INSTANCE; process.env.name process.env.pm_id max-memory-restart pm2 start geoip.js -i max --max-memory-restart 1300M 50M 50K 1G scale // Sumar 3 procesos al actual pm2 scale app +3 // deja 3 procesos activos de todos los que este usando actualmente pm2 scale app 3 cluster logs in the same file // ecosystem.config.js module.exports = { apps: [{ name: 'codetabs', script: 'codetabs.js', ignore_watch: [\"node_modules\", \"tmp\"], output: './../logs/hits.log', error: './../logs/errors.log', env: { NODE_ENV: \"development\", }, env_production: { NODE_ENV: \"production\", }, instances: 8, max_memory_restart: \"1G\", merge_logs: true, log_date_format: 'YYYY-MM-DD HH:mm:ss', }] }; pm2 start ecosystem.config.js --env production","title":"PM2"},{"location":"debian/#npm-sin-ser-root","text":"Como instalar paquetes npm globalmente sin ser root // crear carpeta para los paquetes globales mkdir \"${HOME}/.npm-packages\" // crear .npmrc nano ${HOME}/.npmrc prefix=${HOME}/.npm-packages //editar .bashrc nano ${HOME}/.bashrc NPM_PACKAGES=\"${HOME}/.npm-packages\" PATH=\"$NPM_PACKAGES/bin:$PATH\" unset MANPATH # delete if already modified MANPATH elsewhere export MANPATH=\"$NPM_PACKAGES/share/man:$(manpath)\" // recargar la configuracion para aplicar los cambios source ~/.profile","title":"NPM sin ser ROOT"},{"location":"debian/#systemd","text":"systemctl status servidorGO - nos da informacion del servicion Crear Servicio nano /etc/systemd/servidorGO.service cp servidorGO.service /etc/systemd/system systemctl enable servidorGO.service service servidorGO.service start Borrar servicio systemctl stop [servicename] systemctl disable [servicename] rm /etc/systemd/system/[servicename] systemctl daemon-reload systemctl reset-failed nombre.service [Unit] Description= Descripcion de la tarea [Service] User=user Group=www-data Restart=on-failure WorkingDirectory=/var/www/path/to/binary/folder ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target Commandos service name status service name start systemctl enable name.service systemctl disable name.service systemctl start name.service systemctl stop name.service systemctl restart name.service systemctl status name.service systemctl reload name.service // Required files /etc/systemd/servidorGO.service /etc/systemd/system/servidorGO.service /etc/systemd/system/multi-user.target.wants/servidorGO.service /sys/fs/cgroup/systemd/system.slice/servidorGO.service Otra opcion ? nano /lib/systemd/system/name.service [Unit] Description= Task description [Service] Type=simple Restart=always RestartSec=5s ExecStart=/var/www/path/to/binary/folder/binaryName [Install] WantedBy=multi-user.target service name start service name status // para activarlo desde el reinicio del sistema systemctl enable name.service","title":"SYSTEMD"},{"location":"debian/#systemd-sin-ser-root","text":"Systemd sin ser ROOT Primero asegurarnos de que este instalado dbus para user apt install dbus-user-session apt install policykit-1 por si da guerra org.freedesktop.policytoolkit1 Creamos carpeta donde guardar los servicios mkdir -p ~/.config/systemd/user En esa carpeta creamos el nombreservicio.service [Unit] Description= Descripcion de la tarea [Service] RestartSec=5s Restart=always WorkingDirectory=/ruta/a/la/carpeta/del/binario ExecStart=/ruta/a/la/carpeta/del/binario/./nombreDelBinario [Install] WantedBy=default.target Ahora hacemos que systemd reconozca los cambios systemctl --user daemon-reload Ya podemos gestionar el servicio systemctl --user start nombreDelServicio systemctl --user stop nombreDelServicio systemctl --user restart nombreDelServicio systemctl --user status nombreDelServicio Para que el servicio se inicie automaticamente cuando el usuario se loguea systemctl --user enable nombreDelServicio // sin el .service al final Para desactivarlo systemctl --user disable nombreDelServicio Hay que hacer que el servicio corra siempre, este o no logueado el due\u00f1o y al inicio del sistema. Para ello como root ejecutamos loginctl enable-linger NOMBREUSUARIO Ya como usuario normal podemos ver el estado de los servicios loginctl user-status NOMBREUSUARIO","title":"SYSTEMD sin ser ROOT"},{"location":"debian/#nginx","text":"Instalacion apt-get install nginx chown -R user:user /var/www - Para darle permisos al usuario para toda esa carpeta mkdir -p /var/www/site1 mkdir -p /var/www/site2","title":"NGINX"},{"location":"debian/#configuracion","text":"nano /etc/nginx/nginx.conf El archivo de configuracion se llama default y esta en la carpeta /etc/nginx/sites-available .Lo borramos o lo renombramos a default.old . La copia de default que esta en /etc/nginx/sites-enabled hay que borrarla Ahora podemos crear nuestro archivo/s de configuracion. nano /etc/nginx/sites-available/domain cp /etc/nginx/sites-available/domain /etc/nginx/sites-enabled/domain service nginx restart nginx -s reload solo para recargar el archivo de configuracion","title":"Configuracion"},{"location":"debian/#server-side-includes","text":"Server Side Includes Directivas y variables ssi on - /etc/nginx/sites-available Para las rutas ojo porque es desde la raiz del servidor web nginx para esa location ","title":"server-side-includes"},{"location":"debian/#ocultar-la-version-de-nginx","text":"nano /etc/nginx/nginx.conf http { server_tokens off; }","title":"ocultar la version de nginx"},{"location":"debian/#headerscabeceras","text":"Ojo, que algunas pueden restringir el comportamiento de las aplicaciones que tengamos # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; add_header Content-Security-Policy \"default-src 'self'\"; En el location block para evitar cualquier indexacion de esa location por parte de los robots de busqueda add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\";","title":"headers(cabeceras)"},{"location":"debian/#limitar-tamano-de-los-archivos-de-subida","text":"location /count-loc/ { # set client body size to 10M client_max_body_size 10M; }","title":"Limitar tama\u00f1o de los archivos de subida"},{"location":"debian/#rate-limit","text":"nano /etc/nginx/nginx.conf // aqui definimos por ejemplo la zona=one # limit requests limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s; //luego hay que aplicarlo, mejor en location que en server nano /etc/nginx/sites-available/domain location /count-loc/ { # requests limit limit_req zone=one burst=20; } Apply limits per IP geo $limit { default 1; X.X.X.X 0; Y.Y.Y.Y 0; } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=1r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s;","title":"rate Limit"},{"location":"debian/#http2","text":"nano /etc/nginx/nginx.conf // usar solo cifrados muy seguros ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256: RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; // hay que generar una nuevas claves, lo mejor en /etc/nginx/ssl cd /etc/nginx/ssl openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 // http2 solo funciona con https asi que en el bloque de listen 443 listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; // para mejorar rendimiento ssl_session_cache shared:SSL:5m; ssl_session_timeout 1h;","title":"http2"},{"location":"debian/#cache","text":"// en sites-availables bloque propio # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } // luego en el bloque server que queramos a\u00f1adir expires $expires;","title":"cache"},{"location":"debian/#zonas-privadas","text":"// crear archivo con la contrase\u00f1a apt-get install apache2-utils cd /etc/nginx htpasswd -c .rethinkdb.pass // will ask for password service nginx restart server { listen 443 ssl; server_name sub.domain.com; location / { ... } location /private/ { auth_basic \"Restricted\"; auth_basic_user_file /etc/nginx/.rethinkdb.pass; ... root or proxy for this location } }","title":"zonas privadas"},{"location":"debian/#custom-404","text":"mkdir /var/www/error => 404.html 404.css , js, png ... server { error_page 404 /404.html; location = /404.html { root /var/www/error; internal; } location = /404.css { root /var/www/error; } location = /caution.png { root /var/www/error; } } En 404.html llamamos a los recursos usando rutas absolutas ","title":"custom 404"},{"location":"debian/#block-domains","text":"map $http_referer $bad_referer { default 0; \"~spamdomain1.com\" 1; \"~spamdomain2.com\" 1; \"~spamdomain3.com\" 1; } if ($bad_referer) { return 444; }","title":"block domains"},{"location":"debian/#nginxconf","text":"actualizado 2019-05-08 user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; server_names_hash_bucket_size 64; # 128? # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; # set client body size to 5M # client_max_body_size 2M; # limit requests geo $limit { default 1; X.X.X.X 0; #server1 X.X.X.X 0; #server2 X.X.X:X 0; #server3 X.X.X.X 0; #server4 } map $limit $limit_key { 0 \"\"; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=one:10m rate=5r/s; limit_req_zone $limit_key zone=two:10m rate=2r/m; limit_req_zone $limit_key zone=three:10m rate=12r/m; limit_req_zone $limit_key zone=four:10m rate=2r/s; limit_req_zone $limit_key zone=five:10m rate=1r/s; limit_req_zone $limit_key zone=six:1000m rate=10r/s; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA +AES256:EECDH+3DES:RSA+3DES:!MD5; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; gzip_disable \"msie6\"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml applicati$ ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }","title":"nginx.conf"},{"location":"debian/#dominio-templateconf","text":"actualizado 2019-05-08 ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # my cipher ssl_dhparam /etc/nginx/ssl/dhparam.pem; # server-side-includes ssi on; # Headers to be added: add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always; add_header X-Frame-Options \"DENY\"; add_header X-Content-Type-Options \"nosniff\"; add_header X-XSS-Protection \"1; mode=block\"; #add_header Content-Security-Policy \"default-src 'self'\"; #cache # set client body size to 4M # # client_max_body_size 4M; expires $expires; # custom error error_page 404 /404.html; location = /404.html { root /var/www/codetabs/www/_error; internal; } location = /404.css { root /var/www/codetabs/www/_error; } location = /ct24r.png { root /var/www/codetabs/www/_error; } location = /ct64r.png { root /var/www/codetabs/www/_error; } error_page 429 /429.html; location = /429.html { root /var/www/codetabs/www/_error; #internal; } location /_public { # requests limit, ojo que enlentece la carga de la pagina # limit_req zone=one burst=50; alias /var/www/codetabs/www/_public; }","title":"dominio-template.conf"},{"location":"debian/#sitesdomain","text":"actualizado 2019-05-08 # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css 7d; application/javascript 7d; ~image/ max; } server { listen 80; # Listen to your server ip address server_name 212.24.108.85; # Redirect all traffic comming from your-server-ip to your domain return 301 https://domain.com$request_uri; } server { listen 80; listen [::]:80; server_name domain.com www.domain.com; return 301 https://domain.com$request_uri; server_name *.domain.com; return 301 https://*.domain.com$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name www.domain.com; ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; return 301 https://domain.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS # add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/html; index index.html; } location /freecodecamp { root /var/www/domain; index index.html; } location /notes { root /var/www/domain; index index.html; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name api.domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS add_header 'Access-Control-Allow-Origin' '*' always; location /github-stars/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3501/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /count-loc/ { # requests limit limit_req zone=three ;#burst=50; # set client body size to 10M client_max_body_size 10M; proxy_pass http://127.0.0.1:3502/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /game/ { # requests limit limit_req zone=three ;#burst=50; proxy_pass http://127.0.0.1:3503/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Para coger ip de visitante a\u00f1adir las siguientes dos lineas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name test.domain.com; include /etc/nginx/sites-available/domain.conf; location /admin { # requests limit # limit_req zone=one ;#burst=50; auth_basic \"Area 51\"; auth_basic_user_file /etc/nginx/.admin.pass; root /var/www/domain; index admin.html; } }","title":"SITES/DOMAIN"},{"location":"debian/#subcarpeta-con-php","text":"Hracias serversforhackers.com server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name domain.com; include /etc/nginx/sites-available/domain.conf; # enable CORS #add_header Access-Control-Allow-Origin '*'; location / { root /var/www/domain/beta; index index.html; } location ^~ /blog { alias /var/www/wp-domain; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } } location @nested { rewrite /blog/(.*)$ /blog/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; } } Dokuwiki # DokuWiki location ^~ /wiki { alias /var/www/dokuwiki; index index.php; try_files $uri $uri/ @nested; location ~ \\.php$ { include snippets/fastcgi-php.conf; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } # dokuwiki security location ~ /wiki/(conf|bin|inc)/ { deny all; } location ~ /wiki/data/ { internal; } } location @nested { rewrite /wiki/(.*)$ /wiki/index.php?/$1 last; } location ~ /\\. { deny all; } location ~* /(?:uploads|files)/.*\\.php$ { deny all; }","title":"Subcarpeta con PHP"},{"location":"debian/#webmin","text":"Instalacion Descarga el .deb de aqui dpkg -i package.deb Si debian protesta de dependencias instala las que pida. Estas son las mas posibles: apt install perl libnet-ssleay-perl openssl libpam-runtime libio-pty-perl python libauthen-pam-perl libio-pty-perl apt-show-versions Para desinstalar paramos service webmin stop y despues /etc/webmin/uninstall.sh Modulos nginx module - https://www.justindhoffman.com/project/nginx-webmin-module webmin -> webmin configuration -> webmin modules Actualizacion Despues de actualizarse hay veces que no arranca /etc/init.d/webmin stop /etc/init.d/webmin start Cambiar el password Para cambiar la contrase\u00f1a desde la consola /usr/share/webmin/changepass.pl /etc/webmin root NEWPASSWORD Lets Encrypt Webmin webmin > webmin Configuration > SSL Encryption > SSL Settings /etc/letsencrypt/live/nombreCert/privkey.pem /etc/letsencrypt/live/nombreCert/cert.pem Apply -> service nginx restart","title":"WEBMIN"},{"location":"debian/#lets-encrypt","text":"HTTPS certbot apt-get install certbot - install Create certificate // primero parar nginx service nginx stop // Usar la opcion standalone y creamos todos los dominios juntos // (domain.com www.domain.com sub.domain.com etc) certbot certonly Saving debug log to /var/log/letsencrypt/letsencrypt.log How would you like to authenticate with the ACME CA? ------------------------------------------------------------------------- 1: Place files in webroot directory (webroot) 2: Spin up a temporary webserver (standalone) ------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel):domain.com www.domain.com sub.domain.com Obtaining a new certificate Performing the following challenges: tls-sni-01 challenge for domain.com tls-sni-01 challenge for www.domain.com Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0067_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0067_csr-certbot.pem IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/domain.com/fullchain.pem. Your cert will expire on 2017-11-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run \"certbot renew\" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le Listar certificados certbot certificates - Lista de todos los certificados existentes A\u00f1adir certificado service nginx stop - paramos nginx certbot certonly -d admin.domain.com,api.domain.com,domain.com, sp500.domain.com,www.domain.com,otrosub.domain.com --expand - Eliminar certificado certbot delete - y seleccionamos el que queramos borrar Renovar certbot renew --dry-run - solo testea certbot renew - renueva de verdad certbot renew --force-renew - fuerza la renovacion aunque falte mucho tiempo aun para su caducidad certbot renew --dry-run --cert-name domain.tld ` webroot , no hace falta parar nginx para hacer las renovaciones Leer el manual de certot server { listen 80; listen [::]:80; server_name beta.domain.tld; # location / { # root /var/www/beta.domain.tld; # index index.html; # } return 301 https://beta.domain.tld$request_uri; # } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name beta.domain.tld; ssl_certificate /etc/letsencrypt/live/beta.domain.tld/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/beta.domain.tld/privkey.pem; # ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; #add_header X-Robots-Tag \"noindex, nofollow, nosnippet, noarchive\"; location / { root /var/www/beta.domain.tld; index index.html; } } certbot certonly --webroot -w /var/www/domain.tld -d domain.tld -d www.domain.tld -d beta.domain.tld staging --staging - permite mayopr numero de intentos mientras testeamos","title":"LETS ENCRYPT"},{"location":"debian/#monitorizar-red","text":"vnstat - Bandwidth aptitude install vnstat // lista todas las interfaces de red disponibles vnstat --iflist // configura interface vnstat -u -i eth0 // comienza la ejecucion del servicio como demonio /etc/init.d/vnstat start // cambia de due\u00f1o para poder escribir en su propia base de datos chown -R vnstat:vnstat /var/lib/vnstat/ monitorizar (como un usuario normal) // tiempo real vnstat -l // serie historica por horas-dias-meses-semanas vnstat -h|d|w|m // top 10 dias vnstat -t archivo configuracion (para cambiar la interfaz que por defecto es eth0) nano /etc/vnstat.conf crontab -e 0 * * * * node /var/www/vnstat/vnstat.js // ejecutar cada hora vnstat -i eth0 --json d // dentro de vnstat.js nload apt install nload iftop apt install iftop nethogs apt install nethogs tcptrack apt install tcptrack tcptrack -i interface muestra todas las conexiones existentes en tiempo real nethogs apt install nethogs","title":"MONITORIZAR RED"},{"location":"debian/#mysql","text":"","title":"MYSQL"},{"location":"debian/#instalar-mysql-57x","text":"instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // redirige a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // Descomentar esta line para evitar acceso desde el exterior bind-address = 127.0.0.1 service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; truncate table with fk SET FOREIGN_KEY_CHECKS = 0; TRUNCATE table table_name; SET FOREIGN_KEY_CHECKS = 1;","title":"Instalar MYSQL 5.7.X"},{"location":"debian/#instalar-mysql-80x","text":"Aviso sobre el nuevo sistema de autenticacion MySQL 8 uses a new authentication based on improved SHA256-based password methods. It is recommended that all new MySQL Server installations use this method going forward. This new authentication plugin requires new versions of connectors and clients, with support for this new 8 authentication(caching_sha2_password). Currently MySQL 8 Connectors and community drivers built with libmysqlclient21 support this new method. Clients built with older versions of libmysqlclient may not be able to connect to the new server. To retain compatibility with older client software, the default authentication plugin can be set to the legacy value (mysql_native_password) This should only be done if required third-party software has not been updated to work with the new authentication method. The change will be written to the file /etc/mysql/mysql.conf.d/default-auth-override.cnf After installation, the default can be changed by setting the default_authentication_plugin server setting. instalacion wget => `https://dev.mysql.com/downloads/repo/apt/` dpkg -i packake.deb nano /etc/apt/sources.list.d/mysql.list apt-get update apt-get install mysql-server mysql_secure_installation configuracion nano /etc/mysql/my.cnf // se ven todos los sitios donde puede estar la configuracion // vamos a ... nano /etc/mysql/mysql.conf.d/mysqld.cnf // y debajo de [mysqld] escribimos bind_address = 127.0.0.1 // para prohibir acceso desde el exterior service mysql restart // para crear otros usuarios usamos % en lugar de localhost para // permitir el acceso desde el exterior mysql -u root -pPasswordYouDesire mysql>CREATE USER 'username'@'%' IDENTIFIED BY 'password'; mysql>GRANT ALL ON databaseName.* TO 'username'@'%'; mysql> FLUSH PRIVILEGES; // para apagar mysql password validation UNINSTALL COMPONENT 'file://component_validate_password';","title":"Instalar MYSQL 8.0.X"},{"location":"debian/#redis","text":"","title":"REDIS"},{"location":"debian/#instalar-redis-40x","text":"Instalar apt -t stretch-backports install \"redis-server\" service redis status Configurar nano /etc/redis/redis.conf appendonly yes appendfsync everysec service redis restart","title":"Instalar REDIS 4.0.X"},{"location":"debian/#vps","text":"Benchmark (curl -s wget.racing/nench.sh | bash; curl -s wget.racing/nench.sh | bash) 2>&1 | tee nench.log wget -qO- bench.sh | bash Ram dmidecode -t 17 dd if=/dev/zero of=/dev/null bs=1024M count=200 iperf apt install iperf iperf -c iperf.online.net speedtest curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py chmod +x speedtest-cli http://speedtest.tele2.net/ download wget -O /dev/null http://speedtest.tele2.net/1GB.zip upload curl -T 1GB.zip ftp://speedtest.tele2.net/upload/ hard disk apt install smartmontools // informacion smartctl -a /dev/sda // testear smartctl -t short|long|select /dev/sda // resultados smartctl -a /dev/sda // o solo testear smartctl -l selftest /dev/sdc // informacion hdparm -I /dev/sda // testea hdparm -tT /dev/sda // testea dd if=/dev/zero of=/tmp/output conv=fdatasync bs=384k count=1k; rm -f /tmp/output more benchmarks openssl speed rsa openssl speed -multi numCores rsa2048 7z b SYS arm-XT arreglar el bug de poca velocidad de subida lowendtalk apt install linux-image-4.9.0-6-armmp linux-headers-4.9.0-6-armmp apt purge *armada* reboot modprobe error ufw wget http://last.public.ovh.hdaas.snap.mirrors.ovh.net/ubuntu/pool /main/l/linux-modules-armada375/linux-modules-armada375_4.5.2-4_armhf.deb dpkg -i linux-modules-armada375_4.5.2-4_armhf.deb grub-mkconfig -o /boot/grub/grub.cfg rsync De local a otra remota rsync -aP /home/user/data/ user@destiny.com:/home/user/data # automatizado sin preguntar contrase\u00f1a rsync -arv --delete -e \"sshpass -f '/file/with/passwd' || -p 'password' ssh -p PORT -o StrictHostKeyChecking=no\" --progress /source/data/ user@domain.com:/destination/data De otra remota a local * rsync -charvzP --delete -e \"sshpass -p 'pass' ssh -p port\" --progress user@remote.host:/remote/path /local/path/","title":"VPS"},{"location":"debian/#test-api","text":"siege siege -c 30 -r 1 --no-parser https://api.codetabs.com/v1/ siege -c250 -d10 -t3 https://api.codetabs.com/v1/proxy?quest=http Apache Bench apt-get install apache2-utils - -n numero de peticiones -c concurrencias Mas info ab -n 1000 -c 10 https://jolav.github.io/ \u00a1 Ojo porque ab asume que todas las respuestas son iguales !. Si content-length es distinta lo considera un error y aparece como failed request","title":"TEST API"},{"location":"debian/#openvpn","text":"Script para instalar Crear un Kill Switch // ON-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default deny outgoing ufw allow out on tun0 from any to any ufw enable // OFF-openvpn.sh #!/bin/bash ufw reset ufw default deny incoming ufw default allow outgoing ufw enable chmod +x ON-openvpn.sh OFF-openvpn.sh Conectarte a tu openVpn ./on-openvpn.sh ./off-openvpn.sh more","title":"OPENVPN"},{"location":"debian/#flash-firefox","text":"Download from here tar -xzf flash_player_ppapi_linux*.tar.gz cp libpepflashplayer.so /usr/lib/mozilla/plugins cp -r usr/* /usr // restart firefox","title":"FLASH FIREFOX"},{"location":"debian/#virtualbox","text":"Descargar de aqui en el apartado \"All distributions\" el archivo .run https://www.virtualbox.org/wiki/Linux_Downloads Si tras ejecutarlo e instalarlo dice que falta el dkms es ir aqui buscarlo, bajarlo e instalarlo https://tracker.debian.org/pkg/virtualbox Despues de instalarlo a veces sale este error There were problems setting up VirtualBox. To re-start the set-up process, ru /sbin/vboxconfig as root. If your system is using EFI Secure Boot you may need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information. modprobe vboxdrv","title":"VIRTUALBOX"},{"location":"debian/#gre-tunnel","text":"Tutorial patra configurar Hacerlo persistente con systemd apt install iptables iproute2 ps aux | grep gre ip tunnel show Pantalla modprobe ip_gre iptunnel del gre1 # Solo una vez #echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf #sysctl -p iptunnel add gre1 mode gre local IP_PANTALLA remote IP_SERVIDOR ttl 255 ip addr add 192.168.168.1/30 dev gre1 ip link set gre1 up # aqui ping a 192.168.168.2 # BUYVM # iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor # iptables -t nat -A PREROUTING -d IP_PANTALLA -j DNAT --to-destination 192.168.168.2 # iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # If you're wanting to get more specific, you could add: -p tcp --dport 25565 # HETZNER iptables -t nat -A POSTROUTING -s 192.168.168.0/30 ! -o gre+ -j SNAT --to-source IP_PANTALLA # aqui curl ip desde servidor iptables -A FORWARD -d 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 192.168.168.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.168.2 iptables -t nat -A PREROUTING -d IP_PANTALLA -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.168.2 Extras keepalive en el servidor crontab -e */1 * * * * ping -c2 192.168.168.1 ps aux | grep gre ip tunnel show Servidor modprobe ip_gre iptunnel del gre1 iptunnel add gre1 mode gre local IP_SERVIDOR remote IP_PANTALLA ttl 255 ip addr add 192.168.168.2/30 dev gre1 ip link set gre1 up # TEST-1 ping a 192.168.168.1 # Solo una vez, esto solo se puede borrar luego manualmente # echo '100 GRETUNNEL1' >> /etc/iproute2/rt_tables ip rule add from 192.168.168.0/30 table GRETUNNEL1 ip route add default via 192.168.168.1 table GRETUNNEL1 # TEST-2 # curl http://www.cpanel.net/showip.cgi --interface 192.168.168.2 # wget http://www.cpanel.net/showip.cgi --bind-address=192.168.168.2 -q -O - Persistente crear en cliente y servidor en /etc/systemd/system un nuevo servicio greTunnel.service [Unit] Description=levantar gre tunnel After=network.target [Service] ExecStart=sh /ruta/hasta/el/script Restart=always User=root Group=root Type=simple [Install] WantedBy=multi-user.target","title":"GRE TUNNEL"},{"location":"expressjs/","text":"EXPRESS 4.20.X USO instalacion npm install -g express - Lo instalamos globalmente npm install -g express-generator - Y el generador de codigo plantilla que nos permite usar el comando express A pelo npm init - te pregunta muchas cosas para generar el package.json Con plantillas express -h Muestra las opciones express --hbs miApp Crea el proyecto miApp con handlebars pej cd miApp & npm install Instala las dependencias api application app Es una instancia de la aplicacion express que se usa normalmente para configurar la aplicacion request req Es una envoltura del objeto request del modulo HTTP usado para extraer informacion sobre la peticion response res Es una envoltura del objeto response del modulo HTTP usado para enviar los datos y cabeceras de la respuesta Application settings: env: production, development ... viewcache view engine: jade, ejs, hbs ... views trustproxy (NGINX) Seguimiento de una peticion en express MAIN FILE app.js o main.js Cosas que se hacen en este fichero: Dependencias - Incluir paquetes de terceros y modulos nuestros como manejadores, utilidades ayudantes y modelos Instanciaciones - configurar las opciones de express como motor de plantillas Configuraciones - ajustes y como conectar las bases de datos Middlewares - Definir middlewares Ruteo - definir rutas Arranque - iniciar la app o exportarla app como un modulo ajustes app.set(nombre, valor) - para definir un valor app.set('port', process.env.PORT || 3000); app.get(nombre) - para conseguir un valor app.enable() - app.disable() - app.enabled() - app.disabled() - env - almacena el modo de entorno actual para ese proceso de node.js. Se toma de process.env.NODE_ENV o se pone development por defecto. Opciones {development, test, stage, preview, production} view cache - ponerlo a true para produccion view engine - view engine views - la ruta absoluta al directorio con las plantillas app.set('views', path.join(__dirname, 'templates')) trust proxy - ponerlo a true se esta detras de un proxy como nginx. Por defecto esta desactivado, para activarlo app.set('trust proxy', true); app.enable('trust proxy'); jsonp callback name - vale para hacer llamadas ajax desde otros dominios usando CORS app.set('jsonp callback name', 'cb'); json replacer - json spaces - son dos parametros que se aplican a todas las funciones JSON.stringify(). replacer es un filtro spaces es valor de indentacion app.set('json replacer', function(key, value){ if (key === 'discount') return undefined; else return value; }); app.set('json spaces', 4); case sensitive routing - por defecto disabled, asi /nombre y /Nombres es la misma ruta strict routing - por defeto disabled, asi /users y /users/ son la misma ruta x-powered-by - establece la opcion de la respuesta x-powered-by con el valor Express. Por seguridad lo mejor es desactivarla app.set('x-powered-by', false) // o app.disable('x-powered-by') etag - dejarlo como esta es lo mejor query parser - para parsear las query-string enviadas en la URL. Por defecto extended (usa el modulo qs), true (qs), false (lo desactiva), simple (usa el modulo del nucleo querystring) app.set('query parser', 'simple'); app.set('query parser', false); app.set('query parser', customQueryParsingFunction); subdomain offset - Para aplicaciones desplegadas en varios subdominios contenido estatico Usar directorio de contenido estatico Para servir contenido estatico se usa el middleware express.static incorporado en express. var publicPath = path.resolve(__dirname, 'public'); app.use(express.static(publicPath)); Ya puedes cargar archivos del directorio public El nombre del directorio public no es parte de la url http://localhost:3000/css/style.css http://localhost:3000/public/css/style.css NO Usar multiples directorios de contenido estatico Express busca los archivos en el orden en el que se declaran los directorios estaticos app.use(express.static('public')); app.use(express.static('files')); Prefijo de ruta virtual app.use('/static', express.static('public')); Ahora para cargar los archivos : http://localhost:3000/static/css/style.css TEMPLATES REQUEST (Peticion) Request API req.query - Esta propiedad es un objeto que tiene una propiedad para cada query string en la ruta. Si no hay query string es un objeto vacio {}. // GET /search?q=jolav req.query.q // => \"jolav\" // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order // => \"desc\" req.query.shoe.color // => \"blue\" req.query.shoe.type // => \"converse\" req.params - Esta propiedad es un objeto con propiedades mapeadas a la ruta \"parametros\". Ejemmplo una ruta /usuario/:nombre, la propiedad 'nombre' esta disponoble en req.params.nombre. Por defecto el objeto es {} // GET /user/jolav on route /user/:name req.params.name // => \"jolav\" // GET /file/js/react.js on royte /file/* req.params[0] // => \"js/react.js\" req.body - Contiene pares clave-valor de datos enviados en el body de la peticion. Por defecto es undefined y se llena cuando usas un middleware body-parsing como por ejemplo body-parser o multer req.route - Contiene la ruta actual como una string app.get('/user/:id?', function userIdHandler(req, res) { console.log(req.route); res.send('GET'); }); { path: '/user/:id?', stack: [ { handle: [Function: userIdHandler], name: 'userIdHandler', params: undefined, path: undefined, keys: [], regexp: /^\\/?$/i, method: 'get' } ], methods: { get: true } } req.cookies - Al usar middleware cookie-parser esta propiedad es un objeto que contiene las cookies enviadas con la peticion. Si no hay cookies por defecto es {} req.headers - req.xhr - Es una propiedad booleana que es true si el campo de la cabecera X-Requested-With header de la peticion es \u201cXMLHttpRequest\u201d req.hostname - Contiene el hostname sacado de la cabecera Host HTTP Header de la peticion. Vamos, de que pagina web viene la peticion // Host: \"example.com:3000\" req.hostname // => \"example.com\" req.originalUrl - req.path - req.baseUrl - // GET /search?q=something req.originalUrl // => \"/search?q=something\" // example.com/users?sort=desc req.path // => \"/users\" // GET 'http://www.example.com/admin/new' app.use('/admin', function(req, res, next) { console.log(req.originalUrl); // '/admin/new' console.log(req.baseUrl); // '/admin' console.log(req.path); // '/new' next(); }); req.protocol - Contiene el protocolo de la peticion como string (http o https) RESPONSE (Respuesta) Response API res.headersSent - Propiedad booleana que indica si la aplicacion ya ha enviado cabeceras http para la respuesta (vamos, si ya ha enviado alguna respuesta) app.get('/', function (req, res) { console.log(res.headersSent); // false res.send('OK'); console.log(res.headersSent); // true }); res.cookie(name, value [, options]) - Establece el nombre de la cookie a value (que puede ser una string o un objeto convertido en JSON). Las options es un objeto que puede tener las siguientes propiedades (domain, encode, expires, httpOnly, maxAge, path, secure, signed ,sameSite) res.download(path [, filename] [, options] [, fn]) - Transfiere el archivo en la ruta (path) como un adjunto. Lo normal es que el navegador del cliente pregunte para permitir la descarga res.download('/report-12345.pdf', 'report.pdf', function(err){ if (err) { // Handle error, response may be partially-sent, check res.headersSent } else { // decrement a download credit, etc. } }); res.end([data] [, encoding]) - Finaliza el proceso de respuesta. Se usa para terminar la respuesta sin enviar ningun dato. Si necesitas respondee con datos usas metodos como res.send() o res.json() res.render(view, [locals], callback) - Renderiza una vista y envia el HTML renderizado como string al cliente res.set(field, [value]) - Determina el valor de la cabecera de respuesta http de nombre field a value. Para establecer multiples campos a la vez pasa un objeto como parametro res.set('Content-Type', 'text/plain'); res.set({ 'Content-Type': 'text/plain', 'Content-Length': '123', 'ETag': '12345' }); res.setHeader('Content-Type', 'application/json'); // res.header() is an alias of res.set() method from Express framework. // The only difference is res.setHeader() allows you only to set a // singular header and res.header() will allow you to set multiple headers // res.setHeader() is a native method of Node.js res.status(code) - Establece el estatus HTTP para la respuesta. Se puede encadenar res.status(200).send(JSON.stringify(data, null, 3)); // same as res.status(200).json(data); res.send([status], body) - Envia la respuesta HTTP. El parametro del body puede ser una objeto Buffer, una cadena, un objeto o un array res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('

            some html

            '); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' }); res.sendFile(path [, options] [, fn]) - Envia el fichero que se encuentra el la ruta dada (path). Establece la cabecera de respuesta HTTP Content-Type segun la extension del archivo enviado. Salvo que la option root este especificada es el objeto de opciones el path debe ser ruta absoluta al archivo app.get('/file/:name', function (req, res, next) { const options = { root: __dirname + '/public/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; const fileName = req.params.name; res.sendFile(fileName, options, function (err) { if (err) { next(err); } else { console.log('Sent:', fileName); } }); }) res.json([status], json) - Envia una respuesta JSON ( con el apropiado content-type) que es el parametro convertido a JSON usando JSON.stringify() res.jsonp([status], jsonp) - Envia una respuesta JSON con soporte para JSONP. Este metodo es identico a res.json() salvo que a\u00f1ade soporte para el callback de JSONP res.redirect([status], path) - Redirige a la URL marcada en path con un HTTP status code igual a status, que si no se especifica por defecto es \"302\" res.location(path) - Establece la cabecera HTTP header Location a path res.redirect('/foo/bar'); res.redirect('http://example.com'); res.redirect(301, 'http://example.com'); res.redirect('../login'); MIDDLEWARE https://expressjs.com/en/resources/middleware.html Definicion Se usan para gestionar las peticiones HTTP hechas al servidor, manejarlas y responderlas. Son callbacks que se ejecutan cuando ocurre una peticion HTTP. La mayoria son de dise\u00f1o propio para cubrir nuestras necesidades pero tambien los hay para cosas comunes como logueos, servir ficheros estaticos, parseos y muchas mas cosas. orden - Los middlewares se ejecutan en el mismo orden en el que se cargan Que puede hacer un middleware ejecutar codigo hacer cambios en los objetos request y response terminar el ciclo request-response llamar al siguiente middleware Si el middleware en curso no termina el ciclo request-response debe llamar a next() para pasar el control al siguiente middleware o la peticion se quedara colgada. Cada funcion middleware tiene tres argumentos: req : objeto que contiene toda la informacion de la peticion HTTP res : objeto que contiene toda la informacion de la respuesta HTTP next : es el siguiente middleware definido en el orden de middlewares Crear un middleware var express = require('express'); var app = express(); // Lo definimos var myLogger = function (req, res, next) { console.log('LOGGED'); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(myLogger); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3000); Otro ejemplo middleware pero este manipula la peticion var express = require('express'); var app = express(); // Lo definimos var requestTime = function (req, res, next) { req.requestTime = Date.now(); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(requestTime); app.get('/', function (req, res) { var responseText = 'Hello World!
            '; responseText += 'Requested at: ' + req.requestTime + ''; res.send(responseText); }); app.listen(3000); Limitar un middleware a una cierta rutas app.use(/ruta, middlewareParaEsaRuta); Para cada ciclo request-response de una aplicacion Express Se ejecutan los middlewares de arriba a abajo Para no terminar el ciclo un middleware debe pasar el control al siguiente mediante un next(); next('route'); se salta el resto de middlewares del stack de rutas Para terminar un ciclo debemos usar res.end o usar res.send() \u00f3 res.sendFile() que internamente llaman a res.end Tipos A nivel de aplicacion const app = express(); app.use() app.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] A nivel de router const router = express.Router(); router.use() router.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] Manejo de error Tienen un argumento mas (err) app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Error : something broke!'); }); Incorporados de serie express.static - sirve recursos estaticos como archivos html, imagenes y cosas asi. express.json``- parsea peticiones entrantes con JSON . express.urlencoded` - parsea peticiones entrantes con URLEncoded Terceros npm install middleware; const middleware = require('middleware'); app.use(middleware()); Esenciales compression - gzips los datos transferidos. Debe ponerse my arriba para que comprima los datos de otros middlewares y rutas npm install compression var compression = require('compression'); app.use(compression()); express-static contenido estatico morgan - antiguo logger. Lleva registro de todas las peticiones y otra informacion importante npm install morgan var logger = require('morgan'); app.use(logger(\"common | dev | short | tiny | y mas\")); // usar dev cors - soporte cors para express cors = require('cors'); app.use(cors()); Si no usamos el middleware poner antes de las rutas este codigo para a\u00f1adir las cabeceras app.use(function(req, res, next) { res.header(\"Access-Control-Allow-Origin\", \"*\"); res.header(\"Access-Control-Allow-Headers\", \"Origin, X-Requested-With Content-Type, Accept\"); next(); }); helmet - middlewares de seguridad var helmet = require('helmet'); app.use(helmet()); body-parser - permite procesar los datos que vienen y convertirlos en objetos javascript/node usables. npm install body-parser var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); errorhandler - se usa para manejo basico de errores en desarrollo y prototipado npm install errorhandler var errorHandler = require('errorhandler'); if (app.get('env') === 'development') { app.use(errorhandler()); } connect-busboy - para usar el parseador de formularios busboy npm install connect-busboy var busboy = require('connect-busboy'); app.use('/upload', busboy({immediate: true })); cookie-parser - permite acceder los valores de las cookies del usuario del objeto req.cookie npm install cookie-parser var cookieParser = require('cookie-parser'); app.use(cookieParser()); method-override - permite al servidor soportar metodos http que el cliente no soporte. npm install method-override var methodOverride = require('method-override'); app.use(methodOverride(\"loQueToque\")); serve-index - como un ls en la terminal npm install serve-index var serveIndex = require('serve-index'); app.use('/shared', serveIndex( path.join('public','shared'), {'icons': true} )); express-session - permite al servidor usar sesiones web. Necesita tener activo antes a cookie-parser. npm install express-session response-time - a\u00f1ade la cabecera \"X-Response-Time\" con un tiempo en ms con un numero de 3 digitos por defecto desde el momento en el que la peticion entro en este middleware. npm install response-time var responseTime = require('response-time'); app.use(responseTime(4)); // cambio a 4 digitos csurf - para prevenir CSRF npm install csurf var csrf = require('csurf'); app.use(csrf()); serve-favicon - para configurar el favicon que querramos npm install serve-favicon var favicon = require('serve-favicon'); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname + '/public', 'favicon.ico'))); passport y express-session - autenticacion var passport = require('passport'); var session = require('express-session'); // required for passport app.use(session({ secret: 'kk', saveUninitialized: true, resave: true})); app.use(passport.initialize()); app.use(passport.session()); // persistent login sessions vhost - para usar diferentes rutas basadas en dominios. Por ejemplo tenemos dos apps con express (api y web) para organizar el codigo para diferentes rutas basadas en los dominios api.dominio.com y web.dominio.com npm install vhost var api = express() var web = express() app.use(vhost('www.dominio.com', web)) app.use(vhost('api.dominio.com', api)) connect-timeout - establece un temporizador npm install connect-timeout var timeout = require('connect-timeout'); cookie-session - almacen de sesion de cookies raw-body - para peticiones como buffers express-validator - para sanear y validar datos que se reciben oauth2-server - autenticacion connect-redis - almacen de la sesion en redis SESIONES + COOKIES Actualizacion 04-07-2019 Ya no hacen falta ni cookie-parser , ni body-parser OJO con los dominios desarrollando en local, si expressjs se levanta en localhost, poner el navegador tambien en localhost y no con 127.0.0.1 o las cookies no se podran leer (aunque si funcionan) app.use(express.json()); // to support JSON-encoded bodies app.use(express.urlencoded({ // to support URL-encoded bodies extended: true })); app.set('trust proxy', 1); // trust first proxy app.use(session({ secret: \"process.env.secretSession\", name: 'alpha', saveUninitialized: false, resave: false, cookie: { httpOnly: false, // true to production //secure: true // comment for localhost, only works for https secure: false, path: \"/\" }, })); ROUTING El ruteo determina como responde una aplicacion a una peticion de un cliente que contiene una URI (o ruta) y un metodo HTTP (GET, POST ...) Cada ruta puede tener una o mas funciones manejadoras que se ejecutan cuando la ruta coincide. Las rutas se pueden hacer con expresiones regulares protocolo hostname port path querystring fragment http:// localhost :3000 /about ?test=1 #history http:// www.bing.com /search ?q=grunt&first https:// google.com / #q=express app.METHOD app.METHOD(path, [handler], handler); path es la ruta en el servidor que pueden ser cadenas, patrones de cadenas o expresiones regulares handler es la funcion que se ejecuta cuando la ruta coincide. Cuando hay varios manejadores para evitar que se ejecuten todos hay que invocar next('route') y saltara a la siguiente METHOD get, leer post, crear put, actualizar delete, borrar hay otros cuantos all, para todos // Ejemplos app.get('/', function (req, res) { // GET method route res.send('GET request to the homepage'); }); app.post('/', function (req, res) { // POST method route res.send('POST request to the homepage'); }); parametros en la ruta La ruta puede contener parametros que se capturan en req.params Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { \"userId\": \"34\", \"bookId\": \"8989\" } multiples manejadores de ruta Se puede establecer m\u00faltiples callbacks (manejadores) que se comportan como middlewares para gestionar una petici\u00f3n. La unica excepcion es que podrian invocar next(\"route\") para evitar los restantes manejadores de esa ruta Los manejadores de ruta pueden ser una funcion, un array de funciones o una combinacion de ambos // varias funciones independientes app.get('/example/b', function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from B!'); }); // array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } var cb2 = function (req, res) { res.send('Hello from C!'); } app.get('/example/c', [cb0, cb1, cb2]); // mix de funciones independientes y array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } app.get('/example/d', [cb0, cb1], function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from D!'); }); app.route() cadena de manejadores de ruta app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); }); clase express.Router La clase express.Router se usa para crear manejadores modulares Creamos un archivo perfil.js en el subdirectorio para rutas /routes var express = require('express'); var perfil = express.Router(); // middleware especifico para esta ruta si nos hace falta, es opcional perfil.use (function(req, res, next) { console.log('Hora = ', Date.now()); next(); }); perfil.get(\"/\", function(req, res, next) { res.send(\"En ruta /\"); }); perfil.get(\"/username\", function(req, res, next) { res.send(\"En /username\"); }); module.exports = perfil; Cargamos el modulo de router en la aplicacion en app.js // en app.js con esto creamos dos rutas \"/profile\" y \"/profile/:username\" var perfiles = require('./routes/perfil.js'); app.use('/perfiles', perfiles); Ahora la app ya atiende a las rutas /perfil y /perfil/:username Cada router puede cargar otros router hasta cargar todos en pej index.js y al cargar en app,js /controller/index.js ya estaran todas las rutas ERRORES El middleware de manejo de errores se define el ultimo despues de todos los app.use() y manejo de rutas. En desarrollo if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } En produccion app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); Se produce un error en express cuando llamamos un next(\"algo ha pasado\") Se saltara los middleware que haya hasta llegar al primer middleware que maneje errores Express no maneja errores producidos por la palabra clave throw y tiene protecciones para estas excepciones. La app retirnara un error 500 y esa peticion fallara pero la app continuara ejecutandose. Sin embargo los errores de sintaxis cascan el programa app.use(function(req, res, next) { if (req.url === \"/\") { next(); } else if (req.url === \"/throw\") { throw new Error(\"Gimme that error\"); } else { next(\"You didn't visit the root!\"); } }); app.use(function(req, res) { res.send(\"Welcome to the homepage.\"); }); app.use(function(err, req, res, next) { console.error(err); res.status(500); next(err); }); app.use(function(err, req, res, next) { res.send(\"Got an error: \" + err); }); APIs RESTful API CRUD api crear -> POST leer -> GET actualizar -> PUT borrar -> DELETE Versiones Patron para mantener la retrocompatibilidad api1.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"Sample response for /timezone\"); }); api.get(\"/all_timezones\", function(req, res) { res.send(\"Sample response for /all_timezones\"); }); module.exports = api; api2.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"API 2: super cool new response for /timezone\"); }); module.exports = api; app.js var express = require(\"express\"); var apiVersion1 = require(\"./api1.js\"); var apiVersion2 = require(\"./api2.js\"); var app = express(); app.use(\"/v1\", apiVersion1); app.use(\"/v2\", apiVersion2); app.listen(3000, function() { console.log(\"App started on port 3000\"); }); SEGURIDAD Seguridad en express Cross-site request forgery npm install --save csurf - Se evita al usar el middleware csurf Debe ir precedido por cookie-parser y express-session var cookieParser = require('cookie-parser'), var session = require('express-session'); var csrf = require(\"csurf\"); app.use(cookieParser('FE28D342-4040-4D0E-B080-B85E85DAF7FD')); app.use(session({ secret: 'BD564488-5105-4202-8927-5A5C9AE9154E', resave: true, saveUninitialized: true })); app.use(csrf()); app.use(function (request, response, next) { response.locals.csrftoken = request.csrfToken(); next(); }); Permisos en procesos No correr servicios como root. Los servicios se pueden cambiar de usuario en ejecucion usando GID (group ID) y UID (user ID) var app = express(); http.createServer(app).listen(app.get('port'), function(){ console.log(\"Express server listening on port \" + app.get('port')); process.setgid(parseInt(process.env.GID, 10)); process.setuid(parseInt(process.env.UID, 10)); }); HTTP Security Headess Instalar middleware helmet que es un conjunto de middlewares de seguridad npm install --save helmet var helmet = require('helmet'); app.use(helmet()); Input Validation Chequear manualmente los datos con expresiones regulares de las rutas que aceptan datos externos Deben tambien controlarse el mapeo de objetos de los datos La validacion en el navegador es solo por criterios de usabilidad, no aporta proteccion a la aplicacion web npm install --save express-validator var validator = require('express-validator'); // lo aplico despues del body-parser app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); app.use(validator()); Ahora en los manejadores tenemos acceso a req.assert y req.validationErrors() app.post('/login', function(req, res){ req.assert('password', 'Password is required').notEmpty(); req.assert('email', 'A valid email is required').notEmpty().isEmail(); var errors = req.validationErrors(); if (errors) { res.render('index', {errors: errors}); } else { res.render('login', {email: request.email}); } }); Seguridad de los paquetes npm npm install -g nsp nsp check --output summary app.disable('x-powered-by');","title":"Expressjs"},{"location":"expressjs/#express-420x","text":"","title":"EXPRESS 4.20.X"},{"location":"expressjs/#uso","text":"","title":"USO"},{"location":"expressjs/#instalacion","text":"npm install -g express - Lo instalamos globalmente npm install -g express-generator - Y el generador de codigo plantilla que nos permite usar el comando express A pelo npm init - te pregunta muchas cosas para generar el package.json Con plantillas express -h Muestra las opciones express --hbs miApp Crea el proyecto miApp con handlebars pej cd miApp & npm install Instala las dependencias","title":"instalacion"},{"location":"expressjs/#api","text":"application app Es una instancia de la aplicacion express que se usa normalmente para configurar la aplicacion request req Es una envoltura del objeto request del modulo HTTP usado para extraer informacion sobre la peticion response res Es una envoltura del objeto response del modulo HTTP usado para enviar los datos y cabeceras de la respuesta Application settings: env: production, development ... viewcache view engine: jade, ejs, hbs ... views trustproxy (NGINX) Seguimiento de una peticion en express","title":"api"},{"location":"expressjs/#main-file","text":"app.js o main.js Cosas que se hacen en este fichero: Dependencias - Incluir paquetes de terceros y modulos nuestros como manejadores, utilidades ayudantes y modelos Instanciaciones - configurar las opciones de express como motor de plantillas Configuraciones - ajustes y como conectar las bases de datos Middlewares - Definir middlewares Ruteo - definir rutas Arranque - iniciar la app o exportarla app como un modulo","title":"MAIN FILE"},{"location":"expressjs/#ajustes","text":"app.set(nombre, valor) - para definir un valor app.set('port', process.env.PORT || 3000); app.get(nombre) - para conseguir un valor app.enable() - app.disable() - app.enabled() - app.disabled() - env - almacena el modo de entorno actual para ese proceso de node.js. Se toma de process.env.NODE_ENV o se pone development por defecto. Opciones {development, test, stage, preview, production} view cache - ponerlo a true para produccion view engine - view engine views - la ruta absoluta al directorio con las plantillas app.set('views', path.join(__dirname, 'templates')) trust proxy - ponerlo a true se esta detras de un proxy como nginx. Por defecto esta desactivado, para activarlo app.set('trust proxy', true); app.enable('trust proxy'); jsonp callback name - vale para hacer llamadas ajax desde otros dominios usando CORS app.set('jsonp callback name', 'cb'); json replacer - json spaces - son dos parametros que se aplican a todas las funciones JSON.stringify(). replacer es un filtro spaces es valor de indentacion app.set('json replacer', function(key, value){ if (key === 'discount') return undefined; else return value; }); app.set('json spaces', 4); case sensitive routing - por defecto disabled, asi /nombre y /Nombres es la misma ruta strict routing - por defeto disabled, asi /users y /users/ son la misma ruta x-powered-by - establece la opcion de la respuesta x-powered-by con el valor Express. Por seguridad lo mejor es desactivarla app.set('x-powered-by', false) // o app.disable('x-powered-by') etag - dejarlo como esta es lo mejor query parser - para parsear las query-string enviadas en la URL. Por defecto extended (usa el modulo qs), true (qs), false (lo desactiva), simple (usa el modulo del nucleo querystring) app.set('query parser', 'simple'); app.set('query parser', false); app.set('query parser', customQueryParsingFunction); subdomain offset - Para aplicaciones desplegadas en varios subdominios","title":"ajustes"},{"location":"expressjs/#contenido-estatico","text":"Usar directorio de contenido estatico Para servir contenido estatico se usa el middleware express.static incorporado en express. var publicPath = path.resolve(__dirname, 'public'); app.use(express.static(publicPath)); Ya puedes cargar archivos del directorio public El nombre del directorio public no es parte de la url http://localhost:3000/css/style.css http://localhost:3000/public/css/style.css NO Usar multiples directorios de contenido estatico Express busca los archivos en el orden en el que se declaran los directorios estaticos app.use(express.static('public')); app.use(express.static('files')); Prefijo de ruta virtual app.use('/static', express.static('public')); Ahora para cargar los archivos : http://localhost:3000/static/css/style.css","title":"contenido estatico"},{"location":"expressjs/#templates","text":"","title":"TEMPLATES"},{"location":"expressjs/#request-peticion","text":"Request API req.query - Esta propiedad es un objeto que tiene una propiedad para cada query string en la ruta. Si no hay query string es un objeto vacio {}. // GET /search?q=jolav req.query.q // => \"jolav\" // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order // => \"desc\" req.query.shoe.color // => \"blue\" req.query.shoe.type // => \"converse\" req.params - Esta propiedad es un objeto con propiedades mapeadas a la ruta \"parametros\". Ejemmplo una ruta /usuario/:nombre, la propiedad 'nombre' esta disponoble en req.params.nombre. Por defecto el objeto es {} // GET /user/jolav on route /user/:name req.params.name // => \"jolav\" // GET /file/js/react.js on royte /file/* req.params[0] // => \"js/react.js\" req.body - Contiene pares clave-valor de datos enviados en el body de la peticion. Por defecto es undefined y se llena cuando usas un middleware body-parsing como por ejemplo body-parser o multer req.route - Contiene la ruta actual como una string app.get('/user/:id?', function userIdHandler(req, res) { console.log(req.route); res.send('GET'); }); { path: '/user/:id?', stack: [ { handle: [Function: userIdHandler], name: 'userIdHandler', params: undefined, path: undefined, keys: [], regexp: /^\\/?$/i, method: 'get' } ], methods: { get: true } } req.cookies - Al usar middleware cookie-parser esta propiedad es un objeto que contiene las cookies enviadas con la peticion. Si no hay cookies por defecto es {} req.headers - req.xhr - Es una propiedad booleana que es true si el campo de la cabecera X-Requested-With header de la peticion es \u201cXMLHttpRequest\u201d req.hostname - Contiene el hostname sacado de la cabecera Host HTTP Header de la peticion. Vamos, de que pagina web viene la peticion // Host: \"example.com:3000\" req.hostname // => \"example.com\" req.originalUrl - req.path - req.baseUrl - // GET /search?q=something req.originalUrl // => \"/search?q=something\" // example.com/users?sort=desc req.path // => \"/users\" // GET 'http://www.example.com/admin/new' app.use('/admin', function(req, res, next) { console.log(req.originalUrl); // '/admin/new' console.log(req.baseUrl); // '/admin' console.log(req.path); // '/new' next(); }); req.protocol - Contiene el protocolo de la peticion como string (http o https)","title":"REQUEST (Peticion)"},{"location":"expressjs/#response-respuesta","text":"Response API res.headersSent - Propiedad booleana que indica si la aplicacion ya ha enviado cabeceras http para la respuesta (vamos, si ya ha enviado alguna respuesta) app.get('/', function (req, res) { console.log(res.headersSent); // false res.send('OK'); console.log(res.headersSent); // true }); res.cookie(name, value [, options]) - Establece el nombre de la cookie a value (que puede ser una string o un objeto convertido en JSON). Las options es un objeto que puede tener las siguientes propiedades (domain, encode, expires, httpOnly, maxAge, path, secure, signed ,sameSite) res.download(path [, filename] [, options] [, fn]) - Transfiere el archivo en la ruta (path) como un adjunto. Lo normal es que el navegador del cliente pregunte para permitir la descarga res.download('/report-12345.pdf', 'report.pdf', function(err){ if (err) { // Handle error, response may be partially-sent, check res.headersSent } else { // decrement a download credit, etc. } }); res.end([data] [, encoding]) - Finaliza el proceso de respuesta. Se usa para terminar la respuesta sin enviar ningun dato. Si necesitas respondee con datos usas metodos como res.send() o res.json() res.render(view, [locals], callback) - Renderiza una vista y envia el HTML renderizado como string al cliente res.set(field, [value]) - Determina el valor de la cabecera de respuesta http de nombre field a value. Para establecer multiples campos a la vez pasa un objeto como parametro res.set('Content-Type', 'text/plain'); res.set({ 'Content-Type': 'text/plain', 'Content-Length': '123', 'ETag': '12345' }); res.setHeader('Content-Type', 'application/json'); // res.header() is an alias of res.set() method from Express framework. // The only difference is res.setHeader() allows you only to set a // singular header and res.header() will allow you to set multiple headers // res.setHeader() is a native method of Node.js res.status(code) - Establece el estatus HTTP para la respuesta. Se puede encadenar res.status(200).send(JSON.stringify(data, null, 3)); // same as res.status(200).json(data); res.send([status], body) - Envia la respuesta HTTP. El parametro del body puede ser una objeto Buffer, una cadena, un objeto o un array res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('

            some html

            '); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' }); res.sendFile(path [, options] [, fn]) - Envia el fichero que se encuentra el la ruta dada (path). Establece la cabecera de respuesta HTTP Content-Type segun la extension del archivo enviado. Salvo que la option root este especificada es el objeto de opciones el path debe ser ruta absoluta al archivo app.get('/file/:name', function (req, res, next) { const options = { root: __dirname + '/public/', dotfiles: 'deny', headers: { 'x-timestamp': Date.now(), 'x-sent': true } }; const fileName = req.params.name; res.sendFile(fileName, options, function (err) { if (err) { next(err); } else { console.log('Sent:', fileName); } }); }) res.json([status], json) - Envia una respuesta JSON ( con el apropiado content-type) que es el parametro convertido a JSON usando JSON.stringify() res.jsonp([status], jsonp) - Envia una respuesta JSON con soporte para JSONP. Este metodo es identico a res.json() salvo que a\u00f1ade soporte para el callback de JSONP res.redirect([status], path) - Redirige a la URL marcada en path con un HTTP status code igual a status, que si no se especifica por defecto es \"302\" res.location(path) - Establece la cabecera HTTP header Location a path res.redirect('/foo/bar'); res.redirect('http://example.com'); res.redirect(301, 'http://example.com'); res.redirect('../login');","title":"RESPONSE (Respuesta)"},{"location":"expressjs/#middleware","text":"https://expressjs.com/en/resources/middleware.html","title":"MIDDLEWARE"},{"location":"expressjs/#definicion","text":"Se usan para gestionar las peticiones HTTP hechas al servidor, manejarlas y responderlas. Son callbacks que se ejecutan cuando ocurre una peticion HTTP. La mayoria son de dise\u00f1o propio para cubrir nuestras necesidades pero tambien los hay para cosas comunes como logueos, servir ficheros estaticos, parseos y muchas mas cosas. orden - Los middlewares se ejecutan en el mismo orden en el que se cargan Que puede hacer un middleware ejecutar codigo hacer cambios en los objetos request y response terminar el ciclo request-response llamar al siguiente middleware Si el middleware en curso no termina el ciclo request-response debe llamar a next() para pasar el control al siguiente middleware o la peticion se quedara colgada. Cada funcion middleware tiene tres argumentos: req : objeto que contiene toda la informacion de la peticion HTTP res : objeto que contiene toda la informacion de la respuesta HTTP next : es el siguiente middleware definido en el orden de middlewares Crear un middleware var express = require('express'); var app = express(); // Lo definimos var myLogger = function (req, res, next) { console.log('LOGGED'); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(myLogger); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3000); Otro ejemplo middleware pero este manipula la peticion var express = require('express'); var app = express(); // Lo definimos var requestTime = function (req, res, next) { req.requestTime = Date.now(); next(); }; // Lo cargamos en la app antes de definir las rutas o nunca se ejecutara app.use(requestTime); app.get('/', function (req, res) { var responseText = 'Hello World!
            '; responseText += 'Requested at: ' + req.requestTime + ''; res.send(responseText); }); app.listen(3000); Limitar un middleware a una cierta rutas app.use(/ruta, middlewareParaEsaRuta); Para cada ciclo request-response de una aplicacion Express Se ejecutan los middlewares de arriba a abajo Para no terminar el ciclo un middleware debe pasar el control al siguiente mediante un next(); next('route'); se salta el resto de middlewares del stack de rutas Para terminar un ciclo debemos usar res.end o usar res.send() \u00f3 res.sendFile() que internamente llaman a res.end","title":"Definicion"},{"location":"expressjs/#tipos","text":"A nivel de aplicacion const app = express(); app.use() app.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] A nivel de router const router = express.Router(); router.use() router.METHOD() [METHOD = GET, PUT, POST, UPDATE ...] Manejo de error Tienen un argumento mas (err) app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Error : something broke!'); }); Incorporados de serie express.static - sirve recursos estaticos como archivos html, imagenes y cosas asi. express.json``- parsea peticiones entrantes con JSON . express.urlencoded` - parsea peticiones entrantes con URLEncoded Terceros npm install middleware; const middleware = require('middleware'); app.use(middleware());","title":"Tipos"},{"location":"expressjs/#esenciales","text":"compression - gzips los datos transferidos. Debe ponerse my arriba para que comprima los datos de otros middlewares y rutas npm install compression var compression = require('compression'); app.use(compression()); express-static contenido estatico morgan - antiguo logger. Lleva registro de todas las peticiones y otra informacion importante npm install morgan var logger = require('morgan'); app.use(logger(\"common | dev | short | tiny | y mas\")); // usar dev cors - soporte cors para express cors = require('cors'); app.use(cors()); Si no usamos el middleware poner antes de las rutas este codigo para a\u00f1adir las cabeceras app.use(function(req, res, next) { res.header(\"Access-Control-Allow-Origin\", \"*\"); res.header(\"Access-Control-Allow-Headers\", \"Origin, X-Requested-With Content-Type, Accept\"); next(); }); helmet - middlewares de seguridad var helmet = require('helmet'); app.use(helmet()); body-parser - permite procesar los datos que vienen y convertirlos en objetos javascript/node usables. npm install body-parser var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); errorhandler - se usa para manejo basico de errores en desarrollo y prototipado npm install errorhandler var errorHandler = require('errorhandler'); if (app.get('env') === 'development') { app.use(errorhandler()); } connect-busboy - para usar el parseador de formularios busboy npm install connect-busboy var busboy = require('connect-busboy'); app.use('/upload', busboy({immediate: true })); cookie-parser - permite acceder los valores de las cookies del usuario del objeto req.cookie npm install cookie-parser var cookieParser = require('cookie-parser'); app.use(cookieParser()); method-override - permite al servidor soportar metodos http que el cliente no soporte. npm install method-override var methodOverride = require('method-override'); app.use(methodOverride(\"loQueToque\")); serve-index - como un ls en la terminal npm install serve-index var serveIndex = require('serve-index'); app.use('/shared', serveIndex( path.join('public','shared'), {'icons': true} )); express-session - permite al servidor usar sesiones web. Necesita tener activo antes a cookie-parser. npm install express-session response-time - a\u00f1ade la cabecera \"X-Response-Time\" con un tiempo en ms con un numero de 3 digitos por defecto desde el momento en el que la peticion entro en este middleware. npm install response-time var responseTime = require('response-time'); app.use(responseTime(4)); // cambio a 4 digitos csurf - para prevenir CSRF npm install csurf var csrf = require('csurf'); app.use(csrf()); serve-favicon - para configurar el favicon que querramos npm install serve-favicon var favicon = require('serve-favicon'); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname + '/public', 'favicon.ico'))); passport y express-session - autenticacion var passport = require('passport'); var session = require('express-session'); // required for passport app.use(session({ secret: 'kk', saveUninitialized: true, resave: true})); app.use(passport.initialize()); app.use(passport.session()); // persistent login sessions vhost - para usar diferentes rutas basadas en dominios. Por ejemplo tenemos dos apps con express (api y web) para organizar el codigo para diferentes rutas basadas en los dominios api.dominio.com y web.dominio.com npm install vhost var api = express() var web = express() app.use(vhost('www.dominio.com', web)) app.use(vhost('api.dominio.com', api)) connect-timeout - establece un temporizador npm install connect-timeout var timeout = require('connect-timeout'); cookie-session - almacen de sesion de cookies raw-body - para peticiones como buffers express-validator - para sanear y validar datos que se reciben oauth2-server - autenticacion connect-redis - almacen de la sesion en redis","title":"Esenciales"},{"location":"expressjs/#sesiones-cookies","text":"Actualizacion 04-07-2019 Ya no hacen falta ni cookie-parser , ni body-parser OJO con los dominios desarrollando en local, si expressjs se levanta en localhost, poner el navegador tambien en localhost y no con 127.0.0.1 o las cookies no se podran leer (aunque si funcionan) app.use(express.json()); // to support JSON-encoded bodies app.use(express.urlencoded({ // to support URL-encoded bodies extended: true })); app.set('trust proxy', 1); // trust first proxy app.use(session({ secret: \"process.env.secretSession\", name: 'alpha', saveUninitialized: false, resave: false, cookie: { httpOnly: false, // true to production //secure: true // comment for localhost, only works for https secure: false, path: \"/\" }, }));","title":"SESIONES + COOKIES"},{"location":"expressjs/#routing","text":"El ruteo determina como responde una aplicacion a una peticion de un cliente que contiene una URI (o ruta) y un metodo HTTP (GET, POST ...) Cada ruta puede tener una o mas funciones manejadoras que se ejecutan cuando la ruta coincide. Las rutas se pueden hacer con expresiones regulares protocolo hostname port path querystring fragment http:// localhost :3000 /about ?test=1 #history http:// www.bing.com /search ?q=grunt&first https:// google.com / #q=express","title":"ROUTING"},{"location":"expressjs/#appmethod","text":"app.METHOD(path, [handler], handler); path es la ruta en el servidor que pueden ser cadenas, patrones de cadenas o expresiones regulares handler es la funcion que se ejecuta cuando la ruta coincide. Cuando hay varios manejadores para evitar que se ejecuten todos hay que invocar next('route') y saltara a la siguiente METHOD get, leer post, crear put, actualizar delete, borrar hay otros cuantos all, para todos // Ejemplos app.get('/', function (req, res) { // GET method route res.send('GET request to the homepage'); }); app.post('/', function (req, res) { // POST method route res.send('POST request to the homepage'); }); parametros en la ruta La ruta puede contener parametros que se capturan en req.params Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { \"userId\": \"34\", \"bookId\": \"8989\" } multiples manejadores de ruta Se puede establecer m\u00faltiples callbacks (manejadores) que se comportan como middlewares para gestionar una petici\u00f3n. La unica excepcion es que podrian invocar next(\"route\") para evitar los restantes manejadores de esa ruta Los manejadores de ruta pueden ser una funcion, un array de funciones o una combinacion de ambos // varias funciones independientes app.get('/example/b', function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from B!'); }); // array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } var cb2 = function (req, res) { res.send('Hello from C!'); } app.get('/example/c', [cb0, cb1, cb2]); // mix de funciones independientes y array de funciones var cb0 = function (req, res, next) { console.log('CB0'); next(); } var cb1 = function (req, res, next) { console.log('CB1'); next(); } app.get('/example/d', [cb0, cb1], function (req, res, next) { console.log('the response will be sent by the next function ...'); next(); }, function (req, res) { res.send('Hello from D!'); });","title":"app.METHOD"},{"location":"expressjs/#approute","text":"cadena de manejadores de ruta app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); });","title":"app.route()"},{"location":"expressjs/#clase-expressrouter","text":"La clase express.Router se usa para crear manejadores modulares Creamos un archivo perfil.js en el subdirectorio para rutas /routes var express = require('express'); var perfil = express.Router(); // middleware especifico para esta ruta si nos hace falta, es opcional perfil.use (function(req, res, next) { console.log('Hora = ', Date.now()); next(); }); perfil.get(\"/\", function(req, res, next) { res.send(\"En ruta /\"); }); perfil.get(\"/username\", function(req, res, next) { res.send(\"En /username\"); }); module.exports = perfil; Cargamos el modulo de router en la aplicacion en app.js // en app.js con esto creamos dos rutas \"/profile\" y \"/profile/:username\" var perfiles = require('./routes/perfil.js'); app.use('/perfiles', perfiles); Ahora la app ya atiende a las rutas /perfil y /perfil/:username Cada router puede cargar otros router hasta cargar todos en pej index.js y al cargar en app,js /controller/index.js ya estaran todas las rutas","title":"clase express.Router"},{"location":"expressjs/#errores","text":"El middleware de manejo de errores se define el ultimo despues de todos los app.use() y manejo de rutas. En desarrollo if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } En produccion app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); Se produce un error en express cuando llamamos un next(\"algo ha pasado\") Se saltara los middleware que haya hasta llegar al primer middleware que maneje errores Express no maneja errores producidos por la palabra clave throw y tiene protecciones para estas excepciones. La app retirnara un error 500 y esa peticion fallara pero la app continuara ejecutandose. Sin embargo los errores de sintaxis cascan el programa app.use(function(req, res, next) { if (req.url === \"/\") { next(); } else if (req.url === \"/throw\") { throw new Error(\"Gimme that error\"); } else { next(\"You didn't visit the root!\"); } }); app.use(function(req, res) { res.send(\"Welcome to the homepage.\"); }); app.use(function(err, req, res, next) { console.error(err); res.status(500); next(err); }); app.use(function(err, req, res, next) { res.send(\"Got an error: \" + err); });","title":"ERRORES"},{"location":"expressjs/#apis","text":"RESTful API CRUD api crear -> POST leer -> GET actualizar -> PUT borrar -> DELETE Versiones Patron para mantener la retrocompatibilidad api1.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"Sample response for /timezone\"); }); api.get(\"/all_timezones\", function(req, res) { res.send(\"Sample response for /all_timezones\"); }); module.exports = api; api2.js var express = require(\"express\"); var api = express.Router(); api.get(\"/timezone\", function(req, res) { res.send(\"API 2: super cool new response for /timezone\"); }); module.exports = api; app.js var express = require(\"express\"); var apiVersion1 = require(\"./api1.js\"); var apiVersion2 = require(\"./api2.js\"); var app = express(); app.use(\"/v1\", apiVersion1); app.use(\"/v2\", apiVersion2); app.listen(3000, function() { console.log(\"App started on port 3000\"); });","title":"APIs"},{"location":"expressjs/#seguridad","text":"Seguridad en express Cross-site request forgery npm install --save csurf - Se evita al usar el middleware csurf Debe ir precedido por cookie-parser y express-session var cookieParser = require('cookie-parser'), var session = require('express-session'); var csrf = require(\"csurf\"); app.use(cookieParser('FE28D342-4040-4D0E-B080-B85E85DAF7FD')); app.use(session({ secret: 'BD564488-5105-4202-8927-5A5C9AE9154E', resave: true, saveUninitialized: true })); app.use(csrf()); app.use(function (request, response, next) { response.locals.csrftoken = request.csrfToken(); next(); }); Permisos en procesos No correr servicios como root. Los servicios se pueden cambiar de usuario en ejecucion usando GID (group ID) y UID (user ID) var app = express(); http.createServer(app).listen(app.get('port'), function(){ console.log(\"Express server listening on port \" + app.get('port')); process.setgid(parseInt(process.env.GID, 10)); process.setuid(parseInt(process.env.UID, 10)); }); HTTP Security Headess Instalar middleware helmet que es un conjunto de middlewares de seguridad npm install --save helmet var helmet = require('helmet'); app.use(helmet()); Input Validation Chequear manualmente los datos con expresiones regulares de las rutas que aceptan datos externos Deben tambien controlarse el mapeo de objetos de los datos La validacion en el navegador es solo por criterios de usabilidad, no aporta proteccion a la aplicacion web npm install --save express-validator var validator = require('express-validator'); // lo aplico despues del body-parser app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); app.use(validator()); Ahora en los manejadores tenemos acceso a req.assert y req.validationErrors() app.post('/login', function(req, res){ req.assert('password', 'Password is required').notEmpty(); req.assert('email', 'A valid email is required').notEmpty().isEmail(); var errors = req.validationErrors(); if (errors) { res.render('index', {errors: errors}); } else { res.render('login', {email: request.email}); } }); Seguridad de los paquetes npm npm install -g nsp nsp check --output summary app.disable('x-powered-by');","title":"SEGURIDAD"},{"location":"frontend/","text":"FRONT END IMAGENES IMAGENES tynypng - Comprimir imagenes shrinktheweb - Capturar instantaneas de paginas web ICONOS SoftIcons Material design Iconfinder COLORES Color-hex - Para elegir colores SPRITES css sprites - Generador de sprites y su CSS EDITORES ONLINE Luna pic Resize Image IMAGENES GRATUITAS Pixabay Pexels FUENTES GOOGLE FONTS se pueden importar desde el HTML o desde el CSS @import url('https://fonts.googleapis.com/css?family=name:400,500'); Lato Roboto Oxygen Fira Sans IBM Plex Sans Exo Titillium Web Rambla Open Sans Ovo Varela Varela Round PT Sans Audiowide Orbitron Alegreya Patrick Hand SC Indie Flower Chewy Righteous Pacifico Press Start 2P Luckiest Guy Bungee SEGURIDAD Y ESTADISTICAS STATS Pingdom - Mide la velocidad de carga de las paginas WebPageTets - Mide la velocidad de carga de las paginas GT Metrix - Mide la velocidad de carga de las paginas Google PageSpeed - Optimiza la velocidad de carga de las paginas SECURITY CertBot - Para manejar lor certificados lets encrypt Secarma - Prueba la seguridad de las cabeceras del servidor MXToolbox - Todo sobre DNS SSL Labs - Testea la seguridad del SSL del servidor Scan My Server - Testeo completo sobre las vulnerabilidades del servidor y la pagina UTILS XML Sitemaps - Generador de sitemap.xml FUENTES DE INFORMACION APIs LIST List of public APIs - Github repo con lista de APIs publicas Programmableweb - Pagina con listado de APIs GOVs data Data Gov - Datos del Gobierno USA EU Open Data Portal - Datos de la CEE Spain Gov Data - Datos del Gobierno Espa\u00f1ol FOOD Nutritionix - Api completa sobre comida STOCK MARKET IEX Trading - Api en tiempo real Alphavantage - API en tiempo real Quandl - Bases de datos financieras y economicas LIVE-SERVER // se recarga al cambiar archivos css (que por defecto no lo hace) live-server --no-css-inject // por efecto abre en 127.0.0.1 , para cambiarlo live-server --no-css-inject --host=localhost","title":"Front End"},{"location":"frontend/#front-end","text":"","title":"FRONT END"},{"location":"frontend/#imagenes","text":"IMAGENES tynypng - Comprimir imagenes shrinktheweb - Capturar instantaneas de paginas web ICONOS SoftIcons Material design Iconfinder COLORES Color-hex - Para elegir colores SPRITES css sprites - Generador de sprites y su CSS EDITORES ONLINE Luna pic Resize Image IMAGENES GRATUITAS Pixabay Pexels","title":"IMAGENES"},{"location":"frontend/#fuentes","text":"GOOGLE FONTS se pueden importar desde el HTML o desde el CSS @import url('https://fonts.googleapis.com/css?family=name:400,500'); Lato Roboto Oxygen Fira Sans IBM Plex Sans Exo Titillium Web Rambla Open Sans Ovo Varela Varela Round PT Sans Audiowide Orbitron Alegreya Patrick Hand SC Indie Flower Chewy Righteous Pacifico Press Start 2P Luckiest Guy Bungee","title":"FUENTES"},{"location":"frontend/#seguridad-y-estadisticas","text":"STATS Pingdom - Mide la velocidad de carga de las paginas WebPageTets - Mide la velocidad de carga de las paginas GT Metrix - Mide la velocidad de carga de las paginas Google PageSpeed - Optimiza la velocidad de carga de las paginas SECURITY CertBot - Para manejar lor certificados lets encrypt Secarma - Prueba la seguridad de las cabeceras del servidor MXToolbox - Todo sobre DNS SSL Labs - Testea la seguridad del SSL del servidor Scan My Server - Testeo completo sobre las vulnerabilidades del servidor y la pagina UTILS XML Sitemaps - Generador de sitemap.xml","title":"SEGURIDAD Y ESTADISTICAS"},{"location":"frontend/#fuentes-de-informacion","text":"APIs LIST List of public APIs - Github repo con lista de APIs publicas Programmableweb - Pagina con listado de APIs GOVs data Data Gov - Datos del Gobierno USA EU Open Data Portal - Datos de la CEE Spain Gov Data - Datos del Gobierno Espa\u00f1ol FOOD Nutritionix - Api completa sobre comida STOCK MARKET IEX Trading - Api en tiempo real Alphavantage - API en tiempo real Quandl - Bases de datos financieras y economicas","title":"FUENTES DE INFORMACION"},{"location":"frontend/#live-server","text":"// se recarga al cambiar archivos css (que por defecto no lo hace) live-server --no-css-inject // por efecto abre en 127.0.0.1 , para cambiarlo live-server --no-css-inject --host=localhost","title":"LIVE-SERVER"},{"location":"golang-bases-de-datos/","text":"GOLANG para BASES DE DATOS MYSQL driver go-sql-driver go get -u github.com/go-sql-driver/mysql Crear conexion a la BBDD package store import ( \"database/sql\" \"fmt\" // mysql driver _ \"github.com/go-sql-driver/mysql\" ) type configDB struct { DatabaseType string `json:\"databaseType\"` Host string `json:\"host\"` Port int `json:\"port\"` DB string `json:\"db\"` User string `json:\"user\"` Password string `json:\"password\"` } // DB ... type DB struct { *sql.DB } // NewDB ... func NewDB(mode string) (*DB, error) { var c configDB loadConfigJSON(&c) setDBConnConfig(mode, &c) connPath := fmt.Sprintf(\"%s:%s@tcp(%s:%d)/%s?parseTime=true\", c.User, c.Password, c.Host, c.Port, c.DB, ) //fmt.Println(\"CONNPATH => \", connPath) db, err := sql.Open(c.DatabaseType, connPath) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return &DB{db}, nil } // lo llamo desde otro paquete package login import ( store \"casServer/login/store\" ) var loginDB *store.DB func init() { db, err := store.NewDB(checkAppConfMode()) if err != nil { log.Fatal(\"Error connecting DataBase => \", err) } loginDB = db //users, _ := loginDB.AccountList() //fmt.Println(len(users)) } Select func (loginDB *DB) Account(name string) (*User, error) { //fmt.Println(\"SEARCHING ...\", name) u := new(User) query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, usersTable, ) //fmt.Println(query) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB %s\\n\", err) return u, err } defer stmt.Close() err = stmt.QueryRow(name).Scan( &u.NickID, &u.Nick, &u.PassHashed, &u.Email, &u.Verified, &u.Logo, &u.SecretQuest, &u.SecretHashed, &u.CreatedAt, &u.LastSeen, &u.Online) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", u) return u, nil } log.Printf(\"ERROR 2 DB %s\\n\", err) return nil, err } return u, nil } func (loginDB *DB) AccountList() ([]*User, error) { query := fmt.Sprintf(` SELECT nickID FROM %s `, usersTable, ) stmt, err := loginDB.Prepare(query) if err != nil { return nil, err } defer stmt.Close() rows, err := stmt.Query() if err != nil { return nil, err } defer rows.Close() users := make([]*User, 0) for rows.Next() { user := new(User) err := rows.Scan( &user.NickID, ) if err != nil { return nil, err } users = append(users, user) } return users, nil } func (loginDB *DB) UserSession(usernameID string) (*Session, error) { s := NewSession() query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, sessionsTable, ) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 3 DB SESSIONS %s\\n\", err) return s, err } defer stmt.Close() err = stmt.QueryRow(usernameID).Scan( &s.NickID, &s.SessionID, &s.Expires, ) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", s) return s, nil } log.Printf(\"ERROR 4 DB SESSIONS %s\\n\", err) return nil, err } return s, nil } Insert func (loginDB *DB) NewAccount(u *User) error { //fmt.Println(\"USER => \", u) query := fmt.Sprintf(` INSERT INTO %s ( nickID, nick, passHashed, email, verified, logo, secretQuest, secretHashed, createdAt, lastSeen, online ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, usersTable, ) stmt, err := loginDB.Prepare(query) //fmt.Println(query) if err != nil { log.Printf(\"ERROR 3 DB USERS %s -> %s\\n\", u.Nick, err) return err } defer stmt.Close() _, err = stmt.Exec( u.NickID, u.Nick, u.PassHashed, u.Email, u.Verified, u.Logo, u.SecretQuest, u.SecretHashed, u.CreatedAt, u.LastSeen, u.Online, ) if err != nil { log.Printf(\"ERROR 4 DB USERS %s -> %s\\n\", u.Nick, err) return err } return nil } func (loginDB *DB) SaveSession(s *Session) error { query := fmt.Sprintf(` INSERT INTO %s ( nickID, sessionID, expires ) values (?, ?, ?) ON DUPLICATE KEY UPDATE sessionID=? , expires= ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } defer stmt.Close() _, err = stmt.Exec( s.NickID, s.SessionID, s.Expires, s.SessionID, s.Expires, ) if err != nil { log.Printf(\"ERROR 2 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } return nil } Update Delete func (loginDB *DB) DeleteSession(usernameID string) error { query := fmt.Sprintf(` DELETE FROM %s WHERE nickID = ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 5 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } defer stmt.Close() _, err = stmt.Exec( usernameID, ) if err != nil { log.Printf(\"ERROR 6 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } return nil }","title":"Golang Bases de Datos"},{"location":"golang-bases-de-datos/#golang-para-bases-de-datos","text":"","title":"GOLANG para BASES DE DATOS"},{"location":"golang-bases-de-datos/#mysql","text":"","title":"MYSQL"},{"location":"golang-bases-de-datos/#driver","text":"go-sql-driver go get -u github.com/go-sql-driver/mysql","title":"driver"},{"location":"golang-bases-de-datos/#crear-conexion-a-la-bbdd","text":"package store import ( \"database/sql\" \"fmt\" // mysql driver _ \"github.com/go-sql-driver/mysql\" ) type configDB struct { DatabaseType string `json:\"databaseType\"` Host string `json:\"host\"` Port int `json:\"port\"` DB string `json:\"db\"` User string `json:\"user\"` Password string `json:\"password\"` } // DB ... type DB struct { *sql.DB } // NewDB ... func NewDB(mode string) (*DB, error) { var c configDB loadConfigJSON(&c) setDBConnConfig(mode, &c) connPath := fmt.Sprintf(\"%s:%s@tcp(%s:%d)/%s?parseTime=true\", c.User, c.Password, c.Host, c.Port, c.DB, ) //fmt.Println(\"CONNPATH => \", connPath) db, err := sql.Open(c.DatabaseType, connPath) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return &DB{db}, nil } // lo llamo desde otro paquete package login import ( store \"casServer/login/store\" ) var loginDB *store.DB func init() { db, err := store.NewDB(checkAppConfMode()) if err != nil { log.Fatal(\"Error connecting DataBase => \", err) } loginDB = db //users, _ := loginDB.AccountList() //fmt.Println(len(users)) }","title":"Crear conexion a la BBDD"},{"location":"golang-bases-de-datos/#select","text":"func (loginDB *DB) Account(name string) (*User, error) { //fmt.Println(\"SEARCHING ...\", name) u := new(User) query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, usersTable, ) //fmt.Println(query) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB %s\\n\", err) return u, err } defer stmt.Close() err = stmt.QueryRow(name).Scan( &u.NickID, &u.Nick, &u.PassHashed, &u.Email, &u.Verified, &u.Logo, &u.SecretQuest, &u.SecretHashed, &u.CreatedAt, &u.LastSeen, &u.Online) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", u) return u, nil } log.Printf(\"ERROR 2 DB %s\\n\", err) return nil, err } return u, nil } func (loginDB *DB) AccountList() ([]*User, error) { query := fmt.Sprintf(` SELECT nickID FROM %s `, usersTable, ) stmt, err := loginDB.Prepare(query) if err != nil { return nil, err } defer stmt.Close() rows, err := stmt.Query() if err != nil { return nil, err } defer rows.Close() users := make([]*User, 0) for rows.Next() { user := new(User) err := rows.Scan( &user.NickID, ) if err != nil { return nil, err } users = append(users, user) } return users, nil } func (loginDB *DB) UserSession(usernameID string) (*Session, error) { s := NewSession() query := fmt.Sprintf(` SELECT * FROM %s WHERE nickID=? `, sessionsTable, ) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 3 DB SESSIONS %s\\n\", err) return s, err } defer stmt.Close() err = stmt.QueryRow(usernameID).Scan( &s.NickID, &s.SessionID, &s.Expires, ) if err != nil { if err == sql.ErrNoRows { // no result //log.Println(\"NO RESULT\", s) return s, nil } log.Printf(\"ERROR 4 DB SESSIONS %s\\n\", err) return nil, err } return s, nil }","title":"Select"},{"location":"golang-bases-de-datos/#insert","text":"func (loginDB *DB) NewAccount(u *User) error { //fmt.Println(\"USER => \", u) query := fmt.Sprintf(` INSERT INTO %s ( nickID, nick, passHashed, email, verified, logo, secretQuest, secretHashed, createdAt, lastSeen, online ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `, usersTable, ) stmt, err := loginDB.Prepare(query) //fmt.Println(query) if err != nil { log.Printf(\"ERROR 3 DB USERS %s -> %s\\n\", u.Nick, err) return err } defer stmt.Close() _, err = stmt.Exec( u.NickID, u.Nick, u.PassHashed, u.Email, u.Verified, u.Logo, u.SecretQuest, u.SecretHashed, u.CreatedAt, u.LastSeen, u.Online, ) if err != nil { log.Printf(\"ERROR 4 DB USERS %s -> %s\\n\", u.Nick, err) return err } return nil } func (loginDB *DB) SaveSession(s *Session) error { query := fmt.Sprintf(` INSERT INTO %s ( nickID, sessionID, expires ) values (?, ?, ?) ON DUPLICATE KEY UPDATE sessionID=? , expires= ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 1 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } defer stmt.Close() _, err = stmt.Exec( s.NickID, s.SessionID, s.Expires, s.SessionID, s.Expires, ) if err != nil { log.Printf(\"ERROR 2 DB SESSIONS %s -> %s\\n\", s.NickID, err) return err } return nil }","title":"Insert"},{"location":"golang-bases-de-datos/#update","text":"","title":"Update"},{"location":"golang-bases-de-datos/#delete","text":"func (loginDB *DB) DeleteSession(usernameID string) error { query := fmt.Sprintf(` DELETE FROM %s WHERE nickID = ? `, sessionsTable) stmt, err := loginDB.Prepare(query) if err != nil { log.Printf(\"ERROR 5 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } defer stmt.Close() _, err = stmt.Exec( usernameID, ) if err != nil { log.Printf(\"ERROR 6 DB SESSIONS %s -> %s\\n\", usernameID, err) return err } return nil }","title":"Delete"},{"location":"golang-para-web/","text":"GOLANG PARA DESARROLLO WEB NET/HTTP import net/http Static // sirve el directorio entero func main() { dir := http.Dir(\"./files\") http.ListenAndServe(\":8080\", http.FileServer(dir)) http.HandleFunc(\"/\", readme) } // ServeFile sirve un archivo o un directorio como 3er argumento func main() { http.HandleFunc(\"/\", public) http.ListenAndServe(\":8080\", nil) } func public(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, \"./files/hola.html\") // http.ServeFile(w, r, \"./files/\") } // sirve el directorio ./files en la ruta /static/ // ./files puede estar en cualquier sitio del sistema de archivos // no solo en el dir de la aplicacion func main() { dir := http.Dir(\"./files/\") handler := http.StripPrefix(\"/static/\", http.FileServer(dir)) http.Handle(\"/static/\", handler) http.HandleFunc(\"/\", homePage) http.ListenAndServe(\":8080\", nil) } Handler - Handlers son cualquier struct que tiene un metodo ServeHTTP(w http.ResponseWriter, r *http.Request) con dos parametros: una interface HTTPResponseWriter y un puntero a una Request struct. - Handler functions son funciones que se comportan como handlers. Tienen la misma firma que el metodo ServeHTTP y se utiizan para procesar peticiones (Requests) - Handlers y handler functions se pueden encadenar para permitir el procesado en partes de peticiones mediante la separacion de asuntos. - Multiplexers(routers) tambien son handlers. ServeMux es un router de peticiones HTTP. Acepta peticiones HTTP y las redirige al handler adecuado segun la URL de la peticion. DefaultServeMux es una instancia de ServeMux que se usa como router por defecto Handler // multi handler and chain handler package main import ( \"fmt\" \"net/http\" ) type helloHandler struct{} func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"Hello!\") } type worldHandler struct{} func (h *worldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"World!\") } func log(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ fmt.Printf(\"Handler called - %T\\n\", h) h.ServeHTTP(w, r) }) } func protect(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ // some code to make sure the user is authorized h.ServeHTTP(w, r) }) } func main() { hello := helloHandler{} world := worldHandler{} server := http.Server{ Addr: \"127.0.0.1:8080\", } http.Handle(\"/hello\", protect(log(&hello))) http.Handle(\"/world\", &world) server.ListenAndServe() } HandleFunc package main import ( \"fmt\" \"net/http\" \"reflect\" \"runtime\" ) func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"Hello!\") } func world(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"World!\") } func log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name() fmt.Println(\"Handler function called - \" + name) h(w, r) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/hello\", log(hello)) http.HandleFunc(\"/world\", world) server.ListenAndServe() } Request URL https://golang.org/src/net/url/url.go type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string RawPath string // encoded path hint ForceQuery bool // append a query ('?') even if RawQuery is empty RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } algunos metodos // EscapedPath returns the escaped form of u.Path. func (u *URL) EscapedPath() string {} // IsAbs reports whether the URL is absolute. func (u *URL) IsAbs() bool {} // Query parses RawQuery and returns the corresponding values. func (u *URL) Query() Values {} type Values map[string][]string Headers type Header func (h Header) Add(key, value string) func (h Header) Del(key string) func (h Header) Get(key string) string func (h Header) Set(key, value string) func (h Header) Write(w io.Writer) error func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error func headers(w http.ResponseWriter, r *http.Request) { h := r.Header // h := r.Header[\"Accept-Encoding\"] // devuelve un map de strings // h := r.Header.Get(\"Accept-Encoding\") // devuelve string fmt.Fprintln(w, h) } http.HandleFunc(\"/headers\", headers) Body func body(w http.ResponseWriter, r *http.Request) { len := r.ContentLength body := make([]byte, len) r.Body.Read(body) fmt.Fprintln(w, string(body)) } http.HandleFunc(\"/body\", body) ResponseWriter La interface ResponseWriter tiene tres metodos: - Write - coge un []bytes y lo escribe en el body de la respuesta HTTP. Si la cabecera no especifica content-type usa los los primeros 512 bytes de datos para detectar el tipo de contenido - WriteHeader - envia un numero entero que representa el codigo de estado de la respuesta HTTP. Despues de usar este metodo no se puede escribir ni modificar nada en la cabecera. Si no se use este metodo por defecto cuando se llama a Write se envia el codigo 200 OK Es muy util para enviar codigos de errores - Header - devuelve un map de campos de la cabecera que se pueden modificar y que seran enviados en la respuesta al cliente type post struct { User string Langs []string } func writeExample(w http.ResponseWriter, r *http.Request) { str := ` Write Example

            Hello World

            ` w.Write([]byte(str)) } func writeHeaderExample(w http.ResponseWriter, r *http.Request) { w.WriteHeader(501) fmt.Fprintln(w, \"Not implemented yet\") } func headerExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Location\", \"https://jolav.github.io\") w.WriteHeader(302) } func jsonExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"application/json\") post := &post{ User: \"jolav\", Langs: []string{\"Go\", \"HTML\", \"Javascript\"}, } json, _ := json.Marshal(post) w.Write(json) } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/write\", writeExample) http.HandleFunc(\"/writeheader\", writeHeaderExample) http.HandleFunc(\"/redirect\", headerExample) http.HandleFunc(\"/json\", jsonExample) server.ListenAndServe() } Middleware type Middleware []http.Handler // Adds a handler to the middleware func (m *Middleware) Add(handler http.Handler) { *m = append(*m, handler) } func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http. \u27a5Request) { // Process the middleware } Cookies https://golang.org/src/net/http/cookie.go type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } Si no se usa el campo Expires la cookie es de sesion o temporal y se eliminan del navegador cuando este se cierra. De lo contrario la cookie es persistente y dura hasta que expire o se elimine. Usar MaxAge en lugar de Expires que esta deprecada package main import ( \"encoding/base64\" \"fmt\" \"net/http\" \"time\" ) func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: \"first cookie\", Value: \"Valor de la primera galleta\", HttpOnly: true, } c2 := http.Cookie{ Name: \"second cookie\", Value: \"Valor de la segunda galleta\", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) } func getCookie(w http.ResponseWriter, r *http.Request) { c1, err := r.Cookie(\"first cookie\") if err != nil { fmt.Fprintln(w, \"Cannot get the first cookie\") } cs := r.Cookies() fmt.Fprintln(w, c1) fmt.Fprintln(w, cs) } func setMessage(w http.ResponseWriter, r *http.Request) { msg := []byte(\"Hello World!\") c := http.Cookie{ Name: \"flash\", Value: base64.URLEncoding.EncodeToString(msg), } http.SetCookie(w, &c) } func showMessage(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie(\"flash\") if err != nil { if err == http.ErrNoCookie { fmt.Fprintln(w, \"No message found\") } } else { rc := http.Cookie{ Name: \"flash\", MaxAge: -1, Expires: time.Unix(1, 0), } http.SetCookie(w, &rc) val, _ := base64.URLEncoding.DecodeString(c.Value) fmt.Fprintln(w, string(val)) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/setCookie\", setCookie) http.HandleFunc(\"/getCookie\", getCookie) http.HandleFunc(\"/setMessage\", setMessage) http.HandleFunc(\"/showMessage\", showMessage) server.ListenAndServe() } Sessions Forms 1\u00ba - Parseamos la peticion con ParseForm o ParseMultipartForm 2\u00ba - Accedemos al formulario // formulario para process1
            // formulario para process2 y process3
            package main import ( \"fmt\" \"io/ioutil\" \"net/http\" ) func process1(w http.ResponseWriter, r *http.Request) { r.ParseForm() fmt.Fprintln(w, r.Form[\"campo\"][0]) fmt.Prinltln(w, r.Form.Get(\"campo\")) // fmt.Fprintln(w, r.PostForm) } func process2(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile(\"uploaded\") if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func process3(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(1024) fileHeader := r.MultipartForm.File[\"uploaded\"][0] file, err := fileHeader.Open() if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/process1\", process1) http.HandleFunc(\"/process2\", process2) http.HandleFunc(\"/process3\", process3) server.ListenAndServe() } Cliente HTTP type Client func (c *Client) Do(req *Request) (*Response, error) func (c *Client) Get(url string) (resp *Response, err error) func (c *Client) Head(url string) (resp *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) Ejemplo Hacer peticiones get Poner en el main o donde sea para asegurarse que tiene un tiempo maximo de espera y no se queda colgado esperando hasta el infinito (que es el valor por defecto) https://reddit.com/r/golang/comments/45mzie/dont_use_gos_default_http_client/ http.DefaultClient.Timeout = 10 * time.Second func getHttpRequest() { url := \"https://codetabs.com/tools/geoip/geoip.html\" resp, err := http.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&geo) if err != nil { panic(err) } aux.SendDataToClient(w, r, geo) } ServeMux func mainNormal() { // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) http.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) http.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) http.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) http.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) http.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) // any /voting/* will redirect to voting.Voting http.HandleFunc(\"/voting/\", voting.Router) // any /pintelest/* will redirect to voting.Voting http.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", } server.ListenAndServe() } func mainMux() { mux := http.NewServeMux() // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) mux.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) mux.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) mux.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) mux.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) mux.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) mux.HandleFunc(\"/voting/\", voting.Router) //mux.HandleFunc(\"/voting/p/\", nodePintelest) // any /pintelest/* will redirect to nodePintelest mux.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", Handler: mux, } server.ListenAndServe() } // http://codepodu.com/subdomains-with-golang/ type Subdomains map[string]http.Handler func (subdomains Subdomains) ServeHTTP(w http.ResponseWriter, r *http.Request) { domainParts := strings.Split(r.Host, \".\") if mux := subdomains[domainParts[0]]; mux != nil { // Let the appropriate mux serve the request mux.ServeHTTP(w, r) } else { // Handle 404 http.Error(w, \"Not found\", 404) } } type Mux struct { http.Handler } func (mux Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) } func adminHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerOne , Hello, %q\", r.URL.Path[1:]) } func adminHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerOne , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func main() { adminMux := http.NewServeMux() adminMux.HandleFunc(\"/admin/pathone\", adminHandlerOne) adminMux.HandleFunc(\"/admin/pathtwo\", adminHandlerTwo) analyticsMux := http.NewServeMux() analyticsMux.HandleFunc(\"/analytics/pathone\", analyticsHandlerOne) analyticsMux.HandleFunc(\"/analytics/pathtwo\", analyticsHandlerTwo) subdomains := make(Subdomains) subdomains[\"admin\"] = adminMux subdomains[\"analytics\"] = analyticsMux http.ListenAndServe(\":8080\", subdomains) } HTML/TEMPLATE import html/template Para usarlo hay que importar el paquete html/template crear la plantilla t, _ := template.ParseFiles(\"index.html\") asignar valor a variables de plantilla template_value := \"Hola\" servir la pagina t.Execute(w, template_values) index.html Hello World Hello {{ . }} pagina.go package main import ( \"html/template\" \"net/http\" ) func handler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles(\"index.html\") name := \"World\" t.Execute(w, name) } func main() { http.HandleFunc(\"/\", handler) http.ListenAndServe(\":8080\", nil) } Fields {{}} cualquier cosa a ser renderizada debe ir entre dobles parentesis {{.}} abreviatura para el objeto actual {{ .FieldName}} campo FieldName del objecto actual Arrays and slices type Friend struct { Fname string } type Person struct { UserName string Emails []string Friends []*Friend } func main() { f1 := Friend{Fname: \"minux.ma\"} f2 := Friend{Fname: \"xushiwei\"} t := template.New(\"fieldname example\") t, _ = t.Parse(`hello {{.UserName}}! {{range .Emails}} an email {{.}} {{end}} {{with .Friends}} {{range .}} my friend name is {{.Fname}} {{end}} {{end}} `) p := Person{UserName: \"Astaxie\", Emails: []string{\"astaxie@beego.me\", \"astaxie@gmail.com\"}, Friends: []*Friend{&f1, &f2}} t.Execute(os.Stdout, p) } Arrays and slices index const tmpl = ` {{range $index, $link := .}} {{$index}}: {{$link.Name}} {{end}} ` type Link struct { Name string Href string } func main() { // arrays var la [2]Link la[0] = Link{\"Google\", \"https://www.google.com/\"} la[1] = Link{\"Facebook\", \"https://www.facebook.com/\"} t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, la) // slices var ls []Link ls = append(ls, Link{\"Google\", \"https://www.google.com/\"}) ls = append(ls, Link{\"Facebook\", \"https://www.facebook.com/\"}) t.Execute(os.Stdout, ls) } Maps const tmpl = ` {{range $name, $href := .}} {{$name}} {{end}} ` func main() { // map var m = map[string]string{ \"Google\": \"https://www.google.com/\", \"Facebook\": \"https://www.facebook.com/\", } t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, m) } Conditions {{if}} {{else}} : Solo para valores booleanos, no hace comparaciones {{if ``}} Will not print. {{end}} {{if `anything`}} Will print. {{end}} {{if `anything`}} Print IF part. {{else}} Print ELSE part. {{end}} Pipelines {{ . | html}} Por ejemplo usamos esto para coger el objto actual '.' y aplicarle escape a HTML al objeto Variables Pasar variables a templates // usando anonymous structs var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") templates.ExecuteTemplate(w, \"page.html\", struct { PageTitle string Message string User string }{\"Template example: struct\", \"Hello\", \"World\"}) } // usando Maps var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") m := make(map[string]interface{}) m[\"PageTitle\"] = \"Template example: map\" m[\"Message\"] = \"Hello\" m[\"User\"] = \"World\" templates.ExecuteTemplate(w, \"page.html\", m) } // mapa m := map[string]interface{}{ \"imgs\": imgs, // {{range .imgs.Image}}{{.}}{{end}} \"user\": p, //{{.user.Name}} } // struct , Images []Image type Data struct { I Images P Profile } var d Data d.I = imgs // {{range .I.Image}}{{.}}{{end}} d.P = p // {{.P.Name}}*/ t.Execute(w, &m) Funciones Predefinidas Por ejemplo print equivale a fmt.Sprintf func main() { texto := \"{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}} {{end}}!\\n\" t := template.New(\"test\") t = template.Must(t.Parse(texto)) t.Execute(os.Stdout, nil) // Resultado -> hello Mary! De Dise\u00f1o const tmpl = ` hello {{gettext .}} hello {{. | gettext}} ` var funcMap = template.FuncMap{ \"gettext\": gettext, } func gettext(s string) string { if s == \"world\" { return \"otraCosa\" } return s } func main() { t, _ := template.New(\"foo\").Funcs(funcMap).Parse(tmpl) s := \"world\" t.Execute(os.Stdout, s) } Must Es una funcion del paquete template para validar plantillas Nested templates Se puede declarar una plantilla: {{ define \"sub-plantilla\"}} contenido que sea {{ end}} Luego esa plantilla se inserta {{ template \"sub-plantilla\" }} base.html {{define \"base\"}} {{template \"title\" .}} {{template \"content\" .}} {{end}} index.html {{template \"base\" .}} {{define \"title\"}}my title{{end}} {{define \"content\"}}
            hello {{.}}
            {{end}} nestedTemplates.go func main() { // cannot put base.html before index.html will give empty output // t, _ := template.ParseFiles(\"base.html\", \"index.html\") t, _ := template.ParseFiles(\"index.html\", \"base.html\") name := \"world\" t.Execute(os.Stdout, name) } Pasar vars a js Pasar variables golang a cliente js // voting.go func guest(w http.ResponseWriter, r *http.Request) { var data aPoll data = aPoll{Question: \"Texto de la cuestion\"} tmpl[\"guest.html\"].ExecuteTemplate(w, \"guest.html\", data) } var voting = (function () { function init () { console.log(\"Data from golang\", golang); } return { init: init }; }()); NET/URL A\u00f1adir parametros a URL // sobre una URL existente values := r.URL.Query() values.Add(\"nombreNuevoParamatro\", valor) values.Get(\"nombreDelValor\", valor) r.URL.RawQuery = values.Encode() fmt.Println(r.URL.String()) fmt.Println(values[\"nombreNuevoParametro\"]) // construyendo una URL urlData, err := url.Parse(\"https://apisquesea.com/custom/v1?q=\") params := url.Values{} params.Add(\"q\", r.URL.Query().Get(\"q\")) params.Add(\"cx\", c.APIImage.CseID) params.Add(\"key\", c.APIImage.Key) params.Add(\"num\", r.URL.Query().Get(\"num\")) params.Add(\"offset\", r.URL.Query().Get(\"offset\")) urlData.RawQuery = params.Encode() URL parsing UTILIDADES fresh https://github.com/pilu/fresh - Especie de nodemon para golang. archivo de configuracion que se ejecuta con fresh -c ruta/al/archivo root: . tmp_path: ./tmp build_name: runner-build build_log: runner-build-errors.log valid_ext: .go, .tpl, .tmpl, .html, .css, .js ignored: assets, tmp, pintelest build_delay: 600 colors: 1 log_color_main: cyan log_color_build: yellow log_color_runner: green log_color_watcher: magenta log_color_app:","title":"Golang para web"},{"location":"golang-para-web/#golang-para-desarrollo-web","text":"","title":"GOLANG PARA DESARROLLO WEB"},{"location":"golang-para-web/#nethttp","text":"import net/http","title":"NET/HTTP"},{"location":"golang-para-web/#static","text":"// sirve el directorio entero func main() { dir := http.Dir(\"./files\") http.ListenAndServe(\":8080\", http.FileServer(dir)) http.HandleFunc(\"/\", readme) } // ServeFile sirve un archivo o un directorio como 3er argumento func main() { http.HandleFunc(\"/\", public) http.ListenAndServe(\":8080\", nil) } func public(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, \"./files/hola.html\") // http.ServeFile(w, r, \"./files/\") } // sirve el directorio ./files en la ruta /static/ // ./files puede estar en cualquier sitio del sistema de archivos // no solo en el dir de la aplicacion func main() { dir := http.Dir(\"./files/\") handler := http.StripPrefix(\"/static/\", http.FileServer(dir)) http.Handle(\"/static/\", handler) http.HandleFunc(\"/\", homePage) http.ListenAndServe(\":8080\", nil) }","title":"Static"},{"location":"golang-para-web/#handler","text":"- Handlers son cualquier struct que tiene un metodo ServeHTTP(w http.ResponseWriter, r *http.Request) con dos parametros: una interface HTTPResponseWriter y un puntero a una Request struct. - Handler functions son funciones que se comportan como handlers. Tienen la misma firma que el metodo ServeHTTP y se utiizan para procesar peticiones (Requests) - Handlers y handler functions se pueden encadenar para permitir el procesado en partes de peticiones mediante la separacion de asuntos. - Multiplexers(routers) tambien son handlers. ServeMux es un router de peticiones HTTP. Acepta peticiones HTTP y las redirige al handler adecuado segun la URL de la peticion. DefaultServeMux es una instancia de ServeMux que se usa como router por defecto Handler // multi handler and chain handler package main import ( \"fmt\" \"net/http\" ) type helloHandler struct{} func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"Hello!\") } type worldHandler struct{} func (h *worldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, \"World!\") } func log(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ fmt.Printf(\"Handler called - %T\\n\", h) h.ServeHTTP(w, r) }) } func protect(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ // some code to make sure the user is authorized h.ServeHTTP(w, r) }) } func main() { hello := helloHandler{} world := worldHandler{} server := http.Server{ Addr: \"127.0.0.1:8080\", } http.Handle(\"/hello\", protect(log(&hello))) http.Handle(\"/world\", &world) server.ListenAndServe() } HandleFunc package main import ( \"fmt\" \"net/http\" \"reflect\" \"runtime\" ) func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"Hello!\") } func world(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"World!\") } func log(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name() fmt.Println(\"Handler function called - \" + name) h(w, r) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/hello\", log(hello)) http.HandleFunc(\"/world\", world) server.ListenAndServe() }","title":"Handler"},{"location":"golang-para-web/#request","text":"URL https://golang.org/src/net/url/url.go type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string RawPath string // encoded path hint ForceQuery bool // append a query ('?') even if RawQuery is empty RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } algunos metodos // EscapedPath returns the escaped form of u.Path. func (u *URL) EscapedPath() string {} // IsAbs reports whether the URL is absolute. func (u *URL) IsAbs() bool {} // Query parses RawQuery and returns the corresponding values. func (u *URL) Query() Values {} type Values map[string][]string Headers type Header func (h Header) Add(key, value string) func (h Header) Del(key string) func (h Header) Get(key string) string func (h Header) Set(key, value string) func (h Header) Write(w io.Writer) error func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error func headers(w http.ResponseWriter, r *http.Request) { h := r.Header // h := r.Header[\"Accept-Encoding\"] // devuelve un map de strings // h := r.Header.Get(\"Accept-Encoding\") // devuelve string fmt.Fprintln(w, h) } http.HandleFunc(\"/headers\", headers) Body func body(w http.ResponseWriter, r *http.Request) { len := r.ContentLength body := make([]byte, len) r.Body.Read(body) fmt.Fprintln(w, string(body)) } http.HandleFunc(\"/body\", body)","title":"Request"},{"location":"golang-para-web/#responsewriter","text":"La interface ResponseWriter tiene tres metodos: - Write - coge un []bytes y lo escribe en el body de la respuesta HTTP. Si la cabecera no especifica content-type usa los los primeros 512 bytes de datos para detectar el tipo de contenido - WriteHeader - envia un numero entero que representa el codigo de estado de la respuesta HTTP. Despues de usar este metodo no se puede escribir ni modificar nada en la cabecera. Si no se use este metodo por defecto cuando se llama a Write se envia el codigo 200 OK Es muy util para enviar codigos de errores - Header - devuelve un map de campos de la cabecera que se pueden modificar y que seran enviados en la respuesta al cliente type post struct { User string Langs []string } func writeExample(w http.ResponseWriter, r *http.Request) { str := ` Write Example

            Hello World

            ` w.Write([]byte(str)) } func writeHeaderExample(w http.ResponseWriter, r *http.Request) { w.WriteHeader(501) fmt.Fprintln(w, \"Not implemented yet\") } func headerExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Location\", \"https://jolav.github.io\") w.WriteHeader(302) } func jsonExample(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"application/json\") post := &post{ User: \"jolav\", Langs: []string{\"Go\", \"HTML\", \"Javascript\"}, } json, _ := json.Marshal(post) w.Write(json) } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/write\", writeExample) http.HandleFunc(\"/writeheader\", writeHeaderExample) http.HandleFunc(\"/redirect\", headerExample) http.HandleFunc(\"/json\", jsonExample) server.ListenAndServe() }","title":"ResponseWriter"},{"location":"golang-para-web/#middleware","text":"type Middleware []http.Handler // Adds a handler to the middleware func (m *Middleware) Add(handler http.Handler) { *m = append(*m, handler) } func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http. \u27a5Request) { // Process the middleware }","title":"Middleware"},{"location":"golang-para-web/#cookies","text":"https://golang.org/src/net/http/cookie.go type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } Si no se usa el campo Expires la cookie es de sesion o temporal y se eliminan del navegador cuando este se cierra. De lo contrario la cookie es persistente y dura hasta que expire o se elimine. Usar MaxAge en lugar de Expires que esta deprecada package main import ( \"encoding/base64\" \"fmt\" \"net/http\" \"time\" ) func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: \"first cookie\", Value: \"Valor de la primera galleta\", HttpOnly: true, } c2 := http.Cookie{ Name: \"second cookie\", Value: \"Valor de la segunda galleta\", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) } func getCookie(w http.ResponseWriter, r *http.Request) { c1, err := r.Cookie(\"first cookie\") if err != nil { fmt.Fprintln(w, \"Cannot get the first cookie\") } cs := r.Cookies() fmt.Fprintln(w, c1) fmt.Fprintln(w, cs) } func setMessage(w http.ResponseWriter, r *http.Request) { msg := []byte(\"Hello World!\") c := http.Cookie{ Name: \"flash\", Value: base64.URLEncoding.EncodeToString(msg), } http.SetCookie(w, &c) } func showMessage(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie(\"flash\") if err != nil { if err == http.ErrNoCookie { fmt.Fprintln(w, \"No message found\") } } else { rc := http.Cookie{ Name: \"flash\", MaxAge: -1, Expires: time.Unix(1, 0), } http.SetCookie(w, &rc) val, _ := base64.URLEncoding.DecodeString(c.Value) fmt.Fprintln(w, string(val)) } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/setCookie\", setCookie) http.HandleFunc(\"/getCookie\", getCookie) http.HandleFunc(\"/setMessage\", setMessage) http.HandleFunc(\"/showMessage\", showMessage) server.ListenAndServe() }","title":"Cookies"},{"location":"golang-para-web/#sessions","text":"","title":"Sessions"},{"location":"golang-para-web/#forms","text":"1\u00ba - Parseamos la peticion con ParseForm o ParseMultipartForm 2\u00ba - Accedemos al formulario // formulario para process1
            // formulario para process2 y process3
            package main import ( \"fmt\" \"io/ioutil\" \"net/http\" ) func process1(w http.ResponseWriter, r *http.Request) { r.ParseForm() fmt.Fprintln(w, r.Form[\"campo\"][0]) fmt.Prinltln(w, r.Form.Get(\"campo\")) // fmt.Fprintln(w, r.PostForm) } func process2(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile(\"uploaded\") if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func process3(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(1024) fileHeader := r.MultipartForm.File[\"uploaded\"][0] file, err := fileHeader.Open() if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } } func main() { server := http.Server{ Addr: \"127.0.0.1:8080\", } http.HandleFunc(\"/process1\", process1) http.HandleFunc(\"/process2\", process2) http.HandleFunc(\"/process3\", process3) server.ListenAndServe() }","title":"Forms"},{"location":"golang-para-web/#cliente-http","text":"type Client func (c *Client) Do(req *Request) (*Response, error) func (c *Client) Get(url string) (resp *Response, err error) func (c *Client) Head(url string) (resp *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) Ejemplo Hacer peticiones get Poner en el main o donde sea para asegurarse que tiene un tiempo maximo de espera y no se queda colgado esperando hasta el infinito (que es el valor por defecto) https://reddit.com/r/golang/comments/45mzie/dont_use_gos_default_http_client/ http.DefaultClient.Timeout = 10 * time.Second func getHttpRequest() { url := \"https://codetabs.com/tools/geoip/geoip.html\" resp, err := http.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&geo) if err != nil { panic(err) } aux.SendDataToClient(w, r, geo) }","title":"Cliente HTTP"},{"location":"golang-para-web/#servemux","text":"func mainNormal() { // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) http.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) http.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) http.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) http.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) http.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) // any /voting/* will redirect to voting.Voting http.HandleFunc(\"/voting/\", voting.Router) // any /pintelest/* will redirect to voting.Voting http.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", } server.ListenAndServe() } func mainMux() { mux := http.NewServeMux() // assets for all apps assets := http.FileServer(http.Dir(\"_public\")) mux.Handle(\"/\", http.StripPrefix(\"/\", assets)) // assets for individual apps votingRes := http.FileServer(http.Dir(\"voting/assets\")) mux.Handle(\"/voting/assets/\", http.StripPrefix(\"/voting/assets/\", votingRes)) book := http.FileServer(http.Dir(\"./book/\")) nightlife := http.FileServer(http.Dir(\"./nightlife/\")) stock := http.FileServer(http.Dir(\"./stock/\")) mux.Handle(\"/book/\", http.StripPrefix(\"/book\", book)) mux.Handle(\"/nightlife/\", http.StripPrefix(\"/nightlife\", nightlife)) mux.Handle(\"/stock/\", http.StripPrefix(\"/stock\", stock)) mux.HandleFunc(\"/voting/\", voting.Router) //mux.HandleFunc(\"/voting/p/\", nodePintelest) // any /pintelest/* will redirect to nodePintelest mux.HandleFunc(\"/pintelest/\", nodePintelest) server := http.Server{ Addr: \"localhost:3006\", Handler: mux, } server.ListenAndServe() } // http://codepodu.com/subdomains-with-golang/ type Subdomains map[string]http.Handler func (subdomains Subdomains) ServeHTTP(w http.ResponseWriter, r *http.Request) { domainParts := strings.Split(r.Host, \".\") if mux := subdomains[domainParts[0]]; mux != nil { // Let the appropriate mux serve the request mux.ServeHTTP(w, r) } else { // Handle 404 http.Error(w, \"Not found\", 404) } } type Mux struct { http.Handler } func (mux Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) } func adminHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerOne , Hello, %q\", r.URL.Path[1:]) } func adminHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's adminHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerOne(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerOne , Hello, %q\", r.URL.Path[1:]) } func analyticsHandlerTwo(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, \"It's analyticsHandlerTwo , Hello, %q\", r.URL.Path[1:]) } func main() { adminMux := http.NewServeMux() adminMux.HandleFunc(\"/admin/pathone\", adminHandlerOne) adminMux.HandleFunc(\"/admin/pathtwo\", adminHandlerTwo) analyticsMux := http.NewServeMux() analyticsMux.HandleFunc(\"/analytics/pathone\", analyticsHandlerOne) analyticsMux.HandleFunc(\"/analytics/pathtwo\", analyticsHandlerTwo) subdomains := make(Subdomains) subdomains[\"admin\"] = adminMux subdomains[\"analytics\"] = analyticsMux http.ListenAndServe(\":8080\", subdomains) }","title":"ServeMux"},{"location":"golang-para-web/#htmltemplate","text":"import html/template Para usarlo hay que importar el paquete html/template crear la plantilla t, _ := template.ParseFiles(\"index.html\") asignar valor a variables de plantilla template_value := \"Hola\" servir la pagina t.Execute(w, template_values) index.html Hello World Hello {{ . }} pagina.go package main import ( \"html/template\" \"net/http\" ) func handler(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles(\"index.html\") name := \"World\" t.Execute(w, name) } func main() { http.HandleFunc(\"/\", handler) http.ListenAndServe(\":8080\", nil) }","title":"HTML/TEMPLATE"},{"location":"golang-para-web/#fields","text":"{{}} cualquier cosa a ser renderizada debe ir entre dobles parentesis {{.}} abreviatura para el objeto actual {{ .FieldName}} campo FieldName del objecto actual Arrays and slices type Friend struct { Fname string } type Person struct { UserName string Emails []string Friends []*Friend } func main() { f1 := Friend{Fname: \"minux.ma\"} f2 := Friend{Fname: \"xushiwei\"} t := template.New(\"fieldname example\") t, _ = t.Parse(`hello {{.UserName}}! {{range .Emails}} an email {{.}} {{end}} {{with .Friends}} {{range .}} my friend name is {{.Fname}} {{end}} {{end}} `) p := Person{UserName: \"Astaxie\", Emails: []string{\"astaxie@beego.me\", \"astaxie@gmail.com\"}, Friends: []*Friend{&f1, &f2}} t.Execute(os.Stdout, p) } Arrays and slices index const tmpl = ` {{range $index, $link := .}} {{$index}}: {{$link.Name}} {{end}} ` type Link struct { Name string Href string } func main() { // arrays var la [2]Link la[0] = Link{\"Google\", \"https://www.google.com/\"} la[1] = Link{\"Facebook\", \"https://www.facebook.com/\"} t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, la) // slices var ls []Link ls = append(ls, Link{\"Google\", \"https://www.google.com/\"}) ls = append(ls, Link{\"Facebook\", \"https://www.facebook.com/\"}) t.Execute(os.Stdout, ls) } Maps const tmpl = ` {{range $name, $href := .}} {{$name}} {{end}} ` func main() { // map var m = map[string]string{ \"Google\": \"https://www.google.com/\", \"Facebook\": \"https://www.facebook.com/\", } t, _ := template.New(\"foo\").Parse(tmpl) t.Execute(os.Stdout, m) }","title":"Fields"},{"location":"golang-para-web/#conditions","text":"{{if}} {{else}} : Solo para valores booleanos, no hace comparaciones {{if ``}} Will not print. {{end}} {{if `anything`}} Will print. {{end}} {{if `anything`}} Print IF part. {{else}} Print ELSE part. {{end}}","title":"Conditions"},{"location":"golang-para-web/#pipelines","text":"{{ . | html}} Por ejemplo usamos esto para coger el objto actual '.' y aplicarle escape a HTML al objeto","title":"Pipelines"},{"location":"golang-para-web/#variables","text":"Pasar variables a templates // usando anonymous structs var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") templates.ExecuteTemplate(w, \"page.html\", struct { PageTitle string Message string User string }{\"Template example: struct\", \"Hello\", \"World\"}) } // usando Maps var templates = template.Must(template.ParseGlob(\"templates/*\")) func handle(w http.ResponseWriter, r *http.Request) { w.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\") m := make(map[string]interface{}) m[\"PageTitle\"] = \"Template example: map\" m[\"Message\"] = \"Hello\" m[\"User\"] = \"World\" templates.ExecuteTemplate(w, \"page.html\", m) } // mapa m := map[string]interface{}{ \"imgs\": imgs, // {{range .imgs.Image}}{{.}}{{end}} \"user\": p, //{{.user.Name}} } // struct , Images []Image type Data struct { I Images P Profile } var d Data d.I = imgs // {{range .I.Image}}{{.}}{{end}} d.P = p // {{.P.Name}}*/ t.Execute(w, &m)","title":"Variables"},{"location":"golang-para-web/#funciones","text":"","title":"Funciones"},{"location":"golang-para-web/#predefinidas","text":"Por ejemplo print equivale a fmt.Sprintf func main() { texto := \"{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}} {{end}}!\\n\" t := template.New(\"test\") t = template.Must(t.Parse(texto)) t.Execute(os.Stdout, nil) // Resultado -> hello Mary!","title":"Predefinidas"},{"location":"golang-para-web/#de-diseno","text":"const tmpl = ` hello {{gettext .}} hello {{. | gettext}} ` var funcMap = template.FuncMap{ \"gettext\": gettext, } func gettext(s string) string { if s == \"world\" { return \"otraCosa\" } return s } func main() { t, _ := template.New(\"foo\").Funcs(funcMap).Parse(tmpl) s := \"world\" t.Execute(os.Stdout, s) }","title":"De Dise\u00f1o"},{"location":"golang-para-web/#must","text":"Es una funcion del paquete template para validar plantillas","title":"Must"},{"location":"golang-para-web/#nested-templates","text":"Se puede declarar una plantilla: {{ define \"sub-plantilla\"}} contenido que sea {{ end}} Luego esa plantilla se inserta {{ template \"sub-plantilla\" }} base.html {{define \"base\"}} {{template \"title\" .}} {{template \"content\" .}} {{end}} index.html {{template \"base\" .}} {{define \"title\"}}my title{{end}} {{define \"content\"}}
            hello {{.}}
            {{end}} nestedTemplates.go func main() { // cannot put base.html before index.html will give empty output // t, _ := template.ParseFiles(\"base.html\", \"index.html\") t, _ := template.ParseFiles(\"index.html\", \"base.html\") name := \"world\" t.Execute(os.Stdout, name) }","title":"Nested templates"},{"location":"golang-para-web/#pasar-vars-a-js","text":"Pasar variables golang a cliente js // voting.go func guest(w http.ResponseWriter, r *http.Request) { var data aPoll data = aPoll{Question: \"Texto de la cuestion\"} tmpl[\"guest.html\"].ExecuteTemplate(w, \"guest.html\", data) } var voting = (function () { function init () { console.log(\"Data from golang\", golang); } return { init: init }; }());","title":"Pasar vars a js"},{"location":"golang-para-web/#neturl","text":"","title":"NET/URL"},{"location":"golang-para-web/#anadir-parametros-a-url","text":"// sobre una URL existente values := r.URL.Query() values.Add(\"nombreNuevoParamatro\", valor) values.Get(\"nombreDelValor\", valor) r.URL.RawQuery = values.Encode() fmt.Println(r.URL.String()) fmt.Println(values[\"nombreNuevoParametro\"]) // construyendo una URL urlData, err := url.Parse(\"https://apisquesea.com/custom/v1?q=\") params := url.Values{} params.Add(\"q\", r.URL.Query().Get(\"q\")) params.Add(\"cx\", c.APIImage.CseID) params.Add(\"key\", c.APIImage.Key) params.Add(\"num\", r.URL.Query().Get(\"num\")) params.Add(\"offset\", r.URL.Query().Get(\"offset\")) urlData.RawQuery = params.Encode() URL parsing","title":"A\u00f1adir parametros a URL"},{"location":"golang-para-web/#utilidades","text":"","title":"UTILIDADES"},{"location":"golang-para-web/#fresh","text":"https://github.com/pilu/fresh - Especie de nodemon para golang. archivo de configuracion que se ejecuta con fresh -c ruta/al/archivo root: . tmp_path: ./tmp build_name: runner-build build_log: runner-build-errors.log valid_ext: .go, .tpl, .tmpl, .html, .css, .js ignored: assets, tmp, pintelest build_delay: 600 colors: 1 log_color_main: cyan log_color_build: yellow log_color_runner: green log_color_watcher: magenta log_color_app:","title":"fresh"},{"location":"golang-snippets/","text":"GOLANG SNIPPETS SEND/RECEIVE DATA SendJSONToClient import ( \"encoding/json\" \"log\" \"net/http\" ) // SendJSONToClient ... func SendJSONToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) } SendXMLToClient import ( \"encoding/xml\" \"log\" \"net/http\" ) // SendXMLToClient ... func SendXMLToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/xml\") var dataXML = []byte(``) dataXML, err := xml.Marshal(&d) if err != nil { log.Printf(\"ERROR Parsing into XML %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataXML) } SendErrorToClient import ( \"encoding/json\" \"log\" \"net/http\" ) // SendErrorToClient ... func SendErrorToClient(w http.ResponseWriter, d interface{}) { w.WriteHeader(http.StatusBadRequest) w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) } DoGetRequest import ( \"encoding/json\" \"io/ioutil\" \"log\" \"net/http\" \"time\" ) // DoGetRequest ... func DoGetRequest(w http.ResponseWriter, url string, d interface{}) { var netClient = &http.Client{ Timeout: time.Second * 10, } resp, err := netClient.Get(url) if err != nil { log.Fatal(err) } if resp.StatusCode != 200 { log.Fatal(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // body is a string, for use we must Unmarshal over a struct err = json.Unmarshal(body, &d) if err != nil { log.Fatalln(err) } } DoGetConcurrentRequest import ( \"encoding/json\" \"fmt\" \"io/ioutil\" \"log\" \"net/http\" ) func fillDefaultStocks(links []string) { ch := make(chan []byte) for _, link := range links { go doGetConcurrentRequest(link, ch) } for range links { json.Unmarshal(<-ch, &stocks) } } func doGetConcurrentRequest(url string, ch chan<- []byte) { resp, err := http.Get(url) if err != nil { msg := fmt.Sprintf(\"ERROR 1 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } if resp.StatusCode != 200 { msg := fmt.Sprintf(\"ERROR 2 Status Code %d\", resp.StatusCode) log.Printf(msg) ch <- []byte(msg) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { msg := fmt.Sprintf(\"ERROR 3 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } ch <- body } DoPostRequest func sendRequest(data []byte, a app) { server, _ := os.Hostname() server = strings.ToLower(server) contentType := \"application/x-www-form-urlencoded\" //; param=value\" host := \"https://\" + a.Conf.Host + a.Conf.PathToAPI var client = &http.Client{ Timeout: time.Second * 3, } params := url.Values{ //\"server\": {server}, \"test\": {a.Conf.Valid}, \"data\": {string(data)}, } params.Add(\"server\", server) query := bytes.NewBufferString(params.Encode()) resp, err := http.NewRequest(\"POST\", host, query) resp.Header.Add(\"Content-Type\", contentType) resp.Header.Add(\"Accept-Charset\", \"utf-8\") if err != nil { log.Fatal(\"Error preparing POST request => \", err) } r, err := client.Do(resp) if err != nil { log.Fatal(\"Error sending POST request => \", err) } if r.StatusCode != 200 { log.Fatal(\"Error received from server => \", r.Status, \" \", err) } } GetInterfacesTypes import \"fmt\" // GetInterfacesTypes ... func GetInterfacesTypes(f interface{}) { switch vf := f.(type) { case map[string]interface{}: //fmt.Println(\"is a map:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } case []interface{}: //fmt.Println(\"is an array:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) if k == 4 { fmt.Println(`ALELUYA==>`, vv) } default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } } } IsJSON import \"encoding/json\" // IsJSON ... func IsJSON(str string) bool { var js json.RawMessage return json.Unmarshal([]byte(str), &js) == nil } ERRORCHECK Check import \"log\" // Check ... func Check(err error) { if err != nil { log.Fatal(err) } } FILES ReadFile import ( \"log\" \"os\" ) // ReadFile ... func ReadFile(filePath string) string { file, err := os.Open(filePath) defer file.Close() stat, err := file.Stat() if err != nil { log.Fatal(err) } bs := make([]byte, stat.Size()) _, err = file.Read(bs) if err != nil { log.Fatal(err) } data := string(bs) return data } ReadFileLineByLine import ( \"bufio\" \"fmt\" \"log\" \"os\" ) // ReadFileLineByLine ... func ReadFileLineByLine(filePath string) { file, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { log.Fatal(err) } } WriteFile import ( \"log\" \"os\" ) // WriteFile ... func WriteFile(filePath string, content string) { file, err := os.Create(filePath) if err != nil { log.Fatal(err) } defer file.Close() file.WriteString(content) } LoadJSONfromFileDecoder import ( \"encoding/json\" \"log\" \"os\" ) // LoadJSONfromFileDecoder ... func LoadJSONfromFileDecoder(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() decoder := json.NewDecoder(file) err = decoder.Decode(&data) if err != nil { log.Fatalln(\"Cannot get configuration from file\", err) } } LoadJSONfromFileMarshall import ( \"encoding/json\" \"io/ioutil\" \"log\" \"os\" ) // LoadJSONfromFileMarshall ... func LoadJSONfromFileMarshall(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() body, err := ioutil.ReadAll(file) // get file content if err != nil { log.Fatalln(err) } err = json.Unmarshal(body, &data) if err != nil { log.Fatalln(err) } } WriteJSONtoFile import ( \"encoding/json\" \"os\" ) // WriteJSONtoFile ... func WriteJSONtoFile(filePath string, d interface{}) { f, err := os.Create(filePath) if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&d) } DownloadFile import ( \"io\" \"net/http\" \"os\" ) // DownloadFile ... func DownloadFile(filePath string, url string) (err error) { // Create the file out, err := os.Create(filePath) if err != nil { return err } defer out.Close() // Get the data resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil } SendFileFromServerToClient import ( \"fmt\" \"io\" \"net\" \"net/http\" \"time\" ) func Index(w http.ResponseWriter, r *http.Request) { url := \"http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png\" timeout := time.Duration(5) * time.Second transport := &http.Transport{ ResponseHeaderTimeout: timeout, Dial: func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) }, DisableKeepAlives: true, } client := &http.Client{ Transport: transport, } resp, err := client.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() //copy the relevant headers. If you want to preserve the downloaded // file name, extract it with go's url parser. w.Header().Set(\"Content-Disposition\", \"attachment; filename=Wiki.png\") w.Header().Set(\"Content-Type\", r.Header.Get(\"Content-Type\")) w.Header().Set(\"Content-Length\", r.Header.Get(\"Content-Length\")) //stream the body to the client without fully loading it into memory io.Copy(w, resp.Body) } func main() { http.HandleFunc(\"/\", Index) err := http.ListenAndServe(\":8000\", nil) if err != nil { fmt.Println(err) } } ParseCSVFile // file.csv \"AAPL\",\"Apple Inc\",\"4.10%\" \"AMZN\",\"Amazon.com Inc\",\"3.49%\" \"MSFT\",\"Microsoft Corp\",\"3.23%\" \"GOOGL\",\"Alphabet Inc\",\"3.09%\" import ( \"bufio\" \"encoding/csv\" \"encoding/json\" \"fmt\" \"io\" \"os\" ) type stock struct { Symbol string `json:\"symbol\"` } func main() { csvFile, _ := os.Open(\"sp.csv\") reader := csv.NewReader(bufio.NewReader(csvFile)) var stocks []stock for { line, error := reader.Read() if error == io.EOF { break } aux := stock{ Symbol: line[0], } stocks = append(stocks, aux) } //stocksJSON, _ := json.Marshal(stocks) //fmt.Println(string(stocksJSON)) f, err := os.Create(\"spList.json\") if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&stocks) fmt.Println(`END`) } // result [ { \"symbol\": \"AAPL\" }, { \"symbol\": \"AMZN\" }, { \"symbol\": \"MSFT\" }, { \"symbol\": \"GOOGL\" } ] HTTP SERVER Lectura Request Handling in Go type Handler interface { ServeHttp( ResponseWriter, *Request ) } Wrapper Es muy sencillo pero luego complica para testearlo mux.HandleFunc(\"/path\", func(w http.ResponseWriter, r *http.Request) { nombreFuncion(w, r, loQueQueramosPasar) }) Handle + HandleFunc package main import ( \"fmt\" \"net/http\" \"time\" ) func timeHandler1(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(time.RFC1123) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } func timeHandler2(format string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) }) } /* lo mismo pero con conversion implicita al tipo HandlerFunc func timeHandler2(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } } */ func hiHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { mux := http.NewServeMux() // Creamos un closure con las variables que queremos usar th2 := timeHandler2(time.RFC3339) mux.HandleFunc(\"/time/1\", timeHandler1) mux.Handle(\"/time/2\", th2) mux.HandleFunc(\"/hello\", hiHandler) //http.HandleFunc(\"/time/1\", timeHandler1) //http.Handle(\"/time/2\", th2) //http.HandleFunc(\"/hello\", hiHandler) http.ListenAndServe(\":3000\", mux /*nil*/) } Handler type specificHandler struct { Thing string } func(h *specificHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) { w.Write(h.Thing) } func main() { http.Handle(\"/something\", &specificHandler{Thing: \"Hello world!\"}) http.ListenAndServe(\":8080\", nil) } package main import ( \"fmt\" \"net/http\" \"time\" ) type timeHandler struct { format string } func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(th.format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } type hiHandler struct{} func (ti *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { /mux := http.NewServeMux() th1 := &timeHandler{format: time.RFC1123} th2 := &timeHandler{format: time.RFC3339} hi := &hiHandler{} mux.Handle(\"/time/1\", th1) mux.Handle(\"/time/2\", th2) mux.Handle(\"/hello\", hi) //http.Handle(\"/time/1\", th1) //http.Handle(\"/time/2\", th2) //http.Handle(\"/hello\", hi) http.ListenAndServe(\":3000\", /*nil*/ mux) } Ejemplo Completo package main import ( \"errors\" \"fmt\" \"log\" \"net/http\" \"os\" \"time\" _ \"github.com/go-sql-driver/mysql\" ) type app struct { Config struct { Mode string `json:\"mode\"` Port int `json:\"port\"` Valid string `json:\"valid\"` ErrorsLogFile string `json:\"errorsLogFile\"` HitsLogFile string `json:\"hitsLogFile\"` } `json:\"config\"` Mysql struct { User string `json:\"user\"` Password string `json:\"password\"` DB string `json:\"db\"` Host string `json:\"host\"` Port int `json:\"port\"` TableBW string `json:\"tableBw\"` TableHits string `json:\"tableHits\"` } } type requestError struct { Error error `json:\"-\"` Message string `json:\"message\"` StatusCode int `json:\"-\"` } func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != a.Config.Valid { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } updateBw(w, r, a) } func main() { var a app loadConfigJSON(&a) checkMode(&a) // Custom Log File if a.Config.Mode == \"production\" { var f = a.Config.ErrorsLogFile mylog, err := os.OpenFile(f, os.O_WRONLY|os.O_CREATE|os.O_APPEND , 0644) if err != nil { log.Printf(\"ERROR opening log file %s\\n\", err) } defer mylog.Close() // defer must be in main log.SetOutput(mylog) } mux := http.NewServeMux() mux.Handle(\"/savebw/\", &a) mux.Handle(\"/saveHits/\", checkValid( func(w http.ResponseWriter, r *http.Request) { updateHits(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/get/\", checkValid( func(w http.ResponseWriter, r *http.Request) { getStats(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/\", badRequest) server := http.Server{ Addr: fmt.Sprintf(\"localhost:%d\", a.Config.Port), Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, MaxHeaderBytes: 1 << 20, } log.Printf(\"Server up listening %s in mode %s\", server.Addr , a.Config.Mode) server.ListenAndServe() } func checkValid(next http.HandlerFunc, test string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != test { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } next.ServeHTTP(w, r) } } func badRequest(w http.ResponseWriter, r *http.Request) { re := &requestError{ Error: errors.New(\"Unexistent Endpoint\"), Message: \"Bad Request\", StatusCode: 400, } sendErrorToClient(w, re) } MIDDLEWARES RateLimit import \"net/http\" // ExceedLimit ... func ExceedLimit(ip string) bool { // ToDO return false } // RateLimit ... func RateLimit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if ExceedLimit(GetIP(r)) { http.Error(w, \"Too many requests\", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } NETWORK GetIP import ( \"net\" \"net/http\" ) // GetIP returns string with IP func GetIP(r *http.Request) string { ip := r.Header.Get(\"X-Forwarded-For\") if len(ip) > 0 { return ip } ip, _, _ = net.SplitHostPort(r.RemoteAddr) return ip } IsValidURL import \"net/url\" // IsValidURL ... func IsValidURL(rawurl string) bool { _, err := url.ParseRequestURI(rawurl) if err != nil { return false } return true } ExistsURL import \"net/http\" func ExistsURL(myurl string) bool { resp, err := http.Head(myurl) if err != nil { return false } if resp.StatusCode != http.StatusOK { return false } return true } GetLanguage import ( \"net/http\" \"strings\" ) // GetLanguage ... func GetLanguage(r *http.Request) string { lang := r.Header.Get(\"Accept-Language\") if lang != \"\" { // curl request doesnt have Accept-Language lang = lang[0:strings.Index(lang, \",\")] } return lang } RemoveProtocolFromURL // RemoveProtocolFromURL ... func RemoveProtocolFromURL(url string) string { if strings.HasPrefix(url, \"https://\") { return url[8:] } if strings.HasPrefix(url, \"https:/\") { return url[7:] } if strings.HasPrefix(url, \"http://\") { return url[7:] } if strings.HasPrefix(url, \"http:/\") { return url[6:] } return url } RemoveProtocolAndWWWFromURL // RemoveProtocolAndWWWFromURL ... func RemoveProtocolAndWWWFromURL(url string) string { if strings.HasPrefix(url, \"https://www.\") { return url[12:] } if strings.HasPrefix(url, \"https:/www.\") { return url[11:] } if strings.HasPrefix(url, \"http://www.\") { return url[11:] } if strings.HasPrefix(url, \"http:/www.\") { return url[10:] } return RemoveProtocolFromURL(url) } NUMBERS GetRandomInt import ( \"math/rand\" \"time\" ) // GetRandomInt [min, max] both included func GetRandomInt(min, max int) int { r := rand.New(rand.NewSource(time.Now().UnixNano())) //rand.Seed(time.Now().UnixNano()) // return rand.Intn(max-min+1) + min return r.Intn(max-min+1) + min } GetRandomFloat64 import ( \"math/rand\" \"time\" ) // GetRandomFloat64 [min, max] both included func GetRandomFloat64(min, max float64) float64 { rand.Seed(time.Now().UnixNano()) return (rand.Float64() * (max - min)) + (min) } ToFixedFloat64 import \"math\" // ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat64(untruncated float64, precision int) float64 { coef := math.Pow10(precision) truncated := float64(int(untruncated*coef)) / coef return truncated } ToFixedFloat32 import \"math\" // ToFixedFloat32 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat32(untruncated float32, precision int) float32 { coef := float32(math.Pow10(precision)) truncated := float32(int(untruncated*coef)) / coef return truncated } RoundFloat64 // RoundFloat64 -> rounds float64 into integer func RoundFloat64(num float64) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) } RoundFloat32 // RoundFloat32 -> rounds float32 into integer func RoundFloat32(num float32) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) } ReverseSliceInt // ReverseSliceInt [0,1,2,3,4,5] ==> [5,4,3,2,1,0] func ReverseSliceInt(reverse []int) []int { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse } TransposeMatrixInt // TransposeMatrixInt rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixInt(matrix [][]int) [][]int { result := make([][]int, len(matrix[0])) for i := range result { result[i] = make([]int, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result } SliceContainsInt // SliceContainsInt ... returns true/false func SliceContainsInt(num int, slice []int) bool { for _, v := range slice { if v == num { return true } } return false } ArabicToRomanNumbers import \"math\" // ArabicToRomanNumbers converts arabic int to roman numeral (string) func ArabicToRomanNumbers(n int) string { var rom string hundreds := []string{ \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\"} tens := []string{ \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\"} units := []string{ \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\"} t := int(math.Floor(float64(n / 1000))) h := int(math.Floor(float64(n % 1000 / 100))) d := int(math.Floor(float64(n % 100 / 10))) u := int(math.Floor(float64(n % 10))) for i := 0; i < t; i++ { rom += \"M\" } if h > 0 { rom += hundreds[h-1] } if d > 0 { rom += tens[d-1] } if u > 0 { rom += units[u-1] } return rom } STRINGS RemoveAllWhitespaces import \"strings\" // RemoveAllWhitespaces ... func RemoveAllWhitespaces(str string) string { return strings.Replace(str, \" \", \"\", -1) } ReplaceAllWhitespacesByChar import \"strings\" // ReplaceAllWhitespacesByChar ... func ReplaceAllWhitespacesByChar(str string, otherChar string) string { return strings.Replace(str, \" \", otherChar, -1) } ReverseSliceString // ReverseSliceString [\"H\",\"O\",\"L\",\"A\"] ==> [\"A\",\"L\",\"O\",\"H\"] func ReverseSliceString(reverse []string) []string { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse } TransposeMatrixString // TransposeMatrixString rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixString(matrix [][]string) [][]string { result := make([][]string, len(matrix[0])) for i := range result { result[i] = make([]string, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result } SliceContainsString // SliceContainsString ... returns true/false func SliceContainsString(str string, slice []string) bool { for _, v := range slice { if v == str { return true } } return false } FixBadEncodedStrings // FixBadEncodedStrings ... func FixBadEncodedStrings(bad string) string { //bad := \"Kl\u00c3\u00a4der\" var good []byte for _, c := range bad { good = append(good, byte(c)) } //fmt.Println(string(good)) return string(good) } OS execCommand import ( \"fmt\" \"os/exec\" ) func main() { command := []string{\"vnstat\", \"-i\", ifinterface, \"--json\"} ///fmt.Println(\"Command =>\", command) chunk, err := execCommand(command) if err != nil { log.Fatal(err) } //fmt.Println(`CHUNK =>`, string(chunk)) } func execCommand(args []string) (err error) { _, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { fmt.Println(err) return err } return err } func execCommand(args []string) (c []byte, err error) { c, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { return nil, err } return c, err } func execCommand(comm string) { _, err := exec.Command(\"sh\", \"-c\", comm).CombinedOutput() if err != nil { log.Fatal(err) } } TIME ParseStringToTime import \"time\" // ParseStringToTime ... func ParseStringToTime(start string) time.Time { layout1 := \"2006-01-02\" // Layout numbers? layout2 := \"2006-01-02T15:04:05\" t, err := time.Parse(layout1, start) if err != nil { t, err = time.Parse(layout2, start) } return t } GetTimestampFromDate import ( \"strconv\" \"strings\" \"time\" ) // GetTimestampFromDateString ...(yyyy-mm-dd) func GetTimestampFromDateString(date string) float64 { var t int64 params := strings.Split(date, \"-\") day, _ := strconv.Atoi(params[2]) month, _ := strconv.Atoi(params[1]) year, _ := strconv.Atoi(params[0]) auxT := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) t = int64(auxT.UnixNano() / int64(time.Millisecond)) return float64(t) } OnceADayTask import \"time\" func onceADayTask() { t := time.Now() n := time.Date(t.Year(),t.Month(),t.Day(),3,10,10,0,t.Location()) d := n.Sub(t) if d < 0 { n = n.Add(24 * time.Hour) d = n.Sub(t) } for { time.Sleep(d) d = 24 * time.Hour doSomeTask() } } SetInterval import ( \"fmt\" \"net/http\" \"time\" ) type updates []struct { Symbol string `json:\"symbol\"` Price float64 `json:\"price\"` } func initUpdateIntervals() { var u updates var w http.ResponseWriter ticker := time.NewTicker(time.Millisecond * 1000) go func() { for _ = range ticker.C { u = updates{} lib.MakeGetRequest(w, url, &u) for _, v := range u { if v.Symbol != \"\" { stocks[v.Symbol].PriceNow = v.Price } } t := time.Now() hour, min, sec := t.Clock() fmt.Println(`TICK`, hour, min, sec) if hour == 6 && min == 1 { if sec > 0 && sec < 6 { go dailyWork() } } } }() } ticker := time.NewTicker(2 * time.Second) quit := make(chan struct{}) go func() { for { select { case <-ticker.C: fmt.Println(\"Se ejecuta cada X * time.Second\") case <-quit: ticker.Stop() return } } }() func interval() { ticker := time.NewTicker(time.Millisecond * 2000) for _ = range ticker.C { fmt.Println(\"Hi Every 2 secs\") } } LOGS Custom Logs // main.go /////// Custom Error Log File + Custom Info Log File ///////// iLog := createCustomInfoLogFile2(a.Conf.InfoLogFile) mylog := createCustomErrorLogFile(a.Conf.ErrorsLogFile) defer mylog.Close() ////////////////////////////////////////////////////////////// // ya por donde queramos func createCustomErrorLogFile(f string) *os.File { mylog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Error log file %s\\n\", err) } log.SetOutput(mylog) return mylog } func createCustomInfoLogFile2(f string) *log.Logger { infoLog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Info log file %s\\n\", err) } var iLog *log.Logger iLog = log.New(infoLog, \"INFO :\\t\", log.Ldate|log.Ltime) return iLog } PrettyPrint Structs func prettyPrintStruct(s interface{}) { result, _ := json.MarshalIndent(s, \"\", \"\\t\") fmt.Print(string(result), \"\\n\") } FLAGS Binarios con versiones package main import ( \"flag\" \"fmt\" \"os\" ) var version = \"0.0.0\" var when = \"undefined\" func main() { checkFlags() fmt.Println(\"Continue...\") } func checkFlags() { versionFlag := flag.Bool(\"v\", false, \"Show current version and exit\") flag.Parse() switch { case *versionFlag: fmt.Printf(\"Version:\\t: %s\\n\", version) fmt.Printf(\"Date :\\t: %s\\n\", when) os.Exit(0) } } /* go build -ldflags=\" -X 'main.version=v0.2.0' -X 'main.when=$(date -u +%F_%T)'\" go build -ldflags=\"-X 'main.when=$(date -u +%F_%T)'\" luego podemos hacer ./binary -v */ ORGANIZACION DE CODIGO Compartir structs entre paquetes // main.go package main import ( s \"pruebas/secondarypkg\" \"time\" ) func main() { p := &s.Placeholder{ Name: \"FooBar\", Date: time.Now().String(), } s.Foo(p) } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func Foo(p *Placeholder) { fmt.Println(p.Date, p.Name) } // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func (p *Placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) *Placeholder { return &Placeholder{ Name: name, Date: date, } } Lo mismo usando interfaces // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type PlaceHolder interface { Foo() } type placeholder struct { Name string Date string } func (p *placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) PlaceHolder { return &placeholder{ Name: name, Date: date, } }","title":"Golang snippets"},{"location":"golang-snippets/#golang-snippets","text":"","title":"GOLANG SNIPPETS"},{"location":"golang-snippets/#sendreceive-data","text":"","title":"SEND/RECEIVE DATA"},{"location":"golang-snippets/#sendjsontoclient","text":"import ( \"encoding/json\" \"log\" \"net/http\" ) // SendJSONToClient ... func SendJSONToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) }","title":"SendJSONToClient"},{"location":"golang-snippets/#sendxmltoclient","text":"import ( \"encoding/xml\" \"log\" \"net/http\" ) // SendXMLToClient ... func SendXMLToClient(w http.ResponseWriter, d interface{}) { w.Header().Set(\"Content-Type\", \"application/xml\") var dataXML = []byte(``) dataXML, err := xml.Marshal(&d) if err != nil { log.Printf(\"ERROR Parsing into XML %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataXML) }","title":"SendXMLToClient"},{"location":"golang-snippets/#senderrortoclient","text":"import ( \"encoding/json\" \"log\" \"net/http\" ) // SendErrorToClient ... func SendErrorToClient(w http.ResponseWriter, d interface{}) { w.WriteHeader(http.StatusBadRequest) w.Header().Set(\"Content-Type\", \"application/json\") var dataJSON = []byte(`{}`) dataJSON, err := json.MarshalIndent(d, \"\", \" \") if err != nil { log.Printf(\"ERROR Marshaling %s\\n\", err) w.Write([]byte(`{}`)) } w.Write(dataJSON) }","title":"SendErrorToClient"},{"location":"golang-snippets/#dogetrequest","text":"import ( \"encoding/json\" \"io/ioutil\" \"log\" \"net/http\" \"time\" ) // DoGetRequest ... func DoGetRequest(w http.ResponseWriter, url string, d interface{}) { var netClient = &http.Client{ Timeout: time.Second * 10, } resp, err := netClient.Get(url) if err != nil { log.Fatal(err) } if resp.StatusCode != 200 { log.Fatal(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // body is a string, for use we must Unmarshal over a struct err = json.Unmarshal(body, &d) if err != nil { log.Fatalln(err) } }","title":"DoGetRequest"},{"location":"golang-snippets/#dogetconcurrentrequest","text":"import ( \"encoding/json\" \"fmt\" \"io/ioutil\" \"log\" \"net/http\" ) func fillDefaultStocks(links []string) { ch := make(chan []byte) for _, link := range links { go doGetConcurrentRequest(link, ch) } for range links { json.Unmarshal(<-ch, &stocks) } } func doGetConcurrentRequest(url string, ch chan<- []byte) { resp, err := http.Get(url) if err != nil { msg := fmt.Sprintf(\"ERROR 1 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } if resp.StatusCode != 200 { msg := fmt.Sprintf(\"ERROR 2 Status Code %d\", resp.StatusCode) log.Printf(msg) ch <- []byte(msg) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { msg := fmt.Sprintf(\"ERROR 3 HTTP Request %s\", err) log.Printf(msg) ch <- []byte(msg) return } ch <- body }","title":"DoGetConcurrentRequest"},{"location":"golang-snippets/#dopostrequest","text":"func sendRequest(data []byte, a app) { server, _ := os.Hostname() server = strings.ToLower(server) contentType := \"application/x-www-form-urlencoded\" //; param=value\" host := \"https://\" + a.Conf.Host + a.Conf.PathToAPI var client = &http.Client{ Timeout: time.Second * 3, } params := url.Values{ //\"server\": {server}, \"test\": {a.Conf.Valid}, \"data\": {string(data)}, } params.Add(\"server\", server) query := bytes.NewBufferString(params.Encode()) resp, err := http.NewRequest(\"POST\", host, query) resp.Header.Add(\"Content-Type\", contentType) resp.Header.Add(\"Accept-Charset\", \"utf-8\") if err != nil { log.Fatal(\"Error preparing POST request => \", err) } r, err := client.Do(resp) if err != nil { log.Fatal(\"Error sending POST request => \", err) } if r.StatusCode != 200 { log.Fatal(\"Error received from server => \", r.Status, \" \", err) } }","title":"DoPostRequest"},{"location":"golang-snippets/#getinterfacestypes","text":"import \"fmt\" // GetInterfacesTypes ... func GetInterfacesTypes(f interface{}) { switch vf := f.(type) { case map[string]interface{}: //fmt.Println(\"is a map:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } case []interface{}: //fmt.Println(\"is an array:\") for k, v := range vf { switch vv := v.(type) { case string: //fmt.Printf(\"%v: is string - %q\\n\", k, vv) case int: //fmt.Printf(\"%v: is int - %q\\n\", k, vv) case float64: //fmt.Printf(\"%v: is float64 - %g\\n\", k, vv) if k == 4 { fmt.Println(`ALELUYA==>`, vv) } default: fmt.Sprintln(k, v, vv) //fmt.Printf(\"%v: \", k) GetInterfacesTypes(v) } } } }","title":"GetInterfacesTypes"},{"location":"golang-snippets/#isjson","text":"import \"encoding/json\" // IsJSON ... func IsJSON(str string) bool { var js json.RawMessage return json.Unmarshal([]byte(str), &js) == nil }","title":"IsJSON"},{"location":"golang-snippets/#errorcheck","text":"","title":"ERRORCHECK"},{"location":"golang-snippets/#check","text":"import \"log\" // Check ... func Check(err error) { if err != nil { log.Fatal(err) } }","title":"Check"},{"location":"golang-snippets/#files","text":"","title":"FILES"},{"location":"golang-snippets/#readfile","text":"import ( \"log\" \"os\" ) // ReadFile ... func ReadFile(filePath string) string { file, err := os.Open(filePath) defer file.Close() stat, err := file.Stat() if err != nil { log.Fatal(err) } bs := make([]byte, stat.Size()) _, err = file.Read(bs) if err != nil { log.Fatal(err) } data := string(bs) return data }","title":"ReadFile"},{"location":"golang-snippets/#readfilelinebyline","text":"import ( \"bufio\" \"fmt\" \"log\" \"os\" ) // ReadFileLineByLine ... func ReadFileLineByLine(filePath string) { file, err := os.Open(filePath) if err != nil { log.Fatal(err) } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { log.Fatal(err) } }","title":"ReadFileLineByLine"},{"location":"golang-snippets/#writefile","text":"import ( \"log\" \"os\" ) // WriteFile ... func WriteFile(filePath string, content string) { file, err := os.Create(filePath) if err != nil { log.Fatal(err) } defer file.Close() file.WriteString(content) }","title":"WriteFile"},{"location":"golang-snippets/#loadjsonfromfiledecoder","text":"import ( \"encoding/json\" \"log\" \"os\" ) // LoadJSONfromFileDecoder ... func LoadJSONfromFileDecoder(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() decoder := json.NewDecoder(file) err = decoder.Decode(&data) if err != nil { log.Fatalln(\"Cannot get configuration from file\", err) } }","title":"LoadJSONfromFileDecoder"},{"location":"golang-snippets/#loadjsonfromfilemarshall","text":"import ( \"encoding/json\" \"io/ioutil\" \"log\" \"os\" ) // LoadJSONfromFileMarshall ... func LoadJSONfromFileMarshall(filePath string, data interface{}) { file, err := os.Open(filePath) if err != nil { log.Fatalln(\"Cannot open config file\", err) } defer file.Close() body, err := ioutil.ReadAll(file) // get file content if err != nil { log.Fatalln(err) } err = json.Unmarshal(body, &data) if err != nil { log.Fatalln(err) } }","title":"LoadJSONfromFileMarshall"},{"location":"golang-snippets/#writejsontofile","text":"import ( \"encoding/json\" \"os\" ) // WriteJSONtoFile ... func WriteJSONtoFile(filePath string, d interface{}) { f, err := os.Create(filePath) if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&d) }","title":"WriteJSONtoFile"},{"location":"golang-snippets/#downloadfile","text":"import ( \"io\" \"net/http\" \"os\" ) // DownloadFile ... func DownloadFile(filePath string, url string) (err error) { // Create the file out, err := os.Create(filePath) if err != nil { return err } defer out.Close() // Get the data resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil }","title":"DownloadFile"},{"location":"golang-snippets/#sendfilefromservertoclient","text":"import ( \"fmt\" \"io\" \"net\" \"net/http\" \"time\" ) func Index(w http.ResponseWriter, r *http.Request) { url := \"http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png\" timeout := time.Duration(5) * time.Second transport := &http.Transport{ ResponseHeaderTimeout: timeout, Dial: func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) }, DisableKeepAlives: true, } client := &http.Client{ Transport: transport, } resp, err := client.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() //copy the relevant headers. If you want to preserve the downloaded // file name, extract it with go's url parser. w.Header().Set(\"Content-Disposition\", \"attachment; filename=Wiki.png\") w.Header().Set(\"Content-Type\", r.Header.Get(\"Content-Type\")) w.Header().Set(\"Content-Length\", r.Header.Get(\"Content-Length\")) //stream the body to the client without fully loading it into memory io.Copy(w, resp.Body) } func main() { http.HandleFunc(\"/\", Index) err := http.ListenAndServe(\":8000\", nil) if err != nil { fmt.Println(err) } }","title":"SendFileFromServerToClient"},{"location":"golang-snippets/#parsecsvfile","text":"// file.csv \"AAPL\",\"Apple Inc\",\"4.10%\" \"AMZN\",\"Amazon.com Inc\",\"3.49%\" \"MSFT\",\"Microsoft Corp\",\"3.23%\" \"GOOGL\",\"Alphabet Inc\",\"3.09%\" import ( \"bufio\" \"encoding/csv\" \"encoding/json\" \"fmt\" \"io\" \"os\" ) type stock struct { Symbol string `json:\"symbol\"` } func main() { csvFile, _ := os.Open(\"sp.csv\") reader := csv.NewReader(bufio.NewReader(csvFile)) var stocks []stock for { line, error := reader.Read() if error == io.EOF { break } aux := stock{ Symbol: line[0], } stocks = append(stocks, aux) } //stocksJSON, _ := json.Marshal(stocks) //fmt.Println(string(stocksJSON)) f, err := os.Create(\"spList.json\") if err != nil { panic(err) } defer f.Close() e := json.NewEncoder(f) e.Encode(&stocks) fmt.Println(`END`) } // result [ { \"symbol\": \"AAPL\" }, { \"symbol\": \"AMZN\" }, { \"symbol\": \"MSFT\" }, { \"symbol\": \"GOOGL\" } ]","title":"ParseCSVFile"},{"location":"golang-snippets/#http-server","text":"Lectura Request Handling in Go type Handler interface { ServeHttp( ResponseWriter, *Request ) }","title":"HTTP SERVER"},{"location":"golang-snippets/#wrapper","text":"Es muy sencillo pero luego complica para testearlo mux.HandleFunc(\"/path\", func(w http.ResponseWriter, r *http.Request) { nombreFuncion(w, r, loQueQueramosPasar) })","title":"Wrapper"},{"location":"golang-snippets/#handle-handlefunc","text":"package main import ( \"fmt\" \"net/http\" \"time\" ) func timeHandler1(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(time.RFC1123) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } func timeHandler2(format string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) }) } /* lo mismo pero con conversion implicita al tipo HandlerFunc func timeHandler2(format string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } } */ func hiHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { mux := http.NewServeMux() // Creamos un closure con las variables que queremos usar th2 := timeHandler2(time.RFC3339) mux.HandleFunc(\"/time/1\", timeHandler1) mux.Handle(\"/time/2\", th2) mux.HandleFunc(\"/hello\", hiHandler) //http.HandleFunc(\"/time/1\", timeHandler1) //http.Handle(\"/time/2\", th2) //http.HandleFunc(\"/hello\", hiHandler) http.ListenAndServe(\":3000\", mux /*nil*/) }","title":"Handle + HandleFunc"},{"location":"golang-snippets/#handler","text":"type specificHandler struct { Thing string } func(h *specificHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) { w.Write(h.Thing) } func main() { http.Handle(\"/something\", &specificHandler{Thing: \"Hello world!\"}) http.ListenAndServe(\":8080\", nil) } package main import ( \"fmt\" \"net/http\" \"time\" ) type timeHandler struct { format string } func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { tm := time.Now().Format(th.format) fmt.Println(\"/time/\" + tm) w.Write([]byte(\"The time is: \" + tm)) } type hiHandler struct{} func (ti *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Println(\"/hello\") w.Write([]byte(\"/hello\")) } func main() { /mux := http.NewServeMux() th1 := &timeHandler{format: time.RFC1123} th2 := &timeHandler{format: time.RFC3339} hi := &hiHandler{} mux.Handle(\"/time/1\", th1) mux.Handle(\"/time/2\", th2) mux.Handle(\"/hello\", hi) //http.Handle(\"/time/1\", th1) //http.Handle(\"/time/2\", th2) //http.Handle(\"/hello\", hi) http.ListenAndServe(\":3000\", /*nil*/ mux) }","title":"Handler"},{"location":"golang-snippets/#ejemplo-completo","text":"package main import ( \"errors\" \"fmt\" \"log\" \"net/http\" \"os\" \"time\" _ \"github.com/go-sql-driver/mysql\" ) type app struct { Config struct { Mode string `json:\"mode\"` Port int `json:\"port\"` Valid string `json:\"valid\"` ErrorsLogFile string `json:\"errorsLogFile\"` HitsLogFile string `json:\"hitsLogFile\"` } `json:\"config\"` Mysql struct { User string `json:\"user\"` Password string `json:\"password\"` DB string `json:\"db\"` Host string `json:\"host\"` Port int `json:\"port\"` TableBW string `json:\"tableBw\"` TableHits string `json:\"tableHits\"` } } type requestError struct { Error error `json:\"-\"` Message string `json:\"message\"` StatusCode int `json:\"-\"` } func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != a.Config.Valid { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } updateBw(w, r, a) } func main() { var a app loadConfigJSON(&a) checkMode(&a) // Custom Log File if a.Config.Mode == \"production\" { var f = a.Config.ErrorsLogFile mylog, err := os.OpenFile(f, os.O_WRONLY|os.O_CREATE|os.O_APPEND , 0644) if err != nil { log.Printf(\"ERROR opening log file %s\\n\", err) } defer mylog.Close() // defer must be in main log.SetOutput(mylog) } mux := http.NewServeMux() mux.Handle(\"/savebw/\", &a) mux.Handle(\"/saveHits/\", checkValid( func(w http.ResponseWriter, r *http.Request) { updateHits(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/get/\", checkValid( func(w http.ResponseWriter, r *http.Request) { getStats(w, r, &a) }, a.Config.Valid)) mux.HandleFunc(\"/\", badRequest) server := http.Server{ Addr: fmt.Sprintf(\"localhost:%d\", a.Config.Port), Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, MaxHeaderBytes: 1 << 20, } log.Printf(\"Server up listening %s in mode %s\", server.Addr , a.Config.Mode) server.ListenAndServe() } func checkValid(next http.HandlerFunc, test string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() valid := r.Form.Get(\"test\") if valid != test { http.Error(w, \"Unauthorized\", http.StatusUnauthorized) return } next.ServeHTTP(w, r) } } func badRequest(w http.ResponseWriter, r *http.Request) { re := &requestError{ Error: errors.New(\"Unexistent Endpoint\"), Message: \"Bad Request\", StatusCode: 400, } sendErrorToClient(w, re) }","title":"Ejemplo Completo"},{"location":"golang-snippets/#middlewares","text":"","title":"MIDDLEWARES"},{"location":"golang-snippets/#ratelimit","text":"import \"net/http\" // ExceedLimit ... func ExceedLimit(ip string) bool { // ToDO return false } // RateLimit ... func RateLimit(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if ExceedLimit(GetIP(r)) { http.Error(w, \"Too many requests\", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) }","title":"RateLimit"},{"location":"golang-snippets/#network","text":"","title":"NETWORK"},{"location":"golang-snippets/#getip","text":"import ( \"net\" \"net/http\" ) // GetIP returns string with IP func GetIP(r *http.Request) string { ip := r.Header.Get(\"X-Forwarded-For\") if len(ip) > 0 { return ip } ip, _, _ = net.SplitHostPort(r.RemoteAddr) return ip }","title":"GetIP"},{"location":"golang-snippets/#isvalidurl","text":"import \"net/url\" // IsValidURL ... func IsValidURL(rawurl string) bool { _, err := url.ParseRequestURI(rawurl) if err != nil { return false } return true }","title":"IsValidURL"},{"location":"golang-snippets/#existsurl","text":"import \"net/http\" func ExistsURL(myurl string) bool { resp, err := http.Head(myurl) if err != nil { return false } if resp.StatusCode != http.StatusOK { return false } return true }","title":"ExistsURL"},{"location":"golang-snippets/#getlanguage","text":"import ( \"net/http\" \"strings\" ) // GetLanguage ... func GetLanguage(r *http.Request) string { lang := r.Header.Get(\"Accept-Language\") if lang != \"\" { // curl request doesnt have Accept-Language lang = lang[0:strings.Index(lang, \",\")] } return lang }","title":"GetLanguage"},{"location":"golang-snippets/#removeprotocolfromurl","text":"// RemoveProtocolFromURL ... func RemoveProtocolFromURL(url string) string { if strings.HasPrefix(url, \"https://\") { return url[8:] } if strings.HasPrefix(url, \"https:/\") { return url[7:] } if strings.HasPrefix(url, \"http://\") { return url[7:] } if strings.HasPrefix(url, \"http:/\") { return url[6:] } return url }","title":"RemoveProtocolFromURL"},{"location":"golang-snippets/#removeprotocolandwwwfromurl","text":"// RemoveProtocolAndWWWFromURL ... func RemoveProtocolAndWWWFromURL(url string) string { if strings.HasPrefix(url, \"https://www.\") { return url[12:] } if strings.HasPrefix(url, \"https:/www.\") { return url[11:] } if strings.HasPrefix(url, \"http://www.\") { return url[11:] } if strings.HasPrefix(url, \"http:/www.\") { return url[10:] } return RemoveProtocolFromURL(url) }","title":"RemoveProtocolAndWWWFromURL"},{"location":"golang-snippets/#numbers","text":"","title":"NUMBERS"},{"location":"golang-snippets/#getrandomint","text":"import ( \"math/rand\" \"time\" ) // GetRandomInt [min, max] both included func GetRandomInt(min, max int) int { r := rand.New(rand.NewSource(time.Now().UnixNano())) //rand.Seed(time.Now().UnixNano()) // return rand.Intn(max-min+1) + min return r.Intn(max-min+1) + min }","title":"GetRandomInt"},{"location":"golang-snippets/#getrandomfloat64","text":"import ( \"math/rand\" \"time\" ) // GetRandomFloat64 [min, max] both included func GetRandomFloat64(min, max float64) float64 { rand.Seed(time.Now().UnixNano()) return (rand.Float64() * (max - min)) + (min) }","title":"GetRandomFloat64"},{"location":"golang-snippets/#tofixedfloat64","text":"import \"math\" // ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat64(untruncated float64, precision int) float64 { coef := math.Pow10(precision) truncated := float64(int(untruncated*coef)) / coef return truncated }","title":"ToFixedFloat64"},{"location":"golang-snippets/#tofixedfloat32","text":"import \"math\" // ToFixedFloat32 (untruncated, num) -> untruncated.toFixed(num) func ToFixedFloat32(untruncated float32, precision int) float32 { coef := float32(math.Pow10(precision)) truncated := float32(int(untruncated*coef)) / coef return truncated }","title":"ToFixedFloat32"},{"location":"golang-snippets/#roundfloat64","text":"// RoundFloat64 -> rounds float64 into integer func RoundFloat64(num float64) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) }","title":"RoundFloat64"},{"location":"golang-snippets/#roundfloat32","text":"// RoundFloat32 -> rounds float32 into integer func RoundFloat32(num float32) int { if num < 0 { return int(num - 0.5) } return int(num + 0.5) }","title":"RoundFloat32"},{"location":"golang-snippets/#reversesliceint","text":"// ReverseSliceInt [0,1,2,3,4,5] ==> [5,4,3,2,1,0] func ReverseSliceInt(reverse []int) []int { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse }","title":"ReverseSliceInt"},{"location":"golang-snippets/#transposematrixint","text":"// TransposeMatrixInt rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixInt(matrix [][]int) [][]int { result := make([][]int, len(matrix[0])) for i := range result { result[i] = make([]int, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result }","title":"TransposeMatrixInt"},{"location":"golang-snippets/#slicecontainsint","text":"// SliceContainsInt ... returns true/false func SliceContainsInt(num int, slice []int) bool { for _, v := range slice { if v == num { return true } } return false }","title":"SliceContainsInt"},{"location":"golang-snippets/#arabictoromannumbers","text":"import \"math\" // ArabicToRomanNumbers converts arabic int to roman numeral (string) func ArabicToRomanNumbers(n int) string { var rom string hundreds := []string{ \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\"} tens := []string{ \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\"} units := []string{ \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\"} t := int(math.Floor(float64(n / 1000))) h := int(math.Floor(float64(n % 1000 / 100))) d := int(math.Floor(float64(n % 100 / 10))) u := int(math.Floor(float64(n % 10))) for i := 0; i < t; i++ { rom += \"M\" } if h > 0 { rom += hundreds[h-1] } if d > 0 { rom += tens[d-1] } if u > 0 { rom += units[u-1] } return rom }","title":"ArabicToRomanNumbers"},{"location":"golang-snippets/#strings","text":"","title":"STRINGS"},{"location":"golang-snippets/#removeallwhitespaces","text":"import \"strings\" // RemoveAllWhitespaces ... func RemoveAllWhitespaces(str string) string { return strings.Replace(str, \" \", \"\", -1) }","title":"RemoveAllWhitespaces"},{"location":"golang-snippets/#replaceallwhitespacesbychar","text":"import \"strings\" // ReplaceAllWhitespacesByChar ... func ReplaceAllWhitespacesByChar(str string, otherChar string) string { return strings.Replace(str, \" \", otherChar, -1) }","title":"ReplaceAllWhitespacesByChar"},{"location":"golang-snippets/#reverseslicestring","text":"// ReverseSliceString [\"H\",\"O\",\"L\",\"A\"] ==> [\"A\",\"L\",\"O\",\"H\"] func ReverseSliceString(reverse []string) []string { for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 { reverse[i], reverse[j] = reverse[j], reverse[i] } return reverse }","title":"ReverseSliceString"},{"location":"golang-snippets/#transposematrixstring","text":"// TransposeMatrixString rows > cols or cols > rows // but rows.elements >= cols.elements func TransposeMatrixString(matrix [][]string) [][]string { result := make([][]string, len(matrix[0])) for i := range result { result[i] = make([]string, len(matrix)) } for y, v := range matrix { for x, t := range v { result[x][y] = t } } return result }","title":"TransposeMatrixString"},{"location":"golang-snippets/#slicecontainsstring","text":"// SliceContainsString ... returns true/false func SliceContainsString(str string, slice []string) bool { for _, v := range slice { if v == str { return true } } return false }","title":"SliceContainsString"},{"location":"golang-snippets/#fixbadencodedstrings","text":"// FixBadEncodedStrings ... func FixBadEncodedStrings(bad string) string { //bad := \"Kl\u00c3\u00a4der\" var good []byte for _, c := range bad { good = append(good, byte(c)) } //fmt.Println(string(good)) return string(good) }","title":"FixBadEncodedStrings"},{"location":"golang-snippets/#os","text":"","title":"OS"},{"location":"golang-snippets/#execcommand","text":"import ( \"fmt\" \"os/exec\" ) func main() { command := []string{\"vnstat\", \"-i\", ifinterface, \"--json\"} ///fmt.Println(\"Command =>\", command) chunk, err := execCommand(command) if err != nil { log.Fatal(err) } //fmt.Println(`CHUNK =>`, string(chunk)) } func execCommand(args []string) (err error) { _, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { fmt.Println(err) return err } return err } func execCommand(args []string) (c []byte, err error) { c, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput() if err != nil { return nil, err } return c, err } func execCommand(comm string) { _, err := exec.Command(\"sh\", \"-c\", comm).CombinedOutput() if err != nil { log.Fatal(err) } }","title":"execCommand"},{"location":"golang-snippets/#time","text":"","title":"TIME"},{"location":"golang-snippets/#parsestringtotime","text":"import \"time\" // ParseStringToTime ... func ParseStringToTime(start string) time.Time { layout1 := \"2006-01-02\" // Layout numbers? layout2 := \"2006-01-02T15:04:05\" t, err := time.Parse(layout1, start) if err != nil { t, err = time.Parse(layout2, start) } return t }","title":"ParseStringToTime"},{"location":"golang-snippets/#gettimestampfromdate","text":"import ( \"strconv\" \"strings\" \"time\" ) // GetTimestampFromDateString ...(yyyy-mm-dd) func GetTimestampFromDateString(date string) float64 { var t int64 params := strings.Split(date, \"-\") day, _ := strconv.Atoi(params[2]) month, _ := strconv.Atoi(params[1]) year, _ := strconv.Atoi(params[0]) auxT := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) t = int64(auxT.UnixNano() / int64(time.Millisecond)) return float64(t) }","title":"GetTimestampFromDate"},{"location":"golang-snippets/#onceadaytask","text":"import \"time\" func onceADayTask() { t := time.Now() n := time.Date(t.Year(),t.Month(),t.Day(),3,10,10,0,t.Location()) d := n.Sub(t) if d < 0 { n = n.Add(24 * time.Hour) d = n.Sub(t) } for { time.Sleep(d) d = 24 * time.Hour doSomeTask() } }","title":"OnceADayTask"},{"location":"golang-snippets/#setinterval","text":"import ( \"fmt\" \"net/http\" \"time\" ) type updates []struct { Symbol string `json:\"symbol\"` Price float64 `json:\"price\"` } func initUpdateIntervals() { var u updates var w http.ResponseWriter ticker := time.NewTicker(time.Millisecond * 1000) go func() { for _ = range ticker.C { u = updates{} lib.MakeGetRequest(w, url, &u) for _, v := range u { if v.Symbol != \"\" { stocks[v.Symbol].PriceNow = v.Price } } t := time.Now() hour, min, sec := t.Clock() fmt.Println(`TICK`, hour, min, sec) if hour == 6 && min == 1 { if sec > 0 && sec < 6 { go dailyWork() } } } }() } ticker := time.NewTicker(2 * time.Second) quit := make(chan struct{}) go func() { for { select { case <-ticker.C: fmt.Println(\"Se ejecuta cada X * time.Second\") case <-quit: ticker.Stop() return } } }() func interval() { ticker := time.NewTicker(time.Millisecond * 2000) for _ = range ticker.C { fmt.Println(\"Hi Every 2 secs\") } }","title":"SetInterval"},{"location":"golang-snippets/#logs","text":"","title":"LOGS"},{"location":"golang-snippets/#custom-logs","text":"// main.go /////// Custom Error Log File + Custom Info Log File ///////// iLog := createCustomInfoLogFile2(a.Conf.InfoLogFile) mylog := createCustomErrorLogFile(a.Conf.ErrorsLogFile) defer mylog.Close() ////////////////////////////////////////////////////////////// // ya por donde queramos func createCustomErrorLogFile(f string) *os.File { mylog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Error log file %s\\n\", err) } log.SetOutput(mylog) return mylog } func createCustomInfoLogFile2(f string) *log.Logger { infoLog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644) if err != nil { log.Fatalf(\"ERROR opening Info log file %s\\n\", err) } var iLog *log.Logger iLog = log.New(infoLog, \"INFO :\\t\", log.Ldate|log.Ltime) return iLog }","title":"Custom Logs"},{"location":"golang-snippets/#prettyprint-structs","text":"func prettyPrintStruct(s interface{}) { result, _ := json.MarshalIndent(s, \"\", \"\\t\") fmt.Print(string(result), \"\\n\") }","title":"PrettyPrint Structs"},{"location":"golang-snippets/#flags","text":"","title":"FLAGS"},{"location":"golang-snippets/#binarios-con-versiones","text":"package main import ( \"flag\" \"fmt\" \"os\" ) var version = \"0.0.0\" var when = \"undefined\" func main() { checkFlags() fmt.Println(\"Continue...\") } func checkFlags() { versionFlag := flag.Bool(\"v\", false, \"Show current version and exit\") flag.Parse() switch { case *versionFlag: fmt.Printf(\"Version:\\t: %s\\n\", version) fmt.Printf(\"Date :\\t: %s\\n\", when) os.Exit(0) } } /* go build -ldflags=\" -X 'main.version=v0.2.0' -X 'main.when=$(date -u +%F_%T)'\" go build -ldflags=\"-X 'main.when=$(date -u +%F_%T)'\" luego podemos hacer ./binary -v */","title":"Binarios con versiones"},{"location":"golang-snippets/#organizacion-de-codigo","text":"","title":"ORGANIZACION DE CODIGO"},{"location":"golang-snippets/#compartir-structs-entre-paquetes","text":"// main.go package main import ( s \"pruebas/secondarypkg\" \"time\" ) func main() { p := &s.Placeholder{ Name: \"FooBar\", Date: time.Now().String(), } s.Foo(p) } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func Foo(p *Placeholder) { fmt.Println(p.Date, p.Name) } // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type Placeholder struct { Name string Date string } func (p *Placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) *Placeholder { return &Placeholder{ Name: name, Date: date, } } Lo mismo usando interfaces // main.go package main import ( s \"pruebas/paquete\" \"time\" ) func main() { p := s.NewPlaceHolder(\"FooBar\", time.Now().String()) p.Foo() } // secondarypkg/otro.go package secondarypkg import \"fmt\" type PlaceHolder interface { Foo() } type placeholder struct { Name string Date string } func (p *placeholder) Foo() { fmt.Println(p.Date, p.Name) } func NewPlaceHolder(name string, date string) PlaceHolder { return &placeholder{ Name: name, Date: date, } }","title":"Compartir structs entre paquetes"},{"location":"golang/","text":"GOLANG 1.21.X INSTALACION descargarlo de aqui Como root tar -C /usr/local -xzf go-file.tar.gz // como usuario nano $HOME/.bashrc nano $HOME/.profile // a\u00f1adir a cada uno # Golang conf export PATH=$PATH:/usr/local/go/bin export GOPATH=$HOME/path/to/golang/code export PATH=$PATH:$GOPATH/bin // La siguiente linea hay veces que es necesaria export GOBIN=$PATH:$GOPATH/bin Para recargar la configuracion source ~/.profile Carpetas que se crean: bin - Contiene los binarios compilados. Podemos a\u00f1adir la carpeta bin al path del sistema para hacer los binarios compilados ejecutables desde cualquier sitio pkg - contiene los versiones compiladas de las librerias disponibles para que el compilador las pueda enlazar sin tener que recompilarlas src - contiene todo el codigo organizado por rutas de import VS Code Go: Install/Update Tools ENLACES UTILES Go Interfaces Tipos de funcion Modulos Ejemplos - gobyexample Ejemplos - rosettacode GO MODULES en VSCODE GO MODULES en VSCODE Blogs Jacob Martin - Articulos y tutoriales Dave Cheney Alex Edwards Desarrollo Web Writing Web Applications - Tutorial basico de la wiki de golang.org Ejemplos Golang para web - gowebexamples Librerias database/sql go-sql-driver/mysql gorilla-websocket gobwas-ws Utilidades curl-to-Go - Herramienta online que convierte comandos curl en codigo Go JSON-to-Go - Herramienta online que convierte JSON en structs para Go Despliegue y seguridad GO TOOL go [arguments] The commands are: bug start a bug report build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages or modules mod module maintenance run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages Use \"go help \" for more information about a command. Additional help topics: buildmode build modes c calling between Go and C cache build and test caching environment environment variables filetype file types go.mod the go.mod file gopath GOPATH environment variable gopath-get legacy GOPATH go get goproxy module proxy protocol importpath import path syntax modules modules, module versions, and more module-get module-aware go get packages package lists and patterns testflag testing flags testfunc testing functions Use \"go help \" for more information about that topic. install // descarga el codigo y todas sus dependencias. Lo compila e instala el // binario en el directorio $GOPATH/bin go install github.com/ruta/codigo // instalar la ultima version go install ruta/codigo@latest build // -o nombre para el ejecutable go build -o nombreEjecutable program.go // -s -w eliminan el debug y hacen mas peque\u00f1o el binario go build -ldflags \"-s -w\" // para incluir la fecha en el binario go build -ldflags=\"-X 'main.releaseDate=$(date -u +%F_%T)'\" GOOS - sistema operativo para el que compilamos GOARCH - procesador para el que se compila GOOS=darwin GOARCH=386 go build GOOS=linux GOARCH=amd64 go build -o geoip // -o fuerza el nombre del binario al del parametro GOOS= GOARCH= windows 386 windows amd64 linux 386 linux amd64 linux arm linux arm64 android arm darwin 386 darwin amd64 darwin arm darwin arm64 Lista de combinaciones validas de sistema operativo y arquitectura Usando cgo Ejemplo : usar libreria de C bearlibterminal con bindings para Go. Descargar aqui libBearLibTerminal.so (de linuxx64) va a /usr/lib en gopath (mi caso $HOME/.golang/src/bearlibterminal) ponemos BearLibTerminal.go (los bindings a go) y BearLibTerminal.h (las cabeceras de C) Ahora ya podemos importar la libreria y usarla import ( blt \"bearlibterminal\" ) Para Compilar a Windows usr/bin/ld: cannot find -l // o mingw-64, no tengo claro como van todas esos paquetes tan // similares apt-get install gcc-mingw-w64-x86-64 gcc-multilib cd /usr/x86_64-w64-mingw32/lib // poner ahi todas las librerias para windows *.dll y *.lib GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build main.go OPERADORES Aritmeticos + Suma - Resta * Multiplicacion / Division % Modulo, lo que sobra de la division entera ++ Incremento -- Decremento Asignacion = x = y += x = x + y -= x = x - y *= x = x * y /= x = x / y %= x = x % y Comparacion == igual != no igual > mayor que < menor que >= mayor o igual que <= menor o igual que Logicos && AND || OR ! NOT Punteros & devuelve la direccion de una variable * puntero a una variable VARIABLES Una variable puede contener cualquier tipo, incluso una funcion func main() { accion := func() { fmt.Println(\"Hola\") } accion() } TypeOf(variable) Para averiguar de que tipo es una variable import (\"reflect\") fmt.Println(\"....\", reflect.TypeOf(variable)) Declaracion Declaracion de variables var ( name string age int location string ) var ( name, location string age int ) var name string Inicializacion de variables var ( name string = \"jolav\" age int = 100 ) var ( // inferred typing name = \"jolav\" age = 32 ) var name, location, age = \"jolav\", \"casa\", 100 Sentencia de asignacion := Dentro de una funcion podemos usar := en lugar de var func main() { name, location := \"jolav\", \"casa\" age := 100 } new Pone a cero el valor del tipo y devuelve un puntero a el. x := new(int) make Necesario para slices maps y channels Zero Values Cuando se declaran variables sin un valor explicito se les asigna el valor zero int - 0 float - 0.0 string - \"\" boolean - false pointers - nil map - nil slices - nil array - array listo para usar con sus elementos a zero value que sea functions - nil interfaces - nil channels -nil type package tempconv import \"fmt\" type Celsius float64 type Fahrenheit float64 const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 ) func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) } Alcance El alcance es la region del programa donde una variable definida existe Tipos de variables segun donde se declaren: local variables - dentro de una funcion o un bloque. Fuera de ese entorno no existen package variables - fuera de todas las funciones o bloques. Accesibles desde cualquier parte del paquete formal parameters - en la definicion de los parametros de una funcion. Se tratan como locales para esa funcion y tienen preferencia sobre las globales Cuando coinciden dentro de una funcion o bloque una local y una global prevalece la local Conversion de tipos Go no tiene conversion implicita de tipos T(v) - Convierte el valor v al tipo T i := 42 f := float64(i) u := uint(f) strconv Type Assertion func diffArray(s1, s2 interface{}) []string { var aux1 []int fmt.Println(reflect.TypeOf(s1)) var a1, a2 []string if reflect.TypeOf(s1) == reflect.TypeOf(aux1) { // s1,s2 son []int a1, a2 = convertIntToString(s1.([]int), s2.([]int)) // pasamos s1,s2 como []int y usando type assertion } else { a1, a2 = s1.([]string), s2.([]string) } // aqui ya a1,a2 son []string func diffTwoArrays() { diffArray([]int{1, 2, 3, 5}, []int{1, 2, 3, 4, 5})) diffArray([]string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"}, []string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"}) } Punteros Punteros vs Valor Un puntero contiene la direccion de memoria de un valor Todo en Go se pasa por valor, pero ... Cuando se declara una variable de tipo de referencia se crea un valor llamado header value que contiene un puntero a la estructura de datos subyacente necesaria para segun cada tipo de referencia. Cada tipo de referencia contiene campos unicos para gestionar la estructura de datos subyacente propia. El header value contiene un puntero, por lo tanto puedes pasar una copia de cualquier tipo de referencia y compartir la estructura subyacente intrinsicamente al compartir el puntero. int - valor float - valor string - variable de tipo de referencia, pero funciona como valor boolean - valor arrays - valor slices - variable de tipo de referencia maps - variable de tipo de referencia functions - variable de tipo de referencia interfaces - variable de tipo de referencia channels - variable de tipo de referencia Punteros Por defecto Go pasa los argumentos por valor (crea una copia) Para pasarlos por referencia hay que pasar punteros o usar estructuras de datos que usan valores por referencia como slices y maps. & - para conseguir el puntero de un valor lo ponemos delante de su nombre * - para desreferenciar un puntero y que nos de acceso a su valor Si p es un puntero a x &x --> p = &x p es el puntero de x (contiene la direccion de memoria de x) *p --> *p = x *p es el valor de x i := 42 p := &i // P es un puntero a i fmt.Println(*p) // 42 , lee i a traves del puntero p *p = 21 // establece i a traves del puntero p func main() { v := *getPointer() fmt.Println(\"Value is\", v) // Value is 100 m := getPointer() fmt.Println(\"Memory is\", m) // Memory is 0xc00018c020 } func getPointer() (myPointer *int) { a := 100 return &a } func main() { x := 5 zero(&x) fmt.Println(x) // x is 0 } func zero(x *int) { *x = 0 } func main() { var i int = 7 var p *int p = &i fmt.Println(\"i : \" , i) fmt.Println(\"memory address of i : \", &i) fmt.Println(\"p : \" , p) fmt.Println(\"*p : \" , *p) } [output] i : 7 memory address of i : 0x10328000 p : 0x10328000 *p : 7 new new - coge un tipo como argumento, asigna suficiente memoria para ese tipo de dato y devuelve un puntero que apunta a esa memoria. Luego el GC (garbage collector lo limpia todo) func zero(x *int) { *x = 5 } func main() { x := new(int) zero(x) fmt.Println(*x) // x is 5 } Mutabilidad Solo las constantes son inmutables. Sin embargo como los argumentos se pasan por valor, una funcion que recibe y modifica un argumento no muta el valor original Ejemplo func addOne(x int) { x++ } func main() { x := 0 addOne(x) fmt.Println(x) // x da 0 } // Si usamos punteros func addOne(x *int) { *x++ } func main() { x := 0 addOne(&x) fmt.Println(x) // x da 1 } LECTURA FUNDAMENTAL, stackoverflow pointer vs values type data struct { val int } func myfunc() data { // devuelve una copia del struct return data{val: 1} } func myfunc() *data { // devuelve un puntero al struct creado dentro de la funcion return &data{} } func myfunc(d *data) { // recibe un struct ya existente y sobreescribe su valor d.val = 1 } DATOS BASICOS Numeros Cuando se definen numeros de forma literal se puede usar guion bajo _ para hacerlos mas legibles const segundosEnUnA\u00f1o = 31_557_600 Integers Los enteros son numeros sin decimal int - positivos y negativos uint - unsigned, solo los positivos byte - alias de uint8 (0-255) rune - alias de int32 Numeros de Punto Flotante Son numeros reales (con parte decimal) float32 - conocido como simple precision float64 - conocido como doble precision Numeros Complejos complex64 - parte real float32 + partes imaginarias complex128 - parte real float64 + partes imaginarias Booleanos && - and || - or ! - not Cadenas Estan hechas de bytes (uno por caracter) La diferencia entre comillas simples o dobles es que en estas no pueden contener nuevas lineas y se permiten escapar caracteres especiales len(string) - longitud de la cadena \"Hola mundo\"[1] - acceder a caracteres de la cadena \"Hello, \" + World\" Constantes Se declaran como variables pero con la palabra clave const . No se pueden declarar usando := Solo pueden ser caracteres, string, booleano o valores numericos. const PI = 3.14 Iota iota info Es un identificador usado en declaraciones de constantes para indicar que son autoincrementables. . Se resetea a cero cuando aparece la palabra reservada const const ( // iota is reset to 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) ESTRUCTURAS DE CONTROL for for init; condition; post { } // for normal sum := 0 for i := 0; i < 10; i++ { sum = sum + i } for condition { } // for sin declaraciones pre/post que funciona como un while. Podemos // tambien quitar hasta los punto y coma sum := 1 for ; sum < 1000; { for sum < 1000 { sum = sum + sum } for {} // for infinito for { ..codigo } if if answer != 42 { return \"Wrong answer\" } if err := foo(); err != nil { panic(err) } if { // codigo } else { // codigo } switch switch en golang Solo se pueden comparar valores del mismo tipo declaracion default para ejecutarse si todas las demas fallan en la declaracion se puede usar una expression (pej calcular un valor) case 300 - 150: Se puede tener multiples valores un solo caso case 6, 7: fallthroguh se ejecutan todas las declaraciones que cumplen la condicion break sale del switch, por defecto en cada opcion es automatico el break t := time.Now() switch { case t.Hour() < 12: fmt.Println(\"Good morning!\") case t.Hour() < 17: fmt.Println(\"Good afternoon.\") default: fmt.Println(\"Good evening.\") } switch os := runtime.GOOS; os { case \"darwin\": fmt.Println(\"OS X.\") case \"linux\": fmt.Println(\"Linux.\") default: // freebsd, openbsd,plan9, windows... fmt.Printf(\"%s.\\n\", os) } range Para iterar sobre array , slice , string , map o leer de un channel El valor que nos da range es una copia del valor del elemento original y por tanto si se modifica no afecta al original for k,v := range zoo { v.age = 10 // no modifica el original zoo[k].age = 999 // SI modifica el original } slice var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key, value := range pow { fmt.Println(\"Posicion\", key, \"valor\", value) } Podemos omitir el index o el value usando _ for i, _ := range pow for _, value := range pow Podemos omitir tambien el valor omitiendo por completo , value var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key := range pow { fmt.Println(\"Posicion\", key) } for _, value := range pow { fmt.Println(\"valor\", value) } map El primer parametro no es un entero autoincrementable sino la clave del map for key, value := range cities break Paras la iteracion en cualquier momento continue Omites una iteracion ARRAYS tipo [n]T - es un array de n elementos de tipo T No se pueden redimensionar Se pueden inicializar al declararlos a := [2]string{\"hello\", \"world!\"} a := [...]string{\"hello\", \"world!\"} usando una ellipsis para indicar un numero variable de elementos que en este caso son dos a := [5]int{1: 10, 2: 20} - inicializando solo algunos valores Mostrar arrays fmt.Printf(\"%q\\n\", a) // [\"hello\" \"world!\"] len(array) MultiDimensionales var a [4][2]int array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} SLICES tipo []T - es un slice de elementos de tipo T Crear un slice : Los slice hay que crearlos antes de usarlos slice literal mySlice := []int{2, 3, 5, 7, 11, 13} make - crea un slice vacio de una longitud y (opcional una capacidad) cities := make([]string, len, cap) Recortando un slice s[a:b] - selecciona elementos desde la pos a (inclusive) hasta b (exclusive) s[:b] - un indice a que no se declara es un 0 implicito s[a:] - un indice b que no se declara es implicito un len(s) A\u00f1adiendo a un slice cities = append(cities, \"San Diego\") cities = append(cities, \"San Diego\", \"Mountain View\") otherCities := []string{\"Santa Monica\", \"Venice\"} cities = append(cities, otherCities...) Copiar un slice copy(destino, origen) Length len(slice) Nil slices Declaracion var z []int - El valor cero de un slice es nil. Un slice nil tiene una longitud de cero Inicializacion z := make([]int, 0) z := []int{} Las tres formas son lo mismo BiDimensional // allocate composed 2d array a := make([][]int, row) for i := range a { a[i] = make([]int, col) } // allocate composed 2d array a := make([][]int, row) e := make([]int, row * col) for i := range a { a[i] = e[i*col:(i+1)*col] } // otra posibilidad func get(r, c int) int { return e[r*cols+c] } MAPS tipo map[a]b - es un map de claves tipo a con valores tipo b Formado por pares clave/valor Crear un map : Los map hay que crearlos antes de usarlos map literal amigos := map[string]int{\"Juan\":50, \"Elena\":21, \"Carlos\":41,} make - creas un nil map vacio amigos := make(map[string]int) Si lo declaramos pero no lo inicializamos, al intentar a\u00f1adir elementos no compilara amigos := map[string]int{} - declarado pero no inicializado Modificando maps m[key] = elem - Insertando o actualizando un valor elem = m[key] - Devuelve el elemento delete(m, key) - Borrando un elemento elem, ok = m[key] - Testea si existe un valor con una clave determinada elements := map[string]map[string]string{ \"H\": map[string]string{ \"name\":\"Hydrogen\", \"state\":\"gas\", }, \"He\": map[string]string{ \"name\":\"Helium\", \"state\":\"gas\", }, \"Li\": map[string]string{ \"name\":\"Lithium\", \"state\":\"solid\", }, } if el, ok := elements[\"Li\"]; ok { fmt.Println(el[\"name\"], el[\"state\"]) } STRUCTS Es una coleccion de campos/propiedades Solo los campos exportados (primera letra mayuscula) son accesibles de fuera del paquete Inicializacion type Circle struct { x, y, r float64 } var c Circle - crea una variable local Circle que pone por defecto los valores a cero (0 para int, 0.0 para float. \"\" para string, nil para punteros) c := new(Circle) - asigna memoria para todos los campos, los inicializa a cero y devuelve un puntero a la struct (*Circle), los punteros se usan mucho en structs paa que las funciones puedan modificar los datos. c := Circle{x: 0, y: 0, r: 5} c := Circle{0, 0, 5} c := &Circle{0, 0, 5} c := Circle{x: 1} c := Circle{} type Circle struct { x, y, r float64 } func main() { fmt.Println(c.x, c.y, c.r) c.x = 10 c.y = 5 } // todo en uno var addCases = []struct { in string want string }{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // mas claro type addCases2 []struct { in string want string } ac := addCases2{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // para verlos for i, v := range addCases { fmt.Println(i, v.in) } for i, v := range ac { fmt.Println(i, v) } // con nombres fmt.Printf(\"%+v\\n\", struct) // bien formateado s, _ := json.MarshalIndent(g, \"\", \"\\t\") fmt.Print(string(s)) func show() { fmt.Println(t[0].hola) fmt.Println(test2[1].hola2) } type test []struct { hola string } var t = test{ {\"prueba1\"}, {\"prueba2\"}, } var test2 = []struct { hola2 string }{ {\"prueba3\"}, {\"prueba4\"}, } Metodos Un metodo es una funcion con el primer argumento implicito llamado receptor. func (ReceiverType r) func_name (parameters) (results) El receptor (receiver) del metodo esta entre la palabra clave function y el nombre del metodo func (u User) Greeting() string - nos permite llamarla con u.Greeting() Organizacion del codigo package models // list of packages to import // list of constants // list of variables // Main type(s) for the file, // try to keep the lowest amount of structs per file when possible. // List of functions // List of methods Alias Para definir metodos en un tipo que no es tuyo se usan alias import \"strings\" type MyStr string func (s MyStr) Uppercase() string { return strings.ToUpper(string(s)) } func main() { fmt.Println(MyStr(\"test\").Uppercase()) } Usar punteros en los receptores Los metodos se pueden asociar a un nombre o a puntero. Ventajas de usar punteros: evitar copiar el valor con cada llamada al metodo (pasarlo por referencia) para poder modificar el valor que pasamos type User struct { name string email string } func (u user) notify() { fmt.Printf(\"Mandar correo a %s<%s>\\n\", u.name, u.email) } // sin el puntero del receptor el correo no se cambiaria. func (u *user) changeEmail(email string) { u.email = email } SUGERENCIA Despu\u00e9s de declarar un nuevo tipo, trate de responder a esta pregunta antes de declarar m\u00e9todos para el tipo: \u00bf A\u00f1adir o quitar algo de un valor de este tipo necesita crear un nuevo valor o mutar el existente ? - Si la respuesta es crear un nuevo valor, usa receptores de valor en sus m\u00e9todos. - Si la respuesta es mutar el valor, usa receptores de puntero. Esto tambi\u00e9n se aplica a la forma en que los valores de este tipo deben pasarse a otras partes de su programa. Es importante ser consistente. La idea es no centrarse en lo que el m\u00e9todo est\u00e1 haciendo con el valor, sino centrarse en cu\u00e1l es la naturaleza del valor. Composicion type User struct { Id int Name, Location string } type Player struct { User GameId int } Podemos acceder a la Struct de User: a := new(Player) a.User.Name a.Name INTERFACES Explicacion de interfaces Mas Explicacion de interfaces Mas aun sobre interfaces Es un conjunto de metodos Es un tipo de datos package main import \"fmt\" type cat struct { name string } func (c *cat) born() { fmt.Println(c.name, \"is born Miaouu\") } type dog struct { name string } func (d *dog) born() { fmt.Println(d.name, \"is born Wharff\") } type animal interface { born() } func born(a animal) { a.born() } func main() { Jasper := &cat{\"JASPER\"} Lucy := &dog{\"Lucy\"} Max := new(dog) Max.name = \"Max\" Max.born() // call born function born(Jasper) born(Lucy) born(Max) } package main import \"fmt\" type Human struct { name string age int phone string } type Student struct { Human //an anonymous field of type Human school string loan float32 } // A human likes to stay... err... *say* hi func (h *Human) SayHi() { fmt.Printf(\"Hi, I am %s you can call me on %s\\n\", h.name, h.phone) } // A human can sing a song, preferrably to a familiar tune! func (h *Human) Sing(lyrics string) { fmt.Println(\"La la, la la la, la la la la la...\", lyrics) } // A Human man likes to guzzle his beer! func (h *Human) Guzzle(beerStein string) { fmt.Println(\"Guzzle Guzzle Guzzle...\", beerStein) } // A Student borrows some money func (s *Student) BorrowMoney(amount float32) { s.loan += amount // (again and again and...) } func Prestar(y YoungChap, amount float32) { y.BorrowMoney(amount) } // INTERFACES type Men interface { SayHi() Sing(lyrics string) Guzzle(beerStein string) } type YoungChap interface { SayHi() Sing(song string) BorrowMoney(amount float32) } func main() { mike := Student{Human{\"Mike\", 25, \"222-222-XXX\"}, \"MIT\", 150.50} mike.BorrowMoney(10) mike.BorrowMoney(10) Prestar(&mike, 100) fmt.Println(\"Debe ..\", mike.loan) } interfaces vacias 1- Todo tiene un type , puedes definir un nuevo type por ejemplo T que tiene tres metodos A , B y C 2- El conjunto de metodos especificos de un type se llama interface type . En nuestro ejemplo T_interface = (A, B, C) 3- Puedes crear un nuevo interface type definiendo los metodos que tiene. Pro ejemplo creo MyInterface = (A) 4- Cuando especificas una variable de tipo interface type le puedes asignar solo los tipos que esten en una interface que sea un superset de tu interface, vamos que todos los metodos de MyInterface deben estar en T_interface Conclusion : Todos los tipos de variables satisfacen la empty interface . Por tanto una funcion que tiene una interface{} como argumento admite cualquier valor sea el que sea. Pero dentro de la funcion el runtime de Go convierte ese valor a un valor interface{} func DoSomething(v interface{}) { // la funcion acepta cualquier valor una vez dentro // v es del tipo interface{} } EL valor de una interfaz son dos word de datos: - una word es un puntero a una tabla de metodos para el valor del type subyacente - la otra word es un puntero a los datos actuales de ese valor FUNCIONES Call Stack func main() { fmt.Println(f1()) } func f1() int { return f2() } func f2() int { return 1 } Argumentos Argumentos que reciben. Las funciones pueden recibir 0 o mas argumentos todos tipados despues del nombre de la variable. func add(x int, y int) int { return x + y } func add(x, y int) int { // int afecta a todos los parametros (x, y) return x + y } // ... funciones que aceptan un numero variable de parametros func add(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { // pasamos los parametros que queramos fmt.Println(add(1,2,3)) xs := []int{1,2,3} fmt.Println(add(xs...)) // tambien podemos pasar un slice } Retorno de parametros, puede devolver cualquier numero de ellos return region, continente // devuelve mas de un valor // Si los parametros de retorno estan nombrados vale con solo return func location(name, city string) (region, continent string) { ..codigo return // devuelve region y continent } Closures func generadorPares() func() uint { i := uint(0) return func() (ret uint) { ret = i i = i + 2 return } } func main() { nextPar := generadorPares() fmt.Println(nextPar()) // 0 fmt.Println(nextPar()) // 2 fmt.Println(nextPar()) // 4 } Recursion func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) } type function package main import \"fmt\" type test_int func(int) bool // isOdd takes an ints and returns a bool set to true if the // int parameter is odd, or false if not. // isOdd is of type func(int) bool which is what test_int // is declared to be. func isOdd(integer int) bool { if integer%2 == 0 { return false } return true } // Same comment for isEven func isEven(integer int) bool { if integer%2 == 0 { return true } return false } // We could've written: // func filter(slice []int, f func(int) bool) []int func filter(slice []int, f test_int) []int { var result []int for _, value := range slice { if f(value) { result = append(result, value) } } return result } func main(){ slice := []int {1, 2, 3, 4, 5, 7} fmt.Println(\"slice = \", slice) odd := filter(slice, isOdd) fmt.Println(\"Odd elements of slice are: \", odd) even := filter(slice, isEven) fmt.Println(\"Even elements of slice are: \", even) } defer Aplaza la ejecucion de una funcion hasta que termina la funcion en la que se encuentra. Lo tipico es cerrar archivos o desbloquear un mutex(mutual exclusion, para asegurar que solo una goroutine puede acceder a la vez a una variable) func main() { defer fmt.Println(\"world\") fmt.Println(\"hello\") } Se usa para liberar recursos cuando se pueda f, _ := os.Open(filename) defer f.Close() panic, recover panic(\"valor de panic\") - crea un runtime error . recover() - detiene el panic y devuelve el valor que fue pasado con la llamada a panic Un panic generalmente indica un error de programacion o una condicion excepcional de la que no hay forma facil de recuperarse func main() { defer func() { str := recover() fmt.Println(str) }() panic(\"PANIC\") } CONCURRENCIA goroutines go f(x) comienza la ejecucion de una nueva goroutine que es una funcion capaz de ejecutarse concurrentemente con otras funciones. // sin wait, el programa main puede acabar antes de que las goroutines // hagan lo que tengan que hacer func parallelLetFreq() { var wg sync.WaitGroup wg.Add(3) // suma 3 a las goroutines a esperar go count(\"1\", &wg) go count(\"2\", &wg) go count(\"3\", &wg) wg.Wait() // espera a todas las goroutines (3 en este caso) } func count(n int, wg *sync.WaitGroup) { defer wg.Done() // al terminar la funcion terminar goroutine fmt.Println(\"Number --> \", n)) } channels channels - son un conducto a traves del cual puedes recibir y enviar datos con el operador <- ch <- data - Envia data al canal ch data := <-ch - Recibe informacion del canal ch y lo asigna a data ch := make(chan int) - Los canales hay que crearlos antes de usarlos Por defecto los envios y recepciones esperan hasta que el otro lado este listo. Esto permite a las goroutines sincronizarse sin bloqueos especificos o condiciones func sum(a []int, c chan int) { sum := 0 for _, v := range a { sum += v } c <- sum // send sum to c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) } Buffered channels ch := make(chan int, 100) - Ponemos un buffer a los canales indicando su longitud como segundo argumento en el make para inicializar el canal Enviar datos aun canal con buffer se bloquea si el buffer esta lleno Recibir datos de un canal con buffer se bloquea si el buffer esta vacio func main() { c := make(chan int, 2) c <- 1; c <- 2; c <- 3 fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } // fatal error: all goroutines are asleep - deadlock! Sin embargo el siguiente funcionaria. Al a\u00f1adir el valor extra desde una goroutine no se bloquea el hilo principal pues aunque la goroutine se llama antes que el canal se vacie esta esperara hasta que haya espacio en el canal. func main() { c := make(chan int, 2) c <- 1; c <- 2 c3 := func() { c <- 3 } go c3() fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } Close close(ch) - Solo un emisor puede cerrar un canal. Enviar a un canal cerrado causa un panic. No son como ficheros que hace falta cerrarlos. Solo se cierran para avisar al receptor de que no llegaran mas datos y para terminar los loop range v, ok := <-ch - Un emisor puede cerrar un canal para indicar que no se enviara nada mas. Los receptores pueden testear cuando un canal ha sido cerrado asignando un segundo parametro a la expresion receptora ok sera falso cuando no haya mas valores que recibir y el canal este cerrado. for i := range ch - recibe valores del canal hasta que se cierre Select Es como switch pero con canales 1A - 89 1B - 103 MODULES go mod init nombreModulo go mod init github.com/jolav/nombreModulo // listar todos los modulos con sus dependencias go list -m all go list all ./... // chechear paquetes con actualizaciones go list -m -u all go list -m -u -json all // actualizar // cambiar manualmenrte el archivo go.mod o // actualiza todas salvo nueva version mayor, go get -v -u ./... // para versiones especificas o nueva version mayor go get -v -u github.com/user/repo@v1.1.1 //despues para asegurar que el el codigo que tenemos en el modulo coincide // con el archivo gp.mod ejecutamos go mod tidy PAQUETES Un programa Go esta hecho con paquetes. Los programas empiezan ejecutando la funcion main dentro del paquete main . Por convencion el nombre del paquete es la ultima palabra de la ruta del import. El paquete \"math/rand\" comprende archivos que comienzan con la sentencia package rand Paquetes que no son de la libreria estandar se importan usando una URL web, pero antes hay que descargarlos con go get go get github.com/creador/ruta/al/paquete import \"github.com/creador/ruta/al/paquete\" Despues de importar un paquete podemos usar los nombres que el exporta (sean variables, metodos o funciones) desde fuera de el paquete. Los nombres exportados en Go comienzan por letra mayuscula package main import ( \"fmt\" \"math\" ) func main() { fmt.Println(math.Pi) fmt.Println(math.pi) } // cannot refer to unexported name math.pi Otras formas de importar paquetes \u00ecmport alias \"fmt\" - Crea un alias de fmt. Ahora es alias.LoQueSea en lugar de fmt.LoQueSea import . \"fmt\" - Permite acceder al contenido directamente sin tener que ir precedido de fmt import _ \"fmt\" - Elimina las advertencia del compilado sobre ese paquete si no se usa y ejecuta si hay las funciones de inicializacion ( func init() {} ), El resto del paquete permanece inaccesible. Crear paquetes Los nombres de paquetes coinciden con la carpeta donde estan. Esto se puede cambiar pero no merece la pena Por convencion el nombre del paquete es la ultima palabra de la ruta del import. ~/src/proyectoX/main.go package main import \"fmt\" import \"proyectoX/utilidades\" // la ruta es a partir de srcs func main() { // llamada a utilidades.Media(xs) } ~/src/proyectoX/utilidades/media.go package utilidades func Media() { // codigo que sea } Desinstalar paquetes go clean -i ruta/paquete... - teoricamente borras los pkg y bin, los src hay que borrarlos manualmente Actualizar go get -u all - Actualiza todos go get -u full/package/name - Actualizar solo ese paquete EJECUCION El programa se inicia por la funcion main del package main Antes se ejecutan las funciones init de ese fichero Los paquetes importados \"_ import \"ruta/paquete\" hacen que el compilador acepte un paquete que no se usa y ademas ejecutan la o las funciones init de ese paquete TESTING El compilador ignora todos los archivos que terminan en _test.go ~/src/proyectoX/utilidades/media_test.go package utilidades import \"testing\" type testpair struct { values []float64 average float64 } var tests = []testpair{ {[]float64{1, 2}, 1.5}, {[]float64{1, 1, 1, 1, 1, 1}, 1}, {[]float64{-1, 1}, 0}, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Media(pair.values) if v != pair.average { t.Error( \"For\", pair.values, \"expected\", pair.average, \"got\", v, ) } } } go test ERRORS Errores en Go Los captura un tipo interfaz predefinido cuyo unico metodo Error devuelve una cadena type error interface { Error() string } Forma estandard de tratar los errores. log.Fatal(err) - manda el error a la terminal y detiene el programa f, err := os.Open(\"filename.ext\") if err != nil { log.Fatal(err) } Podemos aligerar la repeticion un poco usando: func check(e error) { if e != nil { panic(e) } } // y ahora ya solo ponemos check(err) LIBRERIA ESTANDAR FMT import \"fmt\" fmt.Print() - imprime fmt.Println() - imprime y salta de linea fmt.Printf() - imprime con un determinado formato type point struct { x, y int } p := point{1, 2} fmt.Printf(\"%v\\n\", p) // {1 2} // en una struct, `%+v` incluye los nombres de los campos de la struct fmt.Printf(\"%+v\\n\", p) // {x:1 y:2} // Imprimir el tipo de un valor fmt.Printf(\"%T\\n\", p) // main.point // `%d` para enteros standard fmt.Printf(\"%d\\n\", 123) // 123 // Imprime el caracter que corresponde al entero fmt.Printf(\"%c\\n\", 65) // a // Imprime floats fmt.Printf(\"%f\\n\", 78.9) // 78.90000 // Imprime string basicas `%s`. fmt.Printf(\"%s\\n\", \"\\\"string\\\"\") // \"string\" // Imprimir Booleano fmt.Printf(\"%t\\n\", a ==b) // true o false // Imprime un puntero`%p`. fmt.Printf(\"%p\\n\", &p) // 0x42135100 fmt.Sprint() - devuelve el resultado a una string fmt.Sprintln() - devuelve el resultado con salto de linea a una string fmt.Sprintf() - devuelve el resultado con un determinado formato a una string // las Sxxx() son como las normales en vez de imprimir el resultado // lo devuelven como un string s := fmt.Sprintf(\"Hi, my name is %s and I'm %d years old.\", \"Bob\", 23) // s vale \"Hi, my name is Bob and I'm 23 years old.\" fmt.Scan() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea cuentan como espacio fmt.Scanln() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea acaban con la lectura de datos verbos - General %v - valor en formato por defecto. En structs %+v a\u00f1ade los nombres de los campos %T - tipo del valor %#v - representacion del tipo del valor con sintaxis de golang - Booleano %t - booleano, devuelve palabra true o false - Integer %b - devuelve en base 2 %c - devuelve caracter representado por el correspondiente codigo Unicode %d - devuelve en base 10 %U - formato Unicode - Floating point f% - notacion decimal sin exponentes e% - notacion decimal con exponentes - Strings y []byte %s - cadenas normales %q - para escapar comillas dobles %x - convierte a base hexadecimal STRINGS import \"strings\" strings.Contains(\"test\", \"es\") = true - Contiene \"test\" a \"es\" strings.Count(\"test\", \"t\") = 2 - Cuantas \"t\" hay en \"test\" strings.HasPrefix(\"test\", \"te\") = true - Comienza \"test\" por \"te\" strings.HasSuffix(\"test\", \"st\") = True - Acaba \"test\" en \"st\" strings.Index(\"test\", \"e\") = 1 - Posicion de string \"e\" dentro de string \"test\", si no esta devuelve -1 strings.Join([]string{\"a\",\"b\"}, \"-\") = \"a-b\" - Coge una lista de strings y las junta en una separadas por otra string (\"-\" en el ejemplo) strings.Repeat(\"a\", 5) = aaaaa - Repite una string n veces strings.Replace(\"aaaa\", \"a\", \"b\", 2) = \"bbaa\" - reemplaza en una cadena una parte por otra n veces (o todas las que se pueda si pasamos -1) strings.Split(\"a-b-c-d-e\", \"-\") = []string{\"a\",\"b\",\"c\",\"d\",\"e\"} - Parte una string en un array de strings usando otra string como separador strings.ToLower(\"test\") = \"TEST \"- convierte la cadena a minusculas strings.ToUpper(\"TEST\") = \"test\" - convierte la cadena a mayusculas strings.Fields(\"cadena que sea) = como split usando espacios en blanco. es equivalente a si usaramos strings.Split(text, \" \") strings.Trim(\"cadena\",\"loquecorta\") = elimina en cadena todas las loquecorta pero solo del comienzo y del final strings.Trim(\" !!! Achtung! Achtung! !!! \", \"! \") == [\"Achtung! Achtung\"] Convertir string en slice of bytes y viceversa arr := []byte(\"test\") str := string([]byte{'t','e','s','t'}) Fuera del paquete string len(\"aquiunacadena\") - nos da la longitud de la string \"cadena\"[3] - nos da el codigo ASCII del caracter de indice 3, \"e\" = 101 string(cadena[n]) - nos da el caracter de la cadena en la posicion n STRCONV import \"strconv\" - conversiones entre numeros y strings s := strconv.Itoa(-42) - int to string i, err := strconv.Atoi(\"-42\") - string to int b, err := strconv.ParseBool(\"true\") - string to boolean f, err := strconv.ParseFloat(\"3.1415\", 64) - string to float i, err := strconv.ParseInt(\"-42\", 10, 64) - string to int u, err := strconv.ParseUint(\"42\", 10, 64) - string to uint s := strconv.FormatBool(true) - boolean value to string s := strconv.FormatFloat(3.1415, 'E', -1, 64) - float to string s := strconv.FormatInt(-42, 16) - int to string s := strconv.FormatUint(42, 16) - uint to string APPEND Trucos con slices func append(slice []T, elements...T) []T. IO import \"io\" Tiene dos interfaces principales Reader soporta leer a a traves del metodo Read Writer soporta escribir a traves del metodo Write IO/IOUTIL import io/ioutil leer y escribir un archivo De esta forma cargamos todo el archivo en memoria de golpe. Mas control a traves de un File struct del paquete OS data := []byte(\"Hello World!\\n\") // write err := ioutil.WriteFile(\"data1\", data, 0644) if err != nil { panic(err) } //read read, err := ioutil.ReadFile(\"data1\") if err != nil { return } fmt.Print(string(read1)) Limitar tama\u00f1o io defer resp.Body.Close() limitReader := &io.LimitedReader{R: resp.Body, N: 2e6} // (2mb) body, err := ioutil.ReadAll(limitReader) OS import \"os\" Saber donde estamos os.Getwd() leer escribir un archivo // Una forma file, err := os.Open(\"test.txt\") if err != nil { // handle the error here } defer file.Close() stat, err := file.Stat() // get the file size if err != nil { return } bs := make([]byte, stat.Size()) // read the file _, err = file.Read(bs) if err != nil { return } str := string(bs) fmt.Println(str) // otra forma data := []byte(\"Hello World!\\n\") // write to file and read from file using the File struct file1, _ := os.Create(\"data2\") defer file1.Close() bytes, _ := file1.Write(data) fmt.Printf(\"Wrote %d bytes to file\\n\", bytes) file2, _ := os.Open(\"data2\") defer file2.Close() read2 := make([]byte, len(data)) bytes, _ = file2.Read(read2) fmt.Printf(\"Read %d bytes from file\\n\", bytes) fmt.Println(string(read2)) crear un archivo func main() { file, err := os.Create(\"test.txt\") if err != nil { return } defer file.Close() file.WriteString(\"test\") } Leer el contenido de un directorio Readdir - coge un argumento que es el numero de entradas que devuelve. Con -1 devuelve todas func main() { dir, err := os.Open(\".\") if err != nil { return } defer dir.Close() fileInfos, err := dir.Readdir(-1) if err != nil { return } for _, fi := range fileInfos { fmt.Println(fi.Name()) } } Walk - para recorrer recursivamente un directorio. Pertenece al paquete path/filepath Command line arguments el primer valor del slice de argumentos es el nombre del comando path incluido argsWithProg := os.Args - slice completo con comando nombre path incluido argsWithoutProg := os.Args[1:] - slice solo de argumentos arg := os.Args[x] - devuelve argumento de posicion X environment variables os.Setenv(\"nombreVariable\", \"valor\") - establece un par clave/valor para una variable de entorno os.Getenv(\"nombreVariable\") - devuelve el valor de esa clave // os.Environ es una lista de todas las variables de entorno for _, e := range os.Environ() { pair := strings.Split(e, \"=\") fmt.Println(pair[0], \"-->\", pair[1]) } PATH/FILEPATH import path/filepath Recorrer recursivamente un directorio Walk func main() { filepath.Walk(\".\", func(path string, info os.FileInfo, err error) error { fmt.Println(path) return nil }) } REGEXP import \"regexp\" // Comprueba si es una cadena patron := \"loquequeremoscomprobar\" match, _ := regexp.MatchString(\"p([a-z]+)ch\", patron) fmt.Println(match) // o compilamos primero una struct optimizada para regexp patron := \"loquequeremoscomprobar\" r, _ := regexp.Compile(\"p([a-z]+)ch\") fmt.Println(r.MatchString(patron)) // Por ejemplo cambiar en la cadena s los guiones bajos por guiones r := regexp.MustCompile(\"_\") s = r.ReplaceAllString(s, `-`) JSON import \"encoding/json\" Golang JSON dataJson, err := json.Marshal(structObject) - Go struct data to JSON data dataJson, err:= json.MarshalIndent(strObj, \"\", \" \") - bien preformateado err := json.Unmarshal(dataJson, &structObject) - JSON data to Go struct data urlDir := \"https://domain.tld/api/que/queramos\" resp, err := http.Get(urlDir) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } body = body[5 : len(body)-6] // quitar mis pegatinas de
             var s structObject err = json.Unmarshal(body, &s) fmt.Println(s) Convertir json to go struct JSON-to-Go online json:\"-\" ignora ese campo tanto al convertir a json o al convertir desde json json:\"nombreCampo,omitempy - no se incluye el campo al convertir a json si ese campo ya tiene un valor por defecto. Decoder Ademas de Unmarshal/Marshal existe Decoder/Encoder , que se debe usar si los datos vienen de una stream io.Reader como por ejemplo el Body de una http.Request. Si los datos estan en una string o en memoria mejor usar Unmarshal type configuration struct { lo que sea } file, _ := os.Open(\"conf.json\") defer file.Close() decoder := json.NewDecoder(file) conf := configuration{} err := decoder.Decode(&conf) if err != nil { fmt.Println(\"Error:\", err) } fmt.Println(conf) Parsing Interfaces An\u00e1lisis de una interfaz Si realmente no tienes ni idea de c\u00f3mo podr\u00eda ser tu JSON, se puede analizar en una interfaz gen\u00e9rica{}. Una interfaz vac\u00eda es una forma de definir una variable en Go como \"esto podr\u00eda ser cualquier cosa\". En tiempo de ejecuci\u00f3n, Go asignar\u00e1 la memoria adecuada para que se ajuste a lo que decida almacenar en ella. Esto es lo que parece: var parsed interface{} err := json.Unmarshal(data, &parsed) En realidad, el uso de parsed es un poco laborioso, ya que Go no puede usarlo sin saber de qu\u00e9 tipo es. switch parsed.(type) { case int: someGreatIntFunction(parsed.(int)) case map: someMapThing(parsed.(map)) default: panic(\"JSON type not understood\") } Tambi\u00e9n puedes hacer aserciones de tipo similares en l\u00ednea: intVal, ok := parsed.(int) if !ok { panic(\"JSON value must be an int\") } Afortunadamente, sin embargo, es raro no tener idea de lo que puede ser un valor. Si, por ejemplo, sabe que su valor JSON es un objeto, puedes analizarlo en una interfaz de map[string]interface{}. Esto te da la ventaja de poder referirte a claves espec\u00edficas. Un ejemplo: var parsed map[string]interface{} data := []byte(` { \"id\": \"k34rAT4\", \"age\": 24 } `) err := json.Unmarshal(data, &parsed) A continuaci\u00f3n, puedes referirte a las teclas espec\u00edficas sin ning\u00fan problema: parsed[\"id\"] Sin embargo, todav\u00eda tienes interfaces como valor de su map, por lo que debes hacer type assertions para utilizarlas: idString := parsed[\"id\"].(string) Go utiliza estos seis tipos para todos los valores analizados en las interfaces: bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null Es decir, tus n\u00fameros siempre ser\u00e1n de tipo float64, y necesitar\u00e1n ser casteados a int, por ejemplo. Si tiene una necesidad de obtener enteros directamente, puedes usar el m\u00e9todo UseNumber. Lo que te da un objeto que puede convertirse en un float64 o en un int a tu discreci\u00f3n. De manera similar, todos los objetos decodificados en una interfaz ser\u00e1n map[string]interface{}, y necesitar\u00e1n ser mapeados manualmente a cualquier estructura aue quieras usar. Sobre JSON TIME import \"time\" now := time.Now() - nos da la hora actual 2012-10-31 15:50:13.793654 +0000 UTC then := time.Date(2015, 10, 10, 18, 30, 08, 0, time.UTC) - Creamos un struct de tiempo asociado a una localizacion (time zone) then.Year() then.Month() then.Day() then.Hour() then.Minute() then.Second() then.Nanosecond() then.Location() then.Weekday() then.Before(now) then.After(now) then.Equal(now) diff := now.Sub(then) - metodo Sub devuelve duracion del intervalo entre dos tiempos diff.Hours() diff.Minutes() diff.Seconds() diff.Nanoseconds() // avanzar o retroceder en el tiempo then.Add(diff) then.Add(-diff) // sumar tiempo tiempoQueSea.Add( 1000 * time.Hours) String to Time // pasar una fecha a string segun un determinado formato layout := \"2006-01-02 15:04:05\" t, err := time.Parse(layout1, start) if err != nil { fmt.Prinltln(err) } // Hora actual a string con determinado formato horaActual = time.Now().Format(layout) Time to String myString = myTime.String() Timestamp Unix epoch now := time.Now() secs := now.Unix() nanos := now.UnixNano() millis := nanos / 1000000 time.Unix(secs, 0) time.Unix(0, nanos) Intervalos timers - para hacer algo una vez dentro de un tiempo timer1 := time.NewTimer(time.Second * 2) <-timer1.C fmt.Println(\"Timer 1 expired\") timer2 := time.NewTimer(time.Second) go func() { <-timer2.C fmt.Println(\"Timer 2 expired\") }() stop2 := timer2.Stop() if stop2 { fmt.Println(\"Timer 2 stopped\") } // Timer 1 expired // Timer 2 stopped // Timer 2 expired NUNCA APARECE, se cancela antes tickers - para hacer algo repetidamente a intervalos regulares ticker := time.NewTicker(time.Millisecond * 500) go func() { for t := range ticker.C { fmt.Println(\"Tick at\", t) } }() time.Sleep(time.Millisecond * 1600) ticker.Stop() fmt.Println(\"Ticker stopped\") MATH import \"math\" math.Floor(x float64) float64 - devuelve el entero (int) mas grande poisble menor o igual que x math.Pow(x,y float64) float64 - x elevado a y MATH/RAND import \"math/rand\" rand.Intn(10) - genera un numero aleatorio entero >= 0 y < 10 rand.Float64() - genera un numero aleatorio >= 0.0 y < 1.0 (rand.Float64()*5)+5 - genera entre >= 5.0 y < 10.0 s1 := rand.NewSource(time.Now().UnixNano()) - semilla para que no sea siempre igual r1 := rand.New(s1) - para ir cambiando la semilla rand.Seed(time.Now().UTC().UnixNano()) - otra forma de cambiar la semilla para que no siempre sea igual func init() { //fmt.Println(`Init from package tracker`) r = rand.New(rand.NewSource(time.Now().UnixNano())) } var r *rand.Rand func createRandomString() string { const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\" result := \"\" for i := 0; i < lenID; i++ { result += string(chars[r.Intn(len(chars))]) } return result } DATABASE/SQL database/sql FLAG import \"flag\" Para enviar argumentos a un comando Ejemplos SORT import sort Contiene funciones para ordenar datos arbitrario de slices de ints y floats y structs definidas por el usuario s = []strings sort.strings(s) - De menor a mayor alfabeticamente n = []ints || float32 || float64 sort.Ints(n) - Ordena los numeros de menor a mayor sort.IntsAreSorted(n) - booleano que devuelve si estan ordenados custom sorting package main import \"sort\" import \"fmt\" // If I have an array/slice of structs in Go and want to sort them // using the sort package it seems to me that I need to implement // the whole sort interface which contains 3 methods: // https://golang.org/pkg/sort/#Interface type ByLength []string func (s ByLength) Len() int { return len(s) } func (s ByLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s ByLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) } func main() { fruits := []string{\"peach\", \"banana\", \"kiwi\"} sort.Sort(ByLength(fruits)) fmt.Println(fruits) }","title":"Golang"},{"location":"golang/#golang-121x","text":"","title":"GOLANG 1.21.X"},{"location":"golang/#instalacion","text":"descargarlo de aqui Como root tar -C /usr/local -xzf go-file.tar.gz // como usuario nano $HOME/.bashrc nano $HOME/.profile // a\u00f1adir a cada uno # Golang conf export PATH=$PATH:/usr/local/go/bin export GOPATH=$HOME/path/to/golang/code export PATH=$PATH:$GOPATH/bin // La siguiente linea hay veces que es necesaria export GOBIN=$PATH:$GOPATH/bin Para recargar la configuracion source ~/.profile Carpetas que se crean: bin - Contiene los binarios compilados. Podemos a\u00f1adir la carpeta bin al path del sistema para hacer los binarios compilados ejecutables desde cualquier sitio pkg - contiene los versiones compiladas de las librerias disponibles para que el compilador las pueda enlazar sin tener que recompilarlas src - contiene todo el codigo organizado por rutas de import VS Code Go: Install/Update Tools","title":"INSTALACION"},{"location":"golang/#enlaces-utiles","text":"Go Interfaces Tipos de funcion Modulos Ejemplos - gobyexample Ejemplos - rosettacode GO MODULES en VSCODE GO MODULES en VSCODE Blogs Jacob Martin - Articulos y tutoriales Dave Cheney Alex Edwards Desarrollo Web Writing Web Applications - Tutorial basico de la wiki de golang.org Ejemplos Golang para web - gowebexamples Librerias database/sql go-sql-driver/mysql gorilla-websocket gobwas-ws Utilidades curl-to-Go - Herramienta online que convierte comandos curl en codigo Go JSON-to-Go - Herramienta online que convierte JSON en structs para Go Despliegue y seguridad","title":"ENLACES UTILES"},{"location":"golang/#go-tool","text":"go  [arguments] The commands are: bug start a bug report build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages or modules mod module maintenance run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages Use \"go help \" for more information about a command. Additional help topics: buildmode build modes c calling between Go and C cache build and test caching environment environment variables filetype file types go.mod the go.mod file gopath GOPATH environment variable gopath-get legacy GOPATH go get goproxy module proxy protocol importpath import path syntax modules modules, module versions, and more module-get module-aware go get packages package lists and patterns testflag testing flags testfunc testing functions Use \"go help \" for more information about that topic.","title":"GO TOOL"},{"location":"golang/#install","text":"// descarga el codigo y todas sus dependencias. Lo compila e instala el // binario en el directorio $GOPATH/bin go install github.com/ruta/codigo // instalar la ultima version go install ruta/codigo@latest","title":"install"},{"location":"golang/#build","text":"// -o nombre para el ejecutable go build -o nombreEjecutable program.go // -s -w eliminan el debug y hacen mas peque\u00f1o el binario go build -ldflags \"-s -w\" // para incluir la fecha en el binario go build -ldflags=\"-X 'main.releaseDate=$(date -u +%F_%T)'\" GOOS - sistema operativo para el que compilamos GOARCH - procesador para el que se compila GOOS=darwin GOARCH=386 go build GOOS=linux GOARCH=amd64 go build -o geoip // -o fuerza el nombre del binario al del parametro GOOS= GOARCH= windows 386 windows amd64 linux 386 linux amd64 linux arm linux arm64 android arm darwin 386 darwin amd64 darwin arm darwin arm64 Lista de combinaciones validas de sistema operativo y arquitectura Usando cgo Ejemplo : usar libreria de C bearlibterminal con bindings para Go. Descargar aqui libBearLibTerminal.so (de linuxx64) va a /usr/lib en gopath (mi caso $HOME/.golang/src/bearlibterminal) ponemos BearLibTerminal.go (los bindings a go) y BearLibTerminal.h (las cabeceras de C) Ahora ya podemos importar la libreria y usarla import ( blt \"bearlibterminal\" ) Para Compilar a Windows usr/bin/ld: cannot find -l // o mingw-64, no tengo claro como van todas esos paquetes tan // similares apt-get install gcc-mingw-w64-x86-64 gcc-multilib cd /usr/x86_64-w64-mingw32/lib // poner ahi todas las librerias para windows *.dll y *.lib GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build main.go","title":"build"},{"location":"golang/#operadores","text":"Aritmeticos + Suma - Resta * Multiplicacion / Division % Modulo, lo que sobra de la division entera ++ Incremento -- Decremento Asignacion = x = y += x = x + y -= x = x - y *= x = x * y /= x = x / y %= x = x % y Comparacion == igual != no igual > mayor que < menor que >= mayor o igual que <= menor o igual que Logicos && AND || OR ! NOT Punteros & devuelve la direccion de una variable * puntero a una variable","title":"OPERADORES"},{"location":"golang/#variables","text":"Una variable puede contener cualquier tipo, incluso una funcion func main() { accion := func() { fmt.Println(\"Hola\") } accion() } TypeOf(variable) Para averiguar de que tipo es una variable import (\"reflect\") fmt.Println(\"....\", reflect.TypeOf(variable))","title":"VARIABLES"},{"location":"golang/#declaracion","text":"Declaracion de variables var ( name string age int location string ) var ( name, location string age int ) var name string Inicializacion de variables var ( name string = \"jolav\" age int = 100 ) var ( // inferred typing name = \"jolav\" age = 32 ) var name, location, age = \"jolav\", \"casa\", 100 Sentencia de asignacion := Dentro de una funcion podemos usar := en lugar de var func main() { name, location := \"jolav\", \"casa\" age := 100 } new Pone a cero el valor del tipo y devuelve un puntero a el. x := new(int) make Necesario para slices maps y channels Zero Values Cuando se declaran variables sin un valor explicito se les asigna el valor zero int - 0 float - 0.0 string - \"\" boolean - false pointers - nil map - nil slices - nil array - array listo para usar con sus elementos a zero value que sea functions - nil interfaces - nil channels -nil type package tempconv import \"fmt\" type Celsius float64 type Fahrenheit float64 const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 ) func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }","title":"Declaracion"},{"location":"golang/#alcance","text":"El alcance es la region del programa donde una variable definida existe Tipos de variables segun donde se declaren: local variables - dentro de una funcion o un bloque. Fuera de ese entorno no existen package variables - fuera de todas las funciones o bloques. Accesibles desde cualquier parte del paquete formal parameters - en la definicion de los parametros de una funcion. Se tratan como locales para esa funcion y tienen preferencia sobre las globales Cuando coinciden dentro de una funcion o bloque una local y una global prevalece la local","title":"Alcance"},{"location":"golang/#conversion-de-tipos","text":"Go no tiene conversion implicita de tipos T(v) - Convierte el valor v al tipo T i := 42 f := float64(i) u := uint(f) strconv Type Assertion func diffArray(s1, s2 interface{}) []string { var aux1 []int fmt.Println(reflect.TypeOf(s1)) var a1, a2 []string if reflect.TypeOf(s1) == reflect.TypeOf(aux1) { // s1,s2 son []int a1, a2 = convertIntToString(s1.([]int), s2.([]int)) // pasamos s1,s2 como []int y usando type assertion } else { a1, a2 = s1.([]string), s2.([]string) } // aqui ya a1,a2 son []string func diffTwoArrays() { diffArray([]int{1, 2, 3, 5}, []int{1, 2, 3, 4, 5})) diffArray([]string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"}, []string{\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"}) }","title":"Conversion de tipos"},{"location":"golang/#punteros","text":"Punteros vs Valor Un puntero contiene la direccion de memoria de un valor Todo en Go se pasa por valor, pero ... Cuando se declara una variable de tipo de referencia se crea un valor llamado header value que contiene un puntero a la estructura de datos subyacente necesaria para segun cada tipo de referencia. Cada tipo de referencia contiene campos unicos para gestionar la estructura de datos subyacente propia. El header value contiene un puntero, por lo tanto puedes pasar una copia de cualquier tipo de referencia y compartir la estructura subyacente intrinsicamente al compartir el puntero. int - valor float - valor string - variable de tipo de referencia, pero funciona como valor boolean - valor arrays - valor slices - variable de tipo de referencia maps - variable de tipo de referencia functions - variable de tipo de referencia interfaces - variable de tipo de referencia channels - variable de tipo de referencia Punteros Por defecto Go pasa los argumentos por valor (crea una copia) Para pasarlos por referencia hay que pasar punteros o usar estructuras de datos que usan valores por referencia como slices y maps. & - para conseguir el puntero de un valor lo ponemos delante de su nombre * - para desreferenciar un puntero y que nos de acceso a su valor Si p es un puntero a x &x --> p = &x p es el puntero de x (contiene la direccion de memoria de x) *p --> *p = x *p es el valor de x i := 42 p := &i // P es un puntero a i fmt.Println(*p) // 42 , lee i a traves del puntero p *p = 21 // establece i a traves del puntero p func main() { v := *getPointer() fmt.Println(\"Value is\", v) // Value is 100 m := getPointer() fmt.Println(\"Memory is\", m) // Memory is 0xc00018c020 } func getPointer() (myPointer *int) { a := 100 return &a } func main() { x := 5 zero(&x) fmt.Println(x) // x is 0 } func zero(x *int) { *x = 0 } func main() { var i int = 7 var p *int p = &i fmt.Println(\"i : \" , i) fmt.Println(\"memory address of i : \", &i) fmt.Println(\"p : \" , p) fmt.Println(\"*p : \" , *p) } [output] i : 7 memory address of i : 0x10328000 p : 0x10328000 *p : 7 new new - coge un tipo como argumento, asigna suficiente memoria para ese tipo de dato y devuelve un puntero que apunta a esa memoria. Luego el GC (garbage collector lo limpia todo) func zero(x *int) { *x = 5 } func main() { x := new(int) zero(x) fmt.Println(*x) // x is 5 } Mutabilidad Solo las constantes son inmutables. Sin embargo como los argumentos se pasan por valor, una funcion que recibe y modifica un argumento no muta el valor original Ejemplo func addOne(x int) { x++ } func main() { x := 0 addOne(x) fmt.Println(x) // x da 0 } // Si usamos punteros func addOne(x *int) { *x++ } func main() { x := 0 addOne(&x) fmt.Println(x) // x da 1 } LECTURA FUNDAMENTAL, stackoverflow pointer vs values type data struct { val int } func myfunc() data { // devuelve una copia del struct return data{val: 1} } func myfunc() *data { // devuelve un puntero al struct creado dentro de la funcion return &data{} } func myfunc(d *data) { // recibe un struct ya existente y sobreescribe su valor d.val = 1 }","title":"Punteros"},{"location":"golang/#datos-basicos","text":"","title":"DATOS BASICOS"},{"location":"golang/#numeros","text":"Cuando se definen numeros de forma literal se puede usar guion bajo _ para hacerlos mas legibles const segundosEnUnA\u00f1o = 31_557_600 Integers Los enteros son numeros sin decimal int - positivos y negativos uint - unsigned, solo los positivos byte - alias de uint8 (0-255) rune - alias de int32 Numeros de Punto Flotante Son numeros reales (con parte decimal) float32 - conocido como simple precision float64 - conocido como doble precision Numeros Complejos complex64 - parte real float32 + partes imaginarias complex128 - parte real float64 + partes imaginarias","title":"Numeros"},{"location":"golang/#booleanos","text":"&& - and || - or ! - not","title":"Booleanos"},{"location":"golang/#cadenas","text":"Estan hechas de bytes (uno por caracter) La diferencia entre comillas simples o dobles es que en estas no pueden contener nuevas lineas y se permiten escapar caracteres especiales len(string) - longitud de la cadena \"Hola mundo\"[1] - acceder a caracteres de la cadena \"Hello, \" + World\"","title":"Cadenas"},{"location":"golang/#constantes","text":"Se declaran como variables pero con la palabra clave const . No se pueden declarar usando := Solo pueden ser caracteres, string, booleano o valores numericos. const PI = 3.14","title":"Constantes"},{"location":"golang/#iota","text":"iota info Es un identificador usado en declaraciones de constantes para indicar que son autoincrementables. . Se resetea a cero cuando aparece la palabra reservada const const ( // iota is reset to 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 )","title":"Iota"},{"location":"golang/#estructuras-de-control","text":"","title":"ESTRUCTURAS DE CONTROL"},{"location":"golang/#for","text":"for init; condition; post { } // for normal sum := 0 for i := 0; i < 10; i++ { sum = sum + i } for condition { } // for sin declaraciones pre/post que funciona como un while. Podemos // tambien quitar hasta los punto y coma sum := 1 for ; sum < 1000; { for sum < 1000 { sum = sum + sum } for {} // for infinito for { ..codigo }","title":"for"},{"location":"golang/#if","text":"if answer != 42 { return \"Wrong answer\" } if err := foo(); err != nil { panic(err) } if { // codigo } else { // codigo }","title":"if"},{"location":"golang/#switch","text":"switch en golang Solo se pueden comparar valores del mismo tipo declaracion default para ejecutarse si todas las demas fallan en la declaracion se puede usar una expression (pej calcular un valor) case 300 - 150: Se puede tener multiples valores un solo caso case 6, 7: fallthroguh se ejecutan todas las declaraciones que cumplen la condicion break sale del switch, por defecto en cada opcion es automatico el break t := time.Now() switch { case t.Hour() < 12: fmt.Println(\"Good morning!\") case t.Hour() < 17: fmt.Println(\"Good afternoon.\") default: fmt.Println(\"Good evening.\") } switch os := runtime.GOOS; os { case \"darwin\": fmt.Println(\"OS X.\") case \"linux\": fmt.Println(\"Linux.\") default: // freebsd, openbsd,plan9, windows... fmt.Printf(\"%s.\\n\", os) }","title":"switch"},{"location":"golang/#range","text":"Para iterar sobre array , slice , string , map o leer de un channel El valor que nos da range es una copia del valor del elemento original y por tanto si se modifica no afecta al original for k,v := range zoo { v.age = 10 // no modifica el original zoo[k].age = 999 // SI modifica el original } slice var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key, value := range pow { fmt.Println(\"Posicion\", key, \"valor\", value) } Podemos omitir el index o el value usando _ for i, _ := range pow for _, value := range pow Podemos omitir tambien el valor omitiendo por completo , value var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} for key := range pow { fmt.Println(\"Posicion\", key) } for _, value := range pow { fmt.Println(\"valor\", value) } map El primer parametro no es un entero autoincrementable sino la clave del map for key, value := range cities break Paras la iteracion en cualquier momento continue Omites una iteracion","title":"range"},{"location":"golang/#arrays","text":"tipo [n]T - es un array de n elementos de tipo T No se pueden redimensionar Se pueden inicializar al declararlos a := [2]string{\"hello\", \"world!\"} a := [...]string{\"hello\", \"world!\"} usando una ellipsis para indicar un numero variable de elementos que en este caso son dos a := [5]int{1: 10, 2: 20} - inicializando solo algunos valores Mostrar arrays fmt.Printf(\"%q\\n\", a) // [\"hello\" \"world!\"] len(array) MultiDimensionales var a [4][2]int array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}","title":"ARRAYS"},{"location":"golang/#slices","text":"tipo []T - es un slice de elementos de tipo T Crear un slice : Los slice hay que crearlos antes de usarlos slice literal mySlice := []int{2, 3, 5, 7, 11, 13} make - crea un slice vacio de una longitud y (opcional una capacidad) cities := make([]string, len, cap) Recortando un slice s[a:b] - selecciona elementos desde la pos a (inclusive) hasta b (exclusive) s[:b] - un indice a que no se declara es un 0 implicito s[a:] - un indice b que no se declara es implicito un len(s) A\u00f1adiendo a un slice cities = append(cities, \"San Diego\") cities = append(cities, \"San Diego\", \"Mountain View\") otherCities := []string{\"Santa Monica\", \"Venice\"} cities = append(cities, otherCities...) Copiar un slice copy(destino, origen) Length len(slice) Nil slices Declaracion var z []int - El valor cero de un slice es nil. Un slice nil tiene una longitud de cero Inicializacion z := make([]int, 0) z := []int{} Las tres formas son lo mismo BiDimensional // allocate composed 2d array a := make([][]int, row) for i := range a { a[i] = make([]int, col) } // allocate composed 2d array a := make([][]int, row) e := make([]int, row * col) for i := range a { a[i] = e[i*col:(i+1)*col] } // otra posibilidad func get(r, c int) int { return e[r*cols+c] }","title":"SLICES"},{"location":"golang/#maps","text":"tipo map[a]b - es un map de claves tipo a con valores tipo b Formado por pares clave/valor Crear un map : Los map hay que crearlos antes de usarlos map literal amigos := map[string]int{\"Juan\":50, \"Elena\":21, \"Carlos\":41,} make - creas un nil map vacio amigos := make(map[string]int) Si lo declaramos pero no lo inicializamos, al intentar a\u00f1adir elementos no compilara amigos := map[string]int{} - declarado pero no inicializado Modificando maps m[key] = elem - Insertando o actualizando un valor elem = m[key] - Devuelve el elemento delete(m, key) - Borrando un elemento elem, ok = m[key] - Testea si existe un valor con una clave determinada elements := map[string]map[string]string{ \"H\": map[string]string{ \"name\":\"Hydrogen\", \"state\":\"gas\", }, \"He\": map[string]string{ \"name\":\"Helium\", \"state\":\"gas\", }, \"Li\": map[string]string{ \"name\":\"Lithium\", \"state\":\"solid\", }, } if el, ok := elements[\"Li\"]; ok { fmt.Println(el[\"name\"], el[\"state\"]) }","title":"MAPS"},{"location":"golang/#structs","text":"Es una coleccion de campos/propiedades Solo los campos exportados (primera letra mayuscula) son accesibles de fuera del paquete","title":"STRUCTS"},{"location":"golang/#inicializacion","text":"type Circle struct { x, y, r float64 } var c Circle - crea una variable local Circle que pone por defecto los valores a cero (0 para int, 0.0 para float. \"\" para string, nil para punteros) c := new(Circle) - asigna memoria para todos los campos, los inicializa a cero y devuelve un puntero a la struct (*Circle), los punteros se usan mucho en structs paa que las funciones puedan modificar los datos. c := Circle{x: 0, y: 0, r: 5} c := Circle{0, 0, 5} c := &Circle{0, 0, 5} c := Circle{x: 1} c := Circle{} type Circle struct { x, y, r float64 } func main() { fmt.Println(c.x, c.y, c.r) c.x = 10 c.y = 5 } // todo en uno var addCases = []struct { in string want string }{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // mas claro type addCases2 []struct { in string want string } ac := addCases2{ { \"2011-04-25\", \"2043-01-01T01:46:40\", }, { \"1977-06-13\", \"2009-02-19T01:46:40\", }, } // para verlos for i, v := range addCases { fmt.Println(i, v.in) } for i, v := range ac { fmt.Println(i, v) } // con nombres fmt.Printf(\"%+v\\n\", struct) // bien formateado s, _ := json.MarshalIndent(g, \"\", \"\\t\") fmt.Print(string(s)) func show() { fmt.Println(t[0].hola) fmt.Println(test2[1].hola2) } type test []struct { hola string } var t = test{ {\"prueba1\"}, {\"prueba2\"}, } var test2 = []struct { hola2 string }{ {\"prueba3\"}, {\"prueba4\"}, }","title":"Inicializacion"},{"location":"golang/#metodos","text":"Un metodo es una funcion con el primer argumento implicito llamado receptor. func (ReceiverType r) func_name (parameters) (results) El receptor (receiver) del metodo esta entre la palabra clave function y el nombre del metodo func (u User) Greeting() string - nos permite llamarla con u.Greeting() Organizacion del codigo package models // list of packages to import // list of constants // list of variables // Main type(s) for the file, // try to keep the lowest amount of structs per file when possible. // List of functions // List of methods Alias Para definir metodos en un tipo que no es tuyo se usan alias import \"strings\" type MyStr string func (s MyStr) Uppercase() string { return strings.ToUpper(string(s)) } func main() { fmt.Println(MyStr(\"test\").Uppercase()) } Usar punteros en los receptores Los metodos se pueden asociar a un nombre o a puntero. Ventajas de usar punteros: evitar copiar el valor con cada llamada al metodo (pasarlo por referencia) para poder modificar el valor que pasamos type User struct { name string email string } func (u user) notify() { fmt.Printf(\"Mandar correo a %s<%s>\\n\", u.name, u.email) } // sin el puntero del receptor el correo no se cambiaria. func (u *user) changeEmail(email string) { u.email = email } SUGERENCIA Despu\u00e9s de declarar un nuevo tipo, trate de responder a esta pregunta antes de declarar m\u00e9todos para el tipo: \u00bf A\u00f1adir o quitar algo de un valor de este tipo necesita crear un nuevo valor o mutar el existente ? - Si la respuesta es crear un nuevo valor, usa receptores de valor en sus m\u00e9todos. - Si la respuesta es mutar el valor, usa receptores de puntero. Esto tambi\u00e9n se aplica a la forma en que los valores de este tipo deben pasarse a otras partes de su programa. Es importante ser consistente. La idea es no centrarse en lo que el m\u00e9todo est\u00e1 haciendo con el valor, sino centrarse en cu\u00e1l es la naturaleza del valor.","title":"Metodos"},{"location":"golang/#composicion","text":"type User struct { Id int Name, Location string } type Player struct { User GameId int } Podemos acceder a la Struct de User: a := new(Player) a.User.Name a.Name","title":"Composicion"},{"location":"golang/#interfaces","text":"Explicacion de interfaces Mas Explicacion de interfaces Mas aun sobre interfaces Es un conjunto de metodos Es un tipo de datos package main import \"fmt\" type cat struct { name string } func (c *cat) born() { fmt.Println(c.name, \"is born Miaouu\") } type dog struct { name string } func (d *dog) born() { fmt.Println(d.name, \"is born Wharff\") } type animal interface { born() } func born(a animal) { a.born() } func main() { Jasper := &cat{\"JASPER\"} Lucy := &dog{\"Lucy\"} Max := new(dog) Max.name = \"Max\" Max.born() // call born function born(Jasper) born(Lucy) born(Max) } package main import \"fmt\" type Human struct { name string age int phone string } type Student struct { Human //an anonymous field of type Human school string loan float32 } // A human likes to stay... err... *say* hi func (h *Human) SayHi() { fmt.Printf(\"Hi, I am %s you can call me on %s\\n\", h.name, h.phone) } // A human can sing a song, preferrably to a familiar tune! func (h *Human) Sing(lyrics string) { fmt.Println(\"La la, la la la, la la la la la...\", lyrics) } // A Human man likes to guzzle his beer! func (h *Human) Guzzle(beerStein string) { fmt.Println(\"Guzzle Guzzle Guzzle...\", beerStein) } // A Student borrows some money func (s *Student) BorrowMoney(amount float32) { s.loan += amount // (again and again and...) } func Prestar(y YoungChap, amount float32) { y.BorrowMoney(amount) } // INTERFACES type Men interface { SayHi() Sing(lyrics string) Guzzle(beerStein string) } type YoungChap interface { SayHi() Sing(song string) BorrowMoney(amount float32) } func main() { mike := Student{Human{\"Mike\", 25, \"222-222-XXX\"}, \"MIT\", 150.50} mike.BorrowMoney(10) mike.BorrowMoney(10) Prestar(&mike, 100) fmt.Println(\"Debe ..\", mike.loan) } interfaces vacias 1- Todo tiene un type , puedes definir un nuevo type por ejemplo T que tiene tres metodos A , B y C 2- El conjunto de metodos especificos de un type se llama interface type . En nuestro ejemplo T_interface = (A, B, C) 3- Puedes crear un nuevo interface type definiendo los metodos que tiene. Pro ejemplo creo MyInterface = (A) 4- Cuando especificas una variable de tipo interface type le puedes asignar solo los tipos que esten en una interface que sea un superset de tu interface, vamos que todos los metodos de MyInterface deben estar en T_interface Conclusion : Todos los tipos de variables satisfacen la empty interface . Por tanto una funcion que tiene una interface{} como argumento admite cualquier valor sea el que sea. Pero dentro de la funcion el runtime de Go convierte ese valor a un valor interface{} func DoSomething(v interface{}) { // la funcion acepta cualquier valor una vez dentro // v es del tipo interface{} } EL valor de una interfaz son dos word de datos: - una word es un puntero a una tabla de metodos para el valor del type subyacente - la otra word es un puntero a los datos actuales de ese valor","title":"INTERFACES"},{"location":"golang/#funciones","text":"Call Stack func main() { fmt.Println(f1()) } func f1() int { return f2() } func f2() int { return 1 } Argumentos Argumentos que reciben. Las funciones pueden recibir 0 o mas argumentos todos tipados despues del nombre de la variable. func add(x int, y int) int { return x + y } func add(x, y int) int { // int afecta a todos los parametros (x, y) return x + y } // ... funciones que aceptan un numero variable de parametros func add(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { // pasamos los parametros que queramos fmt.Println(add(1,2,3)) xs := []int{1,2,3} fmt.Println(add(xs...)) // tambien podemos pasar un slice } Retorno de parametros, puede devolver cualquier numero de ellos return region, continente // devuelve mas de un valor // Si los parametros de retorno estan nombrados vale con solo return func location(name, city string) (region, continent string) { ..codigo return // devuelve region y continent } Closures func generadorPares() func() uint { i := uint(0) return func() (ret uint) { ret = i i = i + 2 return } } func main() { nextPar := generadorPares() fmt.Println(nextPar()) // 0 fmt.Println(nextPar()) // 2 fmt.Println(nextPar()) // 4 } Recursion func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) }","title":"FUNCIONES"},{"location":"golang/#type-function","text":"package main import \"fmt\" type test_int func(int) bool // isOdd takes an ints and returns a bool set to true if the // int parameter is odd, or false if not. // isOdd is of type func(int) bool which is what test_int // is declared to be. func isOdd(integer int) bool { if integer%2 == 0 { return false } return true } // Same comment for isEven func isEven(integer int) bool { if integer%2 == 0 { return true } return false } // We could've written: // func filter(slice []int, f func(int) bool) []int func filter(slice []int, f test_int) []int { var result []int for _, value := range slice { if f(value) { result = append(result, value) } } return result } func main(){ slice := []int {1, 2, 3, 4, 5, 7} fmt.Println(\"slice = \", slice) odd := filter(slice, isOdd) fmt.Println(\"Odd elements of slice are: \", odd) even := filter(slice, isEven) fmt.Println(\"Even elements of slice are: \", even) }","title":"type function"},{"location":"golang/#defer","text":"Aplaza la ejecucion de una funcion hasta que termina la funcion en la que se encuentra. Lo tipico es cerrar archivos o desbloquear un mutex(mutual exclusion, para asegurar que solo una goroutine puede acceder a la vez a una variable) func main() { defer fmt.Println(\"world\") fmt.Println(\"hello\") } Se usa para liberar recursos cuando se pueda f, _ := os.Open(filename) defer f.Close()","title":"defer"},{"location":"golang/#panic-recover","text":"panic(\"valor de panic\") - crea un runtime error . recover() - detiene el panic y devuelve el valor que fue pasado con la llamada a panic Un panic generalmente indica un error de programacion o una condicion excepcional de la que no hay forma facil de recuperarse func main() { defer func() { str := recover() fmt.Println(str) }() panic(\"PANIC\") }","title":"panic, recover"},{"location":"golang/#concurrencia","text":"","title":"CONCURRENCIA"},{"location":"golang/#goroutines","text":"go f(x) comienza la ejecucion de una nueva goroutine que es una funcion capaz de ejecutarse concurrentemente con otras funciones. // sin wait, el programa main puede acabar antes de que las goroutines // hagan lo que tengan que hacer func parallelLetFreq() { var wg sync.WaitGroup wg.Add(3) // suma 3 a las goroutines a esperar go count(\"1\", &wg) go count(\"2\", &wg) go count(\"3\", &wg) wg.Wait() // espera a todas las goroutines (3 en este caso) } func count(n int, wg *sync.WaitGroup) { defer wg.Done() // al terminar la funcion terminar goroutine fmt.Println(\"Number --> \", n)) }","title":"goroutines"},{"location":"golang/#channels","text":"channels - son un conducto a traves del cual puedes recibir y enviar datos con el operador <- ch <- data - Envia data al canal ch data := <-ch - Recibe informacion del canal ch y lo asigna a data ch := make(chan int) - Los canales hay que crearlos antes de usarlos Por defecto los envios y recepciones esperan hasta que el otro lado este listo. Esto permite a las goroutines sincronizarse sin bloqueos especificos o condiciones func sum(a []int, c chan int) { sum := 0 for _, v := range a { sum += v } c <- sum // send sum to c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) } Buffered channels ch := make(chan int, 100) - Ponemos un buffer a los canales indicando su longitud como segundo argumento en el make para inicializar el canal Enviar datos aun canal con buffer se bloquea si el buffer esta lleno Recibir datos de un canal con buffer se bloquea si el buffer esta vacio func main() { c := make(chan int, 2) c <- 1; c <- 2; c <- 3 fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } // fatal error: all goroutines are asleep - deadlock! Sin embargo el siguiente funcionaria. Al a\u00f1adir el valor extra desde una goroutine no se bloquea el hilo principal pues aunque la goroutine se llama antes que el canal se vacie esta esperara hasta que haya espacio en el canal. func main() { c := make(chan int, 2) c <- 1; c <- 2 c3 := func() { c <- 3 } go c3() fmt.Println(<-c); fmt.Println(<-c); fmt.Println(<-c) } Close close(ch) - Solo un emisor puede cerrar un canal. Enviar a un canal cerrado causa un panic. No son como ficheros que hace falta cerrarlos. Solo se cierran para avisar al receptor de que no llegaran mas datos y para terminar los loop range v, ok := <-ch - Un emisor puede cerrar un canal para indicar que no se enviara nada mas. Los receptores pueden testear cuando un canal ha sido cerrado asignando un segundo parametro a la expresion receptora ok sera falso cuando no haya mas valores que recibir y el canal este cerrado. for i := range ch - recibe valores del canal hasta que se cierre Select Es como switch pero con canales 1A - 89 1B - 103","title":"channels"},{"location":"golang/#modules","text":"go mod init nombreModulo go mod init github.com/jolav/nombreModulo // listar todos los modulos con sus dependencias go list -m all go list all ./... // chechear paquetes con actualizaciones go list -m -u all go list -m -u -json all // actualizar // cambiar manualmenrte el archivo go.mod o // actualiza todas salvo nueva version mayor, go get -v -u ./... // para versiones especificas o nueva version mayor go get -v -u github.com/user/repo@v1.1.1 //despues para asegurar que el el codigo que tenemos en el modulo coincide // con el archivo gp.mod ejecutamos go mod tidy","title":"MODULES"},{"location":"golang/#paquetes","text":"Un programa Go esta hecho con paquetes. Los programas empiezan ejecutando la funcion main dentro del paquete main . Por convencion el nombre del paquete es la ultima palabra de la ruta del import. El paquete \"math/rand\" comprende archivos que comienzan con la sentencia package rand Paquetes que no son de la libreria estandar se importan usando una URL web, pero antes hay que descargarlos con go get go get github.com/creador/ruta/al/paquete import \"github.com/creador/ruta/al/paquete\" Despues de importar un paquete podemos usar los nombres que el exporta (sean variables, metodos o funciones) desde fuera de el paquete. Los nombres exportados en Go comienzan por letra mayuscula package main import ( \"fmt\" \"math\" ) func main() { fmt.Println(math.Pi) fmt.Println(math.pi) } // cannot refer to unexported name math.pi Otras formas de importar paquetes \u00ecmport alias \"fmt\" - Crea un alias de fmt. Ahora es alias.LoQueSea en lugar de fmt.LoQueSea import . \"fmt\" - Permite acceder al contenido directamente sin tener que ir precedido de fmt import _ \"fmt\" - Elimina las advertencia del compilado sobre ese paquete si no se usa y ejecuta si hay las funciones de inicializacion ( func init() {} ), El resto del paquete permanece inaccesible.","title":"PAQUETES"},{"location":"golang/#crear-paquetes","text":"Los nombres de paquetes coinciden con la carpeta donde estan. Esto se puede cambiar pero no merece la pena Por convencion el nombre del paquete es la ultima palabra de la ruta del import. ~/src/proyectoX/main.go package main import \"fmt\" import \"proyectoX/utilidades\" // la ruta es a partir de srcs func main() { // llamada a utilidades.Media(xs) } ~/src/proyectoX/utilidades/media.go package utilidades func Media() { // codigo que sea }","title":"Crear paquetes"},{"location":"golang/#desinstalar-paquetes","text":"go clean -i ruta/paquete... - teoricamente borras los pkg y bin, los src hay que borrarlos manualmente","title":"Desinstalar paquetes"},{"location":"golang/#actualizar","text":"go get -u all - Actualiza todos go get -u full/package/name - Actualizar solo ese paquete","title":"Actualizar"},{"location":"golang/#ejecucion","text":"El programa se inicia por la funcion main del package main Antes se ejecutan las funciones init de ese fichero Los paquetes importados \"_ import \"ruta/paquete\" hacen que el compilador acepte un paquete que no se usa y ademas ejecutan la o las funciones init de ese paquete","title":"EJECUCION"},{"location":"golang/#testing","text":"El compilador ignora todos los archivos que terminan en _test.go ~/src/proyectoX/utilidades/media_test.go package utilidades import \"testing\" type testpair struct { values []float64 average float64 } var tests = []testpair{ {[]float64{1, 2}, 1.5}, {[]float64{1, 1, 1, 1, 1, 1}, 1}, {[]float64{-1, 1}, 0}, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Media(pair.values) if v != pair.average { t.Error( \"For\", pair.values, \"expected\", pair.average, \"got\", v, ) } } } go test","title":"TESTING"},{"location":"golang/#errors","text":"Errores en Go Los captura un tipo interfaz predefinido cuyo unico metodo Error devuelve una cadena type error interface { Error() string } Forma estandard de tratar los errores. log.Fatal(err) - manda el error a la terminal y detiene el programa f, err := os.Open(\"filename.ext\") if err != nil { log.Fatal(err) } Podemos aligerar la repeticion un poco usando: func check(e error) { if e != nil { panic(e) } } // y ahora ya solo ponemos check(err)","title":"ERRORS"},{"location":"golang/#libreria-estandar","text":"","title":"LIBRERIA ESTANDAR"},{"location":"golang/#fmt","text":"import \"fmt\" fmt.Print() - imprime fmt.Println() - imprime y salta de linea fmt.Printf() - imprime con un determinado formato type point struct { x, y int } p := point{1, 2} fmt.Printf(\"%v\\n\", p) // {1 2} // en una struct, `%+v` incluye los nombres de los campos de la struct fmt.Printf(\"%+v\\n\", p) // {x:1 y:2} // Imprimir el tipo de un valor fmt.Printf(\"%T\\n\", p) // main.point // `%d` para enteros standard fmt.Printf(\"%d\\n\", 123) // 123 // Imprime el caracter que corresponde al entero fmt.Printf(\"%c\\n\", 65) // a // Imprime floats fmt.Printf(\"%f\\n\", 78.9) // 78.90000 // Imprime string basicas `%s`. fmt.Printf(\"%s\\n\", \"\\\"string\\\"\") // \"string\" // Imprimir Booleano fmt.Printf(\"%t\\n\", a ==b) // true o false // Imprime un puntero`%p`. fmt.Printf(\"%p\\n\", &p) // 0x42135100 fmt.Sprint() - devuelve el resultado a una string fmt.Sprintln() - devuelve el resultado con salto de linea a una string fmt.Sprintf() - devuelve el resultado con un determinado formato a una string // las Sxxx() son como las normales en vez de imprimir el resultado // lo devuelven como un string s := fmt.Sprintf(\"Hi, my name is %s and I'm %d years old.\", \"Bob\", 23) // s vale \"Hi, my name is Bob and I'm 23 years old.\" fmt.Scan() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea cuentan como espacio fmt.Scanln() - para leer una palabra del teclado , almacena sucesivos valores separados por un espacio en sucesivos argumentos. Saltos de linea acaban con la lectura de datos verbos - General %v - valor en formato por defecto. En structs %+v a\u00f1ade los nombres de los campos %T - tipo del valor %#v - representacion del tipo del valor con sintaxis de golang - Booleano %t - booleano, devuelve palabra true o false - Integer %b - devuelve en base 2 %c - devuelve caracter representado por el correspondiente codigo Unicode %d - devuelve en base 10 %U - formato Unicode - Floating point f% - notacion decimal sin exponentes e% - notacion decimal con exponentes - Strings y []byte %s - cadenas normales %q - para escapar comillas dobles %x - convierte a base hexadecimal","title":"FMT"},{"location":"golang/#strings","text":"import \"strings\" strings.Contains(\"test\", \"es\") = true - Contiene \"test\" a \"es\" strings.Count(\"test\", \"t\") = 2 - Cuantas \"t\" hay en \"test\" strings.HasPrefix(\"test\", \"te\") = true - Comienza \"test\" por \"te\" strings.HasSuffix(\"test\", \"st\") = True - Acaba \"test\" en \"st\" strings.Index(\"test\", \"e\") = 1 - Posicion de string \"e\" dentro de string \"test\", si no esta devuelve -1 strings.Join([]string{\"a\",\"b\"}, \"-\") = \"a-b\" - Coge una lista de strings y las junta en una separadas por otra string (\"-\" en el ejemplo) strings.Repeat(\"a\", 5) = aaaaa - Repite una string n veces strings.Replace(\"aaaa\", \"a\", \"b\", 2) = \"bbaa\" - reemplaza en una cadena una parte por otra n veces (o todas las que se pueda si pasamos -1) strings.Split(\"a-b-c-d-e\", \"-\") = []string{\"a\",\"b\",\"c\",\"d\",\"e\"} - Parte una string en un array de strings usando otra string como separador strings.ToLower(\"test\") = \"TEST \"- convierte la cadena a minusculas strings.ToUpper(\"TEST\") = \"test\" - convierte la cadena a mayusculas strings.Fields(\"cadena que sea) = como split usando espacios en blanco. es equivalente a si usaramos strings.Split(text, \" \") strings.Trim(\"cadena\",\"loquecorta\") = elimina en cadena todas las loquecorta pero solo del comienzo y del final strings.Trim(\" !!! Achtung! Achtung! !!! \", \"! \") == [\"Achtung! Achtung\"] Convertir string en slice of bytes y viceversa arr := []byte(\"test\") str := string([]byte{'t','e','s','t'}) Fuera del paquete string len(\"aquiunacadena\") - nos da la longitud de la string \"cadena\"[3] - nos da el codigo ASCII del caracter de indice 3, \"e\" = 101 string(cadena[n]) - nos da el caracter de la cadena en la posicion n","title":"STRINGS"},{"location":"golang/#strconv","text":"import \"strconv\" - conversiones entre numeros y strings s := strconv.Itoa(-42) - int to string i, err := strconv.Atoi(\"-42\") - string to int b, err := strconv.ParseBool(\"true\") - string to boolean f, err := strconv.ParseFloat(\"3.1415\", 64) - string to float i, err := strconv.ParseInt(\"-42\", 10, 64) - string to int u, err := strconv.ParseUint(\"42\", 10, 64) - string to uint s := strconv.FormatBool(true) - boolean value to string s := strconv.FormatFloat(3.1415, 'E', -1, 64) - float to string s := strconv.FormatInt(-42, 16) - int to string s := strconv.FormatUint(42, 16) - uint to string","title":"STRCONV"},{"location":"golang/#append","text":"Trucos con slices func append(slice []T, elements...T) []T.","title":"APPEND"},{"location":"golang/#io","text":"import \"io\" Tiene dos interfaces principales Reader soporta leer a a traves del metodo Read Writer soporta escribir a traves del metodo Write","title":"IO"},{"location":"golang/#ioioutil","text":"import io/ioutil leer y escribir un archivo De esta forma cargamos todo el archivo en memoria de golpe. Mas control a traves de un File struct del paquete OS data := []byte(\"Hello World!\\n\") // write err := ioutil.WriteFile(\"data1\", data, 0644) if err != nil { panic(err) } //read read, err := ioutil.ReadFile(\"data1\") if err != nil { return } fmt.Print(string(read1)) Limitar tama\u00f1o io defer resp.Body.Close() limitReader := &io.LimitedReader{R: resp.Body, N: 2e6} // (2mb) body, err := ioutil.ReadAll(limitReader)","title":"IO/IOUTIL"},{"location":"golang/#os","text":"import \"os\" Saber donde estamos os.Getwd() leer escribir un archivo // Una forma file, err := os.Open(\"test.txt\") if err != nil { // handle the error here } defer file.Close() stat, err := file.Stat() // get the file size if err != nil { return } bs := make([]byte, stat.Size()) // read the file _, err = file.Read(bs) if err != nil { return } str := string(bs) fmt.Println(str) // otra forma data := []byte(\"Hello World!\\n\") // write to file and read from file using the File struct file1, _ := os.Create(\"data2\") defer file1.Close() bytes, _ := file1.Write(data) fmt.Printf(\"Wrote %d bytes to file\\n\", bytes) file2, _ := os.Open(\"data2\") defer file2.Close() read2 := make([]byte, len(data)) bytes, _ = file2.Read(read2) fmt.Printf(\"Read %d bytes from file\\n\", bytes) fmt.Println(string(read2)) crear un archivo func main() { file, err := os.Create(\"test.txt\") if err != nil { return } defer file.Close() file.WriteString(\"test\") } Leer el contenido de un directorio Readdir - coge un argumento que es el numero de entradas que devuelve. Con -1 devuelve todas func main() { dir, err := os.Open(\".\") if err != nil { return } defer dir.Close() fileInfos, err := dir.Readdir(-1) if err != nil { return } for _, fi := range fileInfos { fmt.Println(fi.Name()) } } Walk - para recorrer recursivamente un directorio. Pertenece al paquete path/filepath Command line arguments el primer valor del slice de argumentos es el nombre del comando path incluido argsWithProg := os.Args - slice completo con comando nombre path incluido argsWithoutProg := os.Args[1:] - slice solo de argumentos arg := os.Args[x] - devuelve argumento de posicion X environment variables os.Setenv(\"nombreVariable\", \"valor\") - establece un par clave/valor para una variable de entorno os.Getenv(\"nombreVariable\") - devuelve el valor de esa clave // os.Environ es una lista de todas las variables de entorno for _, e := range os.Environ() { pair := strings.Split(e, \"=\") fmt.Println(pair[0], \"-->\", pair[1]) }","title":"OS"},{"location":"golang/#pathfilepath","text":"import path/filepath Recorrer recursivamente un directorio Walk func main() { filepath.Walk(\".\", func(path string, info os.FileInfo, err error) error { fmt.Println(path) return nil }) }","title":"PATH/FILEPATH"},{"location":"golang/#regexp","text":"import \"regexp\" // Comprueba si es una cadena patron := \"loquequeremoscomprobar\" match, _ := regexp.MatchString(\"p([a-z]+)ch\", patron) fmt.Println(match) // o compilamos primero una struct optimizada para regexp patron := \"loquequeremoscomprobar\" r, _ := regexp.Compile(\"p([a-z]+)ch\") fmt.Println(r.MatchString(patron)) // Por ejemplo cambiar en la cadena s los guiones bajos por guiones r := regexp.MustCompile(\"_\") s = r.ReplaceAllString(s, `-`)","title":"REGEXP"},{"location":"golang/#json","text":"import \"encoding/json\" Golang JSON dataJson, err := json.Marshal(structObject) - Go struct data to JSON data dataJson, err:= json.MarshalIndent(strObj, \"\", \" \") - bien preformateado err := json.Unmarshal(dataJson, &structObject) - JSON data to Go struct data urlDir := \"https://domain.tld/api/que/queramos\" resp, err := http.Get(urlDir) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } body = body[5 : len(body)-6] // quitar mis pegatinas de 
             var s structObject err = json.Unmarshal(body, &s) fmt.Println(s) Convertir json to go struct JSON-to-Go online json:\"-\" ignora ese campo tanto al convertir a json o al convertir desde json json:\"nombreCampo,omitempy - no se incluye el campo al convertir a json si ese campo ya tiene un valor por defecto. Decoder Ademas de Unmarshal/Marshal existe Decoder/Encoder , que se debe usar si los datos vienen de una stream io.Reader como por ejemplo el Body de una http.Request. Si los datos estan en una string o en memoria mejor usar Unmarshal type configuration struct { lo que sea } file, _ := os.Open(\"conf.json\") defer file.Close() decoder := json.NewDecoder(file) conf := configuration{} err := decoder.Decode(&conf) if err != nil { fmt.Println(\"Error:\", err) } fmt.Println(conf) Parsing Interfaces An\u00e1lisis de una interfaz Si realmente no tienes ni idea de c\u00f3mo podr\u00eda ser tu JSON, se puede analizar en una interfaz gen\u00e9rica{}. Una interfaz vac\u00eda es una forma de definir una variable en Go como \"esto podr\u00eda ser cualquier cosa\". En tiempo de ejecuci\u00f3n, Go asignar\u00e1 la memoria adecuada para que se ajuste a lo que decida almacenar en ella. Esto es lo que parece: var parsed interface{} err := json.Unmarshal(data, &parsed) En realidad, el uso de parsed es un poco laborioso, ya que Go no puede usarlo sin saber de qu\u00e9 tipo es. switch parsed.(type) { case int: someGreatIntFunction(parsed.(int)) case map: someMapThing(parsed.(map)) default: panic(\"JSON type not understood\") } Tambi\u00e9n puedes hacer aserciones de tipo similares en l\u00ednea: intVal, ok := parsed.(int) if !ok { panic(\"JSON value must be an int\") } Afortunadamente, sin embargo, es raro no tener idea de lo que puede ser un valor. Si, por ejemplo, sabe que su valor JSON es un objeto, puedes analizarlo en una interfaz de map[string]interface{}. Esto te da la ventaja de poder referirte a claves espec\u00edficas. Un ejemplo: var parsed map[string]interface{} data := []byte(` { \"id\": \"k34rAT4\", \"age\": 24 } `) err := json.Unmarshal(data, &parsed) A continuaci\u00f3n, puedes referirte a las teclas espec\u00edficas sin ning\u00fan problema: parsed[\"id\"] Sin embargo, todav\u00eda tienes interfaces como valor de su map, por lo que debes hacer type assertions para utilizarlas: idString := parsed[\"id\"].(string) Go utiliza estos seis tipos para todos los valores analizados en las interfaces: bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null Es decir, tus n\u00fameros siempre ser\u00e1n de tipo float64, y necesitar\u00e1n ser casteados a int, por ejemplo. Si tiene una necesidad de obtener enteros directamente, puedes usar el m\u00e9todo UseNumber. Lo que te da un objeto que puede convertirse en un float64 o en un int a tu discreci\u00f3n. De manera similar, todos los objetos decodificados en una interfaz ser\u00e1n map[string]interface{}, y necesitar\u00e1n ser mapeados manualmente a cualquier estructura aue quieras usar. Sobre JSON","title":"JSON"},{"location":"golang/#time","text":"import \"time\" now := time.Now() - nos da la hora actual 2012-10-31 15:50:13.793654 +0000 UTC then := time.Date(2015, 10, 10, 18, 30, 08, 0, time.UTC) - Creamos un struct de tiempo asociado a una localizacion (time zone) then.Year() then.Month() then.Day() then.Hour() then.Minute() then.Second() then.Nanosecond() then.Location() then.Weekday() then.Before(now) then.After(now) then.Equal(now) diff := now.Sub(then) - metodo Sub devuelve duracion del intervalo entre dos tiempos diff.Hours() diff.Minutes() diff.Seconds() diff.Nanoseconds() // avanzar o retroceder en el tiempo then.Add(diff) then.Add(-diff) // sumar tiempo tiempoQueSea.Add( 1000 * time.Hours) String to Time // pasar una fecha a string segun un determinado formato layout := \"2006-01-02 15:04:05\" t, err := time.Parse(layout1, start) if err != nil { fmt.Prinltln(err) } // Hora actual a string con determinado formato horaActual = time.Now().Format(layout) Time to String myString = myTime.String() Timestamp Unix epoch now := time.Now() secs := now.Unix() nanos := now.UnixNano() millis := nanos / 1000000 time.Unix(secs, 0) time.Unix(0, nanos) Intervalos timers - para hacer algo una vez dentro de un tiempo timer1 := time.NewTimer(time.Second * 2) <-timer1.C fmt.Println(\"Timer 1 expired\") timer2 := time.NewTimer(time.Second) go func() { <-timer2.C fmt.Println(\"Timer 2 expired\") }() stop2 := timer2.Stop() if stop2 { fmt.Println(\"Timer 2 stopped\") } // Timer 1 expired // Timer 2 stopped // Timer 2 expired NUNCA APARECE, se cancela antes tickers - para hacer algo repetidamente a intervalos regulares ticker := time.NewTicker(time.Millisecond * 500) go func() { for t := range ticker.C { fmt.Println(\"Tick at\", t) } }() time.Sleep(time.Millisecond * 1600) ticker.Stop() fmt.Println(\"Ticker stopped\")","title":"TIME"},{"location":"golang/#math","text":"import \"math\" math.Floor(x float64) float64 - devuelve el entero (int) mas grande poisble menor o igual que x math.Pow(x,y float64) float64 - x elevado a y","title":"MATH"},{"location":"golang/#mathrand","text":"import \"math/rand\" rand.Intn(10) - genera un numero aleatorio entero >= 0 y < 10 rand.Float64() - genera un numero aleatorio >= 0.0 y < 1.0 (rand.Float64()*5)+5 - genera entre >= 5.0 y < 10.0 s1 := rand.NewSource(time.Now().UnixNano()) - semilla para que no sea siempre igual r1 := rand.New(s1) - para ir cambiando la semilla rand.Seed(time.Now().UTC().UnixNano()) - otra forma de cambiar la semilla para que no siempre sea igual func init() { //fmt.Println(`Init from package tracker`) r = rand.New(rand.NewSource(time.Now().UnixNano())) } var r *rand.Rand func createRandomString() string { const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\" result := \"\" for i := 0; i < lenID; i++ { result += string(chars[r.Intn(len(chars))]) } return result }","title":"MATH/RAND"},{"location":"golang/#databasesql","text":"database/sql","title":"DATABASE/SQL"},{"location":"golang/#flag","text":"import \"flag\" Para enviar argumentos a un comando Ejemplos","title":"FLAG"},{"location":"golang/#sort","text":"import sort Contiene funciones para ordenar datos arbitrario de slices de ints y floats y structs definidas por el usuario s = []strings sort.strings(s) - De menor a mayor alfabeticamente n = []ints || float32 || float64 sort.Ints(n) - Ordena los numeros de menor a mayor sort.IntsAreSorted(n) - booleano que devuelve si estan ordenados custom sorting package main import \"sort\" import \"fmt\" // If I have an array/slice of structs in Go and want to sort them // using the sort package it seems to me that I need to implement // the whole sort interface which contains 3 methods: // https://golang.org/pkg/sort/#Interface type ByLength []string func (s ByLength) Len() int { return len(s) } func (s ByLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s ByLength) Less(i, j int) bool { return len(s[i]) < len(s[j]) } func main() { fruits := []string{\"peach\", \"banana\", \"kiwi\"} sort.Sort(ByLength(fruits)) fmt.Println(fruits) }","title":"SORT"},{"location":"html/","text":"HTML FLEXBOX Buena Guia para usar Flexbox Patrones para Flexbox CSS GRID Aprender aqui gridbyexample.com SNIPPETS Plantilla    Title                   Validacion con HTML5 sin submit 
            document.getElementById('addUser').addEventListener('click', addNewUser); function addNewUser (ev) { ev.preventDefault(); const f = document.getElementsByTagName('form')[0]; if (f.checkValidity()) { const newUsername = document.getElementById('newUsername').value; const params = `username=${newUsername}`; makeAjaxRequest(addNewUserUrl, 'POST', params, null, function (data) { showUsersList(data); }); } else { alert(document.getElementById('newUsername').validationMessage); } } Disparar evento click con ENTER
            Button
            function init () { const button = document.getElementById('button'); button.addEventListener('click', action); const input = document.getElementById('inputText'); input.addEventListener('keyup', testEnter); } function testEnter (ev) { ev.preventDefault(); if (ev.keyCode === 13) { document.getElementById('button').click(); } } HTML5 ESTRUCTURA Titulo Block Elements Elementos que siempre empiezan en una nueva linea Inline Elements Elementos que aparecen a continuacion en la misma linea del anterior Caracteres de escape TEXTO white space collapsing : Dos o mas espacios o lineas juntos el navegador solo mostrara uno Elementos para estructurar la pagina

            paragraph

            headings bold italic superscript subscript
            line breaks
            horizontal rules Elementos semanticos contenido importante enfasis
            citar parrafos
            citas cortas dentro de un parrafo abreviaturas o acronimos referencia a algo (libro, peli ...) la primera explicacion de un termino en el documento
            para contener detalles de contacto de alguien
            mostrar contenido que ha sido insertado en el documento mostrar contenido que ha sido borrado en el documento indicar que algo ya no es relevante LISTAS Ordenadas
            1. primero
            2. segundo
            3. tercero
            primero segundo tercero Desordenadas
            • primero
            • segundo
            • tercero
            primero segundo tercero Listas de deficiones
            concepto 1
            definicion de concepto 1
            concepto 2
            definicion de concepto 2
            concepto 3
            definicion de concepto 3
            concepto 1 definicion de concepto 1 concepto 2 definicion de concepto 2 concepto 3 definicion de concepto 3 ENLACES A paginas externas href como url absoluta A paginas del mismo sitio Contacto href como url relativa A direcciones de correo Mandar correo A una nueva pesta\u00f1a Movie Database A una parte de la misma pagina

            Bla bla bla

            \u00f3

            Bla bla bla

            ... ... Subir A una parte de otra pagina Enlace IMAGENES Ponerlas todas en una carpeta /imagenes Salvarlas a resolucion de 72 ppi(pixels per inch), los monitores no dan mas y asi ahorramos peso en la imagen \"lo CODIGO VIEJO -Altura ,anchura y alineamiento de la imagen es mejor hacerlo por CSS \"loquesea\" \"alt\"
            se usa para tener juntas y asociar las imagenes con sus pies de fotos
            Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
            \"loquesea\"
            Pie de foto
            TABLAS para crear la tabla fila CODIGO VIEJO (Ahora por CSS) width spacing bgcolor border
            celda Extiende el texto a dos columnas Extiende el texto a dos filas es una celda pero cabecera de la fila o columna scope=\"row\" scope=\"col\" atributo que indica si es fila o columna
            Sabado Domingo
            Cervezas 4 2
            Cervezas 3 3
            Total 7 5
            FORMULARIOS action method id size CODIGO VIEJO no deberia usarse, para el tama\u00f1o del cuadro. Usar CSS type=\"text\" crea una entrada de texto de una sola linea type=\"password\" como text pero los caracteres no se ven al teclearlos name nombre de la variable, el valor sera lo introducido en el formulario maxlength limitar los caracteres, p ej mes 2 caracteres type=\"submit\" boton que envia el formulario, el value es el texto que sale en el boton placeholder en cualquier input de texto es el valor que saldra por defecto hasta que el usuario lo pinche encima
            Usuario Contrase\u00f1a
            textarea cols y rows son las dos CODIGO VIEJO, mejor con CSS Escribir Aqui... radio button Puedes elegir una opcion Elige una opcion Opcion 1 Opcion 2 Opcion 3

            Elige una opcion
            Opcion 1 Opcion 2 Opcion 3

            checkbox Pues elegir cero, una o mas opciones de las disponibles Elige una opcion Opcion 1 Opcion 2 Opcion 3

            Elige una opcion
            Opcion 1 Opcion 2 Opcion 3

            select : drop down list Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3

            Opcion a elegir ?

            multiple select box Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3 Opcion 4 Opcion 5

            Opcion a elegir ?

            file input box Subir un archivo

            Subir un archivo


            image button Texto de lo que sea

            Texto de lo que sea

            button and hidden controls Add
            labeling form controls uso de etiquetas para accesibilidad grouping form elements Detalles contacto Email: Movil: Telefono fijo:
            Detalles contacto

            Validacion Usuario Contrase\u00f1a
            Usuario
            Contrase\u00f1a
            Fecha Elige Fecha Correo Correo URL URL Telefono Telefono Numero Numero Range Numero Color Color Search Search VIDEO Y AUDIO Video Para poner diferentes formatos usamos Audio Para poner diferentes formatos usamos LAYOUT old Layout new Layout header, footer, nav, article, aside, section hgroup, figure, figcaption
            se usa para tener juntas y asociar las imagenes con sus pies de fotos
            Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
            \"Bok
            Bok Choi
            div
            queda para todo lo que no sea claramente algo de lo anterior y para tener juntos elementos relacionados o envolver partes de la pagina

            Yoko's Kitchen

            Convertir bloque en enlace Envolvemos el elemento a converir en enlace con
            \"Bok
            Bok Choi

            Japanese Vegetarian

            Five week course in London

            A five week introduction to traditional Japanese vegetarian meals, teaching you a selection of rice and noodle dishes.

            ","title":"HTML"},{"location":"html/#html","text":"","title":"HTML"},{"location":"html/#flexbox","text":"Buena Guia para usar Flexbox Patrones para Flexbox","title":"FLEXBOX"},{"location":"html/#css-grid","text":"Aprender aqui gridbyexample.com","title":"CSS GRID"},{"location":"html/#snippets","text":"","title":"SNIPPETS"},{"location":"html/#plantilla","text":" Title ","title":"Plantilla"},{"location":"html/#validacion-con-html5-sin-submit","text":"
            document.getElementById('addUser').addEventListener('click', addNewUser); function addNewUser (ev) { ev.preventDefault(); const f = document.getElementsByTagName('form')[0]; if (f.checkValidity()) { const newUsername = document.getElementById('newUsername').value; const params = `username=${newUsername}`; makeAjaxRequest(addNewUserUrl, 'POST', params, null, function (data) { showUsersList(data); }); } else { alert(document.getElementById('newUsername').validationMessage); } }","title":"Validacion con HTML5 sin submit"},{"location":"html/#disparar-evento-click-con-enter","text":"
            Button
            function init () { const button = document.getElementById('button'); button.addEventListener('click', action); const input = document.getElementById('inputText'); input.addEventListener('keyup', testEnter); } function testEnter (ev) { ev.preventDefault(); if (ev.keyCode === 13) { document.getElementById('button').click(); } }","title":"Disparar evento click con ENTER"},{"location":"html/#html5","text":"","title":"HTML5"},{"location":"html/#estructura","text":" Titulo Block Elements Elementos que siempre empiezan en una nueva linea Inline Elements Elementos que aparecen a continuacion en la misma linea del anterior Caracteres de escape","title":"ESTRUCTURA"},{"location":"html/#texto","text":"white space collapsing : Dos o mas espacios o lineas juntos el navegador solo mostrara uno Elementos para estructurar la pagina

            paragraph

            headings bold italic superscript subscript
            line breaks
            horizontal rules Elementos semanticos contenido importante enfasis
            citar parrafos
            citas cortas dentro de un parrafo abreviaturas o acronimos referencia a algo (libro, peli ...) la primera explicacion de un termino en el documento
            para contener detalles de contacto de alguien
            mostrar contenido que ha sido insertado en el documento mostrar contenido que ha sido borrado en el documento indicar que algo ya no es relevante","title":"TEXTO"},{"location":"html/#listas","text":"Ordenadas
            1. primero
            2. segundo
            3. tercero
            primero segundo tercero Desordenadas
            • primero
            • segundo
            • tercero
            primero segundo tercero Listas de deficiones
            concepto 1
            definicion de concepto 1
            concepto 2
            definicion de concepto 2
            concepto 3
            definicion de concepto 3
            concepto 1 definicion de concepto 1 concepto 2 definicion de concepto 2 concepto 3 definicion de concepto 3","title":"LISTAS"},{"location":"html/#enlaces","text":"A paginas externas href como url absoluta A paginas del mismo sitio Contacto href como url relativa A direcciones de correo Mandar correo A una nueva pesta\u00f1a Movie Database A una parte de la misma pagina

            Bla bla bla

            \u00f3

            Bla bla bla

            ... ... Subir A una parte de otra pagina Enlace","title":"ENLACES"},{"location":"html/#imagenes","text":"Ponerlas todas en una carpeta /imagenes Salvarlas a resolucion de 72 ppi(pixels per inch), los monitores no dan mas y asi ahorramos peso en la imagen \"lo CODIGO VIEJO -Altura ,anchura y alineamiento de la imagen es mejor hacerlo por CSS \"loquesea\" \"alt\"
            se usa para tener juntas y asociar las imagenes con sus pies de fotos
            Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
            \"loquesea\"
            Pie de foto
            ","title":"IMAGENES"},{"location":"html/#tablas","text":" para crear la tabla fila CODIGO VIEJO (Ahora por CSS) width spacing bgcolor border
            celda Extiende el texto a dos columnas Extiende el texto a dos filas es una celda pero cabecera de la fila o columna scope=\"row\" scope=\"col\" atributo que indica si es fila o columna
            Sabado Domingo
            Cervezas 4 2
            Cervezas 3 3
            Total 7 5
            ","title":"TABLAS"},{"location":"html/#formularios","text":"action method id size CODIGO VIEJO no deberia usarse, para el tama\u00f1o del cuadro. Usar CSS type=\"text\" crea una entrada de texto de una sola linea type=\"password\" como text pero los caracteres no se ven al teclearlos name nombre de la variable, el valor sera lo introducido en el formulario maxlength limitar los caracteres, p ej mes 2 caracteres type=\"submit\" boton que envia el formulario, el value es el texto que sale en el boton placeholder en cualquier input de texto es el valor que saldra por defecto hasta que el usuario lo pinche encima
            Usuario Contrase\u00f1a
            textarea cols y rows son las dos CODIGO VIEJO, mejor con CSS Escribir Aqui... radio button Puedes elegir una opcion Elige una opcion Opcion 1 Opcion 2 Opcion 3

            Elige una opcion
            Opcion 1 Opcion 2 Opcion 3

            checkbox Pues elegir cero, una o mas opciones de las disponibles Elige una opcion Opcion 1 Opcion 2 Opcion 3

            Elige una opcion
            Opcion 1 Opcion 2 Opcion 3

            select : drop down list Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3

            Opcion a elegir ?

            multiple select box Opcion a elegir ? Opcion 1 Opcion 2 Opcion 3 Opcion 4 Opcion 5

            Opcion a elegir ?

            file input box Subir un archivo

            Subir un archivo


            image button Texto de lo que sea

            Texto de lo que sea

            button and hidden controls Add
            labeling form controls uso de etiquetas para accesibilidad grouping form elements Detalles contacto Email: Movil: Telefono fijo:
            Detalles contacto

            Validacion Usuario Contrase\u00f1a
            Usuario
            Contrase\u00f1a
            Fecha Elige Fecha Correo Correo URL URL Telefono Telefono Numero Numero Range Numero Color Color Search Search ","title":"FORMULARIOS"},{"location":"html/#video-y-audio","text":"","title":"VIDEO Y AUDIO"},{"location":"html/#video","text":" Para poner diferentes formatos usamos ","title":"Video"},{"location":"html/#audio","text":" Para poner diferentes formatos usamos ","title":"Audio"},{"location":"html/#layout","text":"old Layout new Layout header, footer, nav, article, aside, section hgroup, figure, figcaption
            se usa para tener juntas y asociar las imagenes con sus pies de fotos
            Pero tambien se puede usar para contener imagenes videos graficos diagramas codigo texto
            \"Bok
            Bok Choi
            div
            queda para todo lo que no sea claramente algo de lo anterior y para tener juntos elementos relacionados o envolver partes de la pagina

            Yoko's Kitchen

            Convertir bloque en enlace Envolvemos el elemento a converir en enlace con
            \"Bok
            Bok Choi

            Japanese Vegetarian

            Five week course in London

            A five week introduction to traditional Japanese vegetarian meals, teaching you a selection of rice and noodle dishes.

            ","title":"LAYOUT"},{"location":"javascript-apis/","text":"JAVASCRIPT APIs Para ver si un navegador tiene una funcionalidad if (navigator.geolocation) { // codigo } else { // codigo } Modernizr puede ayudar if (Modernizr.awesomeNewFeature) { showOffAwesomeNewFeature(); } else { getTheOldLameExperience(); } LIBRERIA STANDARD Math Math es un Objeto Global que actua sobre numeros Propiedades Math.PI - Devuelve pi 3.14159265359 Math.E - constante de Euler Math.LN2 - logaritmo natural de 2 Math.LN10 - logaritmo natural de 10 Math.LOG2E - logaritmo en base 2 de e Math.LOG10E - logaritmo en base 10 de e Math.SQRT1_2 - raiz cuadrada de medio (1/2) Math.SQRT2 - raiz cuadrada de 2 Metodos Math.abs(num) - Devuelve el valor absoluto de num Math.round(num) - Redondea num al entero mas cercano Math.sqrt(num) - Devuelve la raiz cuadrada del numero positivo num Math.ceil(num) - Redondea al entero mas cercano por arriba Math.floor(num) - Redondea al entero mas cercano por abajo Math.random() - Genera un numero aleatorio entre 0 (inclusivo) y 1 (no inclusivo) Math.pow(num, pot) - Devuelve num elevado a la pot Math.max(num1, num2, num3) - devuelve el mayor numero Math.min(num1, num2, num3) - devuelve el menor numero Math.acos(x) - Math.asin(x) - Math.atan(x) - Math.atan2(x) - Math.cos(x) - Math.sin(x) - Math.tan(x) - // Crea un numero aleatorio entre min y max ambos inclusivo Math.floor(Math.random() * (max - min + 1) + min); Date Crear Objeto Date var d = new Date(); var d = new Date(millis); var d = new Date(dateString); var d = new Date(year, month, day, hours, minutes, seconds, millis); Metodos Date.now() - devuelve el numero de Milisegundos desde el 1 ene 1970 Date.parse() - parsea la fecha y devuelve el numero de Milisegundos desde el 1 ene 1970 .getDate() , .setDate() - Dia del mes (1-31) .getDay() - Dia de la semana (0-6) .getFullYear() , .setFullYear() - a\u00f1o (4 digitos) .getHours() , .setHours() - Hora (0-23) .getMilliseconds() , .setMilliseconds() - Milisegundos (0-999) .getMinutes() , .setMinutes() - Minutos (0-59) .getMonth() , .setMonth() - Mes (0-11) .getSeconds() , .setSeconds() - Segundos (0-59) .getTime() , .setTime() - Milisegundos desde 1 Enero 1970 00:00:00 y negativo para cualquier tiempo anterior a esa fecha .getTimezoneOffset() - Minutos de diferencia horaria entre UTC y la hora local Version para UTC .getUTCDate() , .setUTCDate() - Dia del mes (1-31) .toDateString() - Fecha del tipo Mon Jan 17 1982 .toTimeString() - Hora del tipo 19:45:15 GMT+0300 (CEST) .toString() - Devuelve una string con la fecha especificada .toISOString() - Devuelve una string con la fecha especificada usando el standard ISO .date.toJSON() - Devuelve una string con la fecha especificada formateado en JSON. .toLocaleDateString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toLocaleTimeString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toLocaleString() - Devuelve una string con la fecha especificada usando las convenciones segun la hora local .toUTCString() - Devuelve una string con la fecha especificada segun la hora universal .valueOf() - Devuelve el valor primitico de un objeto Date JSON JSON.stringify JSON.stringify(value, replacer?, space?) convierte el valor value a una cadena en formato JSON. replacer es opcional y se usa para cambiar value antes de stringify function replacer(key, value) { if (typeof value === 'number') { value = 2 * value; } return value; } JSON.stringify({ a: 5, b: [ 2, 8 ] }, replacer) // '{\"a\":10,\"b\":[4,16]} JSON.parse JSON.parse(text, reviver?) convierte los datos JSON en text y devuelve un valor javascript reviver es opcional y se puede usar para transformar los datos ya parseados STRICT MODE Variables han de ser definidas explicitamente No se puede borrar una variable u objeto usando delete No se puede definir la misma propiedad dos veces No permite los nombres de parametros duplicados En una funcion si no se conoce this en lugar de usar el objeto global window sera undefined Las variables instanciadas dentro del contexto de eval() s\u00f3lo son v\u00e1lidas en ese contexto. La sentencia with(){} ya no se usa js Envolvemos todo la parte del codigo js en una IIFEs (function() { 'use strict'; /* code here */ .. codigo }()); node.js a\u00f1adimos al comienzo del archivo /*jslint node: true */ 'use strict'; WEB STORAGE Objeto Storage Los navegadores guardan sobre 8mb por dominio en un objecto storage Los datos se guardan como propiedades (clave/calor) del objeto storage Acceso a los datos se hace de manera sincrona Los navegadores usan politica del mismo origen, vamos que los datos solo son accesibles por otras paginas del mismo dominio Para ello las 4 partes del URL deben coincidir Protocolo \u00a1 ojo que https es distinto a http ! Subdominio, maps.google.com no puede acceder a datos guardados de www.google.com Dominio debe coincidir Puerto, este tambien debe coincidr Propiedades .length - numero de claves Metodos .setItem('clave', 'valor') - Crea una nueva pareja clave/valor .getItem('clave') - Devuelve el valor de la clave \"clave\" .removeItem('clave') - Elimina la clave/valor para esa clave .clear() - Limpia toda la informacion del objeto storage sessionStorage Cambios frecuentes cada vez que el usuario visita el sitio, (datos de localizacion, logueos) Es personal y privado, no debe ser visto por otros usuarios del dispositivo localStorage Solo cambia en los intervalos establecidos (horarios, listas de precios) y es util almacenarlo offline Cosas que el usuario use de nuevo si vuelve al sitio (guardar preferencias y ajustes) localStorage.setItem(\"username\", \"marijn\"); console.log(localStorage.getItem(\"username\")); // \u2192 marijn localStorage.removeItem(\"username\"); Un valor en localStorage dura hasta que se sobreescribe, se elimina o el usuario limpia sus datos locales Cada pagina tiene su propio almacen que solo puede interactuar con scripts de la misma pagina Ejemplo var basicRecipes = [{ title: 'Cookies', ingredients: ['Cup shortening', 'Peanut Butter', 'Milk', 'Eggs'] }, { title: 'Spaghetti', ingredients: ['Noodles', 'Tomato Sauce', 'Meatballs', 'Onion'] }, { title: 'Rice Pudding', ingredients: ['White Rice', 'Milk', 'Sugar', 'Salt'] }]; // Estas dos hacen lo mismo localStorage.setItem('basicRecipes', JSON.stringify(basicRecipes)); localStorage.basicRecipes = JSON.stringify(basicRecipes); // Dos formas de hacer lo mismo tambien var sol = JSON.parse(localStorage.getItem('basicRecipes')); console.log(sol[0].title); console.log((JSON.parse(localStorage.basicRecipes))[0]); // Esto borra toda la localStorage localStorage.clear() IndexedDB Web SQL Deprecada, pero aun se usa No funciona ni en chrome ni en IE GEOLOCATION Metodos objeto navigation.geolocation getCurrentPosition(exito, error, conf) - exito - funcion para procesar la ubicacion recibida en el objeto Position error -funcion para procesar los errores retornados en el objeto PositionError conf - objeto para configurar como la informacion sera adquirida watchPosition(exito, error, conf) - igual que el anterior excepto que inicia un proceso de vigilancia para detectar nuevas ubicaciones que nos enviara cada cierto tiempo clearWatch(id) - El metodo watchPosition() retorna un valor que puede ser almacenado en una variable para luego ser usado como id aqui y detener la vigilancia Propiedades objeto Position .coords.latitude - Devuelve latitud en grados decimales .coords.longitude - Devuelve longitud en grados decimales .coords.accuracy - Precision de latitud y longitud en metros .coords.altitude - Devuelve metros sobre el nivel del mar .coords.altitudeAccuracy - Precision de la altitud en metros .coords.heading - Devuelve grados respecto al norte .coords.speed - Devuelve velocidad en m/s .coords.timestamp - Devuelve tiempo desde que se creo (en forma de Date ) Propiedades objeto PositionError PositionError.code - Devuelve un numero de error con los valores: Permiso denegado No disponeble Ha expirado el tiempo PositionError.message - Devuelve un mensaje (pero no para el usuario) var elMap = document.getElementById('loc'); var msg = 'Sorry, we were unable to get your location.'; if (Modernizr.geolocation) { navigator.geolocation.getCurrentPosition(success, fail); elMap.textContent = 'Checking location...'; } else { elMap.textContent = msg; } function success(position) { msg = '

            Longitude: '; msg += position.coords.longitude + '

            '; msg += '

            Latitude: '; msg += position.coords.latitude + '

            '; elMap.innerHTML = msg; } function fail(msg) { elMap.textContent = msg; console.log(msg.code); } HISTORY Objeto history Propiedades .length - numero de articulos en el objeto historia Metodos history.back() - Retrocedes en la historia a la anterior posicion history.forward() - Saltas adelante a la siguiente posicion history.go(n) - Te lleva a la pagina n respecto de tu posicion que es la 0. Por ejemplo -2 echa dos para atras y 1 salta uno hacia adelante history.pushState() - A\u00f1ade un elemento a la historia history.replaceState() - Cambia el actual elemento de la historia por el que pasamos ahora Eventos window.onpopstate - Usado para manejar los movimientos de usuario de adelante atras GOOGLE MAPS API Key Se consigue aqui Ajustes Crear un mapa El evento onload llama a la funcion loadScript() LoadScript() crea un elemento
            requestAnimationFrame(funcion) - Sincroniza la animacion con la ventana del navegador y el monitor. hay que llamarlo para cada ciclo del bucle cancelAnimationFrame(variable) - Podemos asignar el valor de arriba a una variable y con ese metodo cancelamos el proceso Hay que concentrar el codigo del juego en un objeto global unico var onoff; function gameLoop() { // haces lo que sea onoff = requestAnimationFrame(gameLoop); } // en otro sitio para parar el bucle cancelAnimationFrame(onoff); function gameLoop () { setTimeout(function () { if (running) { update(); render(); } onoff = requestAnimationFrame(gameLoop); // console.log('gameLoop sigue ... ', onoff) if (cancel) { cancelAnimationFrame(onoff); setScoreToZeros(); } }, 1000 / fps); } var mijuego = { lienzo: { ctx: '', offsetx: 0, offsety: 0 }, nave: { x: 300, y: 200, movex: 0, movey: 0, speed: 1 }, iniciar: function(){ var elem = document.getElementById('lienzo'); mijuego.lienzo.ctx = elem.getContext('2d'); mijuego.lienzo.offsetx = elem.offsetLeft; mijuego.lienzo.offsety = elem.offsetTop; document.addEventListener('click', function(e){ mijuego.control(e); }); mijuego.bucle(); }, bucle: function(){ if(mijuego.nave.speed){ mijuego.procesar(); mijuego.detectar(); mijuego.dibujar(); // requestAnimationFrame(function(){ mijuego.bucle() }); webkitRequestAnimationFrame(function(){ mijuego.bucle() }); }else{ mijuego.lienzo.ctx.font = \"bold 36px verdana, sans-serif\"; mijuego.lienzo.ctx.fillText('JUEGO FINALIZADO', 112, 210); } }, control: function(e){ var distancex = e.clientX - (mijuego.lienzo.offsetx + mijuego.nave.x); var distancey = e.clientY - (mijuego.lienzo.offsety + mijuego.nave.y); var ang = Math.atan2(distancex, distancey); mijuego.nave.movex = Math.sin(ang); mijuego.nave.movey = Math.cos(ang); mijuego.nave.speed += 1; }, dibujar: function(){ mijuego.lienzo.ctx.clearRect(0, 0, 600, 400); mijuego.lienzo.ctx.beginPath(); mijuego.lienzo.ctx.arc(mijuego.nave.x, mijuego.nave.y, 20, 0, Math.PI/180*360, false); mijuego.lienzo.ctx.fill(); }, procesar: function(){ mijuego.nave.x += mijuego.nave.movex * mijuego.nave.speed; mijuego.nave.y += mijuego.nave.movey * mijuego.nave.speed; }, detectar: function(){ if(mijuego.nave.x < 0 || mijuego.nave.x > 600 || mijuego.nave.y < 0 || mijuego.nave.y > 400){ mijuego.nave.speed = 0; } } }; addEventListener('load', function(){ mijuego.iniciar(); }); Procesar Video Coger cada cuadro del video desde el elemento
            ); } } LIFECYCLE METODOS /* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
            {this.props.display}
            ); } } class CounterParent extends React.Component { constructor(props, context) { super(props, context); console.log(\"constructor: Default state time!\"); this.state = { count: 0 }; this.increase = this.increase.bind(this); } getInitialState() { console.log(\"getInitialState: Default state time!\"); return { count: 0 }; } increase() { this.setState({ count: this.state.count + 1 }); } componentWillUpdate(newProps, newState) { console.log(\"componentWillUpdate: Component is about to update!\"); } componentDidUpdate(currentProps, currentState) { console.log(\"componentDidUpdate: Component just updated!\"); } componentWillMount() { console.log(\"componentWillMount: Component is about to mount!\"); } componentDidMount() { console.log(\"componentDidMount: Component just mounted!\"); } componentWillUnmount() { console.log(\"componentWillUnmount: Component is about to be removed from the DOM!\"); } shouldComponentUpdate(newProps, newState) { console.log(\"shouldComponentUpdate: Should component update?\"); if (newState.count < 5) { console.log(\"shouldComponentUpdate: Component should update!\"); return true; } else { ReactDOM.unmountComponentAtNode(destination); console.log(\"shouldComponentUpdate: Component should not update!\"); return false; } } componentWillReceiveProps(newProps) { console.log(\"componentWillReceiveProps: Component will get new props!\"); } render() { const backgroundStyle = { padding: 50, border: \"#333 2px dotted\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; return (
            ); } } console.log(\"defaultProps: Default prop time!\"); CounterParent.defaultProps = { }; const layout = (
            ); ReactDOM.render( layout, destination ); RENDERIZADO CONDICIONAL Variables render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = ; } else { button = ; } return (
            {button}
            ); } If return (

            Hello!

            {unreadMessages.length > 0 &&

            You have {unreadMessages.length} unread messages.

            }
            ); If-else codition ? true : false - return (
            The user is {isLoggedIn ? 'currently' : 'not'} logged in.
            ); return (
            {isLoggedIn ? ( ) : ( )}
            ); EVENTOS Eventos en React son SyntheticEvent que envuelven eventos normales Documentacion en React sobre Eventos del sistema this dentro del manejador de eventos -Fuera de react, el valor de this dentro de una manejador de eventos se refiere al elemento que disparo el evento. -En React, this se refiere al componente donde el manejador de evento vive. Escuchando eventos del DOM class Something extends React.Component { handleMyEvent(e) { // do something } componentDidMount() { window.addEventListener(\"someEvent\", this.handleMyEvent); } componentWillUnmount() { window.removeEventListener(\"someEvent\", this.handleMyEvent); } render() { return (
            Hello!
            ); } }; Synthetic Events /* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
            {this.props.display}
            ); } } class CounterParent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.increase = this.increase.bind(this); } increase(e) { //console.log(e); let currentCount = this.state.count; if (e.shiftKey) { currentCount += 10; } else { currentCount += 1; } this.setState({ count: currentCount }); } render() { const backgroundStyle = { padding: 50, backgroundColor: \"#FFC53A\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; const buttonStyle = { fontSize: \"1em\", width: 30, height: 30, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\", lineHeight: \"3px\" }; return (
            ); } } const layout = (
            ); ReactDOM.render( layout, destination ); Pasar parametros desde los eventos onClick={() => this.functionName(params)} PORTALES Uso // These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = { showModal: false }; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({ showModal: true }); } handleHide() { this.setState({ showModal: false }); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? (
            With a portal, we can render content into a different part of the DOM, as if it were any other React child.
            This is being rendered inside the #modal-container div.
            ) : null; return (
            This div has overflow: hidden. {modal}
            ); } } ReactDOM.render(, appRoot); Burbujas de Eventos // These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = {clicks: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState(prevState => ({ clicks: prevState.clicks + 1 })); } render() { return (

            Number of clicks: {this.state.clicks}

            Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

            ); } } function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
            ); } ReactDOM.render(, appRoot); REACT ROUTER 4.2.0 Basico /* global ReactDOM React */ const destination = document.getElementById('book'); const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; const development = \"/old/apps/book/html\"; const production = \"/old/apps/book\"; class Controller extends React.Component { constructor(props) { super(props); this.state = { data: { }, default: development// production }; } render() { const a = { textAlign: \"center\", fontFamily: \"Indie Flower\" }; return (

            Book Trading Club

            • Index
            • Home
            • About
            ); } } const Index = () => (

            Index

            ); const Home = () => (

            Welcome home

            ); const About = () => (

            About

            ); const layout = ( ); ReactDOM.render( layout, destination ); Ejemplo /* global ReactDOM React lib Home About Index LoginForm SignUpForm ShowBooks MyBooks UserDataForm*/ const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; class Controller extends React.Component { render() { const a = { textAlign: \"center\", }; const gap = { paddingTop: \"75px\", }; const links = { fontFamily: \"arial\", fontSize: \"1em\", }; return (
            {/*

            Index

            Login Signup AllBooks MyBooks UserData */}
            ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> {/**/}
            ); } } const layout = ( ); ReactDOM.render( layout, destination );","title":"Reactjs"},{"location":"reactjs/#reactjs-1620","text":"Instalacion https://unpkg.com/react/ https://unpkg.com/react-dom/ ","title":"REACTJS 16.2.0"},{"location":"reactjs/#jsx","text":"JSX permite mezclar javascript y etiquetas HTML para definer elementos de interfaces de usuario y su funcionalidad","title":"JSX"},{"location":"reactjs/#crear-elemento-jsx","text":"// simple const JSX =

            Hello JSX!

            ; // complejo, todos los elementos son envueltos por un unico elemento padre const JSX = (

            Hello JSX!

            { /* this is a JSX comment */ } { 'this is treated as JavaScript code' }

            Some info

            • An item
            • Another item
            • A third item
            );","title":"Crear elemento JSX"},{"location":"reactjs/#renderizar-elemento-jsx","text":"// ReactDOM.render(componentToRender, targetNode) ReactDOM.render(JSX, document.getElementById('challenge-node'));","title":"Renderizar elemento JSX"},{"location":"reactjs/#sintaxis","text":"Definir una clase HTML en JSX , usa className en lugar de class La convenci\u00f3n de nomenclatura para todos los atributos HTML y referencias de eventos en JSX se convierte en camelCase. Por ejemplo, el evento de clic en JSX es onClick, en lugar de onclick. const JSX = (

            Add a class to this div

            );","title":"Sintaxis"},{"location":"reactjs/#componente","text":"","title":"COMPONENTE"},{"location":"reactjs/#tipos","text":"1.Usar una funcion javascript para crear un componente funcional sin estado // After transpiled,
            will have a CSS class of 'customClass' const MyComponent = function() { return (
            Demo Solution
            ); } 2.Usando sintaxis ES6 class class MyComponent extends React.Component { constructor(props) { super(props); } render() { return (

            Hi

            ); } }","title":"Tipos"},{"location":"reactjs/#props-propiedades","text":"Pasar una propiedad const CurrentDate = (props) => { return (

            The current date is: {props.date}

            ); }; class Calendar extends React.Component { constructor(props) { super(props); } render() { return (

            What date is it?

            ); } }; Pasar un Array como Props const ChildComponent = (props) =>

            {props.colors.join(', ')}

            const List= (props) => { return

            {props.tasks.join(\", \")}

            }; class ToDo extends React.Component { constructor(props) { super(props); } render() { return (

            To Do Lists

            Today

            Tomorrow

            ); } }; Usar default Props -Puedes asignar props por defecto a un componente como una propiedad en el propio componente y React asigna el default prop si es necesario. -React asigna default props si las propiedades no est\u00e1n definidas, pero si pasas nulo como valor de una propiedad, permanecer\u00e1 nulo. -La forma de anular los default props es establecer expl\u00edcitamente los valores de la propiedad para un componente. -Decl\u00e1ralos inmediatamente despu\u00e9s de la declaraci\u00f3n del componente MyComponent.defaultProps = { location: 'San Francisco' } const ShoppingCart = (props) => { return (

            Shopping Cart Component

            ) }; ShoppingCart.defaultProps = { items:0 } // Override Default props const Items = (props) => { return (

            Current Quantity of Items in Cart: {props.quantity}

            ) } Items.defaultProps = { quantity: 0 } class ShoppingCart extends React.Component { constructor(props) { super(props); } render() { return } }; Verificaci\u00f3n de tipos con PropTypes -Establece propTypes cuando sepas de antemano el tipo que tendra la propiedad // require the type function for a prop called handleClick import React, { PropTypes } from 'react'; MyComponent.propTypes = { handleClick: PropTypes.func.isRequired } const Items = (props) => { return

            Current Quantity of Items in Cart: {props.quantity}

            }; Items.propTypes = { quantity: PropTypes.number.isRequired } Items.defaultProps = { quantity: 0 }; class ShoppingCart extends React.Component { constructor(props) { super(props); } render() { return } }; Acceder a Props usando this.props -Pasar una propiedad a un componente de una clase ES6 -Cada vez que se refiera a un componente de la clase dentro de s\u00ed mismo, usa \"this\". -Para acceder a los propiedades dentro de un componente de la clase, pon delante del c\u00f3digo para acceder a \u00e9l \"this\". -Por ejemplo, si un componente de clase ES6 tiene una propiedad llamada data, usa {this.props.data} en JSX. class ReturnTempPassword extends React.Component { constructor(props) { super(props); } render() { return (

            Your temporary password is: {this.props.tempPassword}

            ); } }; class ResetPassword extends React.Component { constructor(props) { super(props); } render() { return (

            Reset Password

            We've generated a new temporary password for you.

            Please reset this password settings ASAP.

            ); } }; Mas props usando componentes de clases es6 class CampSite extends React.Component { constructor(props) { super(props); } render() { return (
            ); } }; // change code below this line const Camper = (props) => { return (

            {props.name}

            ); }; Camper.propTypes = { name: PropTypes.string.isRequired }; Camper.defaultProps = { name: 'CamperBot' };","title":"Props (propiedades)"},{"location":"reactjs/#estilo-css-en-react","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Letter extends React.Component { render() { const letterStyle = { padding: 10, margin: 10, backgroundColor: this.props.bgcolor, color: \"#333\", display: \"inline-block\", fontFamily: \"monospace\", fontSize: 32, textAlign: \"center\" }; return (
            {this.props.children}
            ); } } const layout = (
            A E I O U
            ); ReactDOM.render( layout, destination );","title":"Estilo CSS en React"},{"location":"reactjs/#composicion","text":"Puedes renderizar elementos JSX, componentes funciones sin estado y componentes de clase ES6 dentro de otros componentes","title":"Composicion"},{"location":"reactjs/#composicion-de-componentes","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Card extends React.Component { render() { const cardStyle = { height: 200, width: 150, padding: 0, backgroundColor: \"#FFF\", WebkitFilter: \"drop-shadow(0px 0px 5px #666)\", filter: \"drop-shadow(0px 0px 5px #666)\" }; return (
            ); } } class Square extends React.Component { render() { const squareStyle = { height: 150, backgroundColor: this.props.color }; return (
            ); } } class Label extends React.Component { render() { const labelStyle = { fontFamily: \"sans-serif\", fontWeight: \"bold\", padding: 13, margin: 0 }; return (

            {this.props.color}

            ); } } const layout = (
            ); ReactDOM.render( layout, destination );","title":"Composicion de componentes"},{"location":"reactjs/#transferir-propiedades-con-el-operador-spread","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Display extends React.Component { render() { return (

            {this.props.color}

            {this.props.num}

            {this.props.size}

            ); } } class Label extends React.Component { render() { return ( ); } } class Shirt extends React.Component { render() { return (
            ); } } const layout = (
            ); ReactDOM.render( layout, destination );","title":"Transferir propiedades con el operador spread"},{"location":"reactjs/#estado","text":"","title":"Estado"},{"location":"reactjs/#estado_1","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class LightningCounter extends React.Component { constructor(props, context) { super(props, context); this.state = { strikes: 0 }; this.timerTick = this.timerTick.bind(this); } componentDidMount() { setInterval(this.timerTick, 1000); } timerTick() { this.setState({ strikes: this.state.strikes + 100 }); } render() { const counterStyle = { color: \"#66FFFF\", fontSize: 50 }; const count = this.state.strikes.toLocaleString(); return (

            {count}

            ); } } class LightningCounterDisplay extends React.Component { render() { const commonStyle = { margin: 0, padding: 0 }; const divStyle = { width: 250, textAlign: \"center\", backgroundColor: \"#020202\", padding: 40, fontFamily: \"sans-serif\", color: \"#999999\", borderRadius: 10 }; const textStyles = { emphasis: { fontSize: 38, ...commonStyle }, smallEmphasis: { ...commonStyle }, small: { fontSize: 17, opacity: 0.5, ...commonStyle } } return (

            LIGHTNING STRIKES

            WORLDWIDE

            (since you loaded this example)

            ); } } const layout = (
            ); ReactDOM.render( layout, destination );","title":"Estado"},{"location":"reactjs/#de-los-datos-a-la-ui-interface-de-usuario","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Circle extends React.Component { render() { const circleStyle = { padding: 10, margin: 20, display: \"inline-block\", backgroundColor: this.props.bgColor, borderRadius: \"50%\", width: 100, height: 100, }; return (
            ); } } const colors = [\"#393E41\", \"#E94F37\", \"#1C89BF\", \"#A1D363\", \"#85FFC7\", \"#297373\", \"#FF8552\", \"#A40E4C\"]; const renderData = []; for (let i = 0; i < colors.length; i++) { const color = colors[i]; renderData.push(); } const layout = (
            {renderData}
            ); ReactDOM.render( layout, destination );","title":"De los datos a la UI (interface de usuario)"},{"location":"reactjs/#forceupdate","text":"Si setState no rerenderiza el componete usa forceUpdate() Por defecto, cuando el estado de sus componentes o los props cambian, su componente se volver\u00e1 a renderizar. Sin embargo, si estos cambios son impl\u00edcitos (p.e.: datos profundos dentro de un objeto camabian pero sin cambiar el objeto mismo) o si su render() depende de otros datos, puedes decirle a React que necesita reejecutar render() llamando a forceUpdate().","title":"forceUpdate()"},{"location":"reactjs/#comunicacion-de-datos","text":"Ideas basicas","title":"COMUNICACION DE DATOS"},{"location":"reactjs/#hijos-a-padres","text":"class Container extends React.Component { constructor(props) { super(props); this.state = { input: props.template, }; this.getBackData = this.getBackData.bind(this); } getBackData(data) { this.setState({ input: data }); } render() { return (
            ); } } class Editor extends React.Component { constructor(props) { super(props); this.editing = this.editing.bind(this); } editing(e) { e.preventDefault(); this.props.callback(e.target.value); } render() { return (
            ); } }","title":"Hijos a Padres"},{"location":"reactjs/#lifecycle-metodos","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
            {this.props.display}
            ); } } class CounterParent extends React.Component { constructor(props, context) { super(props, context); console.log(\"constructor: Default state time!\"); this.state = { count: 0 }; this.increase = this.increase.bind(this); } getInitialState() { console.log(\"getInitialState: Default state time!\"); return { count: 0 }; } increase() { this.setState({ count: this.state.count + 1 }); } componentWillUpdate(newProps, newState) { console.log(\"componentWillUpdate: Component is about to update!\"); } componentDidUpdate(currentProps, currentState) { console.log(\"componentDidUpdate: Component just updated!\"); } componentWillMount() { console.log(\"componentWillMount: Component is about to mount!\"); } componentDidMount() { console.log(\"componentDidMount: Component just mounted!\"); } componentWillUnmount() { console.log(\"componentWillUnmount: Component is about to be removed from the DOM!\"); } shouldComponentUpdate(newProps, newState) { console.log(\"shouldComponentUpdate: Should component update?\"); if (newState.count < 5) { console.log(\"shouldComponentUpdate: Component should update!\"); return true; } else { ReactDOM.unmountComponentAtNode(destination); console.log(\"shouldComponentUpdate: Component should not update!\"); return false; } } componentWillReceiveProps(newProps) { console.log(\"componentWillReceiveProps: Component will get new props!\"); } render() { const backgroundStyle = { padding: 50, border: \"#333 2px dotted\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; return (
            ); } } console.log(\"defaultProps: Default prop time!\"); CounterParent.defaultProps = { }; const layout = (
            ); ReactDOM.render( layout, destination );","title":"LIFECYCLE METODOS"},{"location":"reactjs/#renderizado-condicional","text":"","title":"RENDERIZADO CONDICIONAL"},{"location":"reactjs/#variables","text":"render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = ; } else { button = ; } return (
            {button}
            ); }","title":"Variables"},{"location":"reactjs/#if","text":"return (

            Hello!

            {unreadMessages.length > 0 &&

            You have {unreadMessages.length} unread messages.

            }
            );","title":"If"},{"location":"reactjs/#if-else","text":"codition ? true : false - return (
            The user is {isLoggedIn ? 'currently' : 'not'} logged in.
            ); return (
            {isLoggedIn ? ( ) : ( )}
            );","title":"If-else"},{"location":"reactjs/#eventos","text":"Eventos en React son SyntheticEvent que envuelven eventos normales Documentacion en React sobre Eventos del sistema this dentro del manejador de eventos -Fuera de react, el valor de this dentro de una manejador de eventos se refiere al elemento que disparo el evento. -En React, this se refiere al componente donde el manejador de evento vive.","title":"EVENTOS"},{"location":"reactjs/#escuchando-eventos-del-dom","text":"class Something extends React.Component { handleMyEvent(e) { // do something } componentDidMount() { window.addEventListener(\"someEvent\", this.handleMyEvent); } componentWillUnmount() { window.removeEventListener(\"someEvent\", this.handleMyEvent); } render() { return (
            Hello!
            ); } };","title":"Escuchando eventos del DOM"},{"location":"reactjs/#synthetic-events","text":"/* global ReactDOM React */ const destination = document.getElementById('container'); class Counter extends React.Component { render() { const textStyle = { fontSize: 72, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\" }; return (
            {this.props.display}
            ); } } class CounterParent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.increase = this.increase.bind(this); } increase(e) { //console.log(e); let currentCount = this.state.count; if (e.shiftKey) { currentCount += 10; } else { currentCount += 1; } this.setState({ count: currentCount }); } render() { const backgroundStyle = { padding: 50, backgroundColor: \"#FFC53A\", width: 250, height: 100, borderRadius: 10, textAlign: \"center\" }; const buttonStyle = { fontSize: \"1em\", width: 30, height: 30, fontFamily: \"sans-serif\", color: \"#333\", fontWeight: \"bold\", lineHeight: \"3px\" }; return (
            ); } } const layout = (
            ); ReactDOM.render( layout, destination );","title":"Synthetic Events"},{"location":"reactjs/#pasar-parametros-desde-los-eventos","text":"onClick={() => this.functionName(params)}","title":"Pasar parametros desde los eventos"},{"location":"reactjs/#portales","text":"","title":"PORTALES"},{"location":"reactjs/#uso","text":"// These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = { showModal: false }; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({ showModal: true }); } handleHide() { this.setState({ showModal: false }); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? (
            With a portal, we can render content into a different part of the DOM, as if it were any other React child.
            This is being rendered inside the #modal-container div.
            ) : null; return (
            This div has overflow: hidden. {modal}
            ); } } ReactDOM.render(, appRoot);","title":"Uso"},{"location":"reactjs/#burbujas-de-eventos","text":"// These two containers are siblings in the DOM const appRoot = document.getElementById('app-root'); const modalRoot = document.getElementById('modal-root'); class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = {clicks: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState(prevState => ({ clicks: prevState.clicks + 1 })); } render() { return (

            Number of clicks: {this.state.clicks}

            Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

            ); } } function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
            ); } ReactDOM.render(, appRoot);","title":"Burbujas de Eventos"},{"location":"reactjs/#react-router-420","text":"","title":"REACT ROUTER 4.2.0"},{"location":"reactjs/#basico","text":"/* global ReactDOM React */ const destination = document.getElementById('book'); const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; const development = \"/old/apps/book/html\"; const production = \"/old/apps/book\"; class Controller extends React.Component { constructor(props) { super(props); this.state = { data: { }, default: development// production }; } render() { const a = { textAlign: \"center\", fontFamily: \"Indie Flower\" }; return (

            Book Trading Club

            • Index
            • Home
            • About
            ); } } const Index = () => (

            Index

            ); const Home = () => (

            Welcome home

            ); const About = () => (

            About

            ); const layout = ( ); ReactDOM.render( layout, destination );","title":"Basico"},{"location":"reactjs/#ejemplo","text":"/* global ReactDOM React lib Home About Index LoginForm SignUpForm ShowBooks MyBooks UserDataForm*/ const Router = window.ReactRouterDOM.BrowserRouter; const Route = window.ReactRouterDOM.Route; const Link = window.ReactRouterDOM.Link; const Prompt = window.ReactRouterDOM.Prompt; const Switch = window.ReactRouterDOM.Switch; const Redirect = window.ReactRouterDOM.Redirect; class Controller extends React.Component { render() { const a = { textAlign: \"center\", }; const gap = { paddingTop: \"75px\", }; const links = { fontFamily: \"arial\", fontSize: \"1em\", }; return (
            {/*

            Index

            Login Signup AllBooks MyBooks UserData */}
            ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> {/**/}
            ); } } const layout = ( ); ReactDOM.render( layout, destination );","title":"Ejemplo"},{"location":"varios/","text":"MISCELLANEUS IMAGEMAGICK Ejemplos Hacer el fondo transparente convert input.png -transparent red output.png Conversion entre formatos convert image.png image.jpg // bajando la calidad convert image.png -quality 90 image.jpg Convertir color de fondo a transparente o a otro color. convert image.png -background white white.png Montar imagenes montage -label 'FRONT END' frontEnd.png -label 'BACK END' backEnd.png -label 'DATABASE' database.png -label 'UTILS' utils.png -tile 2x2 -geometry 200x200 total.png Recortar los bordes shave Hacer el canvas mayor para encajar la imagen convert input.png -gravity center -background white -extent 500x500 output.png Optimizar imagenes // png convert INPUT.png -strip [-resize WxH] [-alpha Remove] OUTPUT.png //jpg convert INPUT.jpg -sampling-factor 4:2:0 -strip [-resize WxH] [-quality 85] [-interlace JPEG] [-colorspace Gray/sRGB] OUTPUT.jpg Comprimir imagenes // ojo que esto modifica el fichero actual, no crea uno nuevo mogrify -strip -interlace Plane -gaussian-blur 0.05 -quality 40% *.jpg GIT Instalar // Debian backports para pillar la ultima version deb http://ftp.debian.org/debian strecth-backports main aptitude -t strecth-backports install \"package\" // debian aptitude install git git config --global user.name \"John Doe\" git config --global user.email johndoe@example.com git config --list nano ~/.gitconfig Commands git init [project-name] - A\u00f1ade el directorio donde estamos y crea el .git git status - lista todos los archivos nuevos o modificados sin haber sido committed git add [file] - - A\u00f1ade el fichero a la staging area y empieza a seguir los cambios que en el se producen git add . - A\u00f1ade todo en el directorio de forma recursiva a la staging area git reset [file] - Saca al archivo de la staging area git diff - Vemos los cambio del archivo git diff --staged - Vemos los cambio que hemos mandado al staging git commit -m \"mensaje\" - Realiza un commit y le asigna un \"mensaje\" git log - Es un diario con los cambios hechos en commits an la actual rama de .gitignore a github Si a\u00f1adimos algo a .gitignore ya no se commiteara pero tampoco desaparece lo existente en github. Para que se elimine de github ... git rm -r --cached some-directory git commit -m 'Remove the now ignored directory \"some-directory\"' git push origin master - normalmente con git push vale ramas git checkout -b nuevaRama - crea nueva rama de rama nuevaRama git checkout -d nombreRama - delete rama nombreRama git checkout otraRama - cambia a la rama otraRama git push origin nombreRama - push los commits de nombreRama git stash - cambios no committed se arrastran de una rama a otra. Para mantenerlos separados hacemos un stash antes de movernos a otra rama para guardar esos cambios antes de cambiar de rama. git stash apply - cuando vuelves a una rama recuperas los cambios sin hacer commit que se guardaron en esa rama. volver a estado anterior git reset --hard HEAD~5 - elimina los ultimos 5 commits git push origin -f - sincroniza la nueva situacion Volver a un commit anterior sin modificar el head # Paso 1: Encuentra el hash del commit git log # Paso 2: Crea una nueva rama como backup (opcional pero recomendado) git checkout -b nueva-rama # Paso 3: Actualiza el directorio de trabajo al estado del commit # Reemplaza con el hash del commit al que deseas volver git checkout . # Paso 4: A\u00f1ade los cambios al \u00edndice (si es necesario) git add . # Paso 5: Haz un nuevo commit (si es necesario) git commit -m \"Revertir al estado del commit \" # Paso 6: Empuja los cambios al repositorio remoto (si es necesario) git push origin nueva-rama Reducir el tama\u00f1o del directorio .git MKDOCS Instalacion apt-get install python-pip pip list --outdated -lista paquetes que se pueden actualizar pip install mkdocs pip install --upgrade mkdocs -actualizar mkdocs instalar mas temas pip install mkdocs-bootstrap pip install mkdocs-bootswatch pip install mkdocs-material pip install mkdocs-alabaster pip install mkdocs-cinder Configuracion mkdocs new my-project cd my-project $ mkdocs serve Running at: http://127.0.0.1:8000/ Comandos mkdocs build - crea un directorio site con todo el contenido estatico que se subira al servidor mkdocs build --clean - limpia lo que sobra de antes mkdocs build -d ruta/donde/gustes - crea el resultado y con el nombre gustes Ejemplo mkdocs.yml site_name: Chuletas google_analytics: [\"UA-114956807-1\", \"auto\"] repo_url: https://github.com/jolav/chuletas strict: true nav: - 'Menu': 'index.md' - 'HTML': 'html.md' - 'CSS': 'css.md' - 'Front End': 'frontend.md' - 'Javascript': 'javascript.md' - 'Javascript snippets': 'javascript-snippets.md' - 'Reactjs': 'reactjs.md' - 'Vuejs': 'vuejs.md' - 'Nodejs con Expressjs': 'nodejs-expressjs.md' - 'Nodejs snippets': 'nodejs-snippets.md' - 'Nodejs Bases de Datos': 'nodejs-bases-de-datos.md' - 'Golang': 'golang.md' - 'Golang web': 'golang-web.md' - 'Golang snippets': 'golang-snippets.md' - 'Golang Bases de Datos': 'golang-bases-de-datos.md' - 'Debian': 'debian.md' - 'Varios': 'varios.md' #theme: alabaster #theme_dir: \"chuletas-theme\" theme: name: alabaster custom_dir: chuletas-theme site_dir: 'chuletas' docs_dir: 'docs' extra_css: - '_extra/css/extra.css' extra_javascript: - '_extra/js/highlight.pack.js' extra: logo: '_img/chuletas128.png' include_toc: true GLITCH.COM Plantilla package.json { \"name\": \"sp500\", \"version\": \"0.1.11\", \"description\": \"betazone finance sp500 stock real time data\", \"main\": \"sp.js\", \"scripts\": { \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\", \"start\": \"node sp.js\" }, \"engines\": { \"node\": \"8.x\" }, \"author\": \"jolav\", \"license\": \"BSD-3-Clause\", \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/jolav/betazone.git\" }, \"bugs\": { \"url\": \"https://github.com/jolav/betazone/issues\" }, \"homepage\": \"https://github.com/jolav/betazone#readme\", \"dependencies\": { \"express\": \"^4.16.2\", \"dotenv\": \"^5.0.0\", } } EXPRESIONES REGULARES Flags Se a\u00f1aden despues de la expresion regular para indicar algo /expReg/i - ignora mayusculas o minusculas /expReg/g - repetir la busqueda a traves de la cadena entera Basicos . - cualquier cosa \\s - espacio en blanco \\S - cualquiera menos espacio en blanco \\d - numero \\D - no numero \\w - caracter alfanumerico (a-z, A-Z, 0-9) \\W - no caracter alfanumerico \\t - tabulador \\r - retorno de carro \\n - nueva linea Limites ^ - Comienzo de cadena o de multilinea \\A - Comienzo de cadena $ - Fin de cadena o fin de multilinea \\Z - Fin de cadena \\b - Palabra limite , \"\\bcat\\b\" pilla en \"cat in the hat\" pero no en \"locate\" \\B - No es una palabra limite \\< - Comienzo de palabra \\> - Fin de palabra Grupos y rangos Los rangos son inclusive (X|Y) - X o Y, ejemplo \\b(cat|dog)s\\b pilla \"cats\" o \"dogs\" (...) - Grupos [abc] - Rango (\"a\" \u00f3 \"b\" \u00f3 \"c\") [^abc] - No (\"a\" \u00f3 \"b\" \u00f3 \"c\") [a-h] - Minuscula entre la \"a\" y la \"h\" [A-H] - Mayucula entre la \"a\" y la \"h\" [3-6] - Numero entre 3 y 6 ambos inclusive Cuantificadores Por defecto los cuantificadores solo se aplican a un caracter, para aplicarlo a mas usar (...) para especificar la cadena buscada X* - 0 \u00f3 mas repeticiones de X X+ - 1 \u00f3 mas repeticiones de X X? - 0 \u00f3 instancias de X, vamos que es opcional X{m} - exactamente m instancias de X X{m,} - al menos m instancias de X X{m,n} - entre m y n instancias(incluidas) de X Especiales {}[]()^$.|*+?\\ y - entre corchetes deben ser escapados con contrabarra \\ Javascript En Javascript las expresiones regulares han de estar en una sola linea. Los espacios en blanco son significativos Delimitadas por barras / var expreg = /ab+c/; var expreg = new RegExp('/ab+c/'); expreg.test(variableATestarConLaexpresionRegular) // da true o false Metodos regexp.exec(string) Si la expresion regular casa con el string devuelve un array array[0] es la subcadena que casa con la expresion regular array[1] el texto capturado por el primer grupo array[2] el texto capturado por el segundo grupo array[n] el texto capturado por el n grupo Si la expresion regular tiene una bandera g la busqueda empieza en la posicion regexp.lastIndex (inicialmente cero). Si la busqueda es exitosa regexp.lastIndex pasara a ser el siguiente caracter tras la coincidencia. Si falla pasa a 0. Esto permite buscar varias coincidencias en una sola cadena regexp.test(string) Si la expresion regular casa con el string devuelve true, si no false var b = /&.+;/.test('frank & beans'); // b is true string.replace(expreg, nueva) - en la cadena string reemplaza lo que casa con la expresion regular por la string nueva string.match(regexp) - busca la regexp en la cadena string y devuelve las coincidencias en un array var str = \"The rain in SPAIN stays mainly in the plain\"; var res = str.match(/ain/g); console.log(res) // [ 'ain', 'ain', 'ain' ] ExpReg Comunes .replace(/\\s+/g, \"\") - Elimina todos los espacios en blancos .replace(/\\s/g, \"loQueSea\") - Reemplaza todos los espacios en blanco por loQueSea /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/ - direccion de correo valida Aqui","title":"Varios"},{"location":"varios/#miscellaneus","text":"","title":"MISCELLANEUS"},{"location":"varios/#imagemagick","text":"Ejemplos Hacer el fondo transparente convert input.png -transparent red output.png Conversion entre formatos convert image.png image.jpg // bajando la calidad convert image.png -quality 90 image.jpg Convertir color de fondo a transparente o a otro color. convert image.png -background white white.png Montar imagenes montage -label 'FRONT END' frontEnd.png -label 'BACK END' backEnd.png -label 'DATABASE' database.png -label 'UTILS' utils.png -tile 2x2 -geometry 200x200 total.png Recortar los bordes shave Hacer el canvas mayor para encajar la imagen convert input.png -gravity center -background white -extent 500x500 output.png Optimizar imagenes // png convert INPUT.png -strip [-resize WxH] [-alpha Remove] OUTPUT.png //jpg convert INPUT.jpg -sampling-factor 4:2:0 -strip [-resize WxH] [-quality 85] [-interlace JPEG] [-colorspace Gray/sRGB] OUTPUT.jpg Comprimir imagenes // ojo que esto modifica el fichero actual, no crea uno nuevo mogrify -strip -interlace Plane -gaussian-blur 0.05 -quality 40% *.jpg","title":"IMAGEMAGICK"},{"location":"varios/#git","text":"Instalar // Debian backports para pillar la ultima version deb http://ftp.debian.org/debian strecth-backports main aptitude -t strecth-backports install \"package\" // debian aptitude install git git config --global user.name \"John Doe\" git config --global user.email johndoe@example.com git config --list nano ~/.gitconfig Commands git init [project-name] - A\u00f1ade el directorio donde estamos y crea el .git git status - lista todos los archivos nuevos o modificados sin haber sido committed git add [file] - - A\u00f1ade el fichero a la staging area y empieza a seguir los cambios que en el se producen git add . - A\u00f1ade todo en el directorio de forma recursiva a la staging area git reset [file] - Saca al archivo de la staging area git diff - Vemos los cambio del archivo git diff --staged - Vemos los cambio que hemos mandado al staging git commit -m \"mensaje\" - Realiza un commit y le asigna un \"mensaje\" git log - Es un diario con los cambios hechos en commits an la actual rama de .gitignore a github Si a\u00f1adimos algo a .gitignore ya no se commiteara pero tampoco desaparece lo existente en github. Para que se elimine de github ... git rm -r --cached some-directory git commit -m 'Remove the now ignored directory \"some-directory\"' git push origin master - normalmente con git push vale ramas git checkout -b nuevaRama - crea nueva rama de rama nuevaRama git checkout -d nombreRama - delete rama nombreRama git checkout otraRama - cambia a la rama otraRama git push origin nombreRama - push los commits de nombreRama git stash - cambios no committed se arrastran de una rama a otra. Para mantenerlos separados hacemos un stash antes de movernos a otra rama para guardar esos cambios antes de cambiar de rama. git stash apply - cuando vuelves a una rama recuperas los cambios sin hacer commit que se guardaron en esa rama. volver a estado anterior git reset --hard HEAD~5 - elimina los ultimos 5 commits git push origin -f - sincroniza la nueva situacion Volver a un commit anterior sin modificar el head # Paso 1: Encuentra el hash del commit git log # Paso 2: Crea una nueva rama como backup (opcional pero recomendado) git checkout -b nueva-rama # Paso 3: Actualiza el directorio de trabajo al estado del commit # Reemplaza con el hash del commit al que deseas volver git checkout . # Paso 4: A\u00f1ade los cambios al \u00edndice (si es necesario) git add . # Paso 5: Haz un nuevo commit (si es necesario) git commit -m \"Revertir al estado del commit \" # Paso 6: Empuja los cambios al repositorio remoto (si es necesario) git push origin nueva-rama Reducir el tama\u00f1o del directorio .git","title":"GIT"},{"location":"varios/#mkdocs","text":"Instalacion apt-get install python-pip pip list --outdated -lista paquetes que se pueden actualizar pip install mkdocs pip install --upgrade mkdocs -actualizar mkdocs instalar mas temas pip install mkdocs-bootstrap pip install mkdocs-bootswatch pip install mkdocs-material pip install mkdocs-alabaster pip install mkdocs-cinder Configuracion mkdocs new my-project cd my-project $ mkdocs serve Running at: http://127.0.0.1:8000/ Comandos mkdocs build - crea un directorio site con todo el contenido estatico que se subira al servidor mkdocs build --clean - limpia lo que sobra de antes mkdocs build -d ruta/donde/gustes - crea el resultado y con el nombre gustes Ejemplo mkdocs.yml site_name: Chuletas google_analytics: [\"UA-114956807-1\", \"auto\"] repo_url: https://github.com/jolav/chuletas strict: true nav: - 'Menu': 'index.md' - 'HTML': 'html.md' - 'CSS': 'css.md' - 'Front End': 'frontend.md' - 'Javascript': 'javascript.md' - 'Javascript snippets': 'javascript-snippets.md' - 'Reactjs': 'reactjs.md' - 'Vuejs': 'vuejs.md' - 'Nodejs con Expressjs': 'nodejs-expressjs.md' - 'Nodejs snippets': 'nodejs-snippets.md' - 'Nodejs Bases de Datos': 'nodejs-bases-de-datos.md' - 'Golang': 'golang.md' - 'Golang web': 'golang-web.md' - 'Golang snippets': 'golang-snippets.md' - 'Golang Bases de Datos': 'golang-bases-de-datos.md' - 'Debian': 'debian.md' - 'Varios': 'varios.md' #theme: alabaster #theme_dir: \"chuletas-theme\" theme: name: alabaster custom_dir: chuletas-theme site_dir: 'chuletas' docs_dir: 'docs' extra_css: - '_extra/css/extra.css' extra_javascript: - '_extra/js/highlight.pack.js' extra: logo: '_img/chuletas128.png' include_toc: true","title":"MKDOCS"},{"location":"varios/#glitchcom","text":"Plantilla package.json { \"name\": \"sp500\", \"version\": \"0.1.11\", \"description\": \"betazone finance sp500 stock real time data\", \"main\": \"sp.js\", \"scripts\": { \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\", \"start\": \"node sp.js\" }, \"engines\": { \"node\": \"8.x\" }, \"author\": \"jolav\", \"license\": \"BSD-3-Clause\", \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/jolav/betazone.git\" }, \"bugs\": { \"url\": \"https://github.com/jolav/betazone/issues\" }, \"homepage\": \"https://github.com/jolav/betazone#readme\", \"dependencies\": { \"express\": \"^4.16.2\", \"dotenv\": \"^5.0.0\", } }","title":"GLITCH.COM"},{"location":"varios/#expresiones-regulares","text":"Flags Se a\u00f1aden despues de la expresion regular para indicar algo /expReg/i - ignora mayusculas o minusculas /expReg/g - repetir la busqueda a traves de la cadena entera Basicos . - cualquier cosa \\s - espacio en blanco \\S - cualquiera menos espacio en blanco \\d - numero \\D - no numero \\w - caracter alfanumerico (a-z, A-Z, 0-9) \\W - no caracter alfanumerico \\t - tabulador \\r - retorno de carro \\n - nueva linea Limites ^ - Comienzo de cadena o de multilinea \\A - Comienzo de cadena $ - Fin de cadena o fin de multilinea \\Z - Fin de cadena \\b - Palabra limite , \"\\bcat\\b\" pilla en \"cat in the hat\" pero no en \"locate\" \\B - No es una palabra limite \\< - Comienzo de palabra \\> - Fin de palabra Grupos y rangos Los rangos son inclusive (X|Y) - X o Y, ejemplo \\b(cat|dog)s\\b pilla \"cats\" o \"dogs\" (...) - Grupos [abc] - Rango (\"a\" \u00f3 \"b\" \u00f3 \"c\") [^abc] - No (\"a\" \u00f3 \"b\" \u00f3 \"c\") [a-h] - Minuscula entre la \"a\" y la \"h\" [A-H] - Mayucula entre la \"a\" y la \"h\" [3-6] - Numero entre 3 y 6 ambos inclusive Cuantificadores Por defecto los cuantificadores solo se aplican a un caracter, para aplicarlo a mas usar (...) para especificar la cadena buscada X* - 0 \u00f3 mas repeticiones de X X+ - 1 \u00f3 mas repeticiones de X X? - 0 \u00f3 instancias de X, vamos que es opcional X{m} - exactamente m instancias de X X{m,} - al menos m instancias de X X{m,n} - entre m y n instancias(incluidas) de X Especiales {}[]()^$.|*+?\\ y - entre corchetes deben ser escapados con contrabarra \\","title":"EXPRESIONES REGULARES"},{"location":"varios/#javascript","text":"En Javascript las expresiones regulares han de estar en una sola linea. Los espacios en blanco son significativos Delimitadas por barras / var expreg = /ab+c/; var expreg = new RegExp('/ab+c/'); expreg.test(variableATestarConLaexpresionRegular) // da true o false Metodos regexp.exec(string) Si la expresion regular casa con el string devuelve un array array[0] es la subcadena que casa con la expresion regular array[1] el texto capturado por el primer grupo array[2] el texto capturado por el segundo grupo array[n] el texto capturado por el n grupo Si la expresion regular tiene una bandera g la busqueda empieza en la posicion regexp.lastIndex (inicialmente cero). Si la busqueda es exitosa regexp.lastIndex pasara a ser el siguiente caracter tras la coincidencia. Si falla pasa a 0. Esto permite buscar varias coincidencias en una sola cadena regexp.test(string) Si la expresion regular casa con el string devuelve true, si no false var b = /&.+;/.test('frank & beans'); // b is true string.replace(expreg, nueva) - en la cadena string reemplaza lo que casa con la expresion regular por la string nueva string.match(regexp) - busca la regexp en la cadena string y devuelve las coincidencias en un array var str = \"The rain in SPAIN stays mainly in the plain\"; var res = str.match(/ain/g); console.log(res) // [ 'ain', 'ain', 'ain' ]","title":"Javascript"},{"location":"varios/#expreg-comunes","text":".replace(/\\s+/g, \"\") - Elimina todos los espacios en blancos .replace(/\\s/g, \"loQueSea\") - Reemplaza todos los espacios en blanco por loQueSea /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/ - direccion de correo valida Aqui","title":"ExpReg Comunes"}]} \ No newline at end of file diff --git a/www/sitemap.xml b/www/sitemap.xml index 30ee9a8..1b513be 100644 --- a/www/sitemap.xml +++ b/www/sitemap.xml @@ -2,97 +2,97 @@ https://jolav/chuletas/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/css/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/debian/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/expressjs/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/frontend/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/golang-bases-de-datos/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/golang-para-web/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/golang-snippets/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/golang/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/html/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/javascript-apis/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/javascript-para-web/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/javascript-snippets/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/javascript/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/nodejs-bases-de-datos/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/nodejs-snippets/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/nodejs/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/reactjs/ - 2024-09-08 + 2024-09-10 daily https://jolav/chuletas/varios/ - 2024-09-08 + 2024-09-10 daily \ No newline at end of file diff --git a/www/sitemap.xml.gz b/www/sitemap.xml.gz index 4d00a550152528b848716f9b2741c4b92f5c9428..ad54f7c69d82d961f46447f4cf60bf85cbd787d4 100644 GIT binary patch delta 187 zcmV;s07U=A0>uIcABzYGLtfyK2Oxh<$Cz86pnZT9Hj0BlSfc6Mm;6lYwU^FvL6&vr z8-5&{<8`vdjFF6YhjLrhWr0q4ZCrmSKR@2ZYk6!p%_UmGRODnwhjK_Myh*t%OGPH( z1c53adr4}@1Cr06tgC(5Zi?J)1s+fL)>yCFTNTP>MsH!3YPeWT`Q=95Cf6FdKxy*2 p-POAnQSZgJ&MD8>DoqXGdOSruw~@de0iu!LUI^%Ml6d?J003O_S;GJT delta 187 zcmV;s07U=A0>uIcABzYGeRbWD2Oxh*$Cz86pnZT9Hj0BlS)%FNm;6lYwU^FvL6&vr z8-5&{({-}NjFF6Y$8uZMWr0q4ZCrmWKi=QOzC5*?<`OMoDsr-;V>zT0UZq@?r6QAX zfpfq{i p?&{r(s1Ksv=agq`m8J%8J)R?ewvoUd0i%)MUI;%Contenidos