hodza/BlackBox.Shkola.2014 huggingface dataset:
i21прим/Mod/СортДемо2original.odc

MODULE  i21примСортДемо2;
	IMPORT  StdLog,  In := i21sysIn,  Модуль := i21примВставки,  Тест := i21примСортТест;
	
	PROCEDURE Выполнить*;
		VAR  x, n: INTEGER;  a: POINTER TO ARRAY OF INTEGER;
	BEGIN
		(* подсчет количества сортируемых чисел *)
		In.Open;  n := 0;  In.Int( x );
		WHILE  In.Done  DO  INC( n );  In.Int( x ) END;
		IF  n > 0  THEN
			(* инициализация массива *)
			NEW( a, n );
			In.Open;  n := 0;  In.Int( x );
			WHILE  In.Done  DO  a[n] := x;  INC( n );  In.Int( x ) END;

			(* печать до сортировки *)
			StdLog.Ln;  StdLog.String('до сортировки: ');
			FOR  n := 0  TO  LEN(a) - 1  DO  StdLog.Int( a[n] )  END;
			StdLog.Ln;
			
			Модуль.Сорт( a );  (* это сортировка *)
			ASSERT( Тест.Отсортирован( a ) );  (* автоматическая проверка результата *)

			(* печать после сортировки *)
			StdLog.Ln;  StdLog.String('после сортировки: ');
			FOR  n := 0  TO  LEN(a) - 1  DO  StdLog.Int( a[n] )  END;
			StdLog.Ln;
		END
	END Выполнить;
	
END  i21примСортДемо2.

Чтобы выполнить тест, нужно мышкой отметить первое из сортируемых чисел (не обязательно 2  можно отметить, например, и 90), 
а затем кликнуть по коммандеру (черному кружку с восклицат. знаком).
Программа прочтет все числа, начиная с отмеченного и до , отсортирует их и распечатает в рабочем журнале.

i21примСортДемо2.Выполнить  2 0 90 -111 11 -4 8

Можно призвольно менять последовательность чисел  стирать, добавлять новые (в любом количестве) и т.п.

Если после клюка ничего не происходит, то возможно Вы забыли отметить числа.

Можно поменять модуль, содержащий проверяемую программу сортировки: достаточно изменить i21примВставки в операторе IMPORT на i21примПузырь. После этого нужно клюкнуть по следующему коммандеру:
"DevCompiler.Compile;DevDebug.Unload;i21примСортДемо1.Выполнить"

Внимание! Так как процедура сортировки и проверяющие программы реализованы в разных модулях, могут возникнуть проблемы (вызывается старая версия сортировки, когда уже написана и успешно скомпилирована новая). О том, что делать в таких случаях, см. здесь.
i21прим/Mod/СортТест.odc

MODULE  i21примСортТест;

	PROCEDURE Отсортирован* ( IN м: ARRAY OF INTEGER ): BOOLEAN;
		VAR  результат: BOOLEAN;  i: INTEGER;
	BEGIN
		результат := TRUE;
		FOR  i := 1  TO  LEN( м ) - 1  DO
			результат := результат & ( м[i-1] <= м[i] )
		END;
		RETURN  результат
	END Отсортирован;
	
END  i21примСортТест.
i21прим/Mod/Трап.odc

MODULE  i21примТрап;
	IMPORT  Log := StdLog;
	
	VAR  a: INTEGER;  b: ARRAY 3 OF REAL;  c: ARRAY 50 OF CHAR;
	
	PROCEDURE ДругаяПроц;
		VAR  y: INTEGER;
	BEGIN
		y := 256;
		(* следующая команда вызовет аварийную остановку и откроет окошко Трап, в котором видны значения локальных переменных всех процедур в цепочке вызовов на момент остановки: *)
		HALT(0); (*в открывшемся окошке Трап можно покликать по синим ромбам*)
	END ДругаяПроц;
	
	PROCEDURE Вызов*;
		VAR  a, b: INTEGER;

		PROCEDURE ВнутрПроц ( x: INTEGER );
			VAR  y: REAL;
		BEGIN
			y := 3.14592;  ДругаяПроц
		END ВнутрПроц;

	BEGIN
		a := 13;  b := 14;
		ВнутрПроц( 2002 )
	END Вызов;
	
