Quantcast
Channel: Planet Object Pascal
Viewing all 1725 articles
Browse latest View live

Behind the connection: XE3: Adding properties to a set

$
0
0
[Français] Delphi XE3 has a very interesting new feature: the record helpers. Despite his name which reference a specific data type (record), a record helper can be applyed to most standard data types as well, include the sets. Using a record helper, we will be able to add properties and methods to sets. In this artcile, I will show you how it works using a simple case: adding a property to a

Firebird News: Database .NET 7.9 released

$
0
0
Database .NET is an innovative, powerful and intuitive multiple database management tool. You can Browse objects, Design tables, Edit rows, Export data and Run queries with a consistent interface. It is Free, Portable, All-In-One, Easy to Use and Multlanguage. A lot of new features and improvements since 7.6.4741. What’s New (2013/02/21) Added Script all database [...]

Firebird News: LuaSQL Firebird is a simple interface from Lua to Firebird RDBMS

$
0
0
LuaSQL is a simple interface from Lua to a RDBMS , Here is the Github page for Firebird driver

The Wiert Corner - irregular stream of stuff: jpluimers

Firebird News: New maintainer for the SOCI Firebird SQL project (The C++ Database Access Library)

$
0
0
Here is the tweet with announcement: Just added Viacheslav Naydenov to SOCI team as new maintainer of FirebirdSQL backend  to be (re)released with SOCI 3.2.0 and 4.0.0 Originally, SOCI was developed by Maciej Sobczak at CERN as abstraction layer for Oracle, a Simple Oracle Call Interface. Later, several database backends have been developed for SOCI, [...]

Firebird News: Django Firebird driver now available for install from pypi. Just run: pip install django-firebird #django

$
0
0
Django Firebird driver is now available from pypi https://pypi.python.org/pypi/django-firebird This was announced on twitter by Maximiliano Robaina

Firebird News: Firebird mentioned on Evans Data survey

$
0
0
A new survey from EvansData about Software Development Tools mentions Firebird among the preferred Database choices. You can participate in the survey (and win points to trade for prizes later) accessing http://surveys.evansdata.com/20130220.php

Daniel Magin's Logfile: Delphi iOS Intensivtraining 2013

$
0
0

Tag 1 – Die Welt von Apple iOS aus der Sicht von Delphi

"First Steps" als Delphi-Apple-Developer

  • Developer Account
  • wie bringe ich meine Geräte in den Developermodus
  • Werkzeuge (PAServer, XCode, iPhone-Simulator, welche Rolle spielt iTunes?)
  • Zertifikate (welche gibt es, wofür werden sie benötigt)
  • Profile (z.B. “Provisioning Profile” – Was ist das?)
  • Mögliche Wege, die App auf das Gerät zu bringen (Debug, Adhoc vs. AppStore und Enterprise Programm)
  • Auswahl eines mit Delphi kompatiblen SDK (iOS 5, iOS 6 …)
  • Betatesting mit Geräten

Die "Spielregeln" auf einem iOS-Gerät

  • Speicher- und CPU-Verbrauch
  • Programmende
    • Verzögern des Programmendes (speichern, Download abschließen etc)
    • Programmzustände und die verschiedenen Übergänge
  • App im Hintergrund? Reagieren auf Events
    • welche Hintergrund-Prozesse sind erlaubt
      • GPS
      • Musik
      • VOIP
      • Newsstand
      • Externe Geräte Steuerung (Blutdruckmessgerät etc)
    • Unterbrechung z.B. durch Anruf oder Notifications
      • wie sichere ich meine Daten
      • was passiert nach dem Anruf
    • Wann wird eine App vom System abgeschossen

Die Infrastruktur auf einem iOS-Gerät

  • iOS Klassenbibliothek in Delphi
    • NS*-Klassen
    • Delphi-Besonderheiten beim Zugriff auf iOS Klassen (Wrap, OCClass, PNSString)
  • iOS Komponentenbibliothek (User Interface Elements)
    • Buttons
    • Picker-Elemente (Datum etc.)
    • Tastaturen und -typen
    • Tab-Bars
    • Table-Views
    • Orientation
    • Layout-Control
  • SQLite und InterBase auf dem iOS Device
  • Wo lassen sich lokale Informationen persistent sichern?
  • Entitlements
  • “Retina” – Unterstützung
  • Launch-, Spotlight- und Application-Symbole

