Por qué elegí Delphi


Caja de la versión Delphi 1.0

Yo empecé en el mundo de la programación, creo que como todos los de mi generación, con Visual Basic, era el lenguaje que usábamos para hacer nuestros primeros programas, más tarde cuando llegué a la Universidad ya empecé con Delphi (Turbo Pascal),  C++, Assembler, etc... recuerdo en la materia de Algoritmos y Estructura de Datos como el profesor asociaba el pseudo-código de los diferentes algoritmos con las funciones y procedimientos de Delphi, parecía todo muy natural como si Delphi hubiese nacido a propósito para que los alumnos entendiésemos esa materia.
Más tarde en mi trabajo ya tuve que entrar en el mundo de la Web, HTML, Javascript, PHP, y aunque fue un gran cambio, no dejé de trabajar con Delphi.

Estos son algunos de los programas que he desarrollado:

Delphi para Windows:

-Software para gestión de Fundaciones.
-Software para gestión de Asociaciones.
-Generación y envío de recibos formato SEPA.
-Kinect (aplicaciones varias)
-Arduino - BasicX.
-Inteligencia Artificial con FANN aplicada al análisis del precio de las acciones.
-Bots de compra venta automática de acciones.
-Software de Videovigilancia.
-Creación de escenarios en 3D.
-Software para jugar al ajedrez.
-Servidor de correo POP3.
-Gestión de envío / recepción de mensajes SMS.
-Gestión de centralita telefónica (llamadas entrantes, salientes, cómputo).
-Gestión de redes (análisis de tráfico - sniffer - utilización de Whois)

Delphi para la Web:

-Software de Horarios para Centros Educativos.
-Generación de informes Tutoriales en Centros Educativos
-Software para concertar citas de entrevistas Alumno - tutor.
-Gestión de accesos con tarjetas RFID
-Software para Bibliotecas Escolares.
-Gestión del email vía web.
-Gestión de currículos.
-Gestión de servicio médico.

Delphi para dispositivos móviles:

-App detector de metales. (utiliza el magnetómetro del móvil)
-App educativa para aprender la señales de tráfico (utiliza SQLite y criptografía básica)
-App linterna (gestiona el acceso a la cámara del dispositivo)
-App para gestión de un GPS (Utiiza el sensor de orientación, localización y magnetómetro,
incorpora mapas de OpenStreetMap y Google Maps (tráfico, elevación del terreno, ruta entre 2 puntos), usa la Api de Google, base de datos SQLite y maneja la API de Android para ubicación de satélites del GPS, es hasta ahora mi mejor app)

Como veis, la experiencia que tengo en programación es tremenda y todo hecho con este magnífico lenguaje.
Muchos de los módulos anteriores los he implementado utilizando Intraweb en un entorno cliente-servidor bajo IIS7, casi cualquier proyecto que tengáis pensado se puede realizar con este lenguaje.
Últimamente estoy metido de lleno en programación para dispositivos móviles y ya cuento en la Play Store con varias apps con un gran número de descargas (no lo veo como negocio, sino como desarrollo profesional para ir mejorando un poco más cada día).

Una de las opciones que más valoro de este lenguaje es la PORTABILIDAD, es decir la capacidad de programar una vez y tener el código disponible en varias plataformas (Windows, Android, IOS, Linux con FMXLinux), si recordáis antes había que aprender Objective-C si querías hacer algo para Mac, o utilizar Eclipse si querías hacer algo para Android o Visual.Net o Visual Basic si querías programar en Windows y ahora con Delphi eso no es necesario, imagínate el tiempo que te ahorras, yo solamente por eso, creo que jamás dejaré de utilizarlo.

Seguramente te dirán ...¿ y para la web ? bien pues tienes a UNIGUI (utiliza unas librerías Javascript con Delphi) aquí tienes una demo o también Delphi para la Web (Intraweb) que es lo que yo he utilizado en mis proyectos (permite utilizar el lenguaje Pascal o incorporar tus propios módulos en javascript).

Delphi, no se queda parado en el tiempo, con cada nueva versión incorpora funciones y características de otros lenguajes (como los genéricos, funciones anónimas, etc...), la VCL (librería de componentes visuales) ha sido mejorada con la introducción de Firemonkey (es el entorno que permite generar aplicaciones multiplataforma) que por cierto, utiliza la GPU para renderizar los gráficos...es impresionante ver la fluidez del movimiento cuando haces animaciones.

En las últimas versiones incorpora la posibilidad de hacer programación en paralelo, con lo que puedes incrementar drásticamente la capacidad y velocidad de cálculo de tus programas.

Utiliza programación visual basada en componentes, lo que hace que sea sumamente sencillo y rápido iniciar / terminar un proyecto. Te puedo asegurar que con Delphi se hace un proyecto un 70% más rápido que con otros lenguajes.

