sábado, 21 de octubre de 2017

Juego de Serie en c++ con QT


Vamos a tomar el juego : http://emanuelpeg.blogspot.com.ar/2017/10/juego-de-serie-en-c.html y lo llevaremos a qt.

Para eso debemos hacer un nuevo proyecto qt y llevar nuestras clases. Y ahora vamos a programar las pantallas, Vamos a hacer una ventana que se llame MainWindows (original lo mio) :

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "juego.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();


private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    Juego juego;
    void dibujar();
};

#endif // MAINWINDOW_H

Como vemos hemos agregado una propiedad de tipo juego. Veamos el cpp : 

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QString>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->dibujar();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::dibujar() {
    ui->label->setText(QString::number(juego.getValor0()));
    ui->label_2->setText(QString::number(juego.getValor1()));
    ui->label_3->setText(QString::number(juego.getValor3()));
    ui->spinBox->setValue(0);
}

void MainWindow::on_pushButton_clicked()
{   QString msg;

    if (juego.validar(ui->spinBox->value())) {
        msg = "ganaste  Puntaje:"+ QString::number(juego.getPuntos());
    } else {
        msg = "perdio Puntaje:"+ QString::number(juego.getPuntos());
    }

    QMessageBox::warning(this, tr("Resultado"),
                                       msg,
                                       QMessageBox::Ok  ,
                                       QMessageBox::Ok);


    this->dibujar();
}

Ya se no se entiende bien por que falta el diseño de la pantalla : 

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>496</width>
    <height>105</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Secuencia</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QLabel" name="label">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QLabel" name="label_2">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QSpinBox" name="spinBox">
      <property name="minimum">
       <number>-9999999</number>
      </property>
      <property name="maximum">
       <number>9999999</number>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QLabel" name="label_3">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text">
       <string>verificar</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>496</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

Ahora si, como vemos agregamos unos labels que muestran los números y un spinBox que permite ingresar números. Y luego con un botón los validamos. 

Como se puede apreciar el diseño del juego permite generar una interfaz de consola o en qt o en otra tecnología esta es la mayor ventaja de separar nuestros objetos de la capa de presentación. 

miércoles, 18 de octubre de 2017

Ceph

Si tu organización ejecuta aplicaciones con diferentes almacenes de datos, ¡Ceph es para vos! Ceph es un almacén de datos confiable de objetos distribuidos y autónomos (RADOS), que proporciona a sus aplicaciones el almacenamiento de objetos, bloques y sistemas de archivos en un solo cluster de almacenamiento unificado, lo que hace que Ceph sea flexible, altamente confiable y fácil de administrar.

Ceph's RADOS le ofrece una escalabilidad de almacenamiento de datos extraordinaria: miles de hosts de clientes o KVM que acceden a petabytes a exabytes de datos. Cada una de sus aplicaciones puede usar el objeto, el bloque o las interfaces del sistema de archivos al mismo grupo RADOS al mismo tiempo, lo que significa que su sistema de almacenamiento Ceph sirve como una base flexible para todas sus necesidades de almacenamiento de datos. Puede usar Ceph de forma gratuita y desplegarlo en hardware económico. Ceph es una mejor forma de almacenar datos.

El sistema de almacenamiento de objetos de Ceph no está limitado a enlaces nativos o API RESTful. ¡Puedes montar Ceph como un dispositivo de bloque de aprovisionamiento delgado! Cuando escribe datos a Ceph utilizando un dispositivo de bloque, Ceph graba automáticamente y replica los datos en el clúster.

Ceph proporciona una interfaz de sistema de archivos tradicional con semántica POSIX. Los sistemas de almacenamiento de objetos son una innovación significativa, pero muchas veces tratan de reemplazar, los sistemas de archivos tradicionales.

Dejo link:  http://ceph.com

Dejo un video:

lunes, 16 de octubre de 2017

Los 15 lenguajes más utilizados en github

Leí un articulo sobre los 15 lenguajes más usados en github y no me lleve ninguna sorpresa, el primero es javascript. Sin duda el lenguaje más de moda en la comunidad open source.

Veamos todos:

RankLanguagePull Requests
1JavaScript2.3M
2Python1M
3Java986K
4Ruby870K
5PHP559K
6C++413K
7CSS335K
8C#326K
9Go285K
10C239K
11TypeScript207K
12Shell206K
13Swift107K
14Scala99K
15Objective C66K
Como dice el articulo: "De la lista anterior, podemos inferir que JavaScript es el lenguaje más utilizado entre los desarrolladores de todo el mundo, seguido por Python. GitHub mencionó que Python reemplazó a Java como el segundo idioma más popular en su plataforma, con un 40 por ciento más de solicitudes de extracción abiertas este año que el pasado."