Interaktion mit Sensoren

  • GPS (Location Sensor)
  • Motion Sensor
  • Gyroskop

Tag 2 - Delphi für iOS in der Tiefe

Neue Sprachfeatures NEXTGEN-Compiler

  • ARC, das neue Speichermanagement
  • Helper für native Typen
  • Strings
  • Pointer
  • was ändert sich für mich als "alter" Delphiprogrammierer

Multi-Threading in iOS

Interaktion mit Standardprogrammen

Registrieren des eigenen Programm für eine Dateiendung

MutliTier Applikationen mit iOS

  • DataSnap
  • JSON/Rest
  • WebServices
 

Am Abend des ersten Tages bieten wir kostenlos allen Teilnehmern von 20:00 bis 22:00 ein Einsteiger-BootCamp an.

Die Teilnehmer programmieren gemeinsam ihre ersten iOS-Anwendungen. Hierzu benötigen Sie einen Mac (Mac OS 10.6 oder später mit installiertem XCode – aktuelle Version) und eine virtuellen Maschine mit Windows und Delphi/RAD Studio Mobile. Eine genaue Installationsanleitung bzw. Download-Adressen werden rechtzeitig per Mail zugesendet. Sie benötigen einen Apple iOS Developer Account (99$ pro Jahr) da ohne diesen keine Anwendungen auf die Geräte verteilt werden können. Ziel wird es sein das die Teilnehmer ihre ersten Programme mit Delphi auf iOS Geräte (iPhone, iPad oder iPod) zu entwickeln und auf die Geräte zu installieren. Wer nicht selbst forschen will, kann gerne an den “geführten” Progammierbeispielen aktiv mitarbeiten.

Teilnahme und Registrierung:

599,- Euro Komplettpreis für beide Tage, inkl. MwSt und Verpflegung an beiden Tagen (Kaffeepausen, Getränke und Mittagessen)

(Für Frühbucher gilt bis inkl. 01. März 2013 ein "early bird"-Preis von 499,- Euro)

 


twm’s blog: .manifest support in dzPrepBuild

$
0
0

It has taken a while but I have eventually arrived in the “modern” Windows world. After many years of sticking with Windows XP (and Linux) I have updated two computers to Windows 8 (both 64 bit) and another two to Windows 7 (64 bit and 32 bit).

In doing so I have been made aware of some annoyances of Windows >= Vista, one of them being the virtual store. This is a convenience feature Microsoft added to Vista and later Windows versions to allow users to continue using old programs without escalating their security issues. This feature virtualizes write access to directories in the file system and branches of the registry that are read only on properly configured systems (like “c:\windows”, “c:\program files\…” or  HKey_LOCAL_MACHINE).

While Microsoft’s intention was good and normal users won’t have a problem with it, for a software developer this feature is rather inconvenient because it prevents him from realizing if his programs do something undesired. Rather than failing and in Delphi’s case raising an exception, these actions succeed and the programmer won’t notice. Even worse, he will not find the files or registry entries his programs was supposed to make in the place he expects them and waste hours in trying to find out what’s wrong.

The idea was that newer software disables this feature with a .manifest resource. Unfortunately this will only work if the programmer updates his development tools to create these files and bind the resources to the program. Delphi 2007 did not know about .manifest resources so it needs some help. There are already many sites with information about this topic so I won’t repeat them. Suffice to say, that a .manifest resource is a special kind of resource that is added to an executable from a text file in xml format.

That format requires version information and also some descriptions, which are already part of an executable’s version resource so I added support for it to dzPrepBuild. As always, that program “eats its own dog food” (uses itself for building), so you can have a look at the source code on how it is done:

  • add {$ *_manifest.res} to the .dpr file, like the ($ *_version.res} and {$ *_icon.res} entries that were already in place.
  • add a pre-build event to the project which calls the prebuild.cmd file in buildtools if it isn’t already there
  • copy the template.manifest.in file from buildtools\templates to your source directory and rename it to <yourprogram>.manifest.in
  •  modify it to suit your needs
  • The pre-build event will, in addition to creating a *_version.rc file and compiling it, also create a *.manifest file from the contents of the *.manifest.in file + the version information, create a *_manifest.rc file and compile it. This compiled file will then be added by the Delphi compiler to the executable.