Miles de aplicaciones se han desarrollado ya, aquí tienes un resumen, ¿por qué no lo pruebas ? aquí tienes una versión gratuita , ya te aseguro que no te vas a arrepentir.

Y tú, ¿por qué elegiste Delphi? Comparte tus comentarios en tu blog utilizando el hashtag #WhyIChooseDelphi













Ya está disponible Rad Studio 10.2 Tokyo - Release 1

Delphi Tokyo 10.2 Wallpaper


Ya está disponible para su descarga la Release 1 de Rad Studio 10.2 Tokyo, que es una actualización de Delphi 10.2 Tokyo, C++Builder 10.2 Tokyo y RAD Studio 10.2 Tokyo disponible para los clientes que tengan activa una Update Subscription.
Soluciona un número importante de problemas que han reportado los usuarios y añade nuevas mejoras respecto a la versión inicial.

Entre las mejoras hay que mencionar las siguientes:

- Mejoras en el rendimiento del servidor de Delphi Linux para RAD Server y DataSnap.
- Mejoras en Delphi y compilador C++ y actualizaciones del compilador que resuelven problemas de la carga de paquetes, especialmente al depurar en Windows 10 Creators Update que afectan a la forma en que el sistema operativo carga DLLs y paquetes Delphi (BPLs), que hacía que se repitiese la operación de carga varias veces, dificultando gravemente la depuración de aplicaciones con paquetes runtime.
- Soporte para las últimas versiones de iOS y Xcode (iOS 10.3 y XCode 8.3.3) .
- Compatibilidad con FireDAC para MSSQL 2012, 2014, 2016 y controlador ODBC 13.
- Mejoras significativas en el compilador C++ relacionadas con la vinculación de proyectos grandes.
- Correcciones y mejoras a la Biblioteca Runtime y VCL.
- Mejoras adicionales de Android en torno a renderización y rendimiento de control y correcciones para problemas de TEdit con Android N.
- Soporte de FireDAC para Interbase 2017 para el nivel de aislamiento exclusivo y tiempo de espera de transacción.
- Cambios en DataSize para los campos de tipo ftInteger y ftLongWord para evitar el uso de LongInt y LongWordtype dependientes de la plataforma (el cambio afecta sólo a las plataformas Linux de 64 bits y de 64 bits) y los cambios relacionados con SetFieldData y GetFieldData
- Correcciones para más de 140 problemas reportados por los clientes en Quality Portal.

La Release 1 se puede descargar desde aquí, bien como una ISO (iniciando el archivo install_RADStudio.exe) o para su instalación online:

Problemas conocidos:

Después de actualizar a 10.2.1 desde 10.2.0, es posible que vea el siguiente mensaje de error al instalar un componente IOT( Internet of Things ) desde el Administrador de Paquetes GetIt: "Problema al agregar el archivo dcliotReg.pas al proyecto."
Esto se debe a una falta de alineación entre el registro y el estado real de los paquetes.
Como solución, se recomienda quitar la carpeta C: \ Users \ \ Documents \ Embarcadero \ Studio \ 19.0 \ CatalogRepository \ dcliot-250 y volver a ejecutar GetIt para actualizar el componente.



Delphi Academy

DelphiAcademy
Vuelve Delphi Academy, que para los que aún lo conozcan, es un proyecto de Embarcadero que se creó para dar a conocer, sobre todo a los usuarios de habla hispana, las particularidades de Delphi, por medio de videotutoriales de unos 30 minutos (en español), personalmente echo en falta este tipo de proyectos en nuestro idioma ya que la mayoría del material que he podido encontrar (libros, webs, tutoriales, etc..) está inglés y desde luego es de agradecer para la Comunidad de programadores que se creen iniciativas de este estilo.

Tratan temas para todo tipo de usuarios, apto para aquellos que estén comenzando a programar en Delphi, como para los que llevan unos años y quieran profundizar en algunos temas (Linux, Firedac, programación paralela, DataSnap REST, Layouts, desarrollo Web, etc.) desde luego aquí tienen sin duda material de calidad.

La grabación de todos los episodios anteriores se pueden ver desde el canal de Youtube
y el código fuente de los ejemplos y diapositivas los podéis descargar desde aquí

Comienzan el próximo viernes 11 de Agosto con la siguiente agenda:
Delphi Academy ¡Anunciando nuevos episodios para el segundo semestre de 2017

Para inscribirse hay que ir a la siguiente página http://embt.co/AcademyLA






Cómo controlar los gestos en las aplicaciones

Rad Studio nos ofrece un componente llamado tGesture para detectar los movimientos de los dedos sobre la pantalla del dispositivo.
Utilizarlo es muy sencillo, sólo hay que abrir la Tool Palette y colocarlo en el Form principal del proyecto.
Después desde el Object Inspector hay que desplegar la propiedad Touch y asociarlo a GestureManager, con ello nos aparecerán dos nuevas propiedades: Gestures (gestos estándar) e InteractiveGestures.