GitHub también ha compartido algunos puntos de vista sobre la mayoría de las organizaciones y proyectos activos por la cantidad de colaboradores únicos, forks y comentarios. Y aquí están los datos sobre ellos.





Un vistazo a los datos anuales de GitHub:

  • 24 millones de usuarios totales
  • 1,5 millones de organizaciones
  • 67 millones de depósitos totales
  • 1 mil millones de compromisos públicos desde septiembre de 2016
  • 25,3 millones de depósitos activos desde septiembre de 2016
  • 1,3 millones de nuevas solicitudes desde septiembre de 2016


Dejo el articulo: https://curiouspost.com/list-15-popular-programming-languages-used-coders-github/

Juego de Serie en c++

Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.

Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente, para cumplirlo vamos a utilizar las ventajas de herencia y polimorfismo.

Vamos a desarrollar este juego en scala:

Empecemos desarrollo de la serie, la serie tiene como responsabilidad generarse y si lo hacemos de esta manera podemos utilizar la potencia del polimorfismo, para que no quede acoplado la generación de la serie con el desarrollo del juego:

Vamos a dividir nuestros archivos en .h y .cpp empecemos con secuencia.h :

#ifndef SECUENCIA_H
#define SECUENCIA_H

class Secuencia
{
protected:
    int valores[4];
public:
    Secuencia();
    virtual void generarValores()=0;
    int getValor(int index);
};

#endif // SECUENCIA_H

secuencia.cpp :

#include "secuencia.h"

Secuencia::Secuencia()
{
    for(int i=0;i<4; i++){
        valores[i]=0;
    }
}

int Secuencia::getValor(int index){
    return valores[index];
}

Ahora vamos a ver las implementaciones de secuencia, veamos secuenciapar.h :

#ifndef SECUENCIAPAR_H
#define SECUENCIAPAR_H
#include "secuencia.h"

class SecuenciaPar:public Secuencia
{
public:
    SecuenciaPar();
    void generarValores();
};

#endif // SECUENCIAPAR_H

secuenciapar.cpp :

#include "secuenciapar.h"
#include <stdlib.h>
#include <time.h>

SecuenciaPar::SecuenciaPar()
{
}

void SecuenciaPar::generarValores(){
    srand(time(NULL));
    int par = (rand() % 100) * 2;
    srand(time(NULL));
    int par2 = (rand() % 50) * 2;
    for(int i = 0; i<4; i++){
        valores[i] = par + (par2 * i);
    }
}

secuenciaimpar.h :

#ifndef SECUENCIAIMPAR_H
#define SECUENCIAIMPAR_H
#include "secuencia.h"

class SecuenciaImpar:public Secuencia
{
public:
    SecuenciaImpar();
    void generarValores();
};

#endif // SECUENCIAIMPAR_H

secuenciaimpar.cpp :

#include "secuenciaimpar.h"
#include <stdlib.h>
#include <time.h>

SecuenciaImpar::SecuenciaImpar()
{
}

void SecuenciaImpar::generarValores(){
    srand(time(NULL));
    int par = ((rand() % 100) * 2)+1;
    srand(time(NULL));
    int par2 = ((rand() % 50) * 2);
    for(int i = 0; i<4; i++){
        valores[i] = par + (par2 * i);
    }
}

Ahora vamos a ver el juego, este tiene la responsabilidad de verificar si el usuario acertó y tambien debe llevar los puntos: 

#ifndef JUEGO_H
#define JUEGO_H
#include "secuencia.h"

class Juego
{
private:
    int puntos;
    Secuencia * secuencia;
    void regenerar();
public:
    Juego();
    int getValor0();
    int getValor1();
    int getValor3();
    bool validar(int numero);
    int getPuntos();
};

#endif // JUEGO_H

juego.cpp :

#include "juego.h"
#include "secuenciapar.h"
#include "secuenciaimpar.h"
#include <stdlib.h>
#include <time.h>

Juego::Juego()
{
    secuencia = 0;
    this->puntos = 0;
    this->regenerar();
}

void Juego::regenerar() {
    if (secuencia != 0) delete secuencia;
    srand(time(NULL));
    int aleatorio = (rand() % 2);

    switch (aleatorio) {
    case 0:
        secuencia = new SecuenciaPar();
        break;
    default:
        secuencia = new SecuenciaImpar();
        break;
    }
    secuencia->generarValores();
}