Voila: Your program has a valid .manifest resource and Windows will automatically disable virtual store for it. Now you can start finding all the bugs you never noticed. ;-)

Since this is a tool created by one Delphi developer for other Delphi developers and you will probably want to have a look at how it is done anyway, I have not created a release. Just point your favourite svn client to http://svn.code.sf.net/p/dzprepbuild/code/trunk/ and make sure you also include the externals. The project requires Delphi XE2 to compile but it should be easy to revert back to Delphi 2007 if you desire so.

Behind the connection: High speed generic queue class

$
0
0
This article presents a generic class implementing a high speed queue. It has been specially designed for communication use but can be used for anything else. Reading this article, you'll learn: How to design a generic class How to use nested data type How to implement an enumerator How to make a class thread safe How to use variant record How to use methods in a record The code itself is

Firebird News: Firebird SQL Romania Offical Hymn is released

$
0
0
As you might now Firebird does have an Offical Hymn : here is the Sound Cloud Mirror and now we present the Offical Hymn for Firebird SQL Romania

Lazarus Team Anouncements: FPC 2.6.2 released

$
0
0
Hello,

Finally, FPC 2.6.2 has landed. FPC 2.6.2 is an update to 2.6.0 that
contains most library progress over the 2.6.0 and some crucial
compiler fixes.

Building is still in progress and some formats (deb,rpm) and targets might
not be available yet.

C...

Jamie's Blog: Rakefiles for Delphi

$
0
0

It’s not a secret that I’m a big advocate of Continuous Delivery and I’ve also found that I’ve been using a lot of Ruby and Python development workflow tooling recently because I like those languages in this setting and I find the tools to be relatively easy to use (I recently wrote about Fabric for push deployments).

I wanted a build tool to run the builds of my multi-platform targeted Delphi XE2 application because it was getting tedious to publish. As with any Continuous Delivery pipeline, the first step is to map out the steps involved in getting the application to the customer. For this particular application, there were several steps:

  1. Build the application in Release configuration for each platform (Win32 and MacOS32)
  2. Compile a zip file for each platform
  3. Create a manifest XML file with the version for auto-update purposes
  4. Upload the applications binary zip files to Amazon S3
  5. Upload the manifest to Amazon S3

Rake is a fairly mature Ruby based build tool which Martin Fowler has written about in the past. There were a couple of articles about using Rake with Delphi, one from Ed Vander Hoek and another from Shawn Oster but they were both a little out of date for my purposes. So I thought I’d cover enough Rake to get you started with a Delphi Rakefile. The msbuild driven versions of Delphi make building your Delphi project considerably simpler than trying to wrangle the appropriate dcc32 flags.

If you’re already familiar with Ruby or Python then you will find building Rakefiles much easier. If you’re not familiar with ruby, I’d suggest RubyMonk.

To start with, we define a function which will run msbuild after running rsvars.bat to setup the environment:

  def release_project(project_file, platform) 
    buildcmd = "msbuild #{project_file} /t:Rebuild /p:Config=Release /p:Platform=#{platform}";
    result = `"#{RAD_STUDIO_BIN_PATH}\rsvars.bat"&#{buildcmd_win}`
    if result.include? 'Build succeeded.'
      puts "Successfully built Windows 32 project #{project_file}"
    else
      puts result
      puts "Our build failed, there were build errors!"
      raise "Errors during Windows build"
    end
  end

We can then call put this into a simple rake task to build the Win32 version like this:

  desc "Builds MyProject.dproj for Win32 in release configuration"
  task :build_release do
    puts 'Building Project MyProject.dproj..'
    release_project('MyProject.dproj', 'Win32')
  end

We can then call this via:

> rake build_release

We can also list the tasks that rake has via:

> rake -T 
rake build_release       # Builds MyProject.dproj for Win32 in release configuration

We can adapt this method to enable us to run any DUnit tests and code coverage tests.