En este link tenéis en detalle la descripción de todos los gestos que reconoce.
Desplegando en el árbol Gestures - Standard tendremos que hacer clic sobre el gesto que queramos reconocer (izquierda, derecha, arriba, abajo, etc...)

GESTURES:
Consta de más de 30 gestos, como  Left, Right, Scratchout, Circle, ChevronUp, etc...

INTERACTIVE GESTURES:
Son gestos Multi-touch que disparan el evento OnGesture cuando son detectados. El parámetro EventInfo da información adicional sobre la localización del punto de toque, el ángulo, la inercia del desplazamiento, etc...
Los InteractiveGestures pueden ser: "Zoom", "Pan", "Rotate", "Two Finger Tap", "Long Tap", "Double Tap", y  "Press And Tap".

Para obtener el gesto detectado en el evento OnGesture teclearemos:

procedure TForm1.FormGesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
  S: String;
begin
  if GestureToIdent(EventInfo.GestureID, S) then
    ShowMessage(S)
  else
    ShowMessage('Could not translate gesture identifier');
end;
--

Por otra parte también quería enseñaros otra forma menos utilizada para detectar los gestos sin necesidad de añadir componentes a la app, pero más sencilla si cabe, que es utilizar el evento OnTouch del Form, del siguiente modo:



//Autor:http://www.danielespinetti.it

var
    FStartingPoint: TPointF;
    FDeviceScale: Single;
    ScreenSvc: IFMXScreenService;
    FScreenWidth: Single;
    FScreenHeight: Single;
    previousTranslateX: Single;
    startX: Single;
    previousTranslateY: Single;
    startY: Single;
...

procedure TForm1.FormShow(Sender: TObject);
begin

  FStartingPoint := PointF(0, 0);
  if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService,
    IInterface(ScreenSvc)) then
  begin
    FDeviceScale := ScreenSvc.GetScreenScale();
    FScreenWidth := ScreenSvc.GetScreenSize().X;
    FScreenHeight := ScreenSvc.GetScreenSize().Y;
  end;

  Rectangle1.Width := FScreenWidth * 2;
  Rectangle1.Height := FScreenHeight * 2;
  Rectangle1.Position.X := 0;
  Rectangle1.Position.Y := 0;

end;

procedure TForm1.FormTouch(Sender: TObject; const Touches: TTouches;
  const Action: TTouchAction);
begin
  if Length(Touches) <> 2 then
    exit;
  case Action of
    TTouchAction.None:
      ;
    TTouchAction.Up:
      begin
        previousTranslateX := Rectangle1.Position.X;
        previousTranslateY := Rectangle1.Position.Y;
      end;
    TTouchAction.Down:
      begin
        startX := Touches[1].Location.X - previousTranslateX;
        startY := Touches[1].Location.Y - previousTranslateY;
      end;
    TTouchAction.Move:
      begin
        Rectangle1.Position.X := Touches[1].Location.X - startX;
        Rectangle1.Position.Y := Touches[1].Location.Y - startY;
      end;
    TTouchAction.Cancel:
      ;
  end;
end;

Para probarlo lo único que tenéis que hacer es colocar un rectángulo en el Form y colgando de él una imagen

compilar y ejecutar el proyecto y probar a mover el rectángulo utilizando dos dedos.





Quizás te pueda interesar:
App para mostrar moléculas en 3D

Integrar Whatsapp con Delphi

A continuación vamos a ver cómo enviar un texto desde vuestra app a la popular aplicación de mensajería.
Empezamos con nuestro RAD STUDIO XE, desde el menú File-New-Multi Device Application Delphi, para crear un nuevo proyecto que almacenaremos en una carpeta de nuestro PC


En la pantalla siguiente tenemos que elegir entre varias opciones, si queremos que aparezca un form en blanco, o si queremos uno con toolbars de cabecera y pie, etc... en nuestro caso seleccionamos el icono blank application




Después desde la "Tool Palette" seleccionamos dos objetos:

- tEdit ,  propiedad Name="Edit1"
- tButton,  propiedad Name="Button1"

En la propiedad Text del tEdit escribimos "Hola desde RAD STUDIO XE", y en la propiedad Text del tButton tecleamos "Enviar a Whatsapp" y nos quedará de la siguiente forma:



Por otra parte, recordar que al tratarse de un proyecto Android hay que añadir ciertas units, en el uses del proyecto.

implementation
{$R *.fmx}
uses
  FMX.Helpers.Android, Androidapi.Jni.GraphicsContentViewText,
  Androidapi.Jni.Net, Androidapi.Jni.JavaTypes, idUri, Androidapi.Jni,
  Androidapi.JNIBridge, Androidapi.Helpers;



Hacemos doble clic sobre el tButton para modificar el evento "onclic"  y añadimos el siguiente trozo de código:

procedure TForm2.Button1Click(Sender: TObject);
var
  Intent1 : JIntent;
 
begin
   
  Intent1 := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_SEND);
  Intent1.setType(StringToJString('text/plain'));
  Intent1.putExtra(TJIntent.JavaClass.EXTRA_TEXT,
      StringToJString(Edit1.text));
  Intent1.setPackage(StringToJString('com.whatsapp'));
  SharedActivity.startActivity(Intent1);
end;

Bien, pues ahora nos queda ejecutarlo y veremos cómo funciona perfectamente.
Al pulsar el botón se abre automáticamente Whatsapp y nos solicita que seleccionemos un contacto, para después mostrarnos dentro de su chat el texto "Hola desde RAD STUDIO XE"






También te puede interesar:



Visita al centro de datos de Google en 360º

A continuación os dejo el vídeo de una visita a uno de los muchos centros de datos que Google posee.

Os recuerdo que es un recorrido en 360º, es decir que a medida que se va haciendo la presentación del vídeo, haciendo un clic mantenido sobre él, se puede ver todo el entorno que rodea a la escena.

Se muestra una de las plantas del centro de proceso de datos, que alberga un inmenso cluster de PCs, unidos por fibra, hablan del nivel de seguridad de acceso, cómo gestionan la cadena de custodia de los discos estropeados, cómo se refrigera el edificio y de dónde sale la energía necesaria para hacerlo funcionar.



Otro vídeo presentado por el Director Técnico del Centro de Datos  (por cierto dice que la temperatura allí es de 27ºC, superior a lo que es habitual, porque según él, así se comportan los equipos de una forma más eficiente)


Ejemplos de programación paralela



La utilización de la programación paralela puede incrementar drásticamente la velocidad de ejecución de nuestros programas, por ejemplo imaginar el caso en que tengamos dos tareas A y B, una se ejecuta en 5 segundos y otra en 10 segundos entonces:

- Si las ejecutamos secuencialmente, como se hace habitualmente, tardaríamos en terminarlas 15 segundos
- Si utilizamos WaitForAll tardaríamos 15
- Si utilizamos WaitForAny tardaríamos 5.

La Biblioteca de Programación Paralela (PPL) que incorpora Rad Studio Tokyo proporciona una clase TTask para ejecutar una o múltiples tareas en paralelo, y además añade unos métodos que se utilizan para sincronizar o para detener dichas tareas. A continuación tenéis unos ejempl
os de uso:

Utilizando un array de ITask.


procedure TFormThreading.MyButtonClick(Sender: TObject);
var
 tasks: array of ITask;
 value: Integer;
begin
 Setlength (tasks ,2);
 value := 0;

 tasks[0] := TTask.Create (procedure ()
   begin
     sleep (3000); // 3 seconds
     TInterlocked.Add (value, 3000);
   end);
 tasks[0].Start;

 tasks[1] := TTask.Create (procedure ()
   begin
     sleep (5000); // 5 seconds
     TInterlocked.Add (value, 5000);
   end);
 tasks[1].Start;

 TTask.WaitForAll(tasks);
 ShowMessage ('All done: ' + value.ToString);
end; 

Iniciar una tarea en background que no bloquea al programa principal:

procedure TFormThreading.Button1Click(Sender: TObject);
var
 aTask: ITask;
begin
 // not a thread safe snippet
 aTask := TTask.Create (procedure ()
   begin
     sleep (3000); // 3 seconds
     ShowMessage ('Hello');
   end);
 aTask.Start;
end;

Hay que tener cuidado con los interbloqueos asociados con las variables que se utilicen (se debe utilizar los métodos tInterlocked de la unit System.SyncObjs). TInterlocked implementa operaciones con el propósito de asegurar que el “thread” o el “multi-core” sea seguro y estable cuando se modifican variables que pueden ser accedidas durante la ejecución de múltiples threads. Ejemplo de utilización de tInterlocked.

var iCount: Integer;
begin
  iCount := 0;
  TParallel.&For(1, 10,
    procedure (Current: Integer)
    begin
      TInterlocked.Add(iCount, Current);
    end
  );
end;

Ejemplo de utilización de tInterlocked para hacer una suma utilizando variables globales:

 Se utilizan varios procedimientos:
 TInterlocked.Exchange(iSum, 0); copia el valor “0” a la variable iSum
TInterlocked.Add(iSum, Index); suma el valor Index a la variable iSum y lo devuelve en iSum TInterlocked.Read(iSum); Lee el valor de la variable iSum
Como véis no es obligatorio que tInterlocked se sitúe siempre dentro del bloque tTask.Run
 
VAR
iSum:integer;
procedure TFormMain.button1(Sender: TObject);
begin
//calcula iSum:=0;
  TInterlocked.Exchange(iSum, 0);
  TTask.Run(
    procedure
    begin
      TParallel.For(0, 10,
        procedure (Index: Integer)
        begin
         //calcula iSum := iSum + Index;
          TInterlocked.Add(iSum, Index);
        end);
    end);
