Planet Smalltalk

May 21, 2015

Torsten Bergmann - Seaside meets Mustache

Tired of writing all HTML in Seaside using methods. Then just combine Seaside with Mustache - saves you some time in the first place and later you can convert to messages and refactor the way you like.

Marten Feldtmann - PUM/Gemstone – migration of instances …

When creating new versions of a model one might change already defined classes in that model and add or remove attributes from that class definition.

Gemstone is able to handle different versions of classes and allows the programmer to migrate instances of old class versions to a specific new version of that class.

The job of migration can be very difficult and this is my first attempt in PUM is to at least do the initialize stuff (in the initialize method) also in the migration support method. The generated code looks for all current attributes (in den new model) defined and if they are new, they simply initialize them with the value from that model.

migrateFrom: oldValue instVarMap: unusedParameter
	|  oldNames |

	oldNames := oldValue class allInstVarNames.

	(oldNames includes: #'studyMembership') ifFalse:[ studyMembership := StringKeyValueDictionary new ].
	(oldNames includes: #'quotas') ifFalse:[ quotas := Set new ].
	(oldNames includes: #'quotaFullAppointmentHandling') ifFalse:[ quotaFullAppointmentHandling := CATIEnumQuotaFullAppointmentHandling noHandling ].

Filed under: Smalltalk Tagged: Gemstone, PUM, Smalltalk

May 20, 2015

The Weekly Squeak - Dynamic Languages Symposium 2015 Call For Papers

pittsburgDLS copy


C A L L   F O R   P A P E R S


======== DLS 2015 ===========

11th Dynamic Languages Symposium 2015

October, 2015

Pittsburgh, Pennsylvania, United States

Co-located with SPLASH 2015

In association with ACM SIGPLAN

The 11th Dynamic Languages Symposium (DLS) at SPLASH 2015 is the premier forum for researchers and practitioners to share knowledge and research on dynamic languages, their implementation, and applications. The influence of dynamic languages — from Lisp to Smalltalk to Python to Javascript — on real-world practice and research continues to grow.

DLS 2015 invites high quality papers reporting original research, innovative contributions, or experience related to dynamic languages, their implementation, and applications. Accepted papers will be published in the ACM Digital Library, and freely available for 2 weeks before and after the event itself.  Areas of interest include but are not limited to:

Innovative language features and implementation techniques

Development and platform support, tools

Interesting applications

Domain-oriented programming

Very late binding, dynamic composition, and run-time adaptation

Reflection and meta-programming

Software evolution

Language symbiosis and multi-paradigm languages

Dynamic optimization

Hardware support

Experience reports and case studies

Educational approaches and perspectives

Semantics of dynamic languages

== Invited Speaker ==

DLS is pleased to announce a talk by the following invited speaker:

Eelco Visser: Declare your Language.

== Submissions and proceedings ==

Submissions should not have been published previously nor under review at other events. Research papers should describe work that advances the current state of the art. Experience papers should be of broad interest and should describe insights gained from substantive practical applications. The program committee will evaluate each contributed paper based on its relevance, significance, clarity, length, and originality.

Papers are to be submitted electronically at in PDF format. Submissions must be in the ACM format (see and not exceed 12 pages. Authors are reminded that brevity is a virtue.

DLS 2015 will run a two-phase reviewing process to help authors make their final papers the best that they can be. After the first round of reviews, papers will be rejected, conditionally accepted, or unconditionally accepted. Conditionally accepted papers will be given a list of issues raised by reviewers. Authors will then submit a revised version of the paper with a cover letter explaining how they have or why they have not addressed these issues. The reviewers will then consider the cover letter and revised paper and recommend final acceptance or rejection.

Accepted papers will be published in the ACM Digital Library.

Important dates

Abstract Submissions: Sun 7 Jun 2015

Full Submissions: Sun 15 Jun 2015

First phase notification: Mon 27 Jul

Revisions due: Mon 3 Aug

Final notification: Mon 17 Aug

Camera ready: Fri 21 21 Aug

Program chair

Manuel Serrano, Inria Sophia-Antipolis,

Program committee

Carl Friedrich Bolz, DE

William R. Cook, UTexas, USA

Jonathan Edwards, MIT, USA

John Field, Google, USA

Matt Flatt, USA

Elisa Gonzalez Boix, Vrije Universiteit, BE

Robert Hirschfeld, Hasso-Plattner-Institut Potsdam, DE

Benjamin Livshits, Microsoft, USA

Crista Lopes, UC Irvine, USA

Kevin Millikin, Google, DN

James Noble, Victoria University of Wellington, NZ

Manuel Serrano, Inria, FR (General chair)

Didier Verna, EPITA, FR

Jan Vitek, Purdue, USA

Joe Politz, Brown University, USA

Olivier Tardieu, IBM, USA

Robert Hirschfeld

Torsten Bergmann - ICSEconf tool demo video on Vidi in Pharo

Cincom Smalltalk - Smalltalk Digest: May Edition

The May edition of The Cincom Smalltalk Digest is available now.

May 19, 2015

Torsten Bergmann - Smalltalk Reflections episode 13 - an Interview with John O'Keefe from Instantiations

The Smalltalk Reflections podcast episode 13 is up - An Interview with John O'Keefe from Instantiations.

Torsten Bergmann - ARM Cog progress

Tim can now run the ARM cog/spur system on a Pi 2. Read about the progress they made.

Torsten Bergmann - Scripting with Pharo

May 18, 2015

Torsten Bergmann - Osmocom and Pharo

Osmocom (Open Source Mobile Communication) is a collection of Free Software / Open Source Software projects in the area of mobile communications. There is also some activity in the Pharo space for it with an own Osmocom team on SmalltalkHub with several projects like GSM, SMPP, TCAP, ...

Torsten Bergmann - System Monitoring for Pharo Images

Torsten Bergmann - Pharo HoneyGinger on CI

HoneyGinger is a fluid dynamics simulator and visulalizer based on the SPH method written in Pharo. There is now a CI job for it.

Smalltalk Jobs - Smalltalk Jobs – 5/17/15

  • New York, NYObject Oriented/Smalltalk Developer – Associate (Job ID 150046448) and Smalltalk/Object Oriented Developer (Job ID 150050665) at J.P. Morgan
    • Required Skills:
      • Strong understanding of Object Oriented development practices.
      • Experience of Smalltalk programming language preferable but not essential
      • Strong interpersonal skills.
      • Experience or familiarity with basic principles of pricing financial products.
      • The successful applicant is most likely to be a graduate, or equivalent with work experience, who is keen to develop a career in a world class investment bank
      • Good experience developing commercial software and are familiar with controls, tools and processes used in source code management, build management, and development lifecycle.
      • Experience of working in a large development team with groups in various global locations
      • The successful candidate will have confidence, ability and will to work on a trading floor which will require abilty to build and maintain strong working relationships with demanding sponsors and stakeholders
      • Excellent analytical and problem solving skills
      • Excellent verbal and written communication skills, able to communicate accurately, concisely, and effectively in a global organization
      • Experience in project and software development life cycles, particularly Agile technique and methodologies, including breaking down high level requirements into technical deliverables, providing reliable estimates of work and delivering on time.
      • The ability to work under pressure on multiple items in parallel with agreed timelines
      • Self starter with proven ability to produce end results with minimal assistance and supervision
    • Additional listings: J.P. Morgan
  • Jersey City, NJSmalltalk Developer through VDart, Inc.
    • Required Skills:
      • Bachelor‘s degree in a computer related field or equivalent experience
      • 5+ years of experience developing using Smalltalk
      • Excellent planning/organizational, problem-solving, and analytical skills
      • Experience in coordination with client and onsite offshore model
      • Excellent communication skills
      • Basic presentation skills
      • Basic decision-making skills
      • Basic leadership skills
      • Must be able to maintain a high degree of accuracy and confidentiality
      • Some travel may be required, including overnight stays
      • Basic knowledge of insurance and financial services products
      • Basic knowledge of business unit applications preferred
      • Excellent time management skills
  • Omaha, NESmalltalk Developer through SYNTEL Inc.
    • Required Skills:
      • Hands on experience in Smalltalk programming
      • Exposure to basic UNIX commands
      • Exposure to Oracle SQL
      • Exposure to Java programming
      • Strong OOP concepts.
      • Experience in coordination with client and onsite offshore model.
    • Wanted Skills:
      • Cards & payments domain knowledge
    • Additional listings: SYNTEL, SYNTEL
  • Denver, COApplication Developer through CTG
    • Required Skills:
      • 3-5 yrs experience with Visual Age Smalltalk Object Oriented Programming
      • 3-5 yrs experience with Informix
      • Strong OOP concepts
      • Should have good knowledge on Unix Shell Scripting – Korn Shell
    • Additional listings: CTG
  • Bangalore, IndiaSoftware Engineer through Career Creatorz
    • Required Skills:
      • Hands on experience working in C programming language
      • Strong analytical, logical, problem solving, trouble shooting skills
      • Knowledge of project life cycle
      • Excellent communication skills
    • Wanted Skills:
      • Knowledge of OOPS concepts, Scripting
      • Exposure on C++ is a plus
      • Experience in the semiconductor equipment manufacturing industry
      • Understanding of distributed systems and socket programming
      • Understanding of Design Patterns
      • Knowledge of RTOS
      • Knowledge of SQL server
      • Knowledge of SmallTalk and VisualWorks
Good luck with your job hunting,
James T. Savidge

View James T. Savidge's profile on LinkedIn

This blog’s RSS Feed

Filed under: Employment Tagged: jobs, Smalltalk, Smalltalk jobs

May 17, 2015

Smalltalk Jobs - Smalltalk Job at Cincom – 5/17/15

Cincom has an open position in North America in the Smalltalk team.

  • Software Engineer – VisualWorks at Cincom Systems
    • Required Skills:
      • Five years in Smalltalk
      • Documentable experience in Object Oriented Design (OOD) of application frameworks
      • Hands-on experience with VisualWorks and/or ObjectStudio
      • Background developing quality Smalltalk code and delivering product feature documentation
      • Publicly available work in VisualWorks, especially tools enhancements
      • Familiarity with the internals of the VisualWorks tool set
      • Comfortable using VisualWorks to design and build user interfaces
      • Thorough familiarity with agile development methodologies
      • Strong written communication skills and planning abilities
      • Works well in a distributed team environment
Good luck with your job hunting,
James T. Savidge

View James T. Savidge's profile on LinkedIn

This blog’s RSS Feed

Filed under: Employment Tagged: jobs, Smalltalk, Smalltalk jobs

Torsten Bergmann - NBSQLite3 Online Backup

Pharo Weekly - Pharo pi machine

Got my Raspberry Pi B+ with a Tontec® 3.5 touch screen display
to bootstrap into Pharo.

The Raspberry Pi from CI (
worked out of the box on Raspbian. Nice!

Torsten B.


Pierce Ng - Scripting with Pharo

A couple of links to set the scene, one from 2004, the other from 2005. Their titles relate to this post, although their content doesn’t really.

While Pharo is an immersive interactive programming environment, it can also be used for operating system command line-oriented scripting. Take a freshly downloaded standard Pharo 4 image, here renamed p4cli.image:

% pharo -vm-display-null p4cli.image --list
Currently installed Command Line Handlers:
Fuel            Loads fuel files
config          Install and inspect Metacello Configurations from the command line
save            Rename the image and changes file
update          Load updates
printVersion    Print image version
st              Loads and executes .st source files
test            A command line test runner
clean           Run image cleanup
eval            Directly evaluates passed in one line scripts

Let’s see how to use NBSQLite3’s online backup functionality to back up a live SQLite database through a Pharo script.

Firstly, install the current bleedingEdge version of NBSQLite3.

% pharo -vm-display-null p4cli.image config \ \
      ConfigurationOfNBSQLite3 --install=bleedingEdge
'Installing ConfigurationOfNBSQLite3 bleedingEdge'

Loading 1.2 of ConfigurationOfNBSQLite3...
Fetched -> NBSQLite3-Core-PierceNg.7 --- ...
...finished 1.2%

Now make a script of the backup code snippet seen in my previous blog post, changing the database file names. In this case, I am using the script to make a copy of my server’s firewall log database, which is live and constantly updated by the logging daemon. The script is named ‘’.

| srcDB dstDB backup |
srcDB := NBSQLite3Connection openOn: '/var/log/ulog/ulogd.db'.
dstDB := NBSQLite3Connection openOn: '/tmp/ulogd-backup.db'.
[   backup := NBSQLite3Backup new.
    srcDB asBackupSource: backup.
    dstDB asBackupDestination: backup.
    backup prepare.
    [ [ backup completed ] whileFalse: [ backup step ] ] ensure: [ backup finish ]
] ensure: [ srcDB close. dstDB close. ]

Run the script under Unix “time”:

% time pharo -vm-display-null p4cli.image st --quit
pharo -vm-display-null p4cli.image st --quit 
0.26s user 0.10s system 53% cpu 0.675 total

% ls -l /var/log/ulog/ulogd.db* /tmp/*.db
-rw-r--r-- 1 pierce pierce 11636736 May 17 20:49 /tmp/ulogd-backup.db
-rw-r--r-- 1 ulog   ulog   11643904 May 17 20:50 /var/log/ulog/ulogd.db

The database files aren’t identical, because the logging daemon has written yet more data since the backup was taken.

Torsten Bergmann - Short example of composing RTDynamicStackedGrapher

Torsten Bergmann - Adding Magritte forms in GTInspector

Torsten Bergmann - ESUG 2015 in Brescia, Italy - July 13-17

Torsten Bergmann - Portfolio management with Quuve

written in Pharo. Here is a video about it. Read more for the details.

Torsten Bergmann - Poppy with Phratch

Here is a video of a project to connect and to control Poppy with Phratch. Phratch is a Pharo port of Scratch.

Pharo Weekly - A system monitoring for Pharo images

Finally I’ve found some time to release some of my code I’ve been using the last years. It is a project around system monitoring. It defines system parameters to watch and integrates them with popular tools like munin, monit and nagios/icinga/… As an example the following picture shows the monitoring of the vm memory over a day.


System monitoring is basically about monitoring system parameters in order to send alerts when thresholds are exceeded or to plot graphs that enables one to estimate further progression of image behaviour.

The code is here!/~NorbertHartl/Monitoring

and an introduction article (more will follow) to it is here

Feedback is welcomed!

Hopy you enjoy it. And bug me if you have questions or something is not working.


May 16, 2015

Norbert Hartl - System monitoring for pharo images

In our daily programming tasks we all know that having tests is great way of keeping our software under control. It is something that we regularly execute in order to see that we didn't break any of our previous assumptions. If we are keen on tests we even try to have a 100% code coverage meaning that every available code path is executed at least once.

Deploying the software adds additional precautions to take. Apart from having a software running without errors it also needs to deal with resources that are available. And resources run short sometimes. Having the software tested for execution doesn't tell us it doesn't waste resources which prevents the software from running a long time. The software can leak memory which is unseen while we execute isolated single test cases. Having the software run for a longer time will reveal this problem.

Even if there isn't a significant leakage of resources the software can run short on resources if used more frequently. There is a point where we need to think about scaling the deployment to meet the resources needed. Regardless where the shortage comes from we need a way to see an immediate problem or to see a tendency that projects a shortage in an overseeable time frame.

In order to deal with that system monitoring comes into play. System monitoring is the task of inspecting the resources of an environment all the time. These inspections of resources are combined with defined thresholds we find feasible with the environment. Whenever are threshold is exceeded the inspecting software can send us alerts making us have a look at the software before it is going to break. The inspected values of the resources can also be graphed so we can see tendencies of resource usage over time.

I've implemented a utility that helps monitoring a pharo image. It is called Monitoring. The source is availble on smalltalkhub

Install a fresh pharo image (pharo 4.0 at the moment)

$ curl | bash

Open the image using

$ ./pharo-ui Pharo.image

Open a playground and load the project with the following expression

Gofer it
    smalltalkhubUser: 'NorbertHartl' project: 'Monitoring';
    configurationOf: 'Monitoring';

The following text describes some ways how to enable monitoring of a pharo system.


Munin is a tool that can produce graphs like this one.

a memory graph produced by munin

It inspects the image every 5 minutes and puts the inquired values in a RRDTool. From this tool it creates graphs for overviews over day, week, month and year. This enables use to see the progression of resource usage over a whole year which makes it quite easy to project something into the future.

If you've installed the project with the snippet above you should now execute the following in the playground (formerly known as workspace).

MonitorMuninExampleServer image

It starts a zinc server on port 5000 and adds everything needed to monitor vm memory and the garbage collector.

You can request it using curl and the following command line

$ curl

and you should see something like this (the values will be different of course)

oldspace.value 163980984
youngspace.value 1336248
tenures.value 165317588
free.value 5123340

A munin graph needs to be configured. We can request that using the command

$ curl

You should see this

graph_title VM memory
graph_category test-server
graph_vlabel bytes
graph_args --base 1000
memory.label Memory
memory.warning 60000000
memory.critical 80000000
memory.type GAUGE
oldspace.label Oldspace
oldspace.type GAUGE
youngspace.label Youngspace
youngspace.type GAUGE
tenures.label Tenures
tenures.type GAUGE
free.label Free
free.type GAUGE

The configuration of the graph is read by munin at startup. It configures the graph and then every 5 minutes it requests the value and is able to plot it.

Now we need to install munin. In linux execute

$ apt-get install munin

adding a web server

Installing a web server depends highly on which web server you like to use and what environment you are targeted for. In depth configurations of several web servers is beyond the scope of this post. I'll take a shortcut here to just get you something to see. I assume an actual installation of ubuntu (in my case this is a 14.10 distribution). I leave the fine grained configuration as an exercise for the reader. You can find the munin documentation here

The default installation of munin includes a default configuration that is suitable to us. It assumes everything is local. If you need to adjust it you can find the configuration in /etc/munin/munin.conf.

This example uses nginx and assumes you don't have it installed yet. Execute

$ apt-get install nginx

and add the following

    location /munin/static/ {
            alias /etc/munin/static/;
            expires modified +1w;

    location /munin/ {
            alias /var/cache/munin/www/;
            expires modified +310s;

in the server section of


You will find a location statement there already. Just add the above on the same level as the other statement. After you saved the file restart the nginx server by doing

$ service nginx restart

If everything went well you should be able to open the following URI using a web browser


and you should see something like this

a memory graph produced by munin

Connecting the parts

We have now downloaded a pharo image, installed the Monitoring project, started a pharo zinc server, installed munin, installed and configured a web server. Now the only thing we need to do is to add our memory graph to munin.

Create a file /etc/munin/plugin-conf.d/pharo-monitoring with the following content


This tells munin that every plugin that has a prefix of test-server_ will get an environment containing a variable monitorUrl pointing to our pharo image.

Next we need to create a munin plugin (a shell script that translates the way munin calls its plugins to our zinc server). I've made a git repository to ease that task. Install it using

$ cd /opt
$ git clone 

Activate the plugin using

$ cd /etc/munin/plugins
$ ln -s /opt/pharo-scripts/monitoring/munin-plugin test-server_memory

We created the plugin with the prefix test-server_ so munin will assign it the monitorUrl we configured above. The script takes the suffix after the underscore to construct the complete URI.

You can test it by issuing

$ munin-run test-server_memory

that should show the values we saw above and

$ munin-run test-server_memory config

that should show the configuration of the graph from above. The last two invocations of the script are exactly how munin will call them and are a great way to debug problems like permissions et al.

If everything went well we can restart munin

$ service munin-node restart

and after a while the new plugin should appear like you can see here.

the plugin is there

Clicking on the test-server link shows us

more to come

and you can see on the right side of the left graph there are few lines starting to build up. Now we just have to wait for the data to fill the graph.


I might say this is an easy way to start monitoring pharo images. But as this blog shows there are quite some things to set up in order to have it work. These are all basic building blocks like installing and configuring a web server and doing system administration tasks. I assume that if you are interested in system monitoring you know most of this already and you can easily translates everything that has been written here into your own environment.

This post did a quick and rough shortcut throughout the components that need play together. I tried every step but I'm sure there are a lot of things that can go wrong like permission problems or the like. If you have problems don't hesitate to bug me about it.

If you got this far the future of monitoring is bright. The next task to monitor your garbage collector is as simple as

$ cd /etc/munin/plugins
$ ln -s /opt/pharo-scripts/monitoring/munin-plugin test-server_gc
$ service munin-node restart

and wait. The graph will appear automatically. You are now prepared to orchestrate your whole server farm. With munin it is quite easy to collect graphs from a lot of hosts and combine them in a single web page. The example server sets also some thresholds for warning and critical. Just waste a bit memory and see the label in the graph turn yellow in case of exceeding the warning threshold and read in case of critical. You can configure munin the send e.g. an email if the thresholds are exceeded.

This should be enough for an introduction to system monitoring in pharo. In following articles I will present more tools and I'll dig into the code and explain how you can easily monitor any parameter of your system you like.

As always I like to have feedback about things being good and things being bad. Hope you enjoy system monitoring your pharo images.

Happy Monitoring!

Pierce Ng - NBSQLite3 Online Backup

SQLite provides an online backup API that operates incrementally, so that the source database file is locked only when it is actually read from, allowing other applications to use the source database while the backup is in progress.

I’ve added the backup API to NBSQLite3. Here’s a demonstration code snippet using OpenFootball’s World Cup 2014 database:

| srcDB dstDB backup |
srcDB := NBSQLite3Connection openOn: '/tmp/wc2014.db'.
dstDB := NBSQLite3Connection openOn: '/tmp/backup.db'.
[   backup := NBSQLite3Backup new.
    srcDB asBackupSource: backup.
    dstDB asBackupDestination: backup.
    backup prepare.
    [ [ backup completed ] whileFalse: [ backup step ] ] ensure: [ backup finish ]
] ensure: [ srcDB close. dstDB close. ]

Let’s look at the two databases:

% ls -l *.db
-rw-r--r-- 1 pierce pierce 1101824 May 16 10:58 backup.db
-rw-r--r-- 1 pierce pierce 1101824 Jul 22  2014 wc2014.db

% openssl md5 backup.db wc2014.db
MD5(backup.db)= 408494059b67fc3c7d39b672ce7e525e
MD5(wc2014.db)= 28ab0865e87920ca2f2b1f0de710c622

Ok, the two files have the same size, but aren’t bit-wise identical. Now try sqldiff that comes with SQLite:

% sqldiff --help
Usage: sqldiff [options] DB1 DB2
Output SQL text that would transform DB1 into DB2. 

% sqldiff wc2014.db backup.db

No output, meaning the two files are identical structurally and content-wise, according to sqldiff. Let’s make sure:

% sqlite3 backup.db
sqlite> select count(*) from goals;
sqlite> select max(id) from goals;
sqlite> delete from goals where id > 168;
sqlite> select max(id) from goals;
sqlite> ^D

% sqldiff wc2014.db backup.db
DELETE FROM goals WHERE id=169;
DELETE FROM goals WHERE id=170;
DELETE FROM goals WHERE id=171;

The output shows that sqldiff and the SQLite library are in cahoots to make two database files appear identical even when they are not. Haha, no, I mean, the output gives us some assurance that the backup API operated as advertised and created a proper backup of the database.

Now, the demonstration code snippet is somewhat contrived, because it backed up a totally quiescent source database. Next step is to verify backing up a database in active use.

Code updated in Smalltalk Hub. Unit tests and ConfigurationOf update to come.

May 14, 2015

The Weekly Squeak - ESUG 2015 in Brescia, Italy – July 13-17

ESUG 2015

It’s that time again.  For more information see this link: ESUG Conference 2015 in Italy.

May 13, 2015

Pharo Weekly - Parsing code with syntax errors

We can parse code with syntax errors: it generates partial ASTs with the faulty part of the input as a RBParseErrorNode.

Only three methods are needed to allow generating executable methods from such an AST: the SyntaxErrorNotification
 is raised at runtime instead of compile time.

    | ast cm |
    ast := OpalCompiler new
                source: 'method 3+';
                useFaultyForParsing: true;
    self assert: ast isMethod.
    self assert: ast isFaulty.
    cm := ast compiledMethod.
    self should: [cm valueWithReceiver: nil arguments: #()] raise: SyntaxErrorNotification

The syntax error instance is compiled in via a literal variable, in the end the only thing needed was:

visitParseErrorNode: anErrorNode  
		pushLiteralVariable: #error -> anErrorNode asSyntaxErrorNotification;
		send: #signal.

This is in #50044.

Future work: introduce a RuntimeSyntaxError that can be turned off per error and globally.


Torsten Bergmann - C.H.I.P. with Smalltalk

Torsten Bergmann - Playing with Smalltalk and Pharo

There is a newbee playing with Smalltalk and Pharo. See here and here. Nice to see how others find out what we know and do for years. He might soon become shocked when he finds out that he is still at the tip of the iceberg ;)

Torsten Bergmann - Pharocloud Snaphsot Backups

Snapshot backups (both disk and memory) are available for beta-test at Save not Pharo Image only but the whole OS!

May 12, 2015

The Weekly Squeak - Cool, Interesting – WAIT – is that SCRATCH!!