In order to find the version of our executable, we need to call GetFileVersionInfo on the Windows API. Luckily, there was a StackOverflow question on calling GetFileVersionInfo with Ruby. This gives us something like this:

  def get_version(artefact_path)
    require "Win32API"
    s=""
    vsize=Win32API.new('version.dll', 'GetFileVersionInfoSize', 
                       ['P', 'P'], 'L').call(artefact_path, s)
    if (vsize > 0)
      result = ' '*vsize
      Win32API.new('version.dll', 'GetFileVersionInfo', 
                   ['P', 'L', 'L', 'P'], 'L').call(artefact_path, 0, vsize, result)
      rstring = result.unpack('v*').map{|s| s.chr if s<256}*''
      r = /FileVersion..(.*?)\000/.match(rstring)
      "#{r ? r[1] : '??' }"
    else
      raise "GetFileVersionInfoSize returned 0 for #{artefact_path}"
    end
  end

We can create our zip file in two different ways, we can either use a zip gem for Ruby native creation or we can shell out to a command line version. This function uses the zip gem and takes an array of files to zip and a name for the zip file.

  def make_zip_distro(files_to_zip, zip_name)
    require 'zip/zip'

    Zip::ZipFile.open(zip_name, Zip::ZipFile::CREATE) { |zipfile|
      files_to_zip.each { |file_to_zip|
        if File.exists?(file_to_zip) 
          zipfile.get_output_stream(File.basename(file_to_zip)) { |f| 
            File.open(file_to_zip) do |in_file|
              while blk = in_file.read(1024**2)
                f << blk
              end
            end
          }
        else
          raise "Could not find #{file_to_zip}"
        end
      }
    }
  end

For the manifest file, we can either generate it using Ruby string interpolation or a template system like erb, depending on how complex your requirements are.

The final step is the upload all artefacts (the manifest, the artefacts):

  # You need to define AWS_ENDPOINT, AWS_BUCKET, AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY_ID
  def upload_to_s3(file, s3_destination)
    require "aws/s3"
    if File.exists?(file)
      AWS::S3::DEFAULT_HOST.replace AWS_ENDPOINT
      AWS::S3::Base.establish_connection!(
        :access_key_id     => AWS_ACCESS_KEY_ID,
        :secret_access_key => AWS_SECRET_ACCESS_KEY
      )
      AWS::S3::S3Object.store(s3_destination, 
                          open(file), 
                          AWS_BUCKET,
                          :access => :public_read)
      puts "Uploaded #{file} to #{s3_destination}"
    else
      puts "Could not file #{file} to upload to S3"
    end
  end

You will need to define the access keys, secret keys, endpoints and bucket.

The next step is to put it into composite parts and draw up a set of tasks. Rake tasks can be standalone or can have prerequisite dependencies:

  task :my_task => [:dependent_task_1, :dependent_task_2] do
    # task implementation
  end

Rake tasks can also have parallel prerequisite dependencies like this:

 multitask :my_task => [:build_task1, :build_task2] do
    puts "Built all the things!"
 end

Rake tasks can also have parameters, this might be useful if you wanted to pass in a version number manually at build or publish time.

Back to our project pipeline from earlier, here are a selection of tasks that wrap everything together:

  desc "Builds the Win32 release of MyProject.dproj"
  task :build_win_release do
    puts 'Building Project MyProject.dproj for Windows'
    release_project('MyProject.dproj', 'Win32')
  end

  desc "Builds the Mac OS X release of MyProject.dproj"
  task :build_mac_release do
    puts 'Building Project MyProject.dproj for Mac'
    release_project('MyProject.dproj', 'MacOS32')
  end

  desc "Writes the manifest out to manifest.xml in the current working dir"
  task :write_manifest => [:build_win_release] do
    puts 'Writing the update manifest'
    v = get_version(get_executable_path(:Win32))
    write_update_manifest_to(File.join(get_cwd(), 'manifest.xml'), v)
  end

  desc "Uploads the manifest to Amazon S3"
  task :upload_manifest => [:write_manifest] do
    puts 'Uploading the manifest..'
    upload_to_s3(File.join(get_cwd(), 'manifest.xml'), 'myproject/manifests/manifest.xml')
  end

  desc "Builds the Windows zip distributable"
  task :make_win_zip => [:build_win_release] do
    exe = get_executable_path(:Win32)
    v = get_version(exe)
    zip_name = 'MyProject-win-' + v + '.zip'
    make_zip_distro([exe], zip_name) 
    puts "Create zip: " + zip_name
  end

  desc "Builds the Mac zip distributable"
  task :make_mac_zip => [:build_mac_release] do
    exe = get_executable_path(:MacOS32)
    # Call get_version on the Win32 executable. If the Win and Mac OS X version numbers 
    # differ, you will need to extract the version from the generated Info.plist instead.
    v = get_version(get_executable_path(:Win32))
    zip_name = 'MyProject-mac-' + v + '.zip'
    make_zip_distro([exe], zip_name)
    puts "Create zip: " + zip_name
  end

  desc "Uploads all of the zip files"
  task :upload_zips => [:make_win_zip, :make_mac_zip] do
    v = get_version(get_executable_path(:Win32))
    win_name = 'MyProject-win-' + v + '.zip'
    mac_name = 'MyProject-mac-' + v + '.zip'
    puts 'Uploading the win zip version .. ' + v
    upload_to_s3(win_name, 'myproject/downloads/' + win_name) 
    puts 'Uploading the mac zip version .. ' + v
    upload_to_s3(mac_name, 'myproject/downloads/' + mac_name)
  end

  desc "Builds, zips and uploads the artefacts and manifests"
  task :release_all => [:upload_zips, :upload_manifest]