end;
//lee cada segundo la variable global iSum en un tTimer
procedure TFormMain.Timer1Timer(Sender: TObject);
begin
 LabelSum.Text:= TInterlocked.Read(iSum);
end;

BUCLES FOR

 La PPL proporciona una función tParallel.For que permite realizar bucles For en paralelo. Equivalencia entre un “for” secuencial y un “for” en paralelo. 

EJEMPLO: BUCLE FOR SIMPLE (NO BLOQUEANTE) utilizando tThread.queue,

Internamente se espera a que la CPU esté en estado Idle).


procedure TFormMain.ButtonStartParallelForClick(Sender: TObject);
begin
  Memo1.Lines.Clear;
  TTask.Run(
    procedure
    begin
      TParallel.For(0, 9,
        procedure (Index: Integer)
        begin
          Sleep(200);
          TThread.Queue(TThread.CurrentThread,
            procedure
            begin
              Memo1.Lines.Add(Index.ToString);
            end);
        end);
    end);
end;

Ejemplo. Cálculo de los números primos menores o iguales a 5000000

uses
  System.Threading;
  System.Diagnostics;
  System.SyncObjs;


const
  Max =5000000;

procedure TForm1.btnForLoopClick(Sender: TObject);
var
  I, Tot: Integer;
  SW: TStopwatch;
begin
    // counts the prime numbers below a given value
   Tot:=0;
   SW := TStopWatch.Create;
   SW.Start;
   for I := 1 to Max do
   begin
     if IsPrime(I) then
        Inc(Tot);
   end;
   SW.Stop;
   Memo1.Lines.Add(Format('Sequential For loop. Time (in milliseconds): %d - Primes found: %d', [SW.ElapsedMilliseconds,Tot]));
end;



procedure TForm1.btnParallelForClick(Sender: TObject);
var
  Tot: Integer;
  SW: TStopwatch;
begin
     try
     // counts the prime numbers below a given value
       Tot :=0;
       SW :=TStopWatch.Create;
       SW.Start;
//el primer parámetro “2” del bucle FOR es opcional e identifica cómo 
//se agrupan los threads al ser ejecutados
       TParallel.For(2,1,Max,procedure(I:Int64)
       begin
         if IsPrime(I) then
          TInterlocked.Increment(Tot);
       end);
     SW.Stop;
      Memo1.Lines.Add(Format('Parallel For loop. Time (in milliseconds): %d - Primes found: %d', [SW.ElapsedMilliseconds,Tot]));
     except on E:EAggregateException do
      ShowMessage(E.ToString);
     end;
end;

function IsPrime(N: Integer): Boolean;
var
  Test, k: Integer;
begin
  if N <= 3 then
    IsPrime := N > 1
  else if ((N mod 2) = 0) or ((N mod 3) = 0) then
    IsPrime := False
  else
  begin
    IsPrime := True;
    k := Trunc(Sqrt(N));
    Test := 5;
    while Test <= k do
    begin
      if ((N mod Test) = 0) or ((N mod (Test + 2)) = 0) then
      begin
        IsPrime := False;
        break; { jump out of the for loop }
      end;
      Test := Test + 6;
    end;
  end;
end;

El resultado muestra que el bucle en paralelo for es mucho más eficiente que el secuencial; 
 

Ejemplo de descarga de una página web utilizando ttask:

procedure TMyForm.StartDownloadTask(lPath: string)
begin
    TTask.Create(
      procedure
      var
        lHTTP: TIdHTTP;
        IdSSL: TIdSSLIOHandlerSocketOpenSSL;
      begin
        lHTTP := TIdHTTP.Create(nil);

        TThread.Synchronize(nil,
          procedure
          begin
            Form1.Caption := 'Task Running...';
          end
        );

        try
          lHTTP.ReadTimeout := 30000;
          lHTTP.HandleRedirects := True;
          IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
          IdSSL.SSLOptions.Method := sslvTLSv1;
          IdSSL.SSLOptions.Mode := sslmClient;
          lHTTP.IOHandler := IdSSL;
        Finally
          try
            lHTTP.Get('http://website.com/'+lPath, TStream(nil));
          Finally
            lHTTP.Free;
          end;
        end;

        TThread.Synchronize(nil,
          procedure
          begin
            Memo1.Lines.Add(lPath);
           end
        );

      end
    ).Start;
end;

Ejemplo que utiliza TParallel.for para detener la ejecución de todos los threads cuando se encuentra una respuesta.
Utiliza TParallel.LoopState para avisar a otros procesos que utilizan el loop paralelo. Utilizando la señal “Stop” todas las iteraciones se detienen. Las iteraciones en curso deberían chequear loopState.Stopped.


