text:
Transportation Deployment Casebook/2021/Alabama

Introduction
The railroad is a mode of transportation on land that vehicles with flange-wheel will move over two parallel steel rails or tracks, it will be self-powered or using a locomotive to make the propulsion.

The advantage of railroad compared with other transport modes is the efficiency of cost. The transportation of shipping contains many separate parts, transferring goods from different places to the harbor, and loading them from land to ship, after shipping, goods also need to be unloaded from ship to the land. If the procedure of shipping has a high volume of freight, it would cost much more money than the railroad. Time of transit also can be promised since railroads use the tracks and they do not need to share the tracks with other modes.

Compared with trucks, railroads can carry a high volume of freight. It shows that the freight handled by one double-stacked is the same as 280 trucks which is much better for large load moving. Meanwhile, using railroad is environmental-friendly compared with the transport of road which the data showed the greenhouse gas emissions can be saved 70%.

The development of the railroad never stops due to the expanding demand for delivering commodities. The industry over the world has the urgent of transport, such as coal, bulk commodities, automobiles, and other heavy commodities. The great growth of transportation and logistics also push the railroad to develop.

Previous Modes of Transport & Limitation
Before the development of the railroad, using boats or animals such as horses to transfer goods was the common method. Transportation inland mainly relied on horses, as most of the roads were poorly maintained dirt roads, it was not easy for both people and horses to move.

With the bad quality of the road, horsing transport usually caused uncomfortable experiences for people, the results might be increased of heart rate, sweat, dizzy and sick feeling, and vomit. Many disorders could happen to people if they take horses to transfer goods. As the horsing transport needs the horses to pull the cart with goods forward, the weight of cart also has the limitation, thus it is not possible to carry too many goods at one time. Meanwhile, the transfer process will be interrupted because horses need to drink, eat and take the rest, and if they get injured during the time of transport, it would take longer to complete the journey.

There is no guarantee in time as well as the quality of goods since the occurrence of bad weather may damage the goods to a certain extent.

Another mode of transport for moving goods by water is shipping. It is much better since ships can handle large volume goods at the same time and the containers in shipping can be directly used inland. The disadvantage always comes with benefits. Since shipping highly depends on sea and weather, the time and route of the journey are both changeable. . The limitation also includes the risk for people during the trip because they have no way to contact the people inland, and they have to handle all matters if any emergency happens.

People want to move goods faster and safer based on the disadvantage of horsing transport and boat transport, the determination of development made the history changed. Once the railroad been invented, it opened a completely new world for people. The transfer time is much shorter and goods can be transferred in a safe way with a fixed schedule, and people find their country, even the world seemed smaller than before.

Technological Characteristics
Firstly the rail was made of wood which was fragile, and with the development of the technology of iron production, the metal had been used on rails which are the most important addition to it in the 1760s.

In addition, the most vital and dramatic evolvement of the railroad was the application of steam. Before James Watt, the engineer, it has only been used for the water pumps and no one found other usages of it, and James changed the whole situation by using the pistons with high-pressure, and then Richard Trevithick invented the first steam locomotive in 1802.

In 1804 and 1808, the different versions of the locomotive were invented, and this technology had been used on railroad afterward which made a huge improvement. In 1812-1813, the very first commercial railroad with steam-operated was opened.

From the invention and development of the locomotive to the use of locomotive on the railroad, and continuously modify the invention to find the best solution, the whole process credited to chemists and engineers. Using the basic principle with many attempts to develop the technology and finally get the high-quality outcome is the only way to invent.

The process from using horses to draw carts along the tracks to the railroad with the operation of steam, the driving force was the desire of setting people free from controlling the cart and let the transport more efficient. The invention of the railroad not only carry passengers and goods, but it also can carry mails from place to place which is also a good chance for post office to improve.

After that, the revolution of transport and the great development of the railroad soon take around the world. And in 1879, the first electric railroad was invented by Werner von Siemens, a German engineer. At that time, the electric railroad could carry passengers for a short trip.

Early Market Development
The year of history of the railroad in the United States is almost the same as the nation, it must be admitted that the railroad is one of the most important reasons for the prosperity of the nation.

Dated back to 1815, the first charter to build the New Jersey Railroad Company in North America was gained by Colonel John Stevens, and the construction was completed in 1832. The steam locomotive also been tested on the railroad in the nation.

From the beginning, the early railroad was only used for transferring goods. An example could be the first railroad in America, the Granite Railway of Massachusetts. The function of this 3 miles railroad was to transport granite slabs for the monument project.

As people found the advantage of the railroad of cost and time saving, as well as convenient for transferring goods at one time, more railroad projects had begun to start. The technology of tracks develop to carry more cargo, meanwhile, some railroads also could become a role for passengers to travel across the states. The Mohawk & Hudson Railroad built the connection of Hudson River at Albany with the Mohawk River at Schenectady to share the market of transfer people and goods with Erie Canal.

The improvements of the function of railroads such as improving the quality of tracks and upgrading the containers with the enhancement of discovering new function, such as expanding the service groups from transferring goods for merchants to passengers of traveling all can attract more people engage in this industry and also make it have better and faster development.

Policy in the “Birth Phase”
While the railroad develops in the early stage, it didn’t replace shipping in the field of transfer, but with the results of reliable high-speed operation, it was proved that the railroad would have a promising future in the industry. One significant point for the railroad was the charter of Pennsylvania Railroads formed by the state legislature in 1846. Using the legislation to settle the function of the city, and also combined the city with railroads to make the railroads have a long-term development plan.

Government must have a clear view of the railroad development, with the general plan of railroads, it can be seen the railroad would experience a birth phase with success.

Public and Private Sector in “Growth Phase”
It has shown that the number of railroads in 1860 was more than tripled compared with the early stage. As the technology experienced rapid development, railroads, as the witness of the growth of the society, also had a great increment. Due to the need for iron, the government decided to start the plan of completing the railroad across the continent of Golden State. The public sector, in this case, played the vital and irreplaceable role of the leader to control the direction of development. During the evolution period, it was essential to making the right decision on time.

As for the private sector, with the official plan set by the federal government, investors would have the ambition and confidence to invest more money in the industry which makes the system keep circulating. Only in 1850, there are $372 million had been spent on railroads from investors.

On the other hand, the people in opposition may disagree with the development of the railroad which may have some bad impact on the railroad. Due to the market conflict of the railroad and other transport modes, the government must balance these industries as well as consider the whole strategic plan of the railroad to let it develops on the right track, and with the changes of time, the correct direction would be proved.

Opportunity to “Re-invent” the mode
During the mature period, it seems the railroad reaches its limitation, some changes need to be made to best fit the market. The railroad is not capable of transporting commodities between two continents. Meanwhile, it is not cost-effective to use railroad transporting some customer goods which makes some companies less participate in the railroad transportation. The industry should find a way to corporate with those customer goods companies to figure out the method of collaboration, such as combing goods from several companies in the same containers to cost less money to attract the clients.

Some technologies have also been applied on the railroad. The enhancement of safety and efficiency on railroads such as smart sensors, advanced fuel management systems, positive train control, and automated inspection equipment all contribute to better railroad service and experience. To meet the need of the market, the railroad must combine much more technology with them to attract more business to make the expansion.

The Life-Cycle Model
As the graph of life-cycle shown, it illustrates the changing trending of miles of track over the time of 27 years in the state of Alabama, the United States of America. It contains the birth phase, growing phase, and mature phase. With every phase, the external market environment, policies from the public sector, as well as the technology used on the railroad vary with time.

The raw data of miles of track from 1894 to 1920. To identify the phases of the railroad along the selected period of time, S-curve will be used to predict the life-cycle of the miles of track of the railroad in Alabama by mathematical method. The details will be explained by the following equations.

$$ S(t) = \frac{K}{1+e^{-b(t-t_0)}} $$ Where, S(t) is the technology size (miles of track),

K is the saturation status level,

t is the time (in year),

b is the coefficient,

t0 is a inflection time (the point of downturns)

Thus, using K and b, any given year (t) can be put into the S-Curve equation to find the miles of track. As the graph shows, it can be seen the actual miles in Alabama experienced a period of fluctuation which may because of the loss of data collected. The total trend of actual and predicted miles of the track both increased. In 1914, the miles of track reached the peak point, and then it declined and gradually became flat.


text:
User:Rose sprowls/sandbox

hi

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

title: User:Rose sprowls/sandbox


text:
Oberon/ETH Oberon/2.3.7/HTMLDocs.Mod