You can build your releases, create the manifest and upload all with:

> rake release_all 

Simple, repeatable and easy to extend when you have more steps to your pipeline. Further steps for your project might be adding in your acceptance tests or automatically generating and publishing some release notes from your git logs.

Other Links

See Different: My Database-free Application lecture

$
0
0

Today I gave a lecture about database-free applications.

Most people who first read the title, thought that "oh you probably write to memory or disk or something", yet the lecture is not about storing data, but on one approach of designing systems to work.

It is a completely different thing, yet I find that many people can't see it, they are looking for the "catch".

This post was written prior to the actual lecture itself (a day before in fact :) ), so I can't tell if my lecture was good enough or not, but you have my slide notes, and the whole lecture (using html5 and reveal.js -> firefox or chrome recommended), so take a look and tell me yourself :)


Filed under: Object Pascal, Perl, אירועים, אסטרטגייה, חברה, טכנולוגיה, מסדי נתונים, פיתוח, קהילה, קוד פתוח, תוכנה, תכנות Tagged: designing systems, slide notes

Jamie's Blog: Simple REST Client for Delphi

$
0
0

While writing a Delphi Rich client for a personal project talking to RESTful service I recently became frustrated with the available easy REST client interfaces for Delphi.

As a result, I wrote a small wrapper around the Indy TIdHttp component to provide a fluent interface upon which you can use to write REST clients. It’s lightweight wrapper, which currently only has the functionality that I required for this project but I decided to make it available in case anyone else wanted to use it.

You can view a simple example were we post a fictional example of PUT’ing a todo item below:

program SimpleRestRequestSample;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Classes,
  RestRequest in 'RestRequest.pas';

var RestReq: TRestRequest;
    RestResp: THttpResponse;
    putParams: TStringList;
begin
  try
    try
      putParams := TStringList.Create();
      putParams.Add('title=Buy milk');
      putParams.Add('due-date=01/01/2013 00:00:00');
      RestReq := TRestRequest.Create().Domain('localhost').Path('todo').WithCredentials('test', 'test');
      RestResp := RestReq.Put(putParams);
      if RestResp.ResponseCode = 200 then WriteLn('Your todo was added!');
    finally
      RestReq.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

As you can see, the interface is designed to be fluent to make it easy to see the components of the request in your code.

The TRestResponse record that is returned contains the ResponseCode and the ResponseBody but does nothing with the returned body as the type of response will be determined by your Client and Server. For example, in my own client project, I set the Accept header to prefer ‘application/json’ and then parse this in the response after receiving a 200 OK response from the server with the application/json header,. This looks something like the below:

      request := TRestRequest.Create.Domain(Self.FAPIEndPoint).WithCredentials(Self.FUsername, Self.FPassword).Path('todo').Path(IntToStr(id));
      response := request.Get;
      if response.ResponseCode = 200 then
      begin
        result := jsonToObj(response.ResponseStr);
        Self.doOnTodoReturned(result);
      end else Self.doOnErrorStatus(response.ResponseCode, response.ResponseStr);