procedure Parallel3(CS: TCriticalSection);
var
  Ticks: Cardinal;
  i,ix: Integer;  // variables that are only touched once in the Parallel.For loop
begin
  i := 0;
  Ticks := TThread.GetTickCount;
  TParallel.For(1,WorkerCount,
    procedure(index:Integer; loopState: TParallel.TLoopState)
    var
      k,l,m: Integer;
    begin
      // Do something complex
      k := (1000 - index)*1000;
      for l := 0 to Pred(k) do
        m := k div 1000;
      // If criteria to stop fulfilled:
      CS.Enter;
      Try
        if loopState.Stopped then // A solution was already found
          Exit;
        loopState.Stop;  // Signal 
        Inc(i);
        ix := index;
      Finally
        CS.Leave;
      End;
    end
  );
  Ticks := TThread.GetTickCount - Ticks;
  WriteLn('Parallel time ' + Ticks.ToString + ' ticks', ' i :',i,' index:',ix);
end;

EJEMPLO: Utilización de Ttask para dibujar rectángulos, utilizando o no tSyncronize

// Author: Danny Wind
// http://dannywind.nl/wp-content/uploads/2015/10/CodeRageX_DelphiParallelProgrammingDeepDive_DannyWind.zip

procedure TFormMain.ButtonStartParallelForClick(Sender: TObject);
var
  lStride, lFrom, lTo: Integer;
begin
  ClearRectangles;
  lFrom := Low(FRectangles);
  lTo := High(FRectangles);
  lStride := Trunc(NumberBoxStride.Value);
  {TTask.Run executes the entire parallel for loop itself in parallel,
   which enables you to actually see the progress of the for-loop}
  TTask.Run(procedure
            begin
              TParallel.For(lStride, lFrom, lTo, PaintRectangle)
            end);
end;

procedure TFormMain.PaintRectangle(Index: Integer);
var
  lR,lG,lB: Byte;
  lColor:TAlphaColor;
begin
  lR := TThread.CurrentThread.ThreadID MOD High(Byte);
  lG := (2 * lR) MOD High(Byte);
  lB := (4 * lR) MOD High(Byte);
  lColor := MakeColor(lR, lG, lB, High(Byte));
  if CheckBoxSync.IsChecked then
    TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          FRectangles[Index].Fill.Color := lColor;
          TLabel(FRectangles[Index].TagObject).Text := Index.ToString;
          FRectangles[Index].TagString := TimeToStr(Now);
          FRectangles[Index].Repaint;
        end)
  else
  begin
    FRectangles[Index].Fill.Color := lColor;
    TLabel(FRectangles[Index].TagObject).Text := Index.ToString;
    FRectangles[Index].TagString := TimeToStr(Now);
    FRectangles[Index].Repaint;
  end;
  Sleep(100);
end;

Para el cálculo de tiempo que tarda la ejecución de procedimientos os recomiendo utilizar la clase tStopWatch de la unit system.Diagnostics, de esta forma:

Var
Sw:tStopWatch;

begin


   SW := TStopWatch.Create;
   SW.Start;

   for I := 1 to Max do
   begin

   …     

   end;

   SW.Stop;
   showmessage(Format('Tiempo empleado (en milisegundos): %d', [SW.ElapsedMilliseconds]));

end;


Quizás te pueda interesar:

Evitar la propagación del virus WannaCry

Mi Opinión sobre Wanacrypt0r

Desde hace unos días se está hablando del daño causado por el ransomware WannaCry en todo el mundo, recordemos que lo que hace es cifrar los archivos de vuestro PC y luego pedir un "rescate" de los mismos pagando en bitcoins (unos 300 Euros).
El dropper, con el payload, llega por email al PC y cuando se ejecuta comienza a cifrar archivos.
Hasta ahora nadie ha descubierto cómo descifrar los archivos encriptados por este ransomware, por lo que la única opción es tirar de la copia de seguridad que deberíamos tener preparada.
Todo se remonta a marzo de 2017 cuando se robaron por parte del grupo llamado "Shadow Brokers" una serie de exploits y herramientas de seguridad procedentes de la Agencia de Seguridad Nacional (NSA) no descubiertas anteriormente (EthernalBlue-DoblePulsar) y que inmediatamente se pusieron a la venta en la Deep Web, ambas permiten que un atacante envíe paquetes específicamente creados a un servidor Microsoft Server Message Block 1.0 (SMBv1) (Puerto 445)
WannaCry busca equipos que tengan expuesto SMBv1 para atacarlos y una vez dentro escanea la red interna para buscar ficheros y equipos vulnerables.

Características del virus:

Carga el código dañino en el sistema. 
Crea copias en el sistema. 
Crea entradas de persistencia en el Registro de Windows. 
Cifra todos los archivos en todas las unidades que cumplan un patrón de extensión. 
Muestra información acerca del secuestro de los archivos y solicita un rescate para su recuperación. 
Ejecuta determinados programas incluidos en el código dañino. 
Finaliza determinados procesos de bases de datos para poder cifrar sus archivos. 
Elimina las Shadow Copies del sistema.

Los sistemas afectados son los siguientes:
  • Windows 7
  • Windows 8
  • Windows 8.1
  • Windows RT 8.1
  • Windows Server 2008 SP2 y R2 SP1
  • Microsoft Windows Vista SP2 Windows 8.1
  • Windows Server 2012 y R2
  • Windows Server 2016
  • Windows XP
  • Windows Vista
  • Windows Server 2003
Microsoft lanzó un parche (MS17-010), en su momento para solucionar esta vulnerabilidad.

Un analista de MalwareTech descubrió que el virus para iniciarse buscaba un dominio en Internet (iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com) y en caso de no existir empezaría a cifrar archivos, por lo que la solución era registrar el anterior dominio en Internet, de esta forma el virus no se iniciaba y se paraba la infección.
En las siguientes versiones, según he leído, esto ya no sucede.

Un detalle técnico:
EthernalBlue se puede utilizar para atacar sistemas Windows 7 y Windows Server 2008 R2 sin necesidad de autenticación y DoblePulsar se utiliza para inyectar una dll y abrir un backdoor en el sistema, creando un acceso remoto al sistema.

Cómo se evita la propagación:

1) Aplicar el parche MS017-010 a los sistemas windows anteriores  https://technet.microsoft.com/en-us/library/security/ms17-010.aspx

2) Desactivar manualmente el protocolo SMB : Panel de Control – Programas y Características – Activar o desactivar características de Windows – desactivar “Compatibilidad con el protocolo para compartir archivos SMB 1.0/CIFS”.

3) Se deben bloquear las conexiones entrantes a puertos SMB (139 y 445) desde equipos externos a la red.

4) Activar el modo LOCK en todos los perfiles de usuarios.

5) Eliminar el servicio con las siguientes caracteristicas: 
Nombre: mssecsvc2.0 
Descripción: Microsoft Security Center (2.0) Service 
Ruta: %WINDIR%\mssecsvc.exe 
Comando: %s -m security 

6) Eliminar las entradas del registro:

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v "mzaiifkxcyb819" /t REG_SZ /d "\"C:\WINDOWS\tasksche.exe\"" /f 

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v “RANDOM_CHARS” /t REG_SZ /d '\%COMMON_APPDATA%\tasksche.exe\'' /f 

7) Eliminar los archivos:

@Please_Read_Me@.txt 
@WanaDecryptor@.exe

8) Por supuesto habilitar un firewall, antivirus, ...

Para comprobar si hemos sido infectados, verificar en el regedit que existen las siguientes rutas:

1) C:\Users\<...>\AppData\Local\Temp\@WanaDecryptor@.exe.lnk



2) C:\Users\<...>\AppData\Local\Temp\@WanaDecryptor@.exe



3) HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\ = “\tasksche.exe”

4) HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v "mzaiifkxcyb819" /t REG_SZ /d "\"C:\WINDOWS\tasksche.exe\"" /f 

5) HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v “RANDOM_CHARS” /t REG_SZ /d '\%COMMON_APPDATA%\tasksche.exe\'' /f 



6) HKLM\SOFTWARE\WanaCrypt0r\wd = “”



7) HKCU\Control Panel\Desktop\Wallpaper: “\@WanaDecryptor@.bmp”

8) Verificar si existe un servicio con las características siguientes
Nombre: mssecsvc2.0 
Descripción: Microsoft Security Center (2.0) Service 
Ruta: %WINDIR%\mssecsvc.exe 
Comando: %s -m security 

9) La existencia de archivos con la extensión “.wnry” es un indicador del compromiso del sistema. 

10) Comprobar si existen alguno de los siguientes archivos:


El CERT ha publicado una herramienta que mitiga la ejecución del virus WannaCry, que a día de hoy es de obligada instalación si queremos evitar sus efectos.










Obtener datos de los satélites que utiliza el GPS



Como sabéis las coordenadas que establece el GPS de vuestro dispositivo son el resultado de complejos cálculos matemáticos que se realizan en función de la señal de los satélites que capta, estas coordenadas pueden tener una precisión de centímetros (si se utiliza GPS diferencial) aunque lo normal es que la precisión para uso civil sea de varios metros.

Para calcular la posición se necesita como mínimo la información de 3 satélites, para ello cada uno envía su id y la hora de su reloj interno y en base a estos datos el GPS calcula el tiempo que tarda en llegar la señal; posteriormente utilizando un método matemático llamado trilateración inversa calcula la latitud y longitud de tu posición.