(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich. Refer to the license.txt file provided with this distribution. *) MODULE HTMLDocs; (** portable *) (* ejz, Greek & Math support by afi *) IMPORT Objects, Input, Strings, Display, Display3, Fonts, HyperDocs, Texts, Gadgets, Documents, HTTPDocs0, TextDocs, Oberon, TextGadgets, Lists, Attributes, Desktops, Links, Streams, TextStreams; CONST (* class *) WhiteSpace* = 0; OpenTag* = 1; OpenEndTag* = 2; CloseTag* = 3; CharRef* = 4; Character* = 5; Value* = 6; Undef* = 7; (* state *) TextPlain* = 1; TextHtml* = 2; InTag* = 3; End* = 4; (* list types *) DefList = 0; DescList = 1; OrderedList = 2; Menu = "Desktops.Copy[Copy] HyperDocs.Back[Back] HyperDocs.Reload[Reload] TextDocs.Search[Search] Desktops.StoreDoc[Store]"; GreekCap = "0013143516173415192134222324252728202931323337372636180000000000"; GreekMin = "004546674849664751536654555657596052616364656969586850"; ASCIIBullets = TRUE; TYPE DocURL* = POINTER TO DocURLDesc; DocURLDesc* = RECORD (HyperDocs.DefURLDesc) dockey*: LONGINT END; TextAttrs = POINTER TO TextAttrsDesc; TextAttrsDesc = RECORD lib: Objects.Library; style: TextGadgets.Style; col, voff: SHORTINT; next: TextAttrs END; Page* = POINTER TO PageDesc; Scanner* = RECORD page*: Page; S*: Streams.Stream; class*, state*: INTEGER; value*: ARRAY 1024 OF CHAR; pre*, end*: BOOLEAN; ch*, next*, char*: CHAR; avail: LONGINT END; List = POINTER TO ListDesc; ListDesc = RECORD style: TextGadgets.Style; kind, nesting, itemNr: INTEGER; dtok: BOOLEAN; next: List END; Form* = POINTER TO FormDesc; FormDesc* = RECORD (TextGadgets.ControlDesc) elems*: HTTPDocs0.ObjList END; PageDesc* = RECORD (Gadgets.ObjDesc) W*, Ws*: Texts.Writer; textAttrs: TextAttrs; T*, source*: Texts.Text; D*: Documents.Document; alink*, clink: Objects.Object; style: TextGadgets.Style; base*: DocURL; orgLabel: ARRAY 64 OF CHAR; lists: List; orgPos, linkkey*, headerLen, docKey*: LONGINT; next*: Page; task: Oberon.Task; textC*, linkC*, oldLinkC*, textbackC*, lines*: INTEGER; left*, blank*, head, cacheSource*: BOOLEAN END; Item* = POINTER TO ItemDesc; ItemDesc* = RECORD (Lists.ItemDesc) value*: ARRAY 64 OF CHAR; oldSel*, hasVal*: BOOLEAN END; TagHandler* = PROCEDURE (VAR S: Scanner; on: BOOLEAN); ExtTag* = POINTER TO ExtTagDesc; ExtTagDesc* = RECORD tag: ARRAY 32 OF CHAR; handle*: TagHandler; start*, stop*: PROCEDURE (P: Page); next: ExtTag END; TagAttr* = POINTER TO TagAttrDesc; TagAttrDesc* = RECORD name: ARRAY 64 OF CHAR; value*: ARRAY 512 OF CHAR; next: TagAttr END; Task = POINTER TO TaskDesc; TaskDesc = RECORD (Oberon.TaskDesc) S: Scanner; P: Page END; VAR bullets: ARRAY 2 OF RECORD f: Fonts.Font; c: CHAR END; Wr*, Wq: Texts.Writer; imgs*: BOOLEAN; extTags, newTag*: ExtTag; entities*: ARRAY 69, 7 OF CHAR; entityEncoding*: ARRAY 69 OF CHAR; pages*: Page; searchAttr: ARRAY 32 OF CHAR; mono: Fonts.Font; found: BOOLEAN; dispW: INTEGER; GreekTab: ARRAY 128 OF CHAR; PROCEDURE WriteLn*(P: Page); BEGIN INC(P.lines); IF P.lines < 3 THEN Texts.WriteLn(P.W); P.blank := FALSE END END WriteLn; PROCEDURE WriteSpace*(P: Page); BEGIN IF P.blank THEN Texts.Write(P.W, " "); P.blank := FALSE END END WriteSpace; PROCEDURE WriteObj*(P: Page; obj: Objects.Object); BEGIN Texts.WriteObj(P.W, obj); IF (obj IS Display.Frame) & (obj(Display.Frame).W >= (HyperDocs.docW-16)) THEN INC(P.lines); P.blank := FALSE ELSIF obj IS TextGadgets.Style THEN P.blank := FALSE ELSIF ~(obj IS TextGadgets.Control) THEN P.lines := 0; P.blank := TRUE END END WriteObj; PROCEDURE InitTabs(style: TextGadgets.Style); VAR i: LONGINT; BEGIN style.W := ((dispW DIV 8) * 5)-24; style.width := style.W; 		style.noTabs := 32; FOR i := 0 TO 31 DO 			style.tab[i] := SHORT(32+i*32) END END InitTabs; PROCEDURE NewStyle: TextGadgets.Style; VAR style: TextGadgets.Style; BEGIN style := TextGadgets.newStyle; InitTabs(style); Attributes.SetBool(style, "FrameW", TRUE); RETURN style END NewStyle; PROCEDURE Syntax(size: INTEGER; attr: CHAR): Fonts.Font; VAR name: ARRAY 32 OF CHAR; sizeS: ARRAY 4 OF CHAR; BEGIN name := "Default"; IF dispW < 800 THEN DEC(size, 2) END; IF size <= 8 THEN size := 8 ELSIF size <= 10 THEN size := 10 ELSIF size <= 12 THEN size := 12 ELSIF size <= 14 THEN size := 14 ELSIF size <= 16 THEN size := 16 ELSIF size <= 20 THEN size := 20 ELSE size := 24 END; Strings.IntToStr(size, sizeS); IF attr = 0X THEN (* skip *) ELSIF attr = "i" THEN (* skip *) ELSIF attr = "m" THEN attr := "b" ELSIF attr = "b" THEN (* skip *) ELSE attr := 0X END; Strings.Append(name, sizeS); Strings.AppendCh(name, attr); Strings.Append(name, ".Scn.Fnt"); RETURN Fonts.This(name) END Syntax; PROCEDURE PushTextAttrs*(P: Page); VAR attr: TextAttrs; BEGIN NEW(attr); attr.lib := P.W.lib; attr.col := P.W.col; attr.voff := P.W.voff; attr.style := P.style; attr.next := P.textAttrs; P.textAttrs := attr END PushTextAttrs; PROCEDURE PopTextAttrs*(P: Page); VAR style: TextGadgets.Style; M: Objects.CopyMsg; BEGIN IF P.textAttrs # NIL THEN Texts.SetFont(P.W, P.textAttrs.lib); Texts.SetColor(P.W, P.textAttrs.col); Texts.SetOffset(P.W, P.textAttrs.voff); style := P.textAttrs.style; IF (P.style.mode # style.mode) OR (P.style.leftM # style.leftM) OR (P.style.width # style.width) THEN M.id := Objects.shallow; Objects.Stamp(M); M.obj := NIL; M.dlink := NIL; style.handle(style, M); style := M.obj(TextGadgets.Style); P.style := style; WriteObj(P, style) END; P.textAttrs := P.textAttrs.next ELSE Texts.SetFont(P.W, Syntax(12, 0X)); Texts.SetColor(P.W, SHORT(P.textC)); Texts.SetOffset(P.W, 0); style := NewStyle; IF (P.style.mode # style.mode) OR (P.style.leftM # style.leftM) OR (P.style.width # style.width) THEN P.style := style; WriteObj(P, style) END END END PopTextAttrs; PROCEDURE SplitFontName(f: Fonts.Font; VAR family: ARRAY OF CHAR; VAR size: INTEGER; VAR attr: CHAR); VAR val: LONGINT; i: INTEGER; BEGIN i := 0; WHILE (f.name[i] # 0X) & ~Strings.IsDigit(f.name[i]) DO 			INC(i) END; COPY(f.name, family); family[i] := 0X; Strings.StrToIntPos(f.name, val, i); size := SHORT(val); IF Strings.IsAlpha(f.name[i]) THEN attr := f.name[i] ELSE attr := 0X END END SplitFontName; PROCEDURE FontSize(f: Fonts.Font; VAR size: INTEGER); VAR family: ARRAY 64 OF CHAR; attr: CHAR; BEGIN SplitFontName(f, family, size, attr) END FontSize; PROCEDURE GetFontSize*(P: Page): INTEGER; VAR size: INTEGER; BEGIN FontSize(P.W.lib(Fonts.Font), size); IF dispW < 800 THEN INC(size, 2) END; IF size <= 8 THEN size := 1 ELSIF size <= 10 THEN size := 2 ELSIF size <= 12 THEN size := 3 ELSIF size <= 14 THEN size := 4 ELSIF size <= 16 THEN size := 5 ELSIF size <= 20 THEN size := 6 ELSE size := 7 END; RETURN size END GetFontSize; PROCEDURE ChangeFontAttr(f: Fonts.Font; attr: CHAR): Fonts.Font; VAR family: ARRAY 64 OF CHAR; str: ARRAY 4 OF CHAR; size: INTEGER; oldattr: CHAR; BEGIN IF attr = "m" THEN attr := "b" END; SplitFontName(f, family, size, oldattr); IF oldattr # attr THEN Strings.IntToStr(size, str); Strings.Append(family, str); IF attr # 0X THEN Strings.AppendCh(family, attr) END; Strings.Append(family, ".Scn.Fnt"); RETURN Fonts.This(family) ELSE RETURN f 		END END ChangeFontAttr; PROCEDURE ChangeFontSize(f: Fonts.Font; size: INTEGER): Fonts.Font; VAR family: ARRAY 64 OF CHAR; str: ARRAY 4 OF CHAR; oldsize: INTEGER; attr: CHAR; BEGIN IF dispW < 800 THEN DEC(size, 2) END; SplitFontName(f, family, oldsize, attr); IF oldsize # size THEN Strings.IntToStr(size, str); Strings.Append(family, str); IF attr # 0X THEN Strings.AppendCh(family, attr) END; Strings.Append(family, ".Scn.Fnt"); RETURN Fonts.This(family) ELSE RETURN f 		END END ChangeFontSize; PROCEDURE SetFontSize*(P: Page; size: INTEGER); VAR fnt: Fonts.Font; BEGIN fnt := P.W.lib(Fonts.Font); IF size < 1 THEN size := 1 ELSIF size > 9 THEN size := 9 END; PushTextAttrs(P); CASE size OF 			1: Texts.SetFont(P.W, ChangeFontSize(fnt, 8)) |2: Texts.SetFont(P.W, ChangeFontSize(fnt, 10)) |3: Texts.SetFont(P.W, ChangeFontSize(fnt, 12)) |4: Texts.SetFont(P.W, ChangeFontSize(fnt, 14)) |5: Texts.SetFont(P.W, ChangeFontSize(fnt, 16)) |6: Texts.SetFont(P.W, ChangeFontSize(fnt, 20)) |7: Texts.SetFont(P.W, ChangeFontSize(fnt, 24)) |8: fnt := ChangeFontSize(fnt, 24); Texts.SetFont(P.W, ChangeFontAttr(fnt, "m")) |9: fnt := ChangeFontSize(fnt, 24); Texts.SetFont(P.W, ChangeFontAttr(fnt, "b")) END END SetFontSize; PROCEDURE HorzRule*(P: Page; w, h: INTEGER); VAR obj: Objects.Object; BEGIN IF P.lines <= 0 THEN WriteLn(P) END; h := 2*h; IF h < 4 THEN h := 4 END; obj := Gadgets.CreateObject("BasicFigures.NewRect3D"); Attributes.SetBool(obj, "Filled", TRUE); Attributes.SetInt(obj, "Color", P.textbackC); Gadgets.ModifySize(obj(Display.Frame), w, h); WriteObj(P, obj); P.lines := 1; WriteLn(P) END HorzRule; PROCEDURE TextAlign*(VAR align: ARRAY OF CHAR): TextGadgets.Style; VAR style: TextGadgets.Style; BEGIN style := NewStyle; EXCL(style.mode, TextGadgets.left); CASE CAP(align[0]) OF 			|"L": INCL(style.mode, TextGadgets.left) |"R": INCL(style.mode, TextGadgets.right) |"C", "J": INCL(style.mode, TextGadgets.middle) ELSE (* BLEED... *) CASE CAP(align[5]) OF 				"L": INCL(style.mode, TextGadgets.left) |"R": INCL(style.mode, TextGadgets.right) |"C", "J": INCL(style.mode, TextGadgets.middle) ELSE RETURN NIL END END; RETURN style END TextAlign; PROCEDURE CloseA*(P: Page); BEGIN IF P.alink # NIL THEN WriteObj(P, P.alink); P.alink := NIL; WHILE (P.W.col = SHORT(P.linkC)) OR (P.W.col = SHORT(P.oldLinkC)) DO 				PopTextAttrs(P); IF P.textAttrs = NIL THEN RETURN END END END END CloseA; PROCEDURE OpenList(P: Page; kind: INTEGER); VAR list: List; BEGIN PushTextAttrs(P); NEW(list); list.itemNr := 0; list.style := NewStyle; IF P.lists = NIL THEN list.nesting := 0; WriteLn(P); WriteLn(P) ELSE list.nesting := P.lists.nesting+1 END; P.style := list.style; WriteObj(P, list.style); list.dtok := FALSE; list.kind := kind; list.next := P.lists; P.lists := list END OpenList; PROCEDURE CloseList(P: Page); BEGIN IF P.lists # NIL THEN IF P.lists.itemNr = 0 THEN P.lists.style.leftM := 32 END; P.lists := P.lists.next END; PopTextAttrs(P); IF P.lists = NIL THEN WriteLn(P); WriteLn(P) END END CloseList; PROCEDURE FindFormObj*(form: Form; name: ARRAY OF CHAR): Objects.Object; VAR ol: HTTPDocs0.ObjList; oname: ARRAY 64 OF CHAR; obj: Objects.Object; BEGIN obj := NIL; ol := form.elems; WHILE ol # NIL DO 			Attributes.GetString(ol.obj, "Name", oname); IF oname = name THEN obj := ol.obj END; ol := ol.next END; RETURN obj END FindFormObj; PROCEDURE RememberValue*(obj: Objects.Object); VAR A: Objects.AttrMsg; BEGIN A.id := Objects.get; A.name := "Value"; A.class := Objects.Inval; obj.handle(obj, A); A.id := Objects.set; A.name := "IniValue"; obj.handle(obj, A) 	END RememberValue; PROCEDURE AddFormObj*(P: Page; form: Form; obj: Objects.Object; name: ARRAY OF CHAR; storeVal, write: BOOLEAN); VAR ol, op: HTTPDocs0.ObjList; BEGIN NEW(ol); ol.obj := obj; ol.next := NIL; op := form.elems; WHILE (op # NIL) & (op.next # NIL) DO 			op := op.next END; IF op # NIL THEN op.next := ol 		ELSE form.elems := ol 		END; IF storeVal THEN RememberValue(obj) END; IF name # "" THEN Gadgets.NameObj(obj, name) END; IF write THEN WriteObj(P, obj) END END AddFormObj; PROCEDURE *FindA(name: ARRAY OF CHAR); BEGIN IF name = searchAttr THEN found := TRUE END END FindA; PROCEDURE HasA(obj: Objects.Object; name : ARRAY OF CHAR): BOOLEAN; VAR A: Objects.AttrMsg; BEGIN found := FALSE; COPY(name, searchAttr); A.id := Objects.enum; COPY(name, A.name); A.res := -1; A.Enum := FindA; obj.handle(obj, A); RETURN found END HasA; PROCEDURE ResetValues(form: Form); VAR A: Objects.AttrMsg; ol: HTTPDocs0.ObjList; item: Item; BEGIN ol := form.elems; WHILE ol # NIL DO 			IF HasA(ol.obj, "IniValue") THEN A.id := Objects.get; A.name := "IniValue"; A.class := Objects.Inval; ol.obj.handle(ol.obj, A); A.id := Objects.set; A.name := "Value"; ol.obj.handle(ol.obj, A); Gadgets.Update(ol.obj) ELSIF ol.obj IS Lists.List THEN item := ol.obj(Lists.List).items(Item); WHILE item # NIL DO 					item.sel := item.oldSel; IF item.next # NIL THEN item := item.next(Item) ELSE item := NIL END END; Gadgets.Update(ol.obj) END; ol := ol.next END END ResetValues; PROCEDURE GetText*(view: Objects.Object): Texts.Text; VAR model: Objects.Object; BEGIN IF view # NIL THEN Links.GetLink(view, "Model", model); IF (model # NIL) & (model IS Texts.Text) THEN RETURN model(Texts.Text) ELSE RETURN NIL END ELSE RETURN NIL END END GetText; (** HTMLDocs.Locate label 		Used for hyperlinks within the same page. *) PROCEDURE Locate*; VAR S: Attributes.Scanner; F: Texts.Finder; pos: LONGINT; obj: Objects.Object; name: ARRAY 32 OF CHAR; curDoc: Documents.Document; node: HyperDocs.Node; text: Texts.Text; BEGIN curDoc := Desktops.CurDoc(Gadgets.context); node := HyperDocs.NodeByDoc(curDoc); text := GetText(Gadgets.context); IF (curDoc # NIL) & (text # NIL) THEN Attributes.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Attributes.Scan(S); IF (S.class = Attributes.String) OR (S.class = Attributes.Name) THEN Texts.OpenFinder(F, text, 0); pos := F.pos; Texts.FindObj(F, obj); WHILE ~F.eot DO 					IF obj IS Gadgets.Frame THEN Attributes.GetString(obj, "Name", name); IF S.s = name THEN IF node # NIL THEN HyperDocs.RememberOrg(curDoc.dsc(TextGadgets.Frame).org, node, node); HyperDocs.LinkNodeToDoc(curDoc, node) END; HyperDocs.ScrollTo(curDoc.dsc(TextGadgets.Frame), pos); RETURN END END; pos := F.pos; Texts.FindObj(F, obj) END END END END Locate; (** HTMLDocs.ExecNext 		Used by clickable images to activate the surrounding hyperlink. *) PROCEDURE ExecNext*; VAR F: Texts.Finder; exec, obj: Objects.Object; text: Texts.Text; BEGIN exec := Gadgets.executorObj; text := GetText(Gadgets.context); IF (text # NIL) & (exec # NIL) THEN Texts.OpenFinder(F, text, 0); Texts.FindObj(F, obj); WHILE ~F.eot DO 				IF obj = exec THEN exec := NIL ELSIF (exec = NIL) & (obj IS TextGadgets.Control) THEN Gadgets.ExecuteAttr(obj(TextGadgets.Control), "Cmd", Gadgets.context, NIL, NIL); RETURN END; Texts.FindObj(F, obj) END END END ExecNext; PROCEDURE CurForm(context: Objects.Object): Form; VAR F: Texts.Finder; exec, obj: Objects.Object; ol: HTTPDocs0.ObjList; text: Texts.Text; BEGIN IF context # NIL THEN exec := Gadgets.executorObj; text := GetText(context); IF text # NIL THEN Texts.OpenFinder(F, text, 0); Texts.FindObj(F, obj); WHILE ~F.eot DO 					IF obj IS Form THEN ol := obj(Form).elems; WHILE (ol # NIL) & (ol.obj # exec) DO 							ol := ol.next END; IF ol # NIL THEN RETURN obj(Form) END END; Texts.FindObj(F, obj) END END; RETURN CurForm(context.dlink) END; RETURN NIL END CurForm; (** HTMLDocs.Reset 		Used by the "Reset" button in forms. *) PROCEDURE Reset*; BEGIN ResetValues(CurForm(Gadgets.context)) END Reset; PROCEDURE CopyForm(VAR M: Objects.CopyMsg; from, to: Form); BEGIN TextGadgets.CopyControl(M, from, to); to.elems := from.elems END CopyForm; PROCEDURE *FormHandler(F: Objects.Object; VAR M: Objects.ObjMsg); VAR ol: HTTPDocs0.ObjList; obj, action: Objects.Object; key: LONGINT; F1: Form; BEGIN WITH F: Form DO 			IF M IS Objects.AttrMsg THEN WITH M: Objects.AttrMsg DO 					IF (M.id = Objects.get) & (M.name = "Gen") THEN M.class := Objects.String; M.s := "HTMLDocs.NewForm"; M.res := 0 ELSE TextGadgets.ControlHandler(F, M) 					END END ELSIF M IS Objects.FileMsg THEN WITH M: Objects.FileMsg DO 					TextGadgets.ControlHandler(F, M); IF M.id = Objects.load THEN HyperDocs.LoadLink(M.R, key); action := Gadgets.CreateObject("BasicGadgets.NewInteger"); Attributes.SetInt(action, "Value", key); Gadgets.NameObj(action, "@ACTION"); NEW(F.elems); F.elems.obj := action; F.elems.next := NIL; Gadgets.ReadRef(M.R, F.lib, obj); WHILE obj # NIL DO 							NEW(ol); ol.next := F.elems; F.elems := ol; ol.obj := obj; Gadgets.ReadRef(M.R, F.lib, obj) END ELSIF M.id = Objects.store THEN action := FindFormObj(F, "@ACTION"); Attributes.GetInt(action, "Value", key); HyperDocs.StoreLink(M.R, key); ol := F.elems; WHILE ol # NIL DO 							IF ol.obj # action THEN Gadgets.WriteRef(M.R, F.lib, ol.obj) END; ol := ol.next END; Gadgets.WriteRef(M.R, F.lib, NIL) END END ELSIF M IS Objects.CopyMsg THEN WITH M: Objects.CopyMsg DO 					IF M.stamp = F.stamp THEN M.obj := F.dlink ELSE NEW(F1); F.stamp := M.stamp; F.dlink := F1; CopyForm(M, F, F1); M.obj := F1 					END END ELSIF M IS Objects.BindMsg THEN ol := F.elems; WHILE ol # NIL DO 					ol.obj.handle(ol.obj, M); ol := ol.next END ELSE TextGadgets.ControlHandler(F, M) 			END END END FormHandler; PROCEDURE NewForm*; VAR form: Form; BEGIN NEW(form); form.W := 0; form.H := 0; form.elems := NIL; form.handle := FormHandler; Objects.NewObj := form END NewForm; PROCEDURE HexDigit(i: INTEGER): CHAR; BEGIN IF i < 10 THEN RETURN CHR(i+ORD("0")) ELSE RETURN CHR(i-10+ORD("A")) END END HexDigit; PROCEDURE MapCoord(obj: Objects.Object; VAR x, y: INTEGER); VAR M: Display.LocateMsg; BEGIN M.F := NIL; M.loc := NIL; M.res := -1; M.X := Oberon.Mouse.X; M.Y := Oberon.Mouse.Y; 		Display.Broadcast(M); IF M.loc = obj THEN x := M.u; y := -M.v 		ELSE x := 0; y := 0 END END MapCoord; PROCEDURE ComposeQuery(form: Form; exec: Objects.Object; VAR query: Texts.Text); VAR ol: HTTPDocs0.ObjList; x, y: INTEGER; obj: Objects.Object; text: Texts.Text; name: Objects.Name; str: ARRAY 64 OF CHAR; (* LEN(Objects.AttrMsg.s) *) item: Item; A: Objects.AttrMsg; R: Texts.Reader; ch: CHAR; multisel, done: BOOLEAN; PROCEDURE WriteEscCh(ch: CHAR); BEGIN ch := Strings.OberonToISO[ORD(ch)]; IF (ch < 020X) OR (ch = "+") OR(ch = "&") OR (ch = "=") OR (ch = "?") OR (ch = "%") OR (ch = "$") OR 				(ch = ";") OR (ch = "/") OR (ch = "#") OR (ch = ":") THEN Texts.Write(Wr, "%"); Texts.Write(Wr, HexDigit(ORD(ch) DIV 16)); Texts.Write(Wr, HexDigit(ORD(ch) MOD 16)) ELSIF ch = 020X THEN Texts.Write(Wr, "+"); ELSIF ch >= CHR(128) THEN Texts.Write(Wr, "%"); Texts.Write(Wr, HexDigit(ORD(ch) DIV 16)); Texts.Write(Wr, HexDigit(ORD(ch) MOD 16)) ELSE Texts.Write(Wr, ch) END END WriteEscCh; PROCEDURE IntAttr(i: LONGINT); BEGIN Texts.WriteString(Wr, name); Texts.Write(Wr, "="); Texts.WriteInt(Wr, i, 0); Texts.Write(Wr, "&") END IntAttr; PROCEDURE StrAttr(s: ARRAY OF CHAR); VAR i: INTEGER; BEGIN Texts.WriteString(Wr, name); Texts.Write(Wr, "="); i := 0; WHILE s[i] # 0X DO 				WriteEscCh(s[i]); INC(i) END; Texts.Write(Wr, "&") END StrAttr; PROCEDURE RealAttr(y: LONGREAL; l: INTEGER); BEGIN Texts.WriteString(Wr, name); Texts.Write(Wr, "="); Texts.WriteLongReal(Wr, y, l); Texts.Write(Wr, "&") END RealAttr; BEGIN NEW(query); Texts.Open(query, ""); ol := form.elems; WHILE ol # NIL DO 			obj := ol.obj; Gadgets.GetObjName(obj, name); IF (name # "") & (name[0] # "@") THEN IF HasA(obj, "FormElem") THEN Attributes.GetString(obj, "FormElem", str); IF (str = "IMAGE") & (exec = obj) THEN MapCoord(obj, x, y); Strings.Append(name, ".x"); IntAttr(x); Gadgets.GetObjName(obj, name); Strings.Append(name, ".y"); IntAttr(y) ELSIF str = "SELECT" THEN done := FALSE; Attributes.GetBool(obj, "MultiSel", multisel); item := obj(Lists.List).items(Item); WHILE (item # NIL) & (~done OR multisel) DO 							IF item.sel THEN done := TRUE; IF item.hasVal THEN StrAttr(item.value) ELSE StrAttr(item.s) 								END END; IF item.next # NIL THEN item := item.next(Item) ELSE item := NIL END END; IF ~done THEN StrAttr("") END ELSIF str = "TEXTAREA" THEN Texts.WriteString(Wr, name); Texts.Write(Wr, "="); text := GetText(obj); IF text # NIL THEN Texts.OpenReader(R, text, 0); Texts.Read(R, ch); WHILE ~R.eot DO 								IF ch = Strings.CR THEN (* SendText -> CRLF *) Texts.WriteLn(Wr) ELSE WriteEscCh(ch) END; Texts.Read(R, ch) END END; Texts.Write(Wr, "&") ELSIF str = "PASSWORD" THEN Attributes.GetString(obj, "Value", A.s); StrAttr(A.s) 					END ELSIF HasA(obj, "YesVal") THEN Attributes.GetBool(obj, "Value", A.b); IF A.b THEN Attributes.GetString(obj, "YesVal", str); StrAttr(str) ELSIF HasA(obj, "SubmitVal") & (obj = exec) THEN Attributes.GetString(obj, "SubmitVal", str); StrAttr(str) END ELSIF HasA(obj, "Value") THEN IF HasA(obj, "MaxLen") THEN Attributes.GetInt(obj, "MaxLen", A.i); x := SHORT(A.i) 					ELSE x := -1 END; A.id := Objects.get; A.name := "Value"; A.class := Objects.Inval; A.res := -1; obj.handle(obj, A); CASE A.class OF 						Objects.Int: IntAttr(A.i); |Objects.String: IF (x >= 0) & (x < LEN(A.s)) THEN A.s[x] := 0X END; StrAttr(A.s) 						|Objects.Real: IF x > 0 THEN RealAttr(A.x, x) 												ELSE RealAttr(A.x, 15) END |Objects.LongReal: IF x > 0 THEN RealAttr(A.y, x) 												ELSE RealAttr(A.y, 15) END ELSE END END END; ol := ol.next END; Texts.Append(query, Wr.buf); Texts.Delete(query, query.len-1, query.len) END ComposeQuery; (** HTMLDocs.SubmitQuery 		Used by the "Submit" button in forms. *) PROCEDURE SubmitQuery*; VAR exec, obj: Objects.Object; attr, qury: ARRAY 32 OF CHAR; key, mkey: LONGINT; docname: ARRAY 1024 OF CHAR; query: Texts.Text; form: Form; x, y: INTEGER; cont: HTTPDocs0.Context; doc: Documents.Document; clearCache: BOOLEAN; BEGIN query := NIL; exec := Gadgets.executorObj; IF HasA(exec, "Query") & HasA(exec, "Method") THEN clearCache := TRUE; form := CurForm(Gadgets.context); obj := FindFormObj(form, "@ACTION"); Attributes.GetInt(obj, "Value", key); HyperDocs.DocNameByKey(docname, key); Attributes.GetString(exec, "Query", qury); IF qury = "ISINDEX" THEN obj := FindFormObj(CurForm(Gadgets.context), "QUERY"); Attributes.GetString(obj, "Value", attr); NEW(query); Texts.Open(query, ""); Texts.WriteString(Wq, attr); Texts.Append(query, Wq.buf); attr := "GET" ELSIF qury = "ISMAP" THEN IF HasA(exec, "UseMapKey") THEN clearCache := FALSE; query := NIL; Attributes.GetInt(exec, "UseMapKey", mkey) ELSE mkey := HyperDocs.UndefKey END; IF mkey = HyperDocs.UndefKey THEN NEW(query); Texts.Open(query, ""); MapCoord(exec, x, y); Texts.WriteInt(Wq, x, 0); Texts.Write(Wq, ","); Texts.WriteInt(Wq, y, 0); Texts.Append(query, Wq.buf) ELSE query := NIL; key := mkey END; attr := "GET" ELSIF qury = "FORM" THEN ComposeQuery(form, exec, query); Attributes.GetString(exec, "Method", attr) ELSE Texts.WriteString(Wr, "unknown query type "); Texts.WriteString(Wr, qury); Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf); RETURN END; IF (attr = "GET") OR (attr = "POST") THEN NEW(cont); cont.query := query; COPY(attr, cont.method); cont.user := ""; cont.passwd := ""; IF clearCache THEN HyperDocs.CacheDoc(key, NIL); HyperDocs.CacheText(key, NIL) END; HyperDocs.FollowKeyLink(cont, key) ELSIF attr = "Authorization" THEN NEW(cont); cont.query := NIL; cont.method := "GET"; obj := FindFormObj(form, "Username"); Attributes.GetString(obj, "Value", cont.user); obj := FindFormObj(form, "Password"); Attributes.GetString(obj, "Value", cont.passwd); HyperDocs.FollowKeyLink(cont, key) ELSIF attr = "MAILTO" THEN NEW(cont); cont.curDoc := NIL; cont.new := NIL; cont.replace := FALSE; cont.history := FALSE; cont.old := HyperDocs.NodeByDoc(Desktops.CurDoc(Gadgets.context)); HyperDocs.context := cont; HyperDocs.RetrieveLink(key, docname); doc := Documents.Open(docname); HyperDocs.context := NIL; IF (doc # NIL) & (doc.dsc # NIL) THEN IF (query # NIL) & (doc.dsc IS TextGadgets.Frame) THEN Texts.WriteLn(Wr); Texts.Insert(query, 0, Wr.buf); Texts.WriteLn(Wr); Texts.Append(query, Wr.buf); Texts.Save(query, 0, query.len, Wr.buf); Texts.Append(doc.dsc(TextGadgets.Frame).text, Wr.buf) END; Desktops.ShowDoc(doc) ELSIF query # NIL THEN TextDocs.ShowText("mailto query", query, HyperDocs.docW, HyperDocs.docH) END ELSE Texts.WriteString(Wr, "unknown query method "); Texts.WriteString(Wr, attr); Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf); RETURN END END END SubmitQuery; PROCEDURE HREF(P: Page; VAR href, cmd: ARRAY OF CHAR; VAR key: LONGINT); VAR i, j: LONGINT; BEGIN key := -1; COPY("", cmd); i := 0; WHILE (href[i] # 0X) & (href[i] <= " ") DO 			INC(i) END; IF href[i] = "#" THEN COPY("HTMLDocs.Locate ", cmd); href[0] := " "; Strings.Append(cmd, href); cmd[16] := 022X; Strings.AppendCh(cmd, 022X) ELSE WHILE (href[i] # 0X) & (href[i] # "#") DO 				INC(i) END; IF href[i] = "#" THEN DEC(i); j := 0; WHILE P.base.path[j] # 0X DO 					INC(j) END; DEC(j); WHILE (i > 0) & (j > 0) & (href[i] = P.base.path[j]) DO 					DEC(i); DEC(j) END; IF i = 0 THEN COPY("HTMLDocs.Locate ", cmd); j := 0; WHILE cmd[j] # 0X DO 						INC(j) END; cmd[j] := 022X; INC(j); WHILE (href[i] # 0X) & (href[i] # "#") DO 						INC(i) END; INC(i); WHILE href[i] # 0X DO 						cmd[j] := href[i]; INC(j); INC(i) END; cmd[j] := 022X; cmd[j+1] := 0X; RETURN END END; key := HyperDocs.BuildKey(P.base, href); IF key = HyperDocs.UndefKey THEN Texts.WriteString(Wr, href); Texts.WriteString(Wr, " link-typ not supported"); Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf) END END END HREF; PROCEDURE Read*(VAR S: Scanner); VAR St: Streams.Stream; BEGIN St := S.S; S.ch := S.next; IF St.eos & (St.Available(St) <= 0) THEN S.avail := 0; S.next := 0X; S.end := TRUE ELSE TextStreams.Read(St, S.next); DEC(S.avail); Texts.Write(S.page.Ws, S.next); IF S.ch = Strings.CR THEN IF S.next = Strings.LF THEN TextStreams.Read(St, S.next); DEC(S.avail); Texts.Write(S.page.Ws, S.next) END; S.ch := Strings.CR 			ELSIF S.ch = Strings.LF THEN S.ch := Strings.CR 			END END END Read; PROCEDURE ChangeFontFamily(f: Fonts.Font; newfamily: ARRAY OF CHAR): Fonts.Font; VAR family: ARRAY 64 OF CHAR; str: ARRAY 4 OF CHAR; size: INTEGER; attr: CHAR; BEGIN SplitFontName(f, family, size, attr); IF family # newfamily THEN COPY(newfamily, family); Strings.IntToStr(size, str); Strings.Append(family, str); IF attr # 0X THEN Strings.AppendCh(family, attr) END; Strings.Append(family, ".Scn.Fnt"); RETURN Fonts.This(family) ELSE RETURN f 		END END ChangeFontFamily; PROCEDURE WriteCharRef*(P: Page; VAR S: Scanner); VAR i, j, k : LONGINT; entity: ARRAY 64 OF CHAR; istr: ARRAY 4 OF CHAR; lib: Objects.Library; obj: Objects.Object; fnt: Fonts.Font; ref: INTEGER; BEGIN IF S.ch = "#" THEN Read(S); IF Strings.IsDigit(S.ch) THEN i := 0; WHILE ~S.end & (i < 9100 ) & Strings.IsDigit(S.ch) DO 					i := 10*i+ORD(S.ch)-ORD("0"); Read(S) END; IF S.ch = ";" THEN Read(S) END; CASE i OF 					169: Texts.WriteString(P.W, "(c)") |174: Texts.WriteString(P.W, "(R)") |188: Texts.WriteString(P.W, " 1/4") |189: Texts.WriteString(P.W, " 1/2") |190: Texts.WriteString(P.W, " 3/4") ELSE fnt := P.W.lib(Fonts.Font); IF (i >= 913) & (i <= 982) THEN	(* Greek character *) Strings.IntToStr(i - 900, istr); k := 0; WHILE ((istr[0] # GreekTab[k]) OR (istr[1] # GreekTab[k+1])) & (k < 120) DO 							k := k + 2 END; k := k DIV 2; Texts.SetFont (P.W, ChangeFontFamily(fnt, "Greek")); Texts.Write(P.W, CHR(k + ORD("@"))); Texts.SetFont (P.W, fnt); ELSIF (i >= 8501) & (i <= 9002) THEN	(* Math character *) Texts.SetFont (P.W, ChangeFontFamily(fnt, "Math")); CASE i OF	(*  glyph	TeX name *) 9001: Texts.Write(P.W, "a")	(*	 a	 langle *) (* b *)	(*	 b	 vdash *) (* c *)	(*	 c	 models *) (* d *)	(*	 d	 dashv *) | 8721: Texts.Write(P.W, "e")	(*	 e	 sum *) (* f *)	(*	 f	 ll *) (* g *)	(*	 g	 gg *) | 8968: Texts.Write(P.W, "h")	(*	 h 	lceil *) | 8969: Texts.Write(P.W, "i")	(*	 i 	rceil *) | 8970: Texts.Write(P.W, "j")	(*	 j 	lfloor *) | 8971: Texts.Write(P.W, "k")	(*	 k 	rfloor *) (* l *)	(*	 l 	Vert *) (* m *)	(*	 m 	mp *) (* n *)	(*	 n 	prec *) (* o *)	(*	 o 	succ *) | 8776: Texts.Write(P.W, "p")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">p 	simeq *) | 9002: Texts.Write(P.W, "q")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">q 	rangle *) (* r *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">r 	not supset *) | 8629: Texts.Write(P.W, "s")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">s 	(carriage return) *) (* t *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">t 	?? *) (* u *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">u 	?? *) (* v - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">v 	S *) (* w *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">w 	?? *) | 8747: Texts.Write(P.W, "x")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">x	 int *) (* y *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">y 	oint *) (* z *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">z 	because *) (* C *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">C 	wp *) (* D *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">D 	oslash *) | 8853: Texts.Write(P.W, "E")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">E 	oplus *) | 8709: Texts.Write(P.W, "F")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">F 	emptyset *) | 8745: Texts.Write(P.W, "G")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">G 	cap *) | 8746: Texts.Write(P.W, "H")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">H 	cup *) | 8835: Texts.Write(P.W, "I")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">I 	supset *) | 8839: Texts.Write(P.W, "J")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">J 	supseteq *) | 8836: Texts.Write(P.W, "K")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">K 	not subset *) | 8834: Texts.Write(P.W, "L")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">L 	subset *) | 8838: Texts.Write(P.W, "M")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">M 	subseteq *) | 8712: Texts.Write(P.W, "N")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">N 	in *) | 8713: Texts.Write(P.W, "O")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">O 	not in *) | 8736: Texts.Write(P.W, "P")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">P 	angle *) | 8711: Texts.Write(P.W, "Q")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">Q 	nabla *) | 8704: Texts.Write(P.W, "R")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">R 	forall *) | 8707: Texts.Write(P.W, "S")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">S 	exists *) | 8715: Texts.Write(P.W, "T")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">T 	owns *) (* U *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">U 	sqcap *) | 8730: Texts.Write(P.W, "V")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">V 	surb *) | 8901: Texts.Write(P.W, "W")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">W 	cdot *) (* X *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">X 	lnot *) | 8869: Texts.Write(P.W, "Y")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">Y 	land *) | 8870: Texts.Write(P.W, "Z")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">Z 	lor *) (* 0 - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">0 	deg *) (* 1 - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">1 	pm *) | 8805: Texts.Write(P.W, "3")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">3 	geq *) (* 4 *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">4 	times *) | 8733: Texts.Write(P.W, "5")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">5 	propto *) | 8706: Texts.Write(P.W, "6")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">6 	partial *) (* 7 - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">7 	bullet *) (* 8 - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">8 	div *) | 8800: Texts.Write(P.W, "9")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">9 	not= *) (* ) *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">) 	swarrow *) (* ! *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">! 	mathbb R ?? *) | 8501: Texts.Write(P.W, "@")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">@ 	aleph *) | 8804: Texts.Write(P.W, "#")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF"># 	leq *) (* $ - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">$ 	/ *) | 8734: Texts.Write(P.W, "%")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">% 	infty *) | 8658: Texts.Write(P.W, "^")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">^ 	Rightarrow *) (* & *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">& 	>> *) (* * *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">* 	searrow *) (* ( *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">( 	nwarrow *) | 8592: Texts.Write(P.W, ",")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">, 	gets *) | 8594: Texts.Write(P.W, ".")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">. 	to *) | 8773: Texts.Write(P.W, ";")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">; 	approx *) (* ' *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">' 	nearrow *) (* ` *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">` 	?? *) | 8593: Texts.Write(P.W, "-")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">- 	uparrow *) (* = *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">= 	vert *) | 8595: Texts.Write(P.W, "/")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">/ 	downarrow *) | 8656: Texts.Write(P.W, "\")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">\ 	Leftarrow *) | 8660: Texts.Write(P.W, "[")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">[ 	Leftrightarrow *) | 8657: Texts.Write(P.W, "]")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">] 	Uparrow *) (* < - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">< 	dots *) | 8722: Texts.Write(P.W, ">")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">> 	(minus sign) *) | 8801: Texts.Write(P.W, ":")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">: 	equiv *) (* " - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">" 	prime *) (* ~ - moved down *)	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">~ 	cents *) | 8659: Texts.Write(P.W, "_")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">_ 	Downarrow *) | 8596: Texts.Write(P.W, "+")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">+ 	leftrightarrow *) ELSE END; Texts.SetFont (P.W, fnt); ELSIF (i >= 8201) & (i <= 8500) THEN	(* Math character *) Texts.SetFont (P.W, ChangeFontFamily(fnt, "Math")); CASE i OF	(*  glyph	TeX name *) 8465: Texts.Write(P.W, "A")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">A 	Im *) | 8476: Texts.Write(P.W, "B")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">B 	Re *) | 8243: Texts.Write(P.W, "2")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">2 	(double prime) *) | 8226: Texts.Write(P.W, "7")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">7 	bullet *) | 8260: Texts.Write(P.W, "$")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">$ 	/ *) | 8230: Texts.Write(P.W, "<")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">< 	dots *) | 8242: Texts.Write(P.W, '"')	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">" 	prime *) | 8224: Texts.Write(P.W, "}")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">} 	dagger *) ELSE END; Texts.SetFont (P.W, fnt); (* 					ELSIF (i >= 160) & (i <= 250) THEN	(* Math character *) *) ELSIF (i = 167) OR (i = 176) OR (i = 177) OR (i = 162) OR (i = 247) THEN	(* Math character *) Texts.SetFont (P.W, ChangeFontFamily(fnt, "Math")); CASE i OF	(*  glyph	TeX name *) 167: Texts.Write(P.W, "v")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">v 	S *) | 176: Texts.Write(P.W, "0")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">0 	deg *) | 177: Texts.Write(P.W, "1")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">1 	pm *) | 247: Texts.Write(P.W, "8")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">8 	div *) | 162: Texts.Write(P.W, "~")	(*	 <span style="font-family: Math, sans-serif; font-size: 1.08rem; color: #0000FF">~ 	cents *) ELSE END; Texts.SetFont (P.W, fnt); ELSE Texts.Write(P.W, Strings.ISOToOberon[i]) END END ELSE Texts.WriteString(P.W, "&#") END ELSE i := 0; WHILE ~S.end & Strings.IsAlpha(S.ch) & (i < 63) DO 				entity[i] := S.ch; INC(i); entity[i] := 0X; j := 0; WHILE (j < LEN(entities)) & (entities[j] # entity) DO 					INC(j) END; IF j < LEN(entities) THEN i := 63 END; Read(S) END; entity[i] := 0X; i := 0; WHILE (i < LEN(entities)) & (entities[i] # entity) DO 				INC(i) END; IF i < LEN(entities) THEN Texts.Write(P.W, entityEncoding[i]) ELSIF entity = "trade" THEN PushTextAttrs(P); Texts.SetOffset(P.W, 4); Texts.WriteString(P.W, "TM"); PopTextAttrs(P) ELSIF entity = "reg" THEN Texts.WriteString(P.W, "(R)") ELSIF entity = "copy" THEN Texts.WriteString(P.W, "(c)") ELSE lib := Objects.ThisLibrary("HTMLIcons.Lib"); Objects.GetRef(lib.dict, entity, ref); IF ref >= 0 THEN lib.GetObj(lib, ref, obj); WriteObj(P, obj) ELSE Texts.Write(P.W, "&"); Texts.WriteString(P.W, entity); RETURN END END; IF S.ch = ";" THEN Read(S) END END END WriteCharRef; PROCEDURE CharRefStr*(P: Page; VAR S: Scanner; VAR str: ARRAY OF CHAR); VAR i, j: LONGINT; entity: ARRAY 64 OF CHAR; BEGIN COPY("", str); IF S.ch = "#" THEN Read(S); IF Strings.IsDigit(S.ch) THEN i := 0; WHILE ~S.end & (i < 256) & Strings.IsDigit(S.ch) DO 					i := 10*i+ORD(S.ch)-ORD("0"); Read(S) END; IF S.ch = ";" THEN Read(S) END; CASE i OF 					169: Strings.Append(str, "(c)") |174: Strings.Append(str, "(R)") |188: Strings.Append(str, " 1/4") |189: Strings.Append(str, " 1/2") |190: Strings.Append(str, " 3/4") ELSE Strings.AppendCh(str, Strings.ISOToOberon[i]) END ELSE Strings.Append(str, "&#") END ELSIF Strings.IsAlpha(S.ch) THEN i := 0; WHILE ~S.end & Strings.IsAlpha(S.ch) & (i < 63) DO 				entity[i] := S.ch; INC(i); entity[i] := 0X; j := 0; WHILE (j < LEN(entities)) & (entities[j] # entity) DO 					INC(j) END; IF j < LEN(entities) THEN i := 63 END; Read(S) END; entity[i] := 0X; i := 0; WHILE (i < LEN(entities)) & (entities[i] # entity) DO 				INC(i) END; IF i < LEN(entities) THEN Strings.AppendCh(str, entityEncoding[i]) ELSIF entity = "trade" THEN Strings.Append(str, "TM") ELSIF entity = "reg" THEN Strings.Append(str, "(R)") ELSIF entity = "copy" THEN Strings.Append(str, "(c)") ELSE Strings.AppendCh(str, "&"); Strings.Append(str, entity); RETURN END; IF S.ch = ";" THEN Read(S) END ELSE COPY("&", str) END END CharRefStr; PROCEDURE Next*(VAR S: Scanner); VAR i, l: LONGINT; BEGIN CASE S.state OF 			TextHtml: IF S.ch = "<" THEN Read(S); IF Strings.IsAlpha(S.ch) OR (S.ch = "/") OR (S.ch = "!") THEN S.class := OpenTag ELSE S.char := S.ch; S.class := Character END ELSIF S.ch = "&" THEN Read(S); S.class := CharRef ELSIF (S.ch <= " ") & (S.ch # 0X) & ~S.pre THEN WHILE ~S.end & (S.ch <= " ") DO 									Read(S) END; IF (S.ch = "<") & (S.class = CloseTag) THEN Read(S); IF Strings.IsAlpha(S.ch) OR (S.ch = "/") OR (S.ch = "!") THEN S.class := OpenTag ELSE S.char := S.ch; S.class := Character END ELSIF S.end THEN S.class := Undef; S.state := End ELSE S.class := WhiteSpace END ELSIF ~S.end THEN S.char := S.ch; Read(S); S.class := Character(*; S.skipWS := FALSE*) ELSE S.class := Undef; S.state := End END |TextPlain: IF S.ch # 0X THEN S.char := S.ch; Read(S); S.class := Character ELSE S.class := Undef; S.state := End END |InTag: WHILE ~S.end & (S.ch <= " ") DO 							Read(S) END; IF S.ch = "/" THEN Read(S); S.class := OpenEndTag ELSIF S.ch = ">" THEN Read(S); S.class := CloseTag ELSIF S.ch = "&" THEN Read(S); S.class := CharRef ELSIF Strings.IsAlpha(S.ch) THEN i := 0; l := LEN(S.value)-1; WHILE ~S.end & (Strings.IsAlpha(S.ch) OR Strings.IsDigit(S.ch)) DO 								IF i < l THEN S.value[i] := S.ch; INC(i) END; Read(S) END; S.value[i] := 0X; S.class := Value; WHILE ~S.end & (S.ch <= " ") DO 	Read(S) END; IF S.ch = "<" THEN Read(S); WHILE ~S.end & (S.ch <= " ") DO 		Read(S) END; IF Strings.IsAlpha(S.ch) THEN i := 0; l := LEN(S.value)-1; WHILE ~S.end & (Strings.IsAlpha(S.ch) OR Strings.IsDigit(S.ch)) DO 			IF i < l THEN S.value[i] := S.ch; INC(i) END; Read(S) END END END ELSIF ~S.end THEN S.char := S.ch; Read(S); S.class := Character ELSE S.class := Undef; S.state := End END ELSE S.class := Undef; S.state := End END END Next; PROCEDURE NextAttr*(VAR S: Scanner; VAR name: ARRAY OF CHAR): BOOLEAN; VAR i, l: LONGINT; charRef: ARRAY 16 OF CHAR; quoted: BOOLEAN; BEGIN WHILE ~S.end & (S.ch <= " ") DO 			Read(S) END; IF (S.ch = ",") OR (S.ch = ";") THEN Read(S); WHILE ~S.end & (S.ch <= " ") DO 				Read(S) END END; i := 0; l := LEN(name)-1; WHILE ~S.end & Strings.IsAlpha(S.ch) DO 			IF i < l THEN name[i] := CAP(S.ch); INC(i) END; Read(S) END; name[i] := 0X; IF i > 0 THEN WHILE ~S.end & (S.ch <= " ") DO 				Read(S) END; IF S.ch = "=" THEN Read(S); WHILE ~S.end & (S.ch <= " ") DO 					Read(S) END; IF S.ch = 022X THEN Read(S); quoted := TRUE ELSE quoted := FALSE END; i := 0; l := LEN(S.value)-1; WHILE ~S.end & ( (~quoted & (S.ch > " ") & (S.ch # ">")) OR (quoted & (S.ch # 022X)) ) DO 					IF i < l THEN IF S.ch = "&" THEN Read(S); CharRefStr(S.page, S, charRef); S.value[i] := 0X; Strings.Append(S.value, charRef); i := Strings.Length(S.value) ELSIF (S.ch >= " ") OR (S.ch = Strings.Tab) THEN S.value[i] := S.ch; INC(i); Read(S) ELSE Read(S) END ELSE Read(S) END END; IF S.ch = 022X THEN Read(S) END; WHILE ~quoted & (i > 0) & (S.value[i-1] <= " ") DO 					S.value[i-1] := 0X; DEC(i) END; S.value[i] := 0X ELSE COPY("", S.value) END; S.class := Value; RETURN TRUE END; COPY("", name); COPY("", S.value); RETURN FALSE END NextAttr; PROCEDURE GetAttrs*(VAR S: Scanner; VAR attrs: TagAttr); VAR attr: TagAttr; BEGIN attrs := NIL; NEW(attr); WHILE NextAttr(S, attr.name) DO 			attr.next := attrs; attrs := attr; COPY(S.value, attr.value); NEW(attr) END END GetAttrs; PROCEDURE FindAttr*(attrs: TagAttr; name: ARRAY OF CHAR): TagAttr; VAR attr: TagAttr; BEGIN attr := attrs; WHILE (attr # NIL) & (attr.name # name) DO 			attr := attr.next END; RETURN attr END FindAttr; PROCEDURE OpenScanner*(VAR S: Scanner; St: Streams.Stream); BEGIN (*S.skipWS := FALSE; S.genWS := FALSE;*) S.ch := 0X; S.next := 0X; S.end := FALSE; S.S := St; S.class := Undef; S.state := TextHtml; S.pre := FALSE; Read(S) END OpenScanner; PROCEDURE A(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; obj: Objects.Object; isRef, newDoc: BOOLEAN; BEGIN P := S.page; CloseA(P); P.linkkey := HyperDocs.UndefKey; IF on THEN isRef := FALSE; newDoc := FALSE; WHILE NextAttr(S, attr) DO 				IF attr = "HREF" THEN isRef := TRUE; HREF(P, S.value, attr, P.linkkey); IF P.linkkey # HyperDocs.UndefKey THEN P.alink := HyperDocs.LinkControl(P.linkkey) ELSE P.alink := Gadgets.CreateObject("TextGadgets.NewControl"); Attributes.SetString(P.alink, "Cmd", attr) END ELSIF (attr = "NAME") OR (attr = "ID") THEN IF S.value = P.orgLabel THEN Texts.Append(P.T, P.W.buf); P.orgPos := P.T.len END; obj := Gadgets.CreateObject("TextGadgets.NewControl"); WriteObj(P, obj); Attributes.SetString(obj, "Name", S.value) ELSIF attr = "TARGET" THEN newDoc := TRUE END END; IF isRef THEN IF newDoc THEN Attributes.SetString(P.alink, "Opt", "New") END; IF ~HyperDocs.Visited(P.linkkey) THEN PushTextAttrs(P); Texts.SetColor(P.W, SHORT(P.linkC)) ELSE PushTextAttrs(P); Texts.SetColor(P.W, SHORT(P.oldLinkC)) END END END END A; 	PROCEDURE ADDRESS(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, Syntax(12, "i")) ELSE PopTextAttrs(P) END END ADDRESS; PROCEDURE B(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "b")) ELSE PopTextAttrs(P) END END B; 	PROCEDURE SplitHostPort*(VAR url, host: ARRAY OF CHAR; VAR port: INTEGER); VAR i, j: INTEGER; val: LONGINT; BEGIN i := 0; WHILE (url[i] # 0X) & (url[i] # "/") DO 			INC(i) END; WHILE url[i] = "/" DO 			INC(i) END; j := 0; WHILE (url[j] # 0X) & (url[j] # "@") DO 			INC(j) END; IF url[j] = "@" THEN i := j+1 END; j := 0; WHILE (url[i] # 0X) & (url[i] # "/") & (url[i] # ":") DO 			host[j] := url[i]; INC(i); INC(j) END; host[j] := 0X; IF url[i] = ":" THEN INC(i); Strings.StrToIntPos(url, val, i); port := SHORT(val) ELSE port := 0 END END SplitHostPort; PROCEDURE BASE(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr, label: ARRAY 64 OF CHAR; s: HyperDocs.LinkScheme; key: LONGINT; port: INTEGER; BEGIN IF on THEN P := S.page; WHILE NextAttr(S, attr) DO 				IF attr = "HREF" THEN P.base.key := HyperDocs.BuildKey(P.base, S.value); s := HyperDocs.LinkSchemeByKey(P.base.key); IF s = NIL THEN s := HyperDocs.LinkSchemeByPrefix("file") END; COPY(s.prefix, P.base.prefix); HyperDocs.RetrieveLink(P.base.key, S.value); IF P.base.prefix = "http" THEN P.base.key := HTTPDocs0.SplitHTTPAdr(S.value, P.base.host, P.base.path, label, P.base.port) ELSIF P.base.prefix = "file" THEN P.base.key := HyperDocs.SplitFileAdr(S.value, P.base.path, label); P.base.host := ""; P.base.port := 0 ELSE (* proxy *) SplitHostPort(S.value, P.base.host, P.base.port); key := HTTPDocs0.SplitHTTPAdr(S.value, P.base.host, P.base.path, label, port) END END END END END BASE; PROCEDURE HexVal(ch: CHAR): INTEGER; BEGIN IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch)-ORD("0") ELSIF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch)-ORD("A")+10 ELSIF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch)-ORD("a")+10 ELSE RETURN 256 END END HexVal; PROCEDURE Color(VAR val: ARRAY OF CHAR; VAR col: INTEGER); VAR r, g, b, rr, gg, bb, i, bestC: INTEGER; diff, mdiff: REAL; BEGIN IF val = "white" THEN col := 0; RETURN ELSIF val = "red" THEN col := 1; RETURN ELSIF val = "green" THEN col := 2; RETURN ELSIF val = "blue" THEN col := 3; RETURN ELSIF val = "black" THEN col := 15; RETURN ELSIF val[0] = "#" THEN r := 16*HexVal(val[1])+HexVal(val[2]); g := 16*HexVal(val[3])+HexVal(val[4]); b := 16*HexVal(val[5])+HexVal(val[6]) ELSE r := 16*HexVal(val[0])+HexVal(val[1]); g := 16*HexVal(val[2])+HexVal(val[3]); b := 16*HexVal(val[4])+HexVal(val[5]) END; IF (r > 255) OR (g > 255) OR (b > 255) THEN RETURN END; mdiff := MAX(REAL); bestC := 0; i := 0; WHILE (i < 256) & (mdiff > 0.0) DO 			Display.GetColor(i, rr, gg, bb); diff := LONG(rr-r)*LONG(rr-r); diff := diff+LONG(gg-g)*LONG(gg-g); diff := diff+LONG(bb-b)*LONG(bb-b); IF diff < mdiff THEN bestC := i; mdiff := diff END; INC(i) END; col := bestC END Color; PROCEDURE BASEFONT(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; val: LONGINT; size, i: INTEGER; col: BOOLEAN; BEGIN P := S.page; IF on THEN col := FALSE; size := GetFontSize(P); WHILE NextAttr(S, attr) DO 				IF attr = "SIZE" THEN i := 1; IF S.value[0] = "-" THEN Strings.StrToIntPos(S.value, val, i); size := size-SHORT(val) ELSIF S.value[0] = "+" THEN Strings.StrToIntPos(S.value, val, i); size := size+SHORT(val) ELSE i := 0; Strings.StrToIntPos(S.value, val, i); size := SHORT(val) END ELSIF attr = "COLOR" THEN Color(S.value, P.textC); col := TRUE END END; SetFontSize(P, size); IF col THEN Texts.SetColor(P.W, SHORT(P.textC)) END ELSE PopTextAttrs(P) END END BASEFONT; PROCEDURE BIG(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN SetFontSize(P, GetFontSize(P)+2) ELSE PopTextAttrs(P) END END BIG; PROCEDURE BLINK(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetColor(P.W, SHORT(Display3.red)) ELSE PopTextAttrs(P) END END BLINK; PROCEDURE BLOCKQUOTE(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); P.style := NewStyle; WriteObj(P, P.style); Texts.SetFont(P.W, Syntax(12, "i")) ELSE PopTextAttrs(P) END; (*S.skipWS := TRUE*) END BLOCKQUOTE; PROCEDURE ChangeColors(P: Page; from, to: SHORTINT); VAR tattr: TextAttrs; BEGIN IF P.W.col = from THEN Texts.SetColor(P.W, to) END; tattr := P.textAttrs; WHILE tattr # NIL DO 			IF tattr.col = from THEN tattr.col := to 			END; tattr := tattr.next END END ChangeColors; PROCEDURE BODY(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; key: LONGINT; doc: Documents.Document; BackE: HTTPDocs0.Entry; col: INTEGER; BEGIN P := S.page; IF on THEN Texts.Append(P.T, P.W.buf); WHILE NextAttr(S, attr) DO 				IF attr = "BGCOLOR" THEN Color(S.value, P.textbackC); Attributes.SetInt(P.D.dsc, "Color", P.textbackC) ELSIF attr = "TEXT" THEN col := P.textC; Color(S.value, col); ChangeColors(P, SHORT(P.textC), SHORT(col)); P.textC := col ELSIF attr = "LINK" THEN (* hyper text link *) col := P.linkC; Color(S.value, col); ChangeColors(P, SHORT(P.linkC), SHORT(col)); P.linkC := col; Attributes.SetInt(P.D.dsc, "LinkColor", P.linkC) ELSIF attr = "VLINK" THEN (* visited hyper text link *) col := P.oldLinkC; Color(S.value, col); ChangeColors(P, SHORT(P.oldLinkC), SHORT(col)); P.oldLinkC := col; Attributes.SetInt(P.D.dsc, "OldLinkColor", P.oldLinkC) ELSIF attr = "BACKGROUND" THEN key := HyperDocs.BuildKey(P.base, S.value); IF imgs THEN NEW(BackE); BackE.basekey := P.base.dockey; BackE.ol := NIL; BackE.attrs := NIL; BackE.text := P.T; 						BackE.pos := -1; BackE.key := HyperDocs.UndefKey; BackE.obj := P.D; 						NEW(doc); HyperDocs.DocNameByKey(doc.name, key); doc.handle := NIL; doc.dsc := NIL; HTTPDocs0.RequestDoc(doc, HTTPDocs0.httpProxy, key, "GET", FALSE, BackE, NIL) END END END END END BODY; PROCEDURE BR(VAR S: Scanner; on: BOOLEAN); BEGIN IF on THEN WriteLn(S.page)(*; S.page.lines := 0*) END; (*S.skipWS := TRUE*) END BR; PROCEDURE ExecAttrs*; VAR exec, cont: Objects.Object; name, nr: ARRAY 32 OF CHAR; i: LONGINT; BEGIN cont := Gadgets.context; exec := Gadgets.executorObj; IF exec # NIL THEN i := 1; name := "Cmd"; Strings.IntToStr(i, nr); Strings.Append(name, nr); WHILE Attributes.FindAttr(name, exec(Gadgets.Frame).attr) # NIL DO 				Gadgets.ExecuteAttr(exec(Gadgets.Frame), name, cont, NIL, NIL); INC(i); name := "Cmd"; Strings.IntToStr(i, nr); Strings.Append(name, nr) END END END ExecAttrs; PROCEDURE CALL(VAR S: Scanner; on: BOOLEAN); (* ejz *) VAR P: Page; name, attr: ARRAY 32 OF CHAR; i: LONGINT; BEGIN P := S.page; CloseA(P); IF on THEN P.clink := Gadgets.CreateObject("TextGadgets.NewControl"); i := 0; WHILE NextAttr(S, attr) DO 				IF attr = "CMD" THEN INC(i); name := "Cmd"; Strings.IntToStr(i, attr); Strings.Append(name, attr); Attributes.SetString(P.clink, name, S.value) END END; IF i = 0 THEN P.clink := NIL ELSE Attributes.SetString(P.clink, "Cmd", "HTMLDocs.ExecAttrs") END; PushTextAttrs(P); Texts.SetColor(P.W, SHORT(Display3.red)) ELSE IF P.clink # NIL THEN WriteObj(P, P.clink) END; P.clink := NIL; PopTextAttrs(P) END END CALL; PROCEDURE CENTER(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); P.style := NewStyle; EXCL(P.style.mode, TextGadgets.left); INCL(P.style.mode, TextGadgets.middle); WriteObj(P, P.style) ELSE PopTextAttrs(P) END; (*S.skipWS := TRUE*) END CENTER; PROCEDURE CITE(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "i")) ELSE PopTextAttrs(P) END END CITE; PROCEDURE CODEx(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono) ELSE PopTextAttrs(P) END END CODEx; PROCEDURE DD(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN IF (P.lists # NIL) & (P.lists.kind = DescList) & P.lists.dtok THEN Texts.Write(P.W, Strings.Tab) ELSE IF P.lists # NIL THEN INC(P.lists.itemNr); IF P.lists.itemNr > 1 THEN WriteLn(P) END ELSE WriteLn(P) END END END; P.blank := FALSE (*S.skipWS := TRUE*) END DD; PROCEDURE DFN(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "i")) ELSE PopTextAttrs(P) END END DFN; PROCEDURE DIR(VAR S: Scanner; on: BOOLEAN); BEGIN IF on THEN OpenList(S.page, DefList) ELSE CloseList(S.page) END; (*S.skipWS := TRUE*) END DIR; PROCEDURE DIVI(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 32 OF CHAR; style: TextGadgets.Style; BEGIN P := S.page; IF on THEN PushTextAttrs(P); style := NIL; WHILE NextAttr(S, attr) DO 				IF attr = "ALIGN" THEN style := TextAlign(S.value) END END; IF style # NIL THEN P.style := style; WriteObj(P, P.style) END ELSE PopTextAttrs(P) END; (*S.skipWS := TRUE*) END DIVI; PROCEDURE DL(VAR S: Scanner; on: BOOLEAN); BEGIN IF on THEN OpenList(S.page, DescList) ELSE CloseList(S.page) END; (*S.skipWS := TRUE*) END DL; PROCEDURE DT(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN IF P.lists # NIL THEN INC(P.lists.itemNr); IF P.lists.itemNr > 1 THEN WriteLn(P) END; IF P.lists.kind = DescList THEN P.lists.dtok := TRUE; Texts.Write(P.W, Strings.Tab) END ELSE WriteLn(P) END END; P.blank := FALSE (*S.skipWS := TRUE*) END DT; PROCEDURE EM(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "i")) ELSE PopTextAttrs(P) END END EM; PROCEDURE FRAME(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; BEGIN P := S.page; CloseA(P); P.linkkey := HyperDocs.UndefKey; IF on THEN WHILE NextAttr(S, attr) DO 				IF (attr = "SRC") OR (attr = "HREF") THEN P.lines := 0; WriteLn(P); WriteLn(P); Texts.WriteString(P.W, "FRAME Reference: "); HREF(P, S.value, attr, P.linkkey); IF P.linkkey # HyperDocs.UndefKey THEN P.alink := HyperDocs.LinkControl(P.linkkey); HyperDocs.RetrieveLink(P.linkkey, S.value); Attributes.SetString(P.alink, "Opt", "N") ELSE P.alink := Gadgets.CreateObject("TextGadgets.NewControl"); Attributes.SetString(P.alink, "Cmd", attr) END; PushTextAttrs(P); Texts.SetColor(P.W, SHORT(P.linkC)); Texts.WriteString(P.W, S.value); WriteObj(P, P.alink); P.alink := NIL; P.linkkey := HyperDocs.UndefKey; PopTextAttrs(P); WriteLn(P) END END END END FRAME; PROCEDURE FONT(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; val: LONGINT; size, i, textC: INTEGER; col: BOOLEAN; BEGIN P := S.page; IF on THEN col := FALSE; size := GetFontSize(P); WHILE NextAttr(S, attr) DO 				IF attr = "SIZE" THEN i := 1; IF S.value[0] = "-" THEN Strings.StrToIntPos(S.value, val, i); size := size-SHORT(val) ELSIF S.value[0] = "+" THEN Strings.StrToIntPos(S.value, val, i); size := size+SHORT(val) ELSE i := 0; Strings.StrToIntPos(S.value, val, i); size := SHORT(val) END ELSIF attr = "COLOR" THEN Color(S.value, textC); col := TRUE END END; SetFontSize(P, size); IF col THEN Texts.SetColor(P.W, SHORT(textC)) END ELSE PopTextAttrs(P) END END FONT; PROCEDURE GREEN(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetColor(P.W, SHORT(Display3.green)) ELSE PopTextAttrs(P) END END GREEN; PROCEDURE H(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; style: TextGadgets.Style; BEGIN P := S.page; IF on THEN style := NIL; PushTextAttrs(P); IF ~P.left THEN WriteLn(P); WriteLn(P) ELSE P.left := FALSE END; CASE ORD(S.value[1])-ORD("0") OF 				1: Texts.SetFont(P.W, Syntax(20, 0X)) |2: Texts.SetFont(P.W, Syntax(16, 0X)) |3: Texts.SetFont(P.W, Syntax(16, "i")) |4: Texts.SetFont(P.W, Syntax(14, 0X)) |5: Texts.SetFont(P.W, Syntax(14, "i")) |6: Texts.SetFont(P.W, Syntax(12, 0X)) ELSE Texts.SetFont(P.W, Syntax(12, 0X)) END; WHILE NextAttr(S, attr) DO 				IF attr = "ALIGN" THEN style := TextAlign(S.value) ELSIF attr = "SRC" THEN (* get image *) ELSIF attr = "DINGBAT" THEN (* get icon with name value *) END END; IF style # NIL THEN P.style := style; WriteObj(P, P.style) END ELSE CloseA(P); PopTextAttrs(P); WriteLn(P); WriteLn(P) END; (*S.skipWS := TRUE*) END H; 	PROCEDURE HEAD(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END HEAD; PROCEDURE HP(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END HP; PROCEDURE HR(VAR S: Scanner; on: BOOLEAN); VAR attr: ARRAY 64 OF CHAR; P: Page; l: LONGINT; w, h, pos: INTEGER; BEGIN IF on THEN P := S.page; CloseA(P); w := dispW; h := 1; WHILE NextAttr(S, attr) DO 				IF attr = "SIZE" THEN Strings.StrToInt(S.value, l); h := SHORT(l) ELSIF attr = "WIDTH" THEN pos := 0; Strings.StrToIntPos(S.value, l, pos); w := SHORT(l); IF S.value[pos] = "%" THEN w := SHORT( (LONG((5*dispW) DIV 8) * w) DIV LONG(100) ) END END END; HorzRule(P, w, h) 		END; (*S.skipWS := TRUE*) END HR; PROCEDURE HTML(VAR S: Scanner; on: BOOLEAN); BEGIN (*		IF ~on THEN 			Texts.WriteLn(S.page.W); 			(*S.skipWS := TRUE; *)S.state := TextPlain 		END *) END HTML; PROCEDURE HTTP(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END HTTP; PROCEDURE I(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "i")) ELSE PopTextAttrs(P) END END I; 	PROCEDURE KBD(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono) ELSE PopTextAttrs(P) END END KBD; PROCEDURE LI(VAR S: Scanner; on: BOOLEAN); VAR P: Page; i: INTEGER; BEGIN P := S.page; IF on THEN IF P.lists # NIL THEN INC(P.lists.itemNr); IF P.lists.itemNr > 1 THEN WriteLn(P) END; FOR i := 1 TO P.lists.nesting DO 					Texts.Write(P.W, Strings.Tab) END ELSE WriteLn(P) END; IF (P.lists # NIL) & (P.lists.kind = OrderedList) THEN Texts.WriteInt(P.W, P.lists.itemNr, 0) ELSE IF P.lists # NIL THEN i := P.lists.nesting MOD LEN(bullets) ELSE i := 0 END; PushTextAttrs(P); Texts.SetFont(P.W, bullets[i].f); Texts.Write(P.W, bullets[i].c); PopTextAttrs(P) END; Texts.Write(P.W, Strings.Tab) END; P.blank := FALSE (*S.skipWS := TRUE*) END LI; PROCEDURE LINK(VAR S: Scanner; on: BOOLEAN); (*		VAR 			P: Page; 			attr, cmd, caption: ARRAY 64 OF CHAR; 			key: LONGINT; 			obj: Objects.Object; 	BEGIN 		IF on THEN 			P := S.page; caption := ""; cmd := ""; 			WHILE NextAttr(S, attr) DO 				IF attr = "HREF" THEN 					HREF(P, S.value, cmd, key); 					IF key # HyperDocs.UndefKey THEN 						cmd := "HyperDocs.FollowLink #Key" 					END 				ELSIF attr = "REV" THEN 					IF caption = "" THEN 						COPY(S.value, caption) 					END 				ELSIF attr = "REL" THEN 					IF caption = "" THEN 						COPY(S.value, caption) 					END 				ELSIF attr = "TITLE" THEN 					COPY(S.value, caption) 				END 			END; 			IF cmd # "" THEN 				obj := Gadgets.CreateObject("BasicGadgets.NewButton"); 				Attributes.SetString(obj, "Caption", caption); 				Attributes.SetString(obj, "Cmd", cmd); (* ?! fixup on reload *) 				Attributes.SetInt(obj, "Key", key); 				WriteObj(P, obj) 			END 		END	*) END LINK; PROCEDURE LISTING(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono); S.pre := TRUE ELSE PopTextAttrs(P); S.pre := FALSE END END LISTING; PROCEDURE ISINDEX(VAR S: Scanner; on: BOOLEAN); VAR P: Page; objt, objb: Objects.Object; form: Form; attr: ARRAY 64 OF CHAR; prompt: ARRAY 512 OF CHAR; key: LONGINT; BEGIN IF on THEN P := S.page; key := P.base.key; NewForm; form := Objects.NewObj(Form); prompt := "This is a searchable index. Enter search keywords: "; WHILE NextAttr(S, attr) DO 				IF attr = "PROMPT" THEN COPY(S.value, prompt) ELSIF attr = "HREF" THEN key := HyperDocs.BuildKey(P.base, S.value) END END; WriteObj(P, form); HorzRule(P, dispW, 1); Texts.WriteString(P.W, prompt); objt := Gadgets.CreateObject("BasicGadgets.NewInteger"); Attributes.SetInt(objt, "Value", key); AddFormObj(P, form, objt, "@ACTION", FALSE, FALSE); objt := Gadgets.CreateObject("TextFields.NewTextField"); AddFormObj(P, form, objt, "QUERY", FALSE, TRUE); objb := Gadgets.CreateObject("BasicGadgets.NewButton"); objb(Display.Frame).H := objt(Display.Frame).H; 			Attributes.SetString(objb, "Query", "ISINDEX"); Attributes.SetString(objb, "Method", "GET"); Attributes.SetString(objb, "Caption", "Search"); Attributes.SetString(objb, "Cmd", "HTMLDocs.SubmitQuery"); AddFormObj(P, form, objb, "", FALSE, TRUE); HorzRule(P, dispW, 1) END END ISINDEX; PROCEDURE MENU(VAR S: Scanner; on: BOOLEAN); BEGIN IF on THEN OpenList(S.page, DefList) ELSE CloseList(S.page) END; (*S.skipWS := TRUE*) END MENU; PROCEDURE META(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END META; PROCEDURE NEXTID(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END NEXTID; PROCEDURE NOFRAMES(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; HorzRule(P, dispW, 1) END NOFRAMES; PROCEDURE OL(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN OpenList(P, OrderedList) ELSE CloseList(P) END; (*S.skipWS := TRUE*) END OL; PROCEDURE P(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; style: TextGadgets.Style; BEGIN P := S.page; IF on THEN style := NIL; CloseA(P); WriteLn(P); WriteLn(P); (*P.lines := 0;*) WHILE NextAttr(S, attr) DO 				IF attr = "ALIGN" THEN style := TextAlign(S.value) END END; IF style # NIL THEN PushTextAttrs(P); P.style := style; WriteObj(P, P.style) END ELSE PopTextAttrs(P) END; (*S.skipWS := TRUE*) END P; 	PROCEDURE PLAINTEXT(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono); S.state := TextPlain; S.pre := TRUE ELSE PopTextAttrs(P); S.state := TextHtml; S.pre := FALSE END END PLAINTEXT; PROCEDURE PRE(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono); S.pre := TRUE ELSE PopTextAttrs(P); S.pre := FALSE END END PRE; PROCEDURE Q(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN Texts.WriteString(P.W, "<<") ELSE Texts.WriteString(P.W, ">>") END END Q; 	PROCEDURE RANGE(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END RANGE; PROCEDURE SAMP(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono) ELSE PopTextAttrs(P) END END SAMP; PROCEDURE SMALL(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN SetFontSize(P, GetFontSize(P)-2) ELSE PopTextAttrs(P) END END SMALL; PROCEDURE STRIKE(VAR S: Scanner; on: BOOLEAN); (* strikethrough text, how ? *) BEGIN (* ignore *) END STRIKE; PROCEDURE STRONG(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "b")) ELSE PopTextAttrs(P) END END STRONG; PROCEDURE STYLE(VAR S: Scanner; on: BOOLEAN); BEGIN (* ignore *) END STYLE; PROCEDURE SUB(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN SetFontSize(P, GetFontSize(P)-2); Texts.SetOffset(P.W, P.W.voff-4) ELSE PopTextAttrs(P) END END SUB; PROCEDURE SUP(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN SetFontSize(P, GetFontSize(P)-2); Texts.SetOffset(P.W, P.W.voff+4) ELSE PopTextAttrs(P) END END SUP; PROCEDURE TINY(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN SetFontSize(P, GetFontSize(P)-2) ELSE PopTextAttrs(P) END END TINY; PROCEDURE TITLE(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF P.head THEN IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, Syntax(12, 0X)); Texts.WriteString(P.W, "Title: ") ELSE WriteLn(P); PopTextAttrs(P); HorzRule(P, dispW, 2); Texts.Append(P.T, P.W.buf); P.headerLen := P.T.len END ELSIF ~on THEN PushTextAttrs(P); Texts.OpenWriter(P.W); PopTextAttrs(P) END (*S.skipWS := TRUE*) END TITLE; PROCEDURE TT(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono) ELSE PopTextAttrs(P) END END TT; PROCEDURE TAB(VAR S: Scanner; on: BOOLEAN); VAR P: Page; attr: ARRAY 64 OF CHAR; style: TextGadgets.Style; BEGIN P := S.page; IF on THEN Texts.Write(P.W, Strings.Tab); style := NIL; WHILE NextAttr(S, attr) DO 				IF attr = "ALIGN" THEN style := TextAlign(S.value) END END; IF style # NIL THEN PushTextAttrs(P); P.style := style; WriteObj(P, P.style) END ELSE PopTextAttrs(P) END; P.blank := FALSE (*S.skipWS := TRUE*) END TAB; PROCEDURE U(VAR S: Scanner; on: BOOLEAN); (* underline text, how ? *) BEGIN (* ignore *) END U; 	PROCEDURE UL(VAR S: Scanner; on: BOOLEAN); BEGIN IF on THEN OpenList(S.page, DefList) ELSE CloseList(S.page) END; (*S.skipWS := TRUE*) END UL; PROCEDURE VARN(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, ChangeFontAttr(P.W.lib(Fonts.Font), "i")) ELSE PopTextAttrs(P) END END VARN; PROCEDURE XMP(VAR S: Scanner; on: BOOLEAN); VAR P: Page; BEGIN P := S.page; IF on THEN PushTextAttrs(P); Texts.SetFont(P.W, mono); S.pre := TRUE ELSE PopTextAttrs(P); S.pre := FALSE END END XMP; PROCEDURE HandleTag(VAR S: Scanner); VAR Ss: Texts.Scanner; gen: ARRAY 64 OF CHAR; e: ExtTag; i: INTEGER; found, on: BOOLEAN; prev: CHAR; BEGIN WHILE ~S.end & (S.ch <= " ") DO 			Read(S) END; IF S.ch = "!" THEN prev := S.ch; Read(S); IF S.ch = "-" THEN prev := S.ch; Read(S); IF S.ch = "-" THEN WHILE ~S.end & ((S.ch # ">") OR ((prev # "-") & (prev # "!"))) DO 						IF S.ch > " " THEN prev := S.ch 						END; Read(S) END ELSE WHILE ~S.end & (S.ch # ">") DO 						Read(S) END END ELSE WHILE ~S.end & (S.ch # ">") DO 					Read(S) END END; Read(S) ELSIF ~Strings.IsAlpha(S.ch) & (S.ch # "/") THEN Texts.Write(S.page.W, "<") ELSE S.state := InTag; Next(S); IF S.class = OpenEndTag THEN on := FALSE; Next(S) ELSE on := TRUE END; IF S.class = Value THEN Strings.Upper(S.value, S.value); found := TRUE; CASE S.value[0] OF 					"A": IF S.value[1] = 0X THEN A(S, on) ELSIF (S.value = "ADDR") OR (S.value = "ADDRESS") THEN ADDRESS(S, on) ELSE found := FALSE END |"B": IF S.value[1] = 0X THEN B(S, on) ELSIF S.value = "BASE" THEN BASE(S, on) ELSIF S.value = "BASEFONT" THEN BASEFONT(S, on) ELSIF S.value = "BIG" THEN BIG(S, on) ELSIF S.value = "BLINK" THEN BLINK(S, on) ELSIF (S.value = "BQ") OR (S.value = "BLOCKQUOTE") THEN BLOCKQUOTE(S, on) ELSIF S.value = "BODY" THEN BODY(S, on) ELSIF S.value = "BR" THEN BR(S, on) ELSE found := FALSE END |"C": IF S.value = "CALL" THEN CALL(S, on) ELSIF S.value = "CENTER" THEN CENTER(S, on) ELSIF S.value = "CITE" THEN CITE(S, on) ELSIF S.value = "CODE" THEN CODEx(S, on) ELSE found := FALSE END |"D": IF S.value = "DD" THEN DD(S, on) ELSIF S.value = "DFN" THEN DFN(S, on) ELSIF S.value = "DIR" THEN DIR(S, on) ELSIF S.value = "DIV" THEN DIVI(S, on) ELSIF S.value = "DL" THEN DL(S, on) ELSIF S.value = "DT" THEN DT(S, on) ELSE found := FALSE END |"E": IF S.value = "EM" THEN EM(S, on) ELSE found := FALSE END |"F": IF S.value = "FRAME" THEN FRAME(S, on) ELSIF S.value = "FONT" THEN FONT(S, on) ELSE found := FALSE END |"G": IF S.value = "GREEN" THEN GREEN(S, on) ELSE found := FALSE END |"H": IF (S.value = "HEAD") OR (S.value = "HEADER") THEN HEAD(S, on) ELSIF S.value = "HP" THEN HP(S, on) ELSIF S.value = "HR" THEN HR(S, on) ELSIF S.value = "HTML" THEN HTML(S, on) ELSIF S.value = "HTTP" THEN HTTP(S, on) ELSIF Strings.IsDigit(S.value[1]) THEN H(S, on) ELSE found := FALSE END |"I": IF S.value[1] = 0X THEN I(S, on) ELSIF S.value = "ISINDEX" THEN ISINDEX(S, on) ELSE found := FALSE END |"K": IF S.value = "KBD" THEN KBD(S, on) ELSE found := FALSE END |"L": IF S.value = "LI" THEN LI(S, on) ELSIF S.value = "LINK" THEN LINK(S, on) ELSIF S.value = "LISTING" THEN LISTING(S, on) ELSE found := FALSE END |"M": IF S.value = "MENU" THEN MENU(S, on) ELSIF S.value = "META" THEN META(S, on) ELSE found := FALSE END |"N": IF S.value = "NEXTID" THEN NEXTID(S, on) ELSIF S.value = "NOFRAMES" THEN NOFRAMES(S, on) ELSE found := FALSE END |"O": IF S.value = "OL" THEN OL(S, on) ELSE found := FALSE END |"P": IF S.value[1] = 0X THEN P(S, on) ELSIF S.value = "PLAINTEXT" THEN PLAINTEXT(S, on) ELSIF S.value = "PRE" THEN PRE(S, on) ELSE found := FALSE END |"Q": IF S.value[1] = 0X THEN Q(S, on) ELSE found := FALSE END |"R": IF S.value = "RANGE" THEN RANGE(S, on) ELSE found := FALSE END |"S": IF S.value[1] = 0X THEN STRIKE(S, on) ELSIF S.value = "SAMP" THEN SAMP(S, on) ELSIF S.value = "STRIKE" THEN STRIKE(S, on) ELSIF S.value = "STRONG" THEN STRONG(S, on) ELSIF S.value = "STYLE" THEN STYLE(S, on) ELSIF S.value = "SMALL" THEN SMALL(S, on) ELSIF S.value = "SUB" THEN SUB(S, on) ELSIF S.value = "SUP" THEN SUP(S, on) ELSE found := FALSE END |"T": IF S.value = "TITLE" THEN TITLE(S, on) ELSIF S.value = "TT" THEN TT(S, on) ELSIF S.value = "TAB" THEN TAB(S, on) ELSIF S.value = "TINY" THEN TINY(S, on) ELSE found := FALSE END |"U": IF S.value[1] = 0X THEN U(S, on) ELSIF S.value = "UL" THEN UL(S, on) ELSE found := FALSE END |"V": IF S.value = "VAR" THEN VARN(S, on) ELSE found := FALSE END |"X": IF S.value = "XMP" THEN XMP(S, on) ELSE found := FALSE END ELSE found := FALSE END; IF ~found THEN e := extTags; WHILE (e # NIL) & (e.tag # S.value) DO 						e := e.next END; IF e = NIL THEN gen := "HTMLTags."; Strings.Append(gen, S.value); Oberon.OpenScanner(Ss, gen); IF Ss.class IN {Texts.Name, Texts.String} THEN COPY(Ss.s, gen); newTag := NIL; Oberon.Call(gen, Oberon.Par, FALSE, i); IF i # 0 THEN Texts.WriteString(Wr, gen); Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf) END; IF newTag # NIL THEN e := newTag; COPY(S.value, e.tag); e.next := extTags; extTags := e; 								e.start(S.page) END END END; IF e # NIL THEN e.handle(S, on); found := TRUE END END; WHILE ~S.end & (S.class # CloseTag) DO 					Next(S) END; IF ~found THEN ELSE END END END; S.state := TextHtml END HandleTag; PROCEDURE *DocHandler(D: Objects.Object; VAR M: Objects.ObjMsg); BEGIN WITH D: Documents.Document DO 			IF M IS Objects.AttrMsg THEN WITH M: Objects.AttrMsg DO 					IF (M.id = Objects.get) & (M.name = "Gen") THEN M.class := Objects.String; M.s := "HTMLDocs.NewDoc"; M.res := 0 ELSE TextDocs.DocHandler(D, M) 					END END ELSIF M IS Objects.LinkMsg THEN WITH M: Objects.LinkMsg DO 					IF M.id = Objects.get THEN IF M.name = "DeskMenu" THEN M.obj := Gadgets.CopyPublicObject("NetDocs.HTMLDeskMenu", TRUE); IF M.obj = NIL THEN M.obj := Desktops.NewMenu(Menu) END; M.res := 0 ELSIF M.name = "SystemMenu" THEN M.obj := Gadgets.CopyPublicObject("NetDocs.HTMLSystemMenu", TRUE); IF M.obj = NIL THEN M.obj := Desktops.NewMenu(Menu) END; M.res := 0 ELSIF M.name = "UserMenu" THEN M.obj := Gadgets.CopyPublicObject("NetDocs.HTMLUserMenu", TRUE); IF M.obj = NIL THEN M.obj := Desktops.NewMenu(Menu) END; M.res := 0 ELSE TextDocs.DocHandler(D, M) 						END ELSE TextDocs.DocHandler(D, M) 					END END ELSE TextDocs.DocHandler(D, M) 			END END END DocHandler; PROCEDURE TextColor(col: INTEGER): SHORTINT; VAR r, g, b: INTEGER; BEGIN Display.GetColor(col, r, g, b); IF (0.3*r+0.59*g+0.11*b) > 0.35 THEN RETURN SHORT(Display3.black) ELSE RETURN SHORT(Display3.white) END END TextColor; PROCEDURE EndPage(P: Page); VAR me: Oberon.Task; e: ExtTag; p: Page; BEGIN me := P.task; CloseA(P); e := extTags; WHILE e # NIL DO 			e.stop(P); e := e.next END; Texts.Append(P.T, P.W.buf); WITH me: Task DO 			IF me.S.S # NIL THEN me.S.S.Close(me.S.S); me.S.S := NIL END END; P.D.handle := DocHandler; Attributes.SetString(P.D, "Type", "HTML"); Attributes.SetInt(P.D.dsc, "Color", P.textbackC); IF P.textbackC # Display3.textbackC THEN Texts.ChangeLooks(P.T, 0, P.headerLen, {1}, NIL, TextColor(P.textbackC), 0) END; IF (P.orgPos > 0) & (P.D.dsc(TextGadgets.Frame).org = 0) THEN HyperDocs.ScrollTo(P.D.dsc(TextGadgets.Frame), P.orgPos); IF HTTPDocs0.curNode # NIL THEN HyperDocs.RememberOrg(P.orgPos, HTTPDocs0.curNode, HTTPDocs0.curNode) END END; Texts.Append(P.source, P.Ws.buf); IF P.cacheSource THEN HyperDocs.CacheText(HTTPDocs0.StripLoc(P.docKey), P.source) END; Oberon.Remove(me); p := pages; WHILE (p # NIL) & (p.next # P) DO 			p := p.next END; IF p # NIL THEN p.next := P.next ELSE pages := P.next END; P.task := NIL; Oberon.Collect END EndPage; PROCEDURE *ParseNext(me: Oberon.Task); VAR P: Page; St: Streams.Stream; i, minSize, timeOut: LONGINT; app: BOOLEAN; BEGIN WITH me: Task DO 			P := me.S.page; IF me.S.state # End THEN i := Input.Time; timeOut := i + Input.TimeUnit; me.time := i; 				St := me.S.S; app := FALSE; me.S.avail := St.Available(St); minSize := (* 64 *)1 ;	 (* workaround for hang problem after NetSystem.State change *) IF (me.S.avail < minSize) & (me.S.avail > 0) THEN IF St.State(St) = Streams.closed THEN minSize := me.S.avail ELSIF ~St.buffer THEN minSize := 1 END END; WHILE (me.S.avail >= minSize) & (me.time < timeOut) DO 					app := TRUE; CASE me.S.class OF 						WhiteSpace: WriteSpace(P) |OpenTag: HandleTag(me.S) 						|CharRef: WriteCharRef(P, me.S); P.lines := 0; P.blank := TRUE |Character: Texts.Write(P.W, me.S.char); P.lines := 0; P.blank := TRUE ELSE (* ??? *) 					END; Next(me.S); IF me.S.avail <= minSize THEN me.S.avail := St.Available(St); me.time := Input.Time END; IF (me.S.avail < minSize) & (me.S.avail > 0) THEN IF St.State(St) = Streams.closed THEN minSize := me.S.avail ELSIF ~St.buffer THEN minSize := 1 END END END; me.time := Input.Time; i := 0; WHILE St.eos & (me.S.state # End) & (i < 5) DO (* :-) *) 					app := TRUE; 					CASE me.S.class OF 						WhiteSpace: WriteSpace(P) 						|OpenTag: HandleTag(me.S) 						|CharRef: WriteCharRef(P, me.S); P.lines := 0; P.blank := TRUE 						|Character: Texts.Write(P.W, me.S.char); P.lines := 0; P.blank := TRUE 					ELSE 					(* ??? *) 					END; 					Next(me.S); INC(i) 				END; 				me.S.avail := 0; 				IF app THEN 					Texts.Append(P.T, P.W.buf); INC(me.time, Input.TimeUnit DIV 5) 				ELSE 					INC(me.time, Input.TimeUnit) 				END 			END; 			IF me.S.state = End THEN 				EndPage(P) 			END 		END 	END ParseNext; (* Query a string setting in the NetSystem section in Registry. *) 	PROCEDURE QueryString(key: ARRAY OF CHAR; VAR s: ARRAY OF CHAR): BOOLEAN; 	VAR lKey: ARRAY 32 OF CHAR; S: Texts.Scanner; 	BEGIN 		lKey := "NetSystem."; Strings.Append(lKey, key); 		Oberon.OpenScanner(S, lKey); 		IF S.class IN {Texts.Name, Texts.String} THEN 			COPY(S.s, s) 		ELSE 			COPY("", s) 		END; 		RETURN s # "" 	END QueryString; 	PROCEDURE QueryBool(key: ARRAY OF CHAR): BOOLEAN; 		VAR 			str: ARRAY 16 OF CHAR; 			b: BOOLEAN; 	BEGIN 		IF QueryString(key, str) THEN 			Strings.StrToBool(str, b); 			RETURN b 		ELSE 			RETURN FALSE 		END 	END QueryBool; 	PROCEDURE Parse*(D: Documents.Document; basekey: LONGINT; S: Streams.Stream; head, cache, blocking: BOOLEAN); 		VAR 			me: Task; 			s: HyperDocs.LinkScheme; 			e: ExtTag; 			i, j: LONGINT; 	BEGIN 		imgs := QueryBool("HTMLImages"); 		NEW(me); 		IF (D.handle = NIL) OR (D.Store = NIL) THEN 			TextDocs.InitDoc(D); D.W := HyperDocs.docW; D.H := HyperDocs.docH END; D.dsc(TextGadgets.Frame).do := HyperDocs.linkMethods; NEW(me.P); me.P.D := D; NEW(me.P.T); Texts.Open(me.P.T, ""); me.P.alink := NIL; me.P.clink := NIL; me.P.cacheSource := cache; NEW(me.P.source); Texts.Open(me.P.source, ""); Texts.OpenWriter(me.P.Ws); me.P.next := pages; pages := me.P; me.P.task := me; me.P.docKey := basekey; me.P.handle := Gadgets.objecthandle; me.P.blank := FALSE; Links.SetLink(D.dsc, "Model", me.P.T); me.P.lines := 0; me.P.linkkey := HyperDocs.UndefKey; me.P.textAttrs := NIL; Texts.OpenWriter(me.P.W); me.P.left := FALSE; me.P.linkC := HyperDocs.linkC; me.P.oldLinkC := HyperDocs.oldLinkC; me.P.textC := Display3.textC; me.P.textbackC := Display3.textbackC; Attributes.SetInt(me.P.D.dsc, "LinkColor", me.P.linkC); Attributes.SetInt(me.P.D.dsc, "OldLinkColor", me.P.oldLinkC); me.S.page := me.P; me.P.lists := NIL; NEW(me.P.base); me.P.base.key := basekey; me.P.base.dockey := me.P.base.key; me.P.style := NewStyle; WriteObj(me.P, me.P.style); PopTextAttrs(me.P); me.P.orgPos := 0; me.P.head := head; OpenScanner(me.S, S); IF head THEN Texts.WriteString(me.P.W, "URL: "); Texts.Write(me.P.W, 22X) END; s := HyperDocs.LinkSchemeByKey(me.P.base.key); IF s = NIL THEN s := HyperDocs.LinkSchemeByPrefix("file") END; COPY(s.prefix, me.P.base.prefix); HyperDocs.RetrieveLink(me.P.base.key, me.S.value); IF me.P.base.prefix = "http" THEN me.P.base.key := HTTPDocs0.SplitHTTPAdr(me.S.value, me.P.base.host, me.P.base.path, me.P.orgLabel, me.P.base.port); i := 0; WHILE me.S.value[i] # 0X DO 				INC(i) END; WHILE (i > 0) & (me.S.value[i] # "/") DO 				DEC(i) END; IF me.S.value[i] = "/" THEN me.S.value[i+1] := 0X END ELSIF me.P.base.prefix = "file" THEN HyperDocs.RetrieveLink(HyperDocs.loadingKey, me.S.value); i := HyperDocs.SplitFileAdr(me.S.value, me.P.base.path, me.P.orgLabel); HyperDocs.RetrieveLink(me.P.base.key, me.S.value); me.P.base.key := HyperDocs.SplitFileAdr(me.S.value, me.P.base.path, searchAttr); me.P.base.host := ""; me.P.base.port := 0; i := 0; j := 0; WHILE me.P.base.path[i] # 0X DO 				IF me.P.base.path[i] = "/" THEN j := i+1 END; INC(i) END; me.P.base.path[j] := 0X ELSE (* proxy *) me.P.orgLabel := ""; SplitHostPort(me.S.value, me.P.base.host, me.P.base.port); IF me.P.base.prefix = "ftp" THEN i := 6; WHILE (me.S.value[i] # 0X) & (me.S.value[i] # "/") DO 					INC(i) END; j := 0; WHILE me.S.value[i] # 0X DO 					me.P.base.path[j] := me.S.value[i]; INC(j); INC(i) END; IF j > 0 THEN me.P.base.path[j] := 0X ELSE me.P.base.path := "/" END ELSE me.P.base.path := "" END END; HyperDocs.RetrieveLink(me.P.base.key, me.S.value); IF head THEN Texts.WriteString(me.P.W, me.S.value); Texts.Write(me.P.W, 22X); WriteLn(me.P) 		END; e := extTags; WHILE e # NIL DO 			e.start(me.P); e := e.next END; me.P.D.handle := DocHandler; Attributes.SetString(me.P.D, "Type", "HTML"); Attributes.SetInt(me.P.D.dsc, "Color", me.P.textbackC); Texts.Append(me.P.T, me.P.W.buf); Read(me.S); Next(me.S); me.P.headerLen := me.P.T.len; me.time := Oberon.Time; me.safe := FALSE; me.handle := ParseNext; Oberon.Install(me); IF blocking THEN WHILE me.P.task = me DO 				me.handle(me) END END END Parse; PROCEDURE Show*; VAR T: Texts.Text; D: Objects.Object; BEGIN T := Oberon.MarkedText; IF T # NIL THEN HTTPDocs0.curNode := NIL; D := Gadgets.CreateObject("TextDocs.NewDoc"); WITH D: Documents.Document DO 				D.W := HyperDocs.docW; D.H := HyperDocs.docH; D.handle := DocHandler; Parse(D, HyperDocs.UndefKey, TextStreams.OpenReader(T, 0), TRUE, FALSE, TRUE); Desktops.ShowDoc(D) END END END Show; (** HTMLDocs.Stop * 	Stop all background task for the marked html document. *) PROCEDURE Stop*; VAR S: Attributes.Scanner; doc: Documents.Document; P, nextP: Page; BEGIN Attributes.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Attributes.Scan(S); IF (S.class = Attributes.Char) & (S.c = "*") THEN doc := Desktops.CurDoc(Gadgets.context) ELSE doc := NIL; P := NIL END; IF doc # NIL THEN HTTPDocs0.StopDoc(doc); P := pages; WHILE (P # NIL) & (P.D # doc) DO 				P := P.next END; IF P # NIL THEN HTTPDocs0.StopDoc(P.D); EndPage(P) END ELSE P := pages; WHILE P # NIL DO 				nextP := P.next; HTTPDocs0.StopDoc(P.D); EndPage(P); P := nextP END END END Stop; PROCEDURE *LoadDoc(D: Documents.Document); VAR key: LONGINT; s, so: HyperDocs.LinkScheme; T: Texts.Text; path, label: ARRAY 64 OF CHAR; BEGIN key := HyperDocs.BuildKey(NIL, D.name); IF key # HyperDocs.UndefKey THEN s := HyperDocs.LinkSchemeByKey(key); IF s.prefix = "file" THEN IF HyperDocs.context # NIL THEN HTTPDocs0.curNode := HyperDocs.context.new ELSE HyperDocs.Remember(key, NIL, HTTPDocs0.curNode) END; key := HyperDocs.SplitFileAdr(D.name, path, label); NEW(T); Texts.Open(T, path); TextDocs.InitDoc(D); D.W := HyperDocs.docW; D.H := HyperDocs.docH; Parse(D, key, TextStreams.OpenReader(T, 0), TRUE, FALSE, FALSE); IF (D # NIL) & (D.dsc # NIL) THEN IF HyperDocs.context = NIL THEN HyperDocs.LinkNodeToDoc(D, HTTPDocs0.curNode) ELSE HyperDocs.context.history := TRUE END; IF D.name = "" THEN HyperDocs.RetrieveLink(key, D.name) END END ELSE HALT(99) END; IF (HyperDocs.context # NIL) & (HyperDocs.context.old # NIL) THEN so := HyperDocs.LinkSchemeByKey(HyperDocs.context.old.key); IF (so.prefix = "file") OR (so.prefix = "http") THEN HyperDocs.context.replace := TRUE END END END END LoadDoc; PROCEDURE NewDoc*; VAR doc: Objects.Object; BEGIN doc := Gadgets.CreateObject("TextDocs.NewDoc"); WITH doc: Documents.Document DO 			doc.W := HyperDocs.docW; doc.H := HyperDocs.docH; doc.Load := LoadDoc END; doc.handle := DocHandler; Objects.NewObj := doc END NewDoc; PROCEDURE InitEntities; BEGIN entityEncoding := "ÆÁÂÀÅÃÄÇÐÉÊ&EgraveËÍÎÌÏÑÓÔÒØÕÖÞÚÛÙÜÝáâæà&åãäçéêèðë>íîìï<ñóôòøõö"ßþúûùüýÿ"; entityEncoding[57] := 22X; entityEncoding[66] := 22X; entityEncoding[67] := Strings.Tab; entityEncoding[68] := " "; entities[0] := "AElig"; entities[1] := "Aacute"; entities[2] := "Acirc"; entities[3] := "Agrave"; entities[4] := "Aring"; entities[5] := "Atilde"; entities[6] := "Auml"; entities[7] := "Ccedil"; entities[8] := "ETH"; entities[9] := "Eacute"; entities[10] := "Ecirc"; entities[11] := "Egrave"; entities[12] := "Euml"; entities[13] := "Iacute"; entities[14] := "Icirc"; entities[15] := "Igrave"; entities[16] := "Iuml"; entities[17] := "Ntilde"; entities[18] := "Oacute"; entities[19] := "Ocirc"; entities[20] := "Ograve"; entities[21] := "Oslash"; entities[22] := "Otilde"; entities[23] := "Ouml"; entities[24] := "THORN"; entities[25] := "Uacute"; entities[26] := "Ucirc"; entities[27] := "Ugrave"; entities[28] := "Uuml"; entities[29] := "Yacute"; entities[30] := "aacute"; entities[31] := "acirc"; entities[32] := "aelig"; entities[33] := "agrave"; entities[34] := "amp"; entities[35] := "aring"; entities[36] := "atilde"; entities[37] := "auml"; entities[38] := "ccedil"; entities[39] := "eacute"; entities[40] := "ecirc"; entities[41] := "egrave"; entities[42] := "eth"; entities[43] := "euml"; entities[44] := "gt"; entities[45] := "iacute"; entities[46] := "icirc"; entities[47] := "igrave"; entities[48] := "iuml"; entities[49] := "lt"; entities[50] := "ntilde"; entities[51] := "oacute"; entities[52] := "ocirc"; entities[53] := "ograve"; entities[54] := "oslash"; entities[55] := "otilde"; entities[56] := "ouml"; entities[57] := "quot"; entities[58] := "szlig"; entities[59] := "thorn"; entities[60] := "uacute"; entities[61] := "ucirc"; entities[62] := "ugrave"; entities[63] := "uuml"; entities[64] := "yacute"; entities[65] := "yuml"; entities[66] := "quote"; entities[67] := "tab"; entities[68] := "nbsp" END InitEntities; (** HTMLDocs.ShowHTML 		Display the HTML-source of the marked page. *) PROCEDURE ShowHTML*; VAR D: Documents.Document; node: HyperDocs.Node; P: Page; key, pos: LONGINT; T: Texts.Text; R: Texts.Reader; ch: CHAR; BEGIN D := Documents.MarkedDoc; node := HyperDocs.NodeByDoc(D); IF node # NIL THEN Attributes.GetInt(D, "DocURL", key); P := pages; WHILE (P # NIL) & (P.docKey # key) DO 			P := P.next END; IF P # NIL THEN Texts.Append(P.source, P.Ws.buf); T := P.source ELSE key := HTTPDocs0.StripLoc(key); T := HyperDocs.GetCachedText(key) END; IF T # NIL THEN Texts.OpenReader(R, T, 0); Texts.Read(R, ch); pos := 0; WHILE ~R.eot DO 				IF ch = Strings.LF THEN Texts.WriteLn(Wr); Texts.Delete(T, pos, pos+1); Texts.Insert(T, pos, Wr.buf); Texts.OpenReader(R, T, pos) ELSE INC(pos) END; Texts.Read(R, ch) END; TextDocs.ShowText("HTML", T, HyperDocs.docW, HyperDocs.docH) END END END ShowHTML; (** HTMLDocs.SetImages 	Switch image loading on or off. *) PROCEDURE SetImages*; VAR S: Attributes.Scanner; BEGIN Attributes.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Attributes.Scan(S); IF (S.class = Attributes.Name) OR (S.class = Attributes.String) THEN Strings.StrToBool(S.s, imgs) END; END SetImages; PROCEDURE Check; VAR S: Texts.Scanner; BEGIN Oberon.OpenScanner(S, "HTMLTags"); IF S.class = Texts.Inval THEN Texts.WriteString(Wr, "Oberon.Text - HTMLTags not found"); Texts.WriteLn(Wr); Texts.Append(Oberon.Log, Wr.buf) END END Check; BEGIN COPY(GreekCap, GreekTab); Strings.Append(GreekTab, GreekMin); InitEntities; mono := Fonts.This("Courier10.Scn.Fnt"); IF ASCIIBullets THEN bullets[0].f := Fonts.This("Default12.Scn.Fnt"); bullets[0].c := "*"; bullets[1].f := bullets[0].f; bullets[1].c := "o" ELSE bullets[0].f := Fonts.This("Default10.Scn.Fnt"); bullets[0].c := CHR(29); bullets[1].f := bullets[0].f; bullets[1].c := CHR(28) END; Texts.OpenWriter(Wr); Texts.OpenWriter(Wq); imgs := TRUE; extTags := NIL; newTag := NIL; pages := NIL; dispW := Display.Width; Check END HTMLDocs.