BEGIN  
	a := MIN(INTEGER);  
	b[0] := 0;  b[1] := 1;  b[2] := 2;  
	c := "аварийная остановка"
END  i21примТрап.

i21примТрап.Вызов
i21прим/Mod/Уплотнение.odc

MODULE  i21примУплотнение;
	IMPORT  StdLog;
	
	PROCEDURE Проверить ( VAR a: ARRAY OF CHAR );
		VAR  кандидат: INTEGER;
	BEGIN
		кандидат := 0;
		WHILE (кандидат < LEN(a)) & (a[кандидат] # 0X)  DO
			кандидат := кандидат + 1
		END;
		ASSERT( кандидат < LEN(a) )
	END Проверить;
	
	PROCEDURE Уплотнить* ( VAR a: ARRAY OF CHAR );
		VAR  i, j: INTEGER;
	BEGIN  Проверить( a );
		i := 0;  j := 0;
		WHILE  a[j] # 0X  DO
			i := i + 1;
			IF  (a[i] # ' ') OR (a[j] # ' ')  THEN
				j := j + 1;
				a[j] := a[i]
			END
		END
	END Уплотнить;
	
	PROCEDURE Демо* ( цепочка: ARRAY OF CHAR );
		VAR  a: ARRAY 200 OF CHAR;
	BEGIN
		a := цепочка$;
		StdLog.String('до сжатия:');  StdLog.Ln;
		StdLog.String(a);  StdLog.Ln;
		Уплотнить( a );
		StdLog.String('после сжатия:');  StdLog.Ln;
		StdLog.String(a);  StdLog.Ln;
	END Демо;
	
END  i21примУплотнение.

Чтобы выполнить процедуру, нужно кликнуть по коммандеру:

"i21примУплотнение.Демо('Вот пример  для    уплотнения           .')"

При этом можно произвольным образом менять уплотняемую цепочку (между одинарными кавычками) и смотреть, что получается.

Чтобы выполнить процедуру после какого-то изменения модуля, следует после компиляции нового варианта модуля кликнуть по коммандеру с одновременным нажатием на Ctrl (чтобы выгрузить из памяти старый вариант модуля).
Mod/Self.odc

MODULE Self;IMPORT L:=StdLog,I:=i21sysIn;VAR c:CHAR;BEGIN I.OpenFocus;I.Char(c);WHILE c#0DX DO L.Char(c);I.Char(c) END END Self.

Выше приведена самопечатающаяся программа.
Чтобы её выполнить, нужно нажать Ctrl+F9: текст программы скопируется в Рабочий журнал (Log).

Аналогичная программа, копирующая себя с сохранением табуляций и концов строк:

MODULE Self;
	IMPORT L:=StdLog, I:=i21sysIn;
	VAR c: CHAR;
BEGIN
	I.OpenFocus; I.Char(c);
	WHILE I.done DO
		IF c=09X THEN L.Tab
		ELSIF c = 0DX THEN L.Ln
		ELSE L.Char(c)
		END;
		I.Char(c)
	END 
END Self.

Чтобы её выполнить, нужно скопировать её в новый пустой документ (Ctrl+N) и нажать там Ctrl+F9.
Obx/Docu/Actions.odc

Overview by Example: ObxActions

This example demonstrates how background tasks can be implemented using actions. An action is an object which performs some action later when the system is idle, i.e., between user interactions. An action can be scheduled to execute as soon as possible, or after some time has passed. Upon execution, an action may re-schedule itself for a later point in time. In this way, an action can operate as a background task, getting computation time whenever the system is idle. This strategy is called cooperative multitasking. For this to work, an action must not do massive computations, because this would reduce the responsiveness of the system. Longer calculations need to be broken down into less time consuming pieces. This is demonstrated by an algorithm which calculates prime numbers up to a given maximum, as a background task. An action is used to perform the stepwise calculation. Every newly found prime number is written into a text. This text remains invisible as long as the calculation goes on. The action checks whether it has reached a maximum set by the user. If this is not yet the case, it re-schedules itself for further execution. Otherwise, it opens a window with the list of prime numbers, i.e., a text view on the created text.

 "StdCmds.OpenAuxDialog('Obx/Rsrc/Actions', 'Prime Calculation')"

ObxActionssources
Obx/Docu/Address1.odc

Overview by Example: ObxAddress1

This example combines some features of the previous examples: it takes the address record of ObxAddress1  and adds behavior to it. Such a record, whose fields are displayed by controls, is called an interactor.

The behavior for our example interactor is defined by the global OpenText procedure. It creates a new text, into which it writes all the fields of the address record. The fields are written as one line of text, separated by tabulators and terminated by a carriage return. A new text view on this text is then opened in a window.

	MODULE ObxAddress1;

	IMPORT Views, TextModels, TextMappers, TextViews;

	VAR
		adr*: RECORD
			name*:	ARRAY 64 OF CHAR;
			city*:		ARRAY 24 OF CHAR;
			country*:	ARRAY 16 OF CHAR;
			customer*:	INTEGER;
			update*:	BOOLEAN
		END;

	PROCEDURE OpenText*;
		VAR t: TextModels.Model; f: TextMappers.Formatter; v: Views.View;
	BEGIN
		t := TextModels.dir.New();
		f.ConnectTo(t);
		f.WriteString(adr.name); f.WriteTab;
		f.WriteString(adr.city); f.WriteTab;
		f.WriteString(adr.country); f.WriteTab;
		f.WriteInt(adr.customer); f.WriteTab;
		f.WriteBool(adr.update); f.WriteLn;
		v := TextViews.dir.New(t);
		Views.OpenView(v)
	END OpenText;

END ObxAddress1.

After the example has been compiled, and after a form has been created for it and turned into a dialog, you can enter something into the fields (note that customer only accepts numeric values). Then click on the OpenText button. A window will be opened with a contents similar to the following:

Oberon microsystems	Technoparkstrasse 1	Zьrich	ZH	8005	Switzerland	1	$TRUE

In this example, we have seen how behavior can be added to interactors, by assigning global procedures to their procedure-typed fields.
Obx/Docu/Address2.odc

Overview by Example: ObxAddress2

This example combines features of earlier examples: it allows to enter an address via a mask, and a push button causes the entered data to be appended to a text in a file. Afterwards, the entered data is cleared again. Controls must be notified when a program modifies an interactor. For this purpose, there is the Dialog.Update procedure which takes an interactor as parameter.

	MODULE ObxAddress2;

	IMPORT Files, Converters, Views, Dialog, TextModels, TextMappers, TextViews;

	VAR
		adr*: RECORD
			name*:	ARRAY 64 OF CHAR;
			city*:		ARRAY 24 OF CHAR;
			country*:	ARRAY 16 OF CHAR;
			customer:	INTEGER;
			update*:	BOOLEAN
		END;

	PROCEDURE OpenText*;
		VAR loc: Files.Locator; name: Files.Name; conv: Converters.Converter;
			v: Views.View; t: TextModels.Model; f: TextMappers.Formatter;
	BEGIN
		loc := NIL; name := ""; conv := NIL;
		v := Views.Old(Views.ask, loc, name, conv);
		IF (v # NIL) & (v IS TextViews.View) THEN
			t := v(TextViews.View).ThisModel();
			f.ConnectTo(t);
			f.SetPos(t.Length());
			f.WriteString(adr.name); f.WriteTab;
			f.WriteString(adr.city); f.WriteTab;
			f.WriteString(adr.country); f.WriteTab;
			f.WriteInt(adr.customer); f.WriteTab;
			f.WriteBool(adr.update); f.WriteLn;
			Views.OpenView(v);
			adr.name := ""; adr.city := ""; adr.country := ""; adr.customer := 0; adr.update := FALSE;
			Dialog.Update(adr)	(* update all controls for adr *)
		END
	END OpenText;

END ObxAddress2.
Obx/Docu/BlackBox.odc

Overview by Example: ObxBlackBox

This example implements the deductive game BlackBox, using the BlackBox Component Framework. The aim of the game is to guess the positions of atoms within an n by n grid by firing rays into a black box. The rays may be deflected or even absorbed. From the position where the ray leaves the grid one must try to deduce the position of the atoms. For more information about BlackBox and on how to play the game read the rules.

A main point of this example is to demonstrate one advantage of compound documents: The ObxBlackBox views which are implemented can directly be used in the documentation for illustration purposes. Neither additional code nor the use of a drawing program is required. Moreover, these views in the documentation are living elements and can be inspected and modified as desired.

This example also shows how a view-specific menu can be used. If a BlackBox view is the focus view, a special menu appears which offers BlackBox-specific commands that operate on the focus view. For this purpose, the following menu is installed in your Obx menu file (-> Menus):
MENU "BlackBox" ("ObxBlackBox.View")
"Show Solution"		""	"ObxBlackBox.ShowSolution"	"ObxBlackBox.ShowSolutionGuard"
	SEPARATOR
	"New Atoms"	""	"ObxBlackBox.New"	""
	"Set New Atoms"	""	"ObxBlackBox.Set"	""
	SEPARATOR
	"Rules"	""	"StdCmds.OpenBrowser('Obx/Docu/BB-Rules', 'BlackBox Rules')"	""
END
The first menu entry is enabled or disabled depending on the state of the focus view. A user-defined guard is added for this purpose. For more information about the commands themselves see the section on how to play BlackBox in the rules.

 "StdCmds.OpenAuxDialog('Obx/Rsrc/BlackBox', 'BlackBox')"

ObxBlackBoxsources
Obx/Docu/Calc.odc

Overview by Example: ObxCalc

This example implements a simple pocket calculator view for integer numbers. The calculator can be used either with the keyboard or with the mouse. It is implemented as a stack calculator. The topmost entry of the stack is displayed. With the ^ key (or ENTER key on the keyboard) this value is duplicated and pushed onto the stack. The p-key performs a pop operation, that is the topmost entry gets replaced by the second one. With the s-key the two topmost entries of the stack can be swapped. Expressions must be evaluated using the reverse polish notation. The arithmetic operations replace the two topmost entries by the result. / stands for the quotient and ч for the remainder. For example, to add 12 and 25, the keys 12^25+ must be pressed. At the beginning, the stack is filled with zeroes.

The implementation is rather simple. The ObxCalc views are views which do not contain a model. Every view keeps its own stack. When a calculator is copied, the state of the copy gets initialized.
The state of a view is not externalized. This implies that any calculator loaded from a file is always in a cleared state.

From a view-programming point of view the following type-bound procedures are of interest:

	Restore	draws the view's contents.
		HandleCtrlMsg	handles all controller messages which are sent to the view, in particular when the mouse button (Controllers.TrackMsg) or when a key (Controllers.EditMsg) is pressed within the view.
		HandlePropMsg	handles the property messages which are sent to the view by its container. The container asks the view about its (preferred) size (Properties.SizePref), whether it is resizable (Properties.ResizePref) and whether it wants to become focus or not (Properties.FocusPref).
		Externalize	externalizes a version byte
		Internalize	reads the version byte and initializes a new view

With only these five procedures we get a fully working interactive view. The view can be saved to a file (without its internal state) and copied using Drag & Drop or Copy & Paste, it can be printed, and under Windows, it can be exported as ActiveX object into any ActiveX container.

 "ObxCalc.Deposit; StdCmds.Open"

ObxCalcsources
Obx/Docu/Caps.odc

Overview by Example: ObxCaps

This example shows how the built-in text subsystem of the BlackBox Component Builder can be extended by new commands. To demonstrate this possibility, a command is shown which fetches the selection in the focus view (assuming the focus view is a text view), creates a new empty text, copies the selection into this new text (but with all small letters turned into capital letters), and then replaces the selection by the newly created text. In short, this command turns the selected text stretch into all capital letters.

	MODULE ObxCaps;

	IMPORT Stores, Models, TextModels, TextControllers;

	PROCEDURE Do*;
		VAR c: TextControllers.Controller; beg, end: INTEGER;
			r: TextModels.Reader; ch: CHAR;
			buf: TextModels.Model; w: TextModels.Writer; script: Stores.Operation;
	BEGIN
		c := TextControllers.Focus();
		IF (c # NIL) & c.HasSelection() THEN
			c.GetSelection(beg, end);
			(* upper case text will be copied into this buffer *)
			buf := TextModels.CloneOf(c.text); w := buf.NewWriter(NIL);
			r := c.text.NewReader(NIL); r.SetPos(beg);
			r.ReadChar(ch);
			WHILE (r.Pos() <= end) & ~r.eot DO
				IF (ch >= "a") & (ch <= "z") THEN ch := CAP(ch) END;
				w.WriteChar(ch);
				r.ReadChar(ch)
			END;
			Models.BeginScript(c.text, "Caps", script);
			c.text.Delete(beg, end); c.text.Insert(beg, buf, 0, end - beg);
			Models.EndScript(c.text, script)
		END
	END Do;

END ObxCaps.


As an example, select the test string several lines below, and then click on the following commander:

 ObxCaps.Do

teSTstring834 .-st

You'll note that the selection has turned into all caps.

But now comes the surprise: execute UndoCaps in the Edit menu. As a result, the effect of the uppercase operation is undone! In the BlackBox Component Builder, most operations are undoable; this also holds for the Delete and Insert text procedures in the above example. Thus, you need to do nothing special in order to render such a command undoable!

However, you may have noticed that there is something special in the sample program: there is a BeginScript / EndScript pair of procedure calls before resp. after the calls to Delete / Insert. They bundle the sequence of a Delete followed by a Insert into one single compoundcommand, meaning that the user need not undo both of these operations individually, but rather in one single step.

In this example we have seen how an existing displayed text and its selection are accessed, how a buffer text is created, and how the selected text stretch is replaced by the buffer's contents.
Obx/Docu/ContIter.odc

Overview by Example: ObxContIter

This example shows how to iterate over the views embedded in a container, whether it be a text container, a form container, etc. The command searches for the first embedded view whose label is "magic name". At first, the command gets the focus container on which to operate:

	c := Containers.Focus();

This statement obtains the innermost general container's controller in the focus path, even if the container is in mask or browser mode and some control in the container is currently the innermost (non-container) view.
Every general container defines some order for the embedded views. For texts, this is the order of the views in the text, for forms it is the z-ordering, etc. The controller methods GetFirstView and GetNextView allow to iterate over the embedded views in the defined order:

	c.GetFirstView(Containers.any, v);
	c.GetNextView(Containers.any, v);

The first parameters denote whether all embedded views should be traversed (Containers.any) or only the selected views (Containers.selection).
The loop that searches for the specific control has the typical form of a search loop:

	get first element;
	WHILE (element # NIL) & ~(element is the right one) DO
		get next element
	END;

In our example, the condition in the WHILE loop is the following:

	(v # NIL) & ~((v IS Controls.Control) & (v(Controls.Control).label = "magic name"))

The right-side term contains an expression that denotes "element is the right one", in this case:

	(v IS Controls.Control) & (v(Controls.Control).label = "magic name")

This means that the element is a control, and its label is "magic name". The not-operator "~" inverts this condition, so that the loop continues as long as the right element has not yet been found.

Note that you shouldn't modify the selection during iteration over the selection. Also, you shouldn't insert into or delete from the container model during iteration.

ObxContItersources
Obx/Docu/Conv.odc

Overview by Example: ObxConv

While most data files are BlackBox document files, it is sometimes necessary to deal with other file types as well: ASCII files, picture files, or files created by  legacy applications. Sometimes it is sufficient to import such data once and then keep it in BlackBox documents, sometimes it is necessary to export data into some foreign file format, and it may even be desirable to import data from such a file format when opening a file, and to export data back into the same file format upon saving the file. Of course, the latter only works in a satisfying way if the conversion is truly invertible, i.e., both import and export are loss-free.
	The example ObxConv shows a simple ASCII converter, which converts to and from standard BlackBox text views. The module consists of two commands, one is an importer and the other an exporter. Both commands have the same structure: in a loop over all characters of a text, each character is read (from a file or text) and then written (into a text or file).
	Converters are often platform-dependent. In our example this can be seen in the assertion which checks the correct file type. Under Windows, it should read

	ASSERT(f.type = "TXT", 22)	while under Mac OS it should read
	ASSERT(f.type = "TEXT", 22)

Furthermore, the characters would have to be converted from the host platform's native character set to (or from) the portable character set used by the BlackBox Component Builder. This is not done here since it would not contribute to demonstrating the converter mechanism per se.
	Each BlackBox Component Builder implementation provides its own set of standard converters which are registered and thus made available to the user when the system is started up. A programmer may install additional converters in procedure Config.Setup, by calling the Converters.Register procedure:

Windows:
Converters.Register("ObxConv.ImportText", "ObxConv.ExportText", "TextViews.View", "TXT", {})

Mac OS:
Converters.Register("ObxConv.ImportText", "ObxConv.ExportText", "TextViews.View", "TEXT", {})

Config.Setup is called at the end of the BlackBox Component Builder's bootstrap process, i.e., when the core has been loaded successfully.

For each registered converter, there optionally may be a corresponding string mapping; to make the display of a list of importers/exporters more user-friendly. For example, the importer "ObxConv.ImportText" could be mapped to the more telling name "Obx Text" (in the standard file open dialog). The mapping is done in the Strings file in the Rsrc directory of the importer's subsystem, e.g. there is the following line in the Obx/Rsrc/Strings text:

	ObxConv.ImportText	Obx Text File

It is conceivable to implement compound converters: an HTML (Hypertext Markup Language) converter for example could use the standard ASCII converter of the BlackBox Component Builder (i.e., module HostTextConv) to perform a conversion from the platform's ASCII format to an BlackBox text. The created text could then be parsed and converted into an equivalent text which included some kind of hypertext link view instead of the textually specified hyperlinks.

ObxConvsources
Obx/Docu/Cubes.odc

Overview by Example: ObxCubes

This example implements a simple rotating cube view. The cube rotates around two axes. It performs 10 state transformations per second and after 25.6 seconds it is back in its starting position. The example below shows a large cube rotating in front of a smaller one. Both cubes are embedded in a form view, which is embedded in the text view that you are currently reading:
			
What this example shows is the use of actions. Services.Actions  are objects whose Do  procedures are executed in a delayed fashion, when the system is idle. An action which re-installs itself whenever it is invoked as in this example operates as a non-preemptive background task.

This example also demonstrates a simple property editor through which the colors of the sides of a cube can be changed. To open the property editor click into the cube while holding down the modifier key (or execute the command below to open the dialog). The property editor always shows the colors of the selected cube. The synchronization between the color fields in the dialog and the selected cube is also performed through the installed action. The colors of the sides are actually changed by a notifier which is attached to each color control in the property dialog. The color white is interpreted as invisible.


 "ObxCubes.Deposit; StdCmds.Open"
 "StdCmds.OpenToolDialog('Obx/Rsrc/Cubes', 'Cube Colors')"

ObxCubessources
Obx/Docu/Db.odc

Overview by Example: ObxDb

This example provides two commands to the user. The first, EnterData, takes a text selection as input, and reads it line by line. Each line should consist of an integer number, followed by a string, trailed by a real number. Each such tuple is entered into a globally anchored linear list, sorted by the integer value. The second command, ListData, generates a text which displays the data currently in the list.

ObxDbsources


 ObxDb.EnterData		 ObxDb.ListData		 ObxDb.Reset

To try out the example, select the following lines, and then click the left commander above:

1	Cray	14.8
3	NEC	16.6
2	IBM	8.3

Now click the middle commander, as a result a window opens with the sorted input. If you repeat both steps, you'll note that the input has been added to the list a second time, and that consequently every item appears twice in the output.

This example has shown how a text can be scanned symbol by symbol, instead of character by character.