{"id":320,"date":"2023-05-29T08:36:00","date_gmt":"2023-05-29T08:36:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=320"},"modified":"2023-08-11T21:14:15","modified_gmt":"2023-08-11T20:14:15","slug":"introduccion-al-lenguaje-pascal-moderno-para-programadores-parte-6","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=320","title":{"rendered":"Introducci\u00f3n al lenguaje Pascal moderno para programadores (Parte 6)"},"content":{"rendered":"\n<p id=\"block-5521090e-ab25-4c7d-8ff9-7b06a21f4a1b\">Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno.<\/p>\n\n\n\n<p id=\"block-404f08e6-e309-4eb0-84cf-cdf990136039\">Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\/modern_pascal\" target=\"_blank\">original<\/a> escrito por Michalis Kamburelis.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Biblioteca en tiempo de ejecuci\u00f3n (Run-time)<\/h2>\n\n\n\n<p>Los programas modernos deber\u00edan usar la clase TStream y sus muchos descendientes para hacer entrada\/salida. Tiene muchos descendientes \u00fatiles, como TFileStream, TMemoryStream, TStringStream.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils, Classes;\n\nvar\n  S: TStream;\n  InputInt, OutputInt: Integer;\nbegin\n  InputInt := 666;\n\n  S := TFileStream.Create('my_binary_file.data', fmCreate);\n  try\n    S.WriteBuffer(InputInt, SizeOf(InputInt));\n  finally\n    FreeAndNil(S);\n  end;\n\n  S := TFileStream.Create('my_binary_file.data', fmOpenRead);\n  try\n    S.ReadBuffer(OutputInt, SizeOf(OutputInt));\n  finally\n    FreeAndNil(S);\n  end;\n\n  WriteLn('Read from file got integer: ', OutputInt);\nend.<\/pre><\/div>\n\n\n\n<p>En<strong> Castle Game Engine<\/strong>: debe usar la funci\u00f3n de descarga para crear una transmisi\u00f3n que obtenga datos de cualquier URL. Los archivos regulares, los recursos HTTP y HTTPS, los activos de Android y m\u00e1s son compatibles de esta manera. Adem\u00e1s, para abrir el recurso dentro de los datos de tu juego (en el subdirectorio de datos) usa la URL especial castle-data:\/xxx. Ejemplos:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">EnableNetwork := true;\nS := Download('https:\/\/castle-engine.io\/latest.zip');<\/pre><\/div>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">S := Download('file:\/\/\/home\/michalis\/my_binary_file.data');<\/pre><\/div>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">S := Download('castle-data:\/gui\/my_image.png');<\/pre><\/div>\n\n\n\n<p>Para leer archivos de texto, recomendamos utilizar la clase TTextReader. Proporciona una API orientada a la l\u00ednea y envuelve un TStream en su interior. El constructor TTextReader puede tomar una URL lista, o puede pasar all\u00ed su fuente TStream personalizada.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">Text := TTextReader.Create('castle-data:\/my_data.txt');\ntry\n  while not Text.Eof do\n    WriteLnLog('NextLine', Text.ReadLn);\nfinally\n  FreeAndNil(Text);\nend;<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Contenedores (Listas, diccionarios) usando gen\u00e9ricos<\/h2>\n\n\n\n<p>La biblioteca de idiomas y tiempo de ejecuci\u00f3n ofrece varios contenedores flexibles. Hay una serie de clases no gen\u00e9ricas (como TList y TObjectList de la unidad Contnrs), tambi\u00e9n hay matrices din\u00e1micas (matriz de TMyType). Pero para obtener la mayor flexibilidad y seguridad de tipos, recomiendo usar contenedores gen\u00e9ricos para la mayor\u00eda de sus necesidades.<\/p>\n\n\n\n<p>Los contenedores gen\u00e9ricos le brindan muchos m\u00e9todos \u00fatiles para agregar, eliminar, iterar, buscar, clasificar\u2026 El compilador tambi\u00e9n sabe (y verifica) que el contenedor contiene solo elementos del tipo apropiado.Hay tres bibliotecas que proporcionan contenedores gen\u00e9ricos en FPC ahora:<\/p>\n\n\n\n<p>Hay tres bibliotecas que proporcionan contenedores gen\u00e9ricos en FPC ahora:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unidad Generics.Collections y amigos (desde FPC &gt;= 3.2.0)<\/li>\n\n\n\n<li>unidad FGL<\/li>\n\n\n\n<li>Unidad GVector y amigos (juntos en fcl-stl)<\/li>\n<\/ul>\n\n\n\n<p>Recomendamos utilizar la unidad Generics.Collections. Los contenedores gen\u00e9ricos que implementan:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Paquete completo de caracter\u00edscticas \u00fatiles<\/li>\n\n\n\n<li>Muy eficiente, en particular para acceder a diccionarios por su clave<\/li>\n\n\n\n<li>Compatible con FPC y Delphi.<\/li>\n\n\n\n<li>Nombre coherente con la biblioteca est\u00e1ndar.<\/li>\n<\/ul>\n\n\n\n<p>En Castle Game Engine: utilizamos Generics.Collections de forma intensiva en todo el motor y le recomendamos que utilice Generics.Collections tambi\u00e9n en sus aplicaciones.<\/p>\n\n\n\n<p>Las clases m\u00e1s importantes de la unidad Generics.Collections son:<\/p>\n\n\n\n<p><strong>Lista TL<\/strong>: Una lista gen\u00e9rica de tipos.<\/p>\n\n\n\n<p><strong>TObjectList<\/strong>: Una lista gen\u00e9rica de instancias de objetos. Puede \u00abposeer\u00bb hijos, lo que significa que los liberar\u00e1 autom\u00e1ticamente.<\/p>\n\n\n\n<p><strong>TDiccionario<\/strong>:  Un diccionario gen\u00e9rico.<\/p>\n\n\n\n<p><strong>TObjectDiccionario<\/strong>: Un diccionario gen\u00e9rico, que puede \u00abposeer\u00bb las claves y\/o valores.<\/p>\n\n\n\n<p>Aqu\u00ed le mostramos c\u00f3mo usar una TObjectList gen\u00e9rica simple:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleList = specialize TObjectList&lt;TApple&gt;;\n\nvar\n  A: TApple;\n  Apples: TAppleList;\nbegin\n  Apples := TAppleList.Create(true);\n  try\n    A := TApple.Create;\n    A.Name := 'my apple';\n    Apples.Add(A);\n\n    A := TApple.Create;\n    A.Name := 'another apple';\n    Apples.Add(A);\n\n    Writeln('Count: ', Apples.Count);\n    Writeln(Apples[0].Name);\n    Writeln(Apples[1].Name);\n  finally FreeAndNil(Apples) end;\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que algunas operaciones requieren comparar dos elementos, como ordenar y buscar (por ejemplo, mediante los m\u00e9todos Sort e IndexOf). Los contenedores Generics.Collections utilizan para esto un comparador. El comparador predeterminado es razonable para todos los tipos, incluso para registros (en cuyo caso compara el contenido de la memoria, que es un valor predeterminado razonable al menos para buscar usando IndexOf).<\/p>\n\n\n\n<p>Al ordenar la lista, puede proporcionar un comparador personalizado como par\u00e1metro. El comparador es una clase que implementa la interfaz IComparer. En la pr\u00e1ctica, normalmente define la devoluci\u00f3n de llamada adecuada y usa el m\u00e9todo TComparer.Construct para envolver esta devoluci\u00f3n de llamada en una instancia de IComparer. A continuaci\u00f3n se muestra un ejemplo de c\u00f3mo hacerlo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Defaults, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleList = specialize TObjectList&lt;TApple&gt;;\n\nfunction CompareApples(constref Left, Right: TApple): Integer;\nbegin\n  Result := AnsiCompareStr(Left.Name, Right.Name);\nend;\n\ntype\n  TAppleComparer = specialize TComparer&lt;TApple&gt;;\nvar\n  A: TApple;\n  L: TAppleList;\nbegin\n  L := TAppleList.Create(true);\n  try\n    A := TApple.Create;\n    A.Name := '11';\n    L.Add(A);\n\n    A := TApple.Create;\n    A.Name := '33';\n    L.Add(A);\n\n    A := TApple.Create;\n    A.Name := '22';\n    L.Add(A);\n\n    L.Sort(TAppleComparer.Construct(@CompareApples));\n\n    Writeln('Count: ', L.Count);\n    Writeln(L[0].Name);\n    Writeln(L[1].Name);\n    Writeln(L[2].Name);\n  finally FreeAndNil(L) end;\nend.<\/pre><\/div>\n\n\n\n<p>La clase TDictionary implementa un diccionario, tambi\u00e9n conocido como mapa (clave \u2192 valor), tambi\u00e9n conocido como matriz asociativa. Su API es un poco similar a la clase C# TDictionary. Tiene iteradores \u00fatiles para claves, valores y pares de clave\u2192valor.<\/p>\n\n\n\n<p>Un c\u00f3digo de ejemplo usando un diccionario:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleDictionary = specialize TDictionary&lt;string, TApple&gt;;\n\nvar\n  Apples: TAppleDictionary;\n  A, FoundA: TApple;\n  ApplePair: TAppleDictionary.TDictionaryPair;\n  AppleKey: string;\nbegin\n  Apples := TAppleDictionary.Create;\n  try\n    A := TApple.Create;\n    A.Name := 'my apple';\n    Apples.AddOrSetValue('apple key 1', A);\n\n    if Apples.TryGetValue('apple key 1', FoundA) then\n      Writeln('Found apple under key \"apple key 1\" with name: ' +\n        FoundA.Name);\n\n    for AppleKey in Apples.Keys do\n      Writeln('Found apple key: ' + AppleKey);\n    for A in Apples.Values do\n      Writeln('Found apple value: ' + A.Name);\n    for ApplePair in Apples do\n      Writeln('Found apple key-&gt;value: ' +\n        ApplePair.Key + '-&gt;' + ApplePair.Value.Name);\n\n    { Line below works too, but it can only be used to set\n      an *existing* dictionary key.\n      Instead of this, usually use AddOrSetValue\n      to set or add a new key, as necessary. }\n    \/\/ Apples['apple key 1'] := ... ;\n\n    Apples.Remove('apple key 1');\n\n    { Note that the TDictionary doesn't own the items,\n      you need to free them yourself.\n      We could use TObjectDictionary to have automatic ownership\n      mechanism. }\n    A.Free;\n  finally FreeAndNil(Apples) end;\nend.<\/pre><\/div>\n\n\n\n<p>TObjectDictionary tambi\u00e9n puede poseer las claves y\/o valores del diccionario, lo que significa que se liberar\u00e1n autom\u00e1ticamente. Tenga cuidado de poseer solo claves y\/o valores si son instancias de objetos. Si configura \u00abpropiedad\u00bb de alg\u00fan otro tipo, como un n\u00famero entero (por ejemplo, si sus claves son n\u00fameros enteros e incluye doOwnsKeys), obtendr\u00e1 un bloqueo desagradable cuando se ejecute el c\u00f3digo.<\/p>\n\n\n\n<p>A continuaci\u00f3n se muestra un c\u00f3digo de ejemplo que usa TObjectDictionary. Compile este ejemplo con la detecci\u00f3n de fugas de memoria, como fpc -gl -gh generics_object_dictionary.lpr, para ver que todo se libera cuando se cierra el programa.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleDictionary = specialize TObjectDictionary&lt;string, TApple&gt;;\n\nvar\n  Apples: TAppleDictionary;\n  A: TApple;\n  ApplePair: TAppleDictionary.TDictionaryPair;\nbegin\n  Apples := TAppleDictionary.Create([doOwnsValues]);\n  try\n    A := TApple.Create;\n    A.Name := 'my apple';\n    Apples.AddOrSetValue('apple key 1', A);\n\n    for ApplePair in Apples do\n      Writeln('Found apple key-&gt;value: ' +\n        ApplePair.Key + '-&gt;' + ApplePair.Value.Name);\n\n    Apples.Remove('apple key 1');\n  finally FreeAndNil(Apples) end;\nend.<\/pre><\/div>\n\n\n\n<p>Si prefiere usar la unidad FGL en lugar de Generics.Collections, las clases m\u00e1s importantes de la unidad FGL son:<\/p>\n\n\n\n<p><strong>Lista TFPGL<\/strong>: Una lista gen\u00e9rica de tipos.<\/p>\n\n\n\n<p><strong>TFPGObjectList<\/strong>:  Una lista gen\u00e9rica de instancias de objetos. Puede \u00abposeer\u00bb hijos.<\/p>\n\n\n\n<p><strong>TFPGMapa<\/strong>:  Un diccionario gen\u00e9rico.<\/p>\n\n\n\n<p>En la unidad FGL, TFPGList solo se puede usar para tipos para los que se define el operador de igualdad (=). Para TFPGMap, los operadores \u00abmayor que\u00bb (&gt;) y \u00abmenor que\u00bb (&lt;) deben definirse para el tipo de clave. Si desea utilizar estas listas con tipos que no tienen operadores de comparaci\u00f3n incorporados (por ejemplo, con registros), debe sobrecargar sus operadores como se muestra en la sobrecarga de operadores.<\/p>\n\n\n\n<p>En Castle Game Engine incluimos una unidad CastleGenericLists que agrega las clases TGenericStructList y TGenericStructMap. Son similares a TFPGList y TFPGMap, pero no requieren una definici\u00f3n de los operadores de comparaci\u00f3n para el tipo apropiado (en su lugar, comparan los contenidos de la memoria, lo que suele ser apropiado para registros o punteros de m\u00e9todos). Pero la unidad CastleGenericLists est\u00e1 obsoleta desde la versi\u00f3n 6.3 del motor, ya que recomendamos usar Generics.Collections en su lugar.<\/p>\n\n\n\n<p>Si desea obtener m\u00e1s informaci\u00f3n sobre los gen\u00e9ricos, consulte Gen\u00e9ricos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Clonaci\u00f3n: TPersistent.Assign <\/h2>\n\n\n\n<p>Al copiar las instancias de clase mediante un operador de asignaci\u00f3n simple, se copia la referencia.<\/p>\n\n\n\n<p>Para copiar el contenido de la instancia de clase, el enfoque est\u00e1ndar es derivar su clase de TPersistent y anular su m\u00e9todo Assign. Una vez que se implementa correctamente en TMyObject, lo usa as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  X, Y: TMyObject;\nbegin\n  X := TMyObject.Create;\n  Y := TMyObject.Create;\n  Y.Assign(X);\n  Y.MyField := 123; \/\/ this does not change X.MyField\n  FreeAndNil(X);\n  FreeAndNil(Y);\nend;<\/pre><\/div>\n\n\n\n<p>Para que funcione, debe implementar el m\u00e9todo Asignar para copiar realmente los campos que desea. Debe implementar cuidadosamente el m\u00e9todo Assign, para copiar de una clase que puede ser descendiente de la clase actual.<\/p>\n\n\n\n<p>A veces es m\u00e1s c\u00f3modo anular alternativamente el m\u00e9todo AssignTo en la clase de origen, en lugar de anular el m\u00e9todo Assign en la clase de destino.<\/p>\n\n\n\n<p>Tenga cuidado cuando llame heredado en la implementaci\u00f3n de Asignaci\u00f3n anulada. Hay dos situaciones:<\/p>\n\n\n\n<p><strong>Su clase es descendiente directa de la clase TPersistent. (O bien, no es un descendiente directo de TPersistent, pero ning\u00fan ancestro anul\u00f3 el m\u00e9todo Assign).<\/strong><\/p>\n\n\n\n<p>En este caso, su clase debe usar la palabra clave heredada (para llamar a TPersistent.Assign) solo si no puede manejar la asignaci\u00f3n en su c\u00f3digo.<\/p>\n\n\n\n<p><strong>Su clase desciende de alguna clase que ya ha anulado el m\u00e9todo Assign.<\/strong><\/p>\n\n\n\n<p>En este caso, su clase siempre debe usar la palabra clave heredada (para llamar al ancestro Asignar). En general, llamar a m\u00e9todos heredados en anulados suele ser una buena idea.<\/p>\n\n\n\n<p>Para comprender el motivo detr\u00e1s de la regla anterior (cu\u00e1ndo debe llamar y cu\u00e1ndo no debe llamar heredada de la implementaci\u00f3n de Assign) y c\u00f3mo se relaciona con el m\u00e9todo AssignTo, veamos las implementaciones de TPersistent.Assign y TPersistent.AssignTo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure TPersistent.Assign(Source: TPersistent);\nbegin\n  if Source &lt;&gt; nil then\n    Source.AssignTo(Self)\n  else\n    raise EConvertError...\nend;\n\nprocedure TPersistent.AssignTo(Destination: TPersistent);\nbegin\n  raise EConvertError...\nend;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Nota: Esta no es la implementaci\u00f3n exacta de TPersistent. Copi\u00e9 el c\u00f3digo de la biblioteca est\u00e1ndar de FPC, pero luego lo simplifiqu\u00e9 para ocultar detalles sin importancia sobre el mensaje de excepci\u00f3n.<\/p>\n\n\n\n<p>Las conclusiones que se pueden sacar de lo anterior son:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si no se anulan ni Assign ni AssignTo, llamarlos dar\u00e1 como resultado una excepci\u00f3n.<\/li>\n\n\n\n<li>Adem\u00e1s, tenga en cuenta que no hay c\u00f3digo en la implementaci\u00f3n de TPersistent que copia autom\u00e1ticamente todos los campos (o todos los campos publicados) de las clases. Es por eso que debe hacerlo usted mismo, anulando Asignar en todas las clases. Puede usar RTTI (informaci\u00f3n de tipo de tiempo de ejecuci\u00f3n) para eso, pero para casos simples, probablemente solo enumere los campos que se copiar\u00e1n manualmente.<\/li>\n<\/ul>\n\n\n\n<p>Cuando tiene una clase como TApple, su implementaci\u00f3n de TApple.Assign generalmente se ocupa de copiar campos que son espec\u00edficos de la clase TApple (no del ancestro de TApple, como TFruit). Por lo tanto, la implementaci\u00f3n de TAple.Assign generalmente verifica si la Fuente es TAple al principio, antes de copiar los campos relacionados con Apple. Luego, llama heredado para permitir que TFruit maneje el resto de los campos.<\/p>\n\n\n\n<p>Suponiendo que implement\u00f3 TFruit.Assign y TApple.Assign siguiendo el patr\u00f3n est\u00e1ndar (como se muestra en el ejemplo anterior), el efecto es as\u00ed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si pasa la instancia de TApple a TApple.Assign, funcionar\u00e1 y copiar\u00e1 todos los campos.<\/li>\n\n\n\n<li>Si pasa la instancia de TOrange a TApple.Assign, funcionar\u00e1 y solo copiar\u00e1 los campos comunes compartidos por TOrange y TApple. En otras palabras, los campos definidos en TFruit<\/li>\n\n\n\n<li>Si pasa la instancia de TWerewolf a TApple.Assign, generar\u00e1 una excepci\u00f3n (porque TApple.Assign llamar\u00e1 a TFruit.Assign, que llamar\u00e1 a TPersistent.Assign, que generar\u00e1 una excepci\u00f3n).<\/li>\n<\/ul>\n\n\n\n<p>Nota: Recuerde que al descender de TPersistent, se publica el especificador de visibilidad predeterminado, para permitir la transmisi\u00f3n de descendientes de TPersistent. No todos los tipos de campos y propiedades est\u00e1n permitidos en la secci\u00f3n publicada. Si obtiene errores relacionados con \u00e9l y no le importa la transmisi\u00f3n, simplemente cambie la visibilidad a p\u00fablico. Consulte los especificadores de visibilidad.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-trasteando-por-vicio wp-block-embed-trasteando-por-vicio\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"Gtz7yCTI4j\"><a href=\"https:\/\/jorgeturiel.es\/?p=327\">Introducci\u00f3n al lenguaje Pascal moderno para programadores (Parte 7)<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"\u00abIntroducci\u00f3n al lenguaje Pascal moderno para programadores (Parte 7)\u00bb \u2014 Trasteando por vicio\" src=\"https:\/\/jorgeturiel.es\/?p=327&#038;embed=true#?secret=s5Iu6Y5Tso#?secret=Gtz7yCTI4j\" data-secret=\"Gtz7yCTI4j\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno. Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto original escrito por Michalis Kamburelis.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,25,26],"tags":[22,23,21,24],"class_list":["post-320","post","type-post","status-publish","format-standard","hentry","category-lazarus","category-pascal","category-programacion","tag-delphi","tag-lazarus","tag-pascal","tag-programacion"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/320","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=320"}],"version-history":[{"count":9,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/320\/revisions"}],"predecessor-version":[{"id":498,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/320\/revisions\/498"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=320"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=320"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=320"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}