There are a few limitations: for example, it doesn’t currently support the PATCH method as TIdHttp doesn’t currently support this method and I didn’t have the time or motivation to mock out TIdHttp so the unit test coverage doesn’t currently extend that far. Aside from that, I’ve found it pretty nice to work with in my own project so any thoughts would be appreciated.

I’m completely open to help or contributions and you can view the SimpleRestClient project on Github.


The Wiert Corner - irregular stream of stuff: jpluimers

$
0
0

I remember having heard this interview on audio a long while ago, but couldn’t find it back. Now I stumbled across Cape Cod Gunny writing about this great video where Anders Hejlsberg is interviews by Research Channel for an hour. To quote Cape Cod Gunny:

I just watched this interview with Anders Hejlsberg for the first time. This is truly an amazing interview. It’s rather long, about 1 hour, but it is so worth it. I’m not giving anything away… you’ll have to just watch and enjoy.

I am giving a few things away: trip down memory lane, putting big parts of software development history into perspective,

Since Anders has been so versatile, influential and still humble, this is a must watch for anyone in the software field. To quote Research Channel:

This episode features industry luminary, Anders Hejlsberg. Before coming to Microsoft in 1996 he was well noted for his work as the principal engineer of Turbo Pascal and the chief architect of the Delphi product line. At Microsoft, he was the architect for the Visual J++ development system and the Windows Foundation Classes (WFC). Promoted to Distinguished Engineer in 2000, Anders is the chief designer of the C# programming language and a key participant in the development of Microsoft’s .NET Framework. In this show, Anders is joined by a surprise guest. This episode of ‘Behind the Code’ is hosted by Barbara Fox – former senior security architect of cryptography and digital rights management for Microsoft.

Thanks Gunny for pointing me at this!

–jeroen

via: Cape Cod Gunny Does Delphi: Priceless: Behind the Code with Anders Hejlsberg.

(PS: how a video published in the C# 3 era can be so current <g>).

And if you feel for more, here, hereherehere and here are some more, are a few lists of videos where Anders speaks.
From a historic perspective, I like these most:


Filed under: .NET, .NET 1.x, .NET 2.0, .NET 3.0, .NET 3.5, .NET 4.0, .NET 4.5, C#, C# 1.0, C# 2.0, C# 3.0, C# 4.0, C# 5.0, Delphi, Delphi 1, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Development, Software Development

Behind the connection: Operator overloading for records

$
0
0
Operator overloading for records Operator overloading is a mechanism which gives you control over what an operator does on a given data type. Applied to a record, you can use it to provide a transparent conversion from one data type to another. The example code I will show in a moment comes from one of my applications (simplified version for brevity). I have a system which requires a parameter

The Wiert Corner - irregular stream of stuff: jpluimers

$
0
0

Firebird News: FreePascal 2.6.2 is released

$
0
0
FPC 2.6.2 has landed. FPC 2.6.2 is an update to 2.6.0 that contains most library progress over the 2.6.0 and some crucial compiler fixes. Building is still in progress and some formats (deb,rpm) and targets might not be available yet. Changes that may break backwards compatibility are documented at: http://wiki.freepascal.org/User_Changes_2.6.2 For Downloads, please use the [...]

See Different: FPC 2.6.2 שוחרר

$
0
0

השבוע שוחרר FPC 2.6.2 המכיל בעיקר תיקוני באגים, אשר חלקם הם שינויים ב API או בהתנהגות של פונקציות/מחלקות בשביל לתקן את הבעיות.

  • מתודות שונות בTDataset שונו במבנה שלהן, והוחלפו מPChar ל TRecordBuffer‏
  • DLLParam שונה מ longint ל PtrInt‏
  • פונקציות וסמלים ביחידות unix וunixutils סומנו כ deprecated‏
  • התנהגות TStrings.DelimitedText שונתה
  • בfcl-image‏, TTiffIDF שונה ל TTiffIFD‏
  • היחידה libc מחזירה אזהרת deprecated‏
  • הוסרה התמיכה עבור UPX בקבצי ה Makefile‏

הסבר מלא בנושא השינויים


Filed under: FPC, Object Pascal, טכנולוגיה, פיתוח, קוד פתוח, תוכנה, תכנות
Viewing all 1725 articles
Browse latest View live