Android nos proporciona una serie de procedimientos que nos informan de los parámetros de cada satélite: elevación, azimut, nivel de ruido de la señal, etc...
Realmente no es tan sencillo como pudiera parecer inicialmente llegar a estos datos ya que además de utilizar el servicio del sistema "LOCATION_SERVICE" hay que configurar la clase tGPSListener que automáticamente genera eventos que nos avisan del instante en el que el GPS se activa, se desactiva, del tiempo del primer "fix", y -lo que nos interesa en este caso- cada vez que se recopile información de los satélites, que se hace mediante el disparo del evento "GPS_EVENT_SATELLITE_STATUS".

Una vez que se dispare capturaremos los datos de esta forma:
 
 satelites := FLocationManager.getGpsStatus(NIL).getSatellites;

Después recorreremos "satelites" para obtener la información asociada a cada uno de ellos tecleando lo siguiente:


satelite := tjgpssatellite.wrap((Objeto AS ILocalObject).GetObjectID);

con lo que obtendremos:

satelite.getAzimut()  : el azimut del satélite en grados
satelite.getElevation()  :  la elevacion en grados
satelite.getPrn: Un número pseudo aleatorio
satelite.getSnr: El ruido de la señal
satelite.hasAlmanac(): si tiene datos de almanaque
satelie.hasEphemeris(): si tiene datos de efemérides
satelite.usedInFix(): si se usa para fijar la posición

El procedimiento que he utilizado es el siguiente:


....

tform1 = class(tform)

   ..VARIABLES..;  

PROCEDURE onGpsStatusChanged(event: Integer);
PROCEDURE IniciarGPS;

PUBLIC
 { Public declarations }
PRIVATE
 { Private declarations }
    satelites: jIterable;
    FLocationManager: JLocationManager;
    locationListener: TLocationListener;
    LocationManagerService: JObject;
END; //tform1

// Definimos la clase TGpsListener

TGpsListener = CLASS(TJavaLocal, JGpsStatus_Listener)
  PRIVATE
    FParent: Tform1;
  PUBLIC
    CONSTRUCTOR Create(AParent: Tform1);
    PROCEDURE onGpsStatusChanged(event: Integer); CDECL;
END;

CONSTRUCTOR TGpsListener.Create(AParent: TfGPS);
BEGIN
  INHERITED Create;
  FParent := AParent;
END;

PROCEDURE TGpsListener.onGpsStatusChanged(event: Integer);
BEGIN
    FParent.onGpsStatusChanged(event);
END;
....


PROCEDURE tform1.IniciarGPS;
BEGIN
  LocationManagerService := tAndroidHelper.context.getSystemService(TJContext.JavaClass.LOCATION_SERVICE);
  FLocationManager := TJLocationManager.wrap((LocationManagerService AS ILocalObject).GetObjectID);
  GPSListener := TGpsListener.Create(self);
END;

PROCEDURE tform1.onGpsStatusChanged(event: Integer);
VAR
  satelite: jgpssatellite;
  Objeto: JObject;
  iter: jiterator;

BEGIN


  //SI SE DISPARA EL EVENTO gps_event_satellite_status...
  IF event = tjgpsstatus.JavaClass.GPS_EVENT_SATELLITE_STATUS THEN
    BEGIN

      IF assigned(FLocationManager) THEN
        BEGIN

            //OBTENGO LOS DATOS DE TODOS LOS SATELITES
            satelites := FLocationManager.getGpsStatus(NIL).getSatellites;
            iter := form1.satelites.iterator;
            
            // RECORRO LA LISTA UNO A UNO PARA OBTENER SUS CARACTERISTICAS  
            Objeto := NIL;
            WHILE iter.hasnext DO
              BEGIN
                Objeto := iter.next;
                IF assigned(Objeto) THEN
                  BEGIN
                      
                      //OBTENGO UN SATELITE DE LA LISTA

                      satelite := tjgpssatellite.wrap((Objeto AS ILocalObject).GetObjectID);
                      //Ojo, no confundir la variable satelites:JIterable con satelite: jgpssatellite
                      // LEO SUS CARACTERISTICAS
                      Label1.text := satelite.getSnr; // 'Ruido        '
                      Label2.text := satelite.getPrn;
                      Label3.text := satelite.getAzimuth.Tostring; // 'Azimuth      '
                      label4.text := satelite.getElevation.Tostring; // 'Elevación    '

                      { 
                        OTROS PARAMETROS DEL SATELITE
                        satelite.hasAlmanac
                        satelite.HasEphemeris
                        satelite.usedInFix
                      }               

                  END;

              END;
        END;
    END;
END;

En la app GPS TOTAL RUN  en el menú "Satélites" tenéis un ejemplo de como quedaría todo lo expuesto anteriormente.



Quizás te pueda interesar:

Cómo añadir gráficos a vuestra app
Programación paralela con Delphi
Rotaciones en 3D
Obtener la elevación en un punto del mapa
Un app para mostrar moléculas en 3D