title: Oberon/ETH Oberon/2.3.7/HTMLDocs.Mod


text:
Category:Pages that use a deprecated format of the math tags

__HIDDENCAT__

Pages with deprecated command in  equations. Please visit mw:Extension:Math/Roadmap for the update plan, leave some feedback or join our commission at T195861.

The specific replacement the bot makes inside  tags are

There are some false positives. The minimum false positive example is  indeed anything with an escaped % seems to trigger the category. Report any others at.


text:
School Science/Types of Electric Circuit

An electric circuit is a complete path of electrical current formed by the interconnection of one or more sources with or without electric loads (resistant). Mainly electric circuits are 2 types. They are 1.AC Circuit and 2.DC Circuit. But here are more some kinds of circuit which shown below.

There are 2 types of electric circuit according to the source
They are active circuit and passive circuit. 1.Active circuit- This is a one kind of electric circuit which has one or more active electric sources. 2.Passive circuit- This is a one kind of electric circuit which has no electric source.

There are 3 types of electric circuit according to connection
They are series circuit, parallel circuit and mixed circuit. 1.Series circuit- Series circuit is an electric circuit which has one way for passing the current. 2.Parallel circuit- This is an electric circuit which has more than one way for passing the current. 3.Mixed circuit- Mixed circuit means that a circuit with series and parallel connection.

There are 2 types of electric circuit according to the characteristics of parameters
1.Linear circuit- This is an electric circuit whose parameters are always constant. And No.2 Non-linear circuit- This is an electric circuit whose parameters are non-constant.