int Juego::getValor0(){
    return this->secuencia->getValor(0);
}

int Juego::getValor1(){
    return this->secuencia->getValor(1);
}

int Juego::getValor3(){
    return this->secuencia->getValor(3);
}

bool Juego::validar(int numero) {
    bool resultado = false;
    if (numero == this->secuencia->getValor(2)) {
        this->puntos++;
        resultado = true;
    } else {
        this->puntos--;
    }
    this->regenerar();
    return resultado;
}

int Juego::getPuntos(){
    return this->puntos;
}

Ahora programemos la interfaz en este caso utilizaremos la consola:


#include <iostream>
#include <stdlib.h>
#include "juego.h"

using namespace std;

int main()
{
    Juego juego;
    cout << " ========== BIENVENIDO =========== "<<endl;
    cout << endl;
    while (true) {
        cout << " La secuencia es : "<<endl;
        cout << "                    " << juego.getValor0() << "   " ;
        cout << juego.getValor1() << "   ?   " << juego.getValor3()<<endl;
        int valor = 0;
        cout << "                               ";
        cin >> valor;
        if  (juego.validar(valor)) {
            cout << "     Ganaste!!  :D "<< endl;
        } else {
            cout << "     Perdiste   :(  "<< endl;
        }
        cout << endl << "     Sus puntos son :  " << juego.getPuntos() << endl;
        cout << "     Desea continuar jugando ? (y/n)  ";
        char opt;
        cin >> opt;
        if (opt == 'n') return 0;
           else cout << endl << endl;
    }

}

Y eso es todo a jugar se a dicho!!

Dejo el repositorio git: https://github.com/emanuelpeg/SerieCpp



domingo, 15 de octubre de 2017

Juego de Serie en Scala


Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.

Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente, para cumplirlo vamos a utilizar las ventajas de herencia y polimorfismo.

Vamos a desarrollar este juego en scala:

Empecemos desarrollo de la serie, la serie tiene como responsabilidad generarse y si lo hacemos de esta manera podemos utilizar la potencia del polimorfismo, para que no quede acoplado la generación de la serie con el desarrollo del juego:

package com.blog.serie

import scala.util.Random

abstract class Serie {
 
  var semilla = Random.nextInt(2000) + 1;
 
  def generate(): Seq[Int];
 
  val serie : Seq[Int]= generate();

}

Luego implementemos las series:

package com.blog.model.serie

import scala.util.Random

/**
 * @author emanuel
 *
 */
class SeriePar extends Serie {
 
  override def generate(): Seq[Int] = for(i <- 0 to 3) yield (i + semilla) * 2

}

Una serie impar:

package com.blog.model.serie

import scala.util.Random
import scala.collection.immutable.List

/**
 * @author emanuel
 *
 */
class SerieImpar extends Serie {

  override def generate(): Seq[Int] =
    for(i <- 0 to 3) yield if ((semilla%2)==0) (i * 2) + semilla + 1 else (i * 2) + semilla
 
}

Serie normal

package com.blog.model.serie

import scala.util.Random

class SerieNormal extends Serie {

  override def generate(): Seq[Int] = for(i <- 0 to 3) yield (i + semilla)
 
}

Serie de fibonacci;

package com.blog.model.serie

import scala.util.Random

/**
 * @author emanuel
 *
 */
class SerieFibonacci extends Serie {
 
 override def generate(): Seq[Int] =  {
   semilla = Random.nextInt(20) + 1
 
   def fibo(n:Int) : Int = n match {
     case 0 => 1
     case 1 => 1
     case _ => fibo(n-1) + fibo(n-2)
   }
 
   for(i <- 0 to 3) yield fibo(i + semilla)
 }
 
}

Ya tenemos un conjunto interesante de series, ahora a programar el juego:

package com.blog.model

import com.blog.model.serie._
import scala.util.Random

class Juego {

  var serie : Serie = null
  var puntos = 0
 
  def generarSerie():Unit = {
    val selector = Random.nextInt(4);
   
    selector match {
      case 0 => serie = new SerieNormal()
      case 1 => serie = new SeriePar()
      case 2 => serie = new SerieFibonacci()
      case _ => serie = new SerieImpar()
    }
  }
 
  generarSerie()
 
  def getValor0() = serie.serie.seq(0)
  def getValor1() = serie.serie.seq(1)
  def getValor3() = serie.serie.seq(3)
 
  def isValid(i: Int):Boolean =
    if (i == serie.serie.seq(2)) {
       puntos= puntos+1
       generarSerie()
       true
    } else {
      generarSerie()
      false
    }
 
}

El Juego es el encargado de crear la serie, mostrar los valores y validar si la respuesta es correcta. Ahora programemos la interfaz en este caso utilizaremos la consola:

package com.blog.model


object Principal extends App {

  var juego = new Juego
  var op = "ok"

  while (op == "ok") {
 
    println("Serie " + juego.getValor0() + " , "+ juego.getValor1() + " ___ " + juego.getValor3())
    println()
    print(" Indique el valor faltante : ")
    val i = readInt()
   
    if (juego.isValid(i)) {
      println(" Ganaste !! Puntaje : " + juego.puntos)
    } else {
      println(" Perdiste !! Puntaje : " + juego.puntos)
    }
   
    println(" Si desea continuar ingrese ok : ")
    op = readLine()
 
  }
 
  println(" chau !! ")
 
}

Y eso es todo a jugar se a dicho!!

Dejo el repositorio git: https://github.com/emanuelpeg/serieScala


jueves, 12 de octubre de 2017

Mantenlo Simple estupido


Se ha hablado mucho del principio Kiss (Keep it simple, Stupid!), el cual es un principio que toma como estandarte la simplicidad. El código debe ser simple y debemos priorizar el entendimiento, porque luego si tenemos que mantenerlo debemos entenderlo (que no es poco)

Muchas veces se toma este principio como una escusa para tomar el camino más fácil (que no es el más simple) para dar un ejemplo el encapsulamiento no es algo fácil, nos genera un trabajo extra acceder a los atributos solo a través de método, pero esto es simple. Nos libera de la responsabilidad de saber la estructura de los objeto o porque se guardo de una manera y no de otra, debo saber que puedo modificar y que no, etc. Por lo tanto el encapsulamiento genera un mayor trabajo pero por lejos es el camino más simple, no debo conocer la estructura interna de mi objeto, solo lo debo usar.

Se trata de hacerlo todo sencillo y simple. No debemos entender sencillo como falta de elaboración o falta de horas de dedicación a la acción en sí, sino que lo simple es algo de una sencillez tal que el esfuerzo psicológico / mental por el receptor es mínimo. Esto conlleva a un aumento (por parte de los consumidores para con la marca) de:

  • Aceptación.
  • Asimilación.
  • Comprensión.
  • Recuerdo
Por lo tanto no uses kiss como una excusa para no esforzarte. Debemos buscar entre cientos de diseños y elegir el que de modo más simple represente mejor la realidad.

miércoles, 11 de octubre de 2017

Cursos online gratuitos que inician en octubre 2017

Para todos los que les interese empezar un curso online, les dejo una buena lista:


Introducción a la programación orientada a objetos en Java
Impartido por: Universidad de los Andes
Plataforma: Coursera
Enlace: Ir al curso

¡A Programar! Una introducción a la programación
Impartido por: Universidad ORT Uruguay
Plataforma: Coursera
Enlace: Ir al curso

Introducción a la programación en Python I
Impartido por: Pontificia Universidad Católica de Chile
Plataforma: Coursera
Enlace: Ir al curso

La Web Semántica
Impartido por: Pontificia Universidad Católica de Chile
Plataforma: Coursera
Enlace: Ir al curso

Detección de objetos
Impartido por: Universitat Autònoma de Barcelona
Plataforma: Coursera
Enlace: Ir al curso

Ludificación
Impartido por: Universidad de Pensilvania
Plataforma: Coursera
Enlace: Ir al curso

Sistemas Digitales: De las puertas lógicas al procesador
Impartido por: Universitat Autònoma de Barcelona
Plataforma: Coursera
Enlace: Ir al curso

Introducción a Data Science: Programación Estadística con R
Impartido por: Universidad Nacional Autónoma de México
Plataforma: Coursera
Enlace: Ir al curso

Arduino y algunas aplicaciones
Impartido por: Universidad Nacional Autónoma de México
Plataforma: Coursera
Enlace: Ir al curso

Excel
Impartido por: Universidad Politécnica de Valencia
Plataforma: edX
Enlace: Ir al curso

Excel 2: Gestión de datos
Impartido por: Universidad Politécnica de Valencia
Plataforma: edX
Enlace: Ir al curso

Diseña presentaciones eficaces con Powerpoint
Impartido por: Universidad Politécnica de Valencia
Plataforma: edX
Enlace: Ir al curso

Android: Introducción a la Programación
Impartido por: Universidad Politécnica de Valencia
Plataforma: edX
Enlace: Ir al curso

domingo, 8 de octubre de 2017

Swift 4 fue liberado



Este post llega muy tarde pero llego! Swift 4 fue liberado (hace rato)

Esta versión contiene muchos cambios y actualizaciones del lenguaje y la biblioteca estándar, especialmente las nuevas funciones de String, las colecciones extendidas, archivo y la serialización, entre otros.

En Swift 4 las cadenas son colecciones propiamente dichas por lo cual son directamente iterable y proporciona todos los métodos de las colecciones y las secuencias, por ejemplo:

for c in myString {
  print(c)
}
myString.filter { c in
  return boolCheck(c)
}
let l = myString.count
let myString2 = myString.dropFirst()

Otra nueva característica es que ahora los string soportan Unicode 9 and literales multi-lineas.

Swift 4 también mejora la forma en que puedes crear, usar y administrar tipos de colecciones, como Dictionary y Set.

En primer lugar, ahora puede crear un diccionario a partir de una secuencia de tuplas, así como especificar cómo manejar los duplicados, si los hay, tanto al crear un diccionario como al fusionar dos diccionarios:

let items = ["ItemA", "ItemB", "ItemC", "ItemA"]
let prices = [14.40, 41.63, 3.71, 15.63]
let catalog1 = Dictionary(uniqueKeysWithValues: zip(items, prices))
let catalog2 = Dictionary(prices, uniquingKeysWith: { (l, r) in
    l })
let catalog3 = Dictionary(prices, uniquingKeysWith: { (l, r) in
    l + r })
let merged = catalog.merge(catalog3) { (l, r) in r }

Dictionary y Set ahora se puede filtrar en otro  tipo, en lugar de en un Array. Además, los diccionarios soportan un nuevo método mapValues:

let catalog4 = catalog.filter { $0.value < 15.0 }
let catalog5 = catalog.mapValues { $0 * 1.2 }

Otra característica útil en los diccionarios es la posibilidad de especificar un valor predeterminado al acceder a sus elementos:

let price1 : Float = catalog['none', default: 0.0]
let price2 : Float? = catalog['none']

Swift 4 añade serialización a todos los tipos a través del protocolo Codable. Por ejemplo:

struct Card: Codable, Equatable {
    enum Suit: String, Codable {
        case clubs, spades, hearts, diamonds
    }

    enum Rank: Int, Codable {
        case two = 2, three, four, five, six, seven, eight, nine, ten, jack, queen, king, ace
    }

    var suit: Suit
    var rank: Rank

    static func ==(lhs: Card, rhs: Card) -> Bool {
        return lhs.suit == rhs.suit && lhs.rank == rhs.rank
    }
}
let hand = [Card(suit: .clubs, rank: .ace), Card(suit: .hearts, rank: .queen)]

Por ultimo, Swift 4 tiene dos modos, seleccionados a través de la opción -swift-version compiler. En el modo Swift 3.2, el compilador aceptará la mayoría de fuentes compatibles con los compiladores Swift 3.x. En este modo, la mayoría de las características del lenguaje Swift 4 estarán disponibles, pero las actualizaciones de las API existentes anteriormente no. En el modo Swift 4.0, obtendrá acceso a todas las funciones de Swift 4, a expensas de algunos cambios de origen, que como de costumbre pueden manejarse utilizando el asistente de migración de Xcode.

Ojo!! Hay mucho más para Swift 4.

Dejo link:
https://www.infoq.com/news/2017/09/swift-4-official-release
https://swift.org

jueves, 5 de octubre de 2017

Un resumen de Scala for the Impatient, parte 31


Sobre escribir métodos abstractos en Traits

Del ejemplo anterior, podemos deducir que TimestampLogger y ShortLogger extienden de ConsoleLogger, la cual extiende del trait Logger el cual no tiene implementación para el método log

trait Logger {
    def log(msg: String) // This method is abstract
}

Por lo tanto

trait TimestampLogger extends Logger {
    override def log(msg: String) { // Overrides an abstract method
        super.log(s"${java.time.Instant.now()} $msg") // Is super.log defined?
    }
}

Esto no debería compilar porque super.log no fue definido pero scala lo toma como que la clase TimestampLogger es abstracta y solo se puede utilizar si se mixea con una clase que implemente este método

Traits para interfaces ricas.

Un trait puede tener muchos métodos útiles que dependan de unos pocos abstractos. Un ejemplo de esto es el Iterator que define docenas de métodos en términos de los métodos abstractos next y hasnext. Vamos a construir métodos que nos permitan imprimir diferentes tipos de logs     

trait Logger {
def log(msg: String)
def info(msg: String) { log(s"INFO: $msg") }
def warn(msg: String) { log(s"WARN: $msg") }
def severe(msg: String) { log(s"SEVERE: $msg") }
}

Note que estamos combinando métodos abstractos con implementaciones concretas. 

abstract class SavingsAccount extends Account with Logger {
def withdraw(amount: Double) {
if (amount > balance) severe("Fondos insuficientes")
else …
}
}

Un campo concreto en Traits

Un campo de un traits puede ser concreto o abstracto. Si se asigna un valor al campo este será concreto, 

trait ShortLogger extends Logger {
val maxLength = 15 // A concrete field
abstract override def log(msg: String) {
super.log(
if (msg.length <= maxLength) msg
else s"${msg.substring(0, maxLength – 3)}...")
}
}

 Una clase puede mixear con el campo maxLenght

class SavingsAccount extends Account with ConsoleLogger with ShortLogger {
     var interest = 0.0
     def withdraw(amount: Double) {
          if (amount > balance) log("Fondos insuficientes")
          else …
     }
}

Note que la clase SavingsAccount tiene la variable interest, pero no balance, balance viene de Account

class Account {
     var balance = 0.0
}

La maquina virtual java no permite heredar campos de diferentes interfaces o super clases, por lo que el compilador scala debe copiarlos. 

Campos abstractos en Traits

Los campos que no son inicializados son abstractos, y deben ser sobreescritos por la subclase concreta. 

Por ejemplo: 

trait ShortLogger extends Logger {
     val maxLength: Int // An abstract field
     
      abstract override def log(msg: String) { ... }

      super.log(
                if (msg.length <= maxLength) msg
                else s"${msg.substring(0, maxLength – 3)}...")
                // El campo maxLength es utilizado en la implementación. 
}

Cuando se utiliza este trait se debe asignar un valor a maxLength: 

class SavingsAccount extends Account with ConsoleLogger with ShortLogger {
     val maxLength = 20 // No es necesario escribir override
}

Ahora todos los mensajes de registro se truncan después de 20 caracteres.

Esta forma de proporcionar valores para los parámetros de rasgo es particularmente útil cuando se construyen objetos sobre la marcha. Volvamos a nuestra cuenta de ahorros original:

class SavingsAccount extends Account with Logger { ... }

Ahora, podemos truncar los mensajes en una instancia de la siguiente manera:

val acct = new SavingsAccount with ConsoleLogger with ShortLogger {
      val maxLength = 20
}


miércoles, 4 de octubre de 2017

Monitoriando tu servidor con Monit

Tuve un requerimiento especial, me pidieron que cuando se baje el server (en este caso un tomcat se envíe un mail) y gracias a este requerimiento conocí a Monit

Monit es un software que se utiliza en linux con el podemos monitoriar nuestro servidor, procesos, aplicaciones, archivos, etc. Muy fácil de configurar podemos indicarle que nos envíe mail cuando hay un evento determinado o que baje una aplicación o que la reinicie.

Es muy fácil de instalar y configurar. Si estamos en alguna distribución rhel, la instalación sería:

 yum install monit

o en distros basadas en debian:

sudo apt-get install monit

Una vez instalado debemos modificar el archivo /etc/monit.conf esta muy bien comentado y tiene ejemplos de configuraciones, para escuchar procesos o servicio o archivos. Otra cosa que esta muy buena es que se puede enviar una notificación cuando un proceso ocupa mucho cpu o memoria.

Veamos un ejemplo de monit.conf :

###############################################################################
## Monit control file
###############################################################################
##
## Comments begin with a '#' and extend through the end of the line. Keywords
## are case insensitive. All path's MUST BE FULLY QUALIFIED, starting with '/'.
##
## Below you will find examples of some frequently used statements. For 
## information about the control file, a complete list of statements and 
## options please have a look in the monit manual.
##
##
###############################################################################
## Global section
###############################################################################
##
## Start monit in the background (run as a daemon):
#
set daemon  120           # check services at 2-minute intervals
    with start delay 240  # optional: delay the first check by 4-minutes
#                           # (by default check immediately after monit start)
#
#
## Set syslog logging with the 'daemon' facility. If the FACILITY option is
## omitted, monit will use 'user' facility by default. If you want to log to 
## a stand alone log file instead, specify the path to a log file
#
set logfile syslog facility log_daemon                       
#
#
### Set the location of monit id file which saves the unique id specific for
### given monit. The id is generated and stored on first monit start.
### By default the file is placed in $HOME/.monit.id.
#
# set idfile /var/.monit.id
#
### Set the location of monit state file which saves the monitoring state
### on each cycle. By default the file is placed in $HOME/.monit.state. If
### state file is stored on persistent filesystem, monit will recover the
### monitoring state across reboots. If it is on temporary filesystem, the
### state will be lost on reboot.
#
# set statefile /var/.monit.state
#
## Set the list of mail servers for alert delivery. Multiple servers may be 
## specified using comma separator. By default monit uses port 25 - this
## is possible to override with the PORT option.
#
set mailserver localhost
#
#
## By default monit will drop alert events if no mail servers are available. 
## If you want to keep the alerts for a later delivery retry, you can use the 
## EVENTQUEUE statement. The base directory where undelivered alerts will be 
## stored is specified by the BASEDIR option. You can limit the maximal queue
## size using the SLOTS option (if omitted, the queue is limited by space 
## available in the back end filesystem).
#
# set eventqueue
#     basedir /var/monit  # set the base directory where events will be stored
#     slots 100           # optionaly limit the queue size
#
#
## Send status and events to M/Monit (Monit central management: for more
## informations about M/Monit see http://www.tildeslash.com/mmonit).
#
# set mmonit http://monit:monit@192.168.1.10:8080/collector
#
#
## Monit by default uses the following alert mail format:
##
## --8<--
## From: monit@$HOST                         # sender
## Subject: monit alert --  $EVENT $SERVICE  # subject
##
## $EVENT Service $SERVICE                   #
##                                           #
## Date:        $DATE                   #
## Action:      $ACTION                 #
## Host:        $HOST                   # body
## Description: $DESCRIPTION            #
##                                           #
## Your faithful employee,                   #
## monit                                     #
## --8<--
##
## You can override this message format or parts of it, such as subject
## or sender using the MAIL-FORMAT statement. Macros such as $DATE, etc.
## are expanded at runtime. For example, to override the sender:

set mail-format { from: monit@conexion-empleo.com }

#
## You can set alert recipients here whom will receive alerts if/when a 
## service defined in this file has errors. Alerts may be restricted on 
## events by using a filter as in the second example below. 
#

set alert franck.dagostini@gmail.com

# set alert manager@foo.bar only on { timeout }  # receive just service-
#                                                # timeout alert
#
#
## Monit has an embedded web server which can be used to view status of 
## services monitored, the current configuration, actual services parameters
## and manage services from a web interface.
#
set httpd port 2812 and
#     use address localhost  # only accept connection from localhost
  allow localhost        # allow localhost to connect to the server and
  allow admin:monit      # require user 'admin' with password 'monit'
#     allow @monit           # allow users of group 'monit' to connect (rw)
#     allow @users readonly  # allow users of group 'users' to connect readonly
#
#
###############################################################################
## Services
###############################################################################
##
## Check general system resources such as load average, cpu and memory
## usage. Each test specifies a resource, conditions and the action to be
## performed should a test fail.
#
check system conexion-empleo.com
  if loadavg (1min) > 4 then alert
  if loadavg (5min) > 2 then alert
  if memory usage > 75% then alert
  if cpu usage (user) > 70% then alert
  if cpu usage (system) > 30% then alert
  if cpu usage (wait) > 20% then alert
#
#    
## Check a file for existence, checksum, permissions, uid and gid. In addition
## to alert recipients in the global section, customized alert will be sent to 
## additional recipients by specifying a local alert handler. The service may 
## be grouped using the GROUP option.
#    
#  check file apache_bin with path /usr/local/apache/bin/httpd
#    if failed checksum and 
#       expect the sum 8f7f419955cefa0b33a2ba316cba3659 then unmonitor
#    if failed permission 755 then unmonitor
#    if failed uid root then unmonitor
#    if failed gid root then unmonitor
#    alert security@foo.bar on {
#           checksum, permission, uid, gid, unmonitor
#        } with the mail-format { subject: Alarm! }
#    group server
#
#    
## Check that a process is running, in this case Apache, and that it respond
## to HTTP and HTTPS requests. Check its resource usage such as cpu and memory,
## and number of children. If the process is not running, monit will restart 
## it by default. In case the service was restarted very often and the 
## problem remains, it is possible to disable monitoring using the TIMEOUT
## statement. This service depends on another service (apache_bin) which
## is defined above.
#    
#  check process apache with pidfile /usr/local/apache/logs/httpd.pid
#    start program = "/etc/init.d/httpd start" with timeout 60 seconds
#    stop program  = "/etc/init.d/httpd stop"
#    if cpu > 60% for 2 cycles then alert
#    if cpu > 80% for 5 cycles then restart
#    if totalmem > 200.0 MB for 5 cycles then restart
#    if children > 250 then restart
#    if loadavg(5min) greater than 10 for 8 cycles then stop
#    if failed host www.tildeslash.com port 80 protocol http
#       and request "/monit/doc/next.php"
#       then restart
#    if failed port 443 type tcpssl protocol http
#       with timeout 15 seconds
#       then restart
#    if 3 restarts within 5 cycles then timeout
#    depends on apache_bin
#    group server
#    
#    
## Check filesystem permissions, uid, gid, space and inode usage. Other services,
## such as databases, may depend on this resource and an automatically graceful
## stop may be cascaded to them before the filesystem will become full and data
## lost.
#
#  check filesystem datafs with path /dev/sdb1
#    start program  = "/bin/mount /data"
#    stop program  = "/bin/umount /data"
#    if failed permission 660 then unmonitor
#    if failed uid root then unmonitor
#    if failed gid disk then unmonitor
#    if space usage > 80% for 5 times within 15 cycles then alert
#    if space usage > 99% then stop
#    if inode usage > 30000 then alert
#    if inode usage > 99% then stop
#    group server
#
#
## Check a file's timestamp. In this example, we test if a file is older 
## than 15 minutes and assume something is wrong if its not updated. Also,
## if the file size exceed a given limit, execute a script
#
#  check file database with path /data/mydatabase.db
#    if failed permission 700 then alert
#    if failed uid data then alert
#    if failed gid data then alert
#    if timestamp > 15 minutes then alert
#    if size > 100 MB then exec "/my/cleanup/script" as uid dba and gid dba
#
#
## Check directory permission, uid and gid.  An event is triggered if the 
## directory does not belong to the user with uid 0 and gid 0.  In addition, 
## the permissions have to match the octal description of 755 (see chmod(1)).
#
#  check directory bin with path /bin
#    if failed permission 755 then unmonitor
#    if failed uid 0 then unmonitor
#    if failed gid 0 then unmonitor
#
#
## Check a remote host network services availability using a ping test and 
## check response content from a web server. Up to three pings are sent and 
## connection to a port and a application level network check is performed.
#
#  check host myserver with address 192.168.1.1
#    if failed icmp type echo count 3 with timeout 3 seconds then alert
#    if failed port 3306 protocol mysql with timeout 15 seconds then alert
#    if failed url
#       http://user:password@www.foo.bar:8080/?querystring
#       and content == 'action="j_security_check"'
#       then alert
#
#
###############################################################################
## Includes
###############################################################################
##
## It is possible to include additional configuration parts from other files or
## directories.
#
#  include /etc/monit.d/*

# mysql
check process mysqld with pidfile /var/lib/mysql/ns388683.pid
  group database
  start program = "/etc/init.d/mysql start"
  stop program = "/etc/init.d/mysql stop"
  if failed host 127.0.0.1 port 3306 then restart
  if 5 restarts within 5 cycles then timeout

# nginx
check process nginx with pidfile /opt/nginx/logs/nginx.pid
  start program = "/etc/init.d/nginx start"
  stop  program = "/etc/init.d/nginx stop"
  if failed host 127.0.0.1 port 80 then restart
  if cpu is greater than 40% for 2 cycles then alert
  if cpu > 60% for 5 cycles then restart 
  if 10 restarts within 10 cycles then timeout

# redis
check process redis with pidfile /var/run/redis.pid
  start program = "/etc/init.d/redis-server start"
  stop program = "/etc/init.d/redis-server stop"
  group redis

check file dump.rdb with path /var/lib/redis/dump.rdb
  if size > 100 MB then alert

# tomcat
check process tomcat with pidfile /var/run/tomcat/tomcat.pid
  start program = "/etc/init.d/tomcat start" 
  as uid solr gid solr
  stop program = "/etc/init.d/tomcat stop" 
  as uid solr gid solr
  if failed port 8080 then alert
  if failed port 8080 for 5 cycles then restart

A la vez tenemos un visor de todo lo monitoriado que se denomina mmonit, este producto permite ver en mayor detalle la información de monit, a la vez cuenta con algunos gráficos.

No lo he probado mmonit aun pero voy a hacerlo, por la pagina se ve muy bien.

Por lo pronto y como conclusión podemos decir que monit es un software liviano de fácil configuración que es excelente para notificar el estado de un server, proceso o archivo.

Dejo link: https://github.com/arnaudsj/monit
https://mmonit.com/monit/