text:
User:Jinpeng Li Usyd/sandbox

= The early historic life-cycle of the Florida streetcar system =

= 0. Introduction = Streetcar, or tram/trolley, is a major passenger transport mode in the late-nineteenth and early-twentieth-century urban cities and has become one of the icons of the cities in that time. Now, it can only be seen in a few cities as a heritage railway for tourist attraction or in museums.

First introduced to America in the form of “omnibus”, then after electrification, streetcar networks rapidly expanded in many cities in the United States and peaked in the early 1900s, and then declined after 1930. In Florida, between the period of 1894-1920, 15 urban areas developed streetcar systems.

This article looks into this period of time to provide a detailed life-cycle analysis of the streetcar system in Florida, United States, by conducting both qualitative analysis (US) and quantitative analysis. (dedicated to the state of Florida)

1.1 Before Streetcars
Before the invention of streetcars, the most common urban public transport in North American urban cities is horsebus or so-called omnibus driven by horses operating in regular lines in the city, it is regarded as the first kind of public transportation. While other stagecoaches or carriages are mostly private, the enlarged stagecoach adopted a hop-and-go mode. In 1827, the horsebus/omnibus service emerged in New York, operating on Broadway between Posh Bond St and the Battery (Ephemeral New York, 2011). However, despite the success of omnibus, it still can not fully satisfy the needs of public transport in urban areas. The maintenance of horses or other animals and the limited working hours of horses all limited the business. The industrial revolution prompts urban sprawl and population growth in 19th-century cities, which urges an improved service of public transport. To overcome this, omnibus operators were in the look of refinements that helped to cater for the demand, which propelled the invention of the streetcar. Meanwhile, the technology of the railway is advanced by the introduction of metal rail, and the invention of the steam engine provides the building blocks for the invention of the streetcar. From this, two pathways are developed to advance omnibus: elevated rails and locomotives powered. (Schultz)

1.2 Invention and Technology Evolution
1.2.1 First recognized streetcar in the US

Based on the success of the omnibus, in 1832 John Stephenson introduced the first streetcar to New York. It was still driven by horses but running on a rail laid in the street on The Bowery. This innovative refinement allows streetcars to carry more passengers, increase the travel distance, and make the journey smoother. This improvement led to a rail network that had a larger coverage of the city. (Builders of Wooden Railway Cars, 2006)

1.2.2 Steam-powered streetcar

To substitute the primitive animal power, the steam engine was transplanted from rail locomotive to streetcar and defined as a tram dummy. Certain standards were established to ensure the operation of steam-powered trams will not cause disruption in the urban setting where lots of horses were still on-street. Safety prevention is done by enclosing the wheels, and the engine is confined to decrease the noise. To avoid generating a black fume of smoke, coke instead of coal is used as fuel. And to decrease the disruption of another emission steam, devices such as superheating and condenser were deployed to make it invisible. Despite all these efforts, steam-powered streetcars or steam dummies were hard to popularize due to the underpower issued caused by the limited engine room and the higher operating cost than traditional horse-powered ones. It is gradually replaced by electric power. (Wingler, 2019)

1.2.3 Cable-hauled streetcar

The cable-hauled streetcar is another motive alternation to improve the streetcar at the time. The cable technology has been employed by Andrew Hallidie in mines to transport ores and coals. But the idea of controlling the grip and release of the constantly rolling cable is an innovation that makes it possible to stop at the stations and to be used on streetcars in the city. After being designed by Andrew Hallidie, San Francisco was the first city in the world that owns a cable car. A powerhouse where steam engines are burning coals to provide power to drive the cable. The moving cable was put underground inside a channel, and the streetcar pulls on this cable through slots with the grip. (Cable Car Museum San Francisco) The hilly terrains in San Francisco make it an ideal operating environment for the cable car. However, the downside of the cable car system is the expensive construction cost. Hence, it is only feasible in highly demanded lines. (Schultz)

1.2.4 Elevated railway

The elevated railway is an exclusive track that is elevated above street level for streetcars to operate in order to separate the streetcars and other traffic flows on the street. This method could eliminate the mutual disruption of streetcars and other street users such as horsecars, and pedestrians. While the capacity for streetcars operating in elevated railway is increased, the construction cost also goes up. Therefore, it is only economically possible in major cities such as New York and Chicago. (Schultz)

1.2.5 Electrified streetcar

Electrification is a game-changer in the streetcar market which facilitated the blossom of the streetcar in the US. The first attempt to electrify the streetcar was through the use of batteries by Thomas Davenport in 1835. But the short range of this type of electric power tram limits its practicality. Then only after the technology development of dynamo and motor, the electrified streetcar is feasible. In 1888, Frank Sprague constructed the Richmond Union Passenger Railway in Virginia with the technology of electric cars. His streetcar is powered by a mounted motor and collects the needed electricity from the hanging cables with a trolley pole. He further refined his streetcar by his multi-unit control invention, which combined various rolling stocks together as one unit, this inspired today's subway. His streetcar system came out as a huge success which soon spread all over the US, in 12 years time, the electric streetcar took over almost the entire streetcar market. (Streetcars in The USA (Trains): Definition & history)

Originating from the omnibus, the evolution of streetcars took around a century. From driven by animals such as horses and mules to powered by electricity. The evolution of streetcars also reflects the industrialisation of 19th-century cities. Engineers from different fields propelled the evolution of streetcars with various technology and improved them from different pathways. To improve the operating environment, steel tracks are laid and elevated railways are built. To find the best power unit, several attempts are made such as steam-powered, cable-hauled, battery-powered, gas-powered, and then electrified streetcar turns out to be the optimal solution.

1.3 Market development
The early market niche of the streetcar system is discovered by the omnibus system. After industrialisation, urban populations fastly grew, and the urban sprawl separated and increased the distance of the industrial/business zone and residential zone. A public transport mode that can be economically practical for passengers to conduct their daily intra-urban trips was in great need. The emergence of the omnibus in New York in 1827, filled the blank of mass public transport and changed the lifestyle of many middle-class people in New York City. And then the first streetcar opened five years later in the same city, the metal rail allowing the horse-pulled car to carry more people thus increasing the supply of streetcar. The streetcar network was also expanded in the city. The later technology improvement on the motive parts such as steam engine and cable also increased the capacity, working hours, and speed of streetcar, which furtherly increased the supply of streetcar systems. However, only routes in major cities that have great demand can match the supply due to the expensive construction cost of these systems. Hence, these systems only expand the streetcar markets in major cities such as New York, and Chicago. It is not until the late 19th century after the electrification of the streetcar system, the streetcar market finds its revolutionary change. The electrified streetcar is not only quieter, cleaner, more efficient than the other old streetcar systems, which makes it the most ideal to operate in the urban area, but also more economically practical. More routes that have less demand can be covered in the streetcar network, and more people can use the streetcar service because of the lower fare cost. Furthermore, more cities that own a smaller population now are economically feasible to develop streetcars. This advancement of the streetcar system also shapes the way urban cities grow, people now can live further away from the city centre.

1.4 Policy and Growth of the Mode
Sprague’s great invention in 1888 marks the wild growth of the electric streetcar, in around a decade, 15,000 miles of track was laid and took over the entire market share of the streetcar system. (Streetcars in The USA (Trains): Definition & history)

And the annual patronage rapidly increased from two billion to five billion, which is a 250% increase in the period of 1890-1905. (Young, 2015)

In those days, the streetcar was a very profitable industry owned by private investors such as streetcar builders, private bankers and so on. And later the improved accessibility which could raise the land value got real-estate developers interested in investing streetcar business. At the raising phase of streetcars, all streetcar systems no matter cable-driven, steam-powered or electrified require a large amount of upfront investment to build the infrastructure. To scale up the investment return, these streetcar owners turned into “traction magnets” that developed monopolies on the streetcar network in each city. Some monopolies were achieved by contracting with the local government and becoming municipal franchises. The contract with governments often included terms such as constant fare price, the obligation of maintaining trackside pavements.

This kind of business model foreshadowed the fading of the streetcar in the later competition of automobiles. (Stromberg, 2015)

1.5 Development at the mature phase and revival.
The development of streetcars started to slow down in the 1910s and go downslope in the 1920s, which is the time that automobiles became common. The strong competition from automobiles was reflected in the drop in ridership. The inflation from 1910 forced street companies to reduce investment due to the raised raw-material cost, labour cost, and maintenance cost. And even worse, many franchises can’t adjust the fare price due to the constant fare rate agreement with the governments. And based on the fact that since the invention, the streetcar has been mostly a private sector instead of public, and it was perceived as an often corrupted business with the government, hence no subsidy or support from the public side was provided. And after the development of economics and mass transport, the market was rather mature and demanding better services from different user groups. All these factors contributed to the decades-long decline of streetcars. After the introduction of automobiles in the 1920s, automobiles, in comparison to streetcars, provided much higher mobility and degree of freedom, and they did not need to pay any fees for using the road. And politics also impacted the streetcars cruelly. In 1924, an official policy of buses over streetcars was established, despite the given technical facts that streetcar might be more advantageous than the bus in easing congestion and solving other urban transport issues. After 1924 even the streetcar companies shifted to buses because of the flexibility of buses and the cheaper investment in the bus fleet, and another important reason is that it is regarded as a way to bypass the fixed fare rule and the pavement maintenance obligation. (Schrag, 2000). The great depression in the 1920s accelerated these transitions. Then during World War II, streetcar ridership reached its highest ridership record in history due to fuel control, and the halt in automobile and tires production. Yet this can not save streetcar transit from its doom, instead, it strengthened the public’s determination to own an automobile due to the horrible travel experience on crowded streetcars. The government took over the streetcar business in the 1950s but failed to recover. (Young, 2015). Meanwhile, all government levels were prioritizing motorways in urban planning, which promoted the automobile mode (Stromberg, 2015).

Barely any street system survived today, and the ones do mostly serve as heritage trolleys that attract tourists and remain as a symbol of city history.

After the subsidy by the federal government, collaborations between city mayors and railway companies started to happen. And in 1964 President Lyndon Johnson established the Urban Mass Transportation Act (UMTA) which allows the federal government to invest in transit projects for the value of up to two-thirds of the total project cost. Using the fund provided by the federal government, local cities started the wave of buying up private systems. When it comes to the 1970s, the growing concern of the environmental impact of automobiles, and the revisiting the priority of cars, roads in urban design enlightens the new vision of mass transit. (Young, 2015)

Since the 1980s the streetcar is making a comeback in some cities in a slightly new form, “Light Rail Transit” to tackle the urban transport issues again and compete with automobiles again on this same battlefield. Thanks to its cleaner energy, quiet operation, and high capacity. Light rail is adopted by many cites to be the solution for urban congestion, motor vehicle pollution and a favourable option of urban mobility.

= 2. Quantitative Analysis = A quantitative analysis has been conducted to evaluate the life-cycle of streetcar systems in Florida. The analysis period is from 1894 to 1920. In this period of time, 14 streetcar systems in various urban areas in Florida had been developed. Among these systems, there were horse-pulled tracks in small population areas such as Fernandina, Fort Meade, Daytona, Palatka, Orlando. And in major urban areas such as Jacksonville, Pensacola, and Tempa electrified streetcar networks were developed.

2.1 Data Source
The data input for this analysis (Track Miles) is extracted from “Mcgraw Electric Railway Manual: The Red Book Of American Street Railway Investment 1894 - 1920”.

2.2 Methodology
To distinguish the four different phases: birthing, growth, and maturity, S-curve is used to fit the data. The S-curve is a logistic function that contains three parameters: S(t) reflects the status in this case the track miles, t is the year, and t0 is the year when 1/2k(half of the total market size), K which is the total developed market size, and b is the coefficient.

S(t) = K/[1+exp(-b(t-t0)]

To perform the regression analysis that finds the best-fit K value, the above function is derived into this linear form:

Y = bX + c

Where

Y = LN(Track/(K-Track Miles))

X = Year

b is the intercept

c is the constant

K values are assumed based on the final year market size (Track Miles). After linear regression analysis, the best-fit K value (which owns the highest R-square value) is picked, and the coefficients of b and c are then calculated. (Garrison & Levinson, 2006)

2.3 Results
Jacksonville Comments:

The prediction has a good fit. The prediction plot reflects the overall trend, and only some discrepancies at the birthing and mature phase.

Tampa Comments:

The prediction has a good fit, with several major discrepancies at the birthing and sudden increase at 1907, but accurately reflects the overall trend.

Pensacola Comments:

The prediction has a good fit.

St. Augustine Comments:

The prediction does not fit with the record data that well, possible reason for this is maybe the St. Augustine is already in a mature phase, the track mile is in stagnation, hence the s-curve can not fit too well.

St. Petersburg Comments:

The prediction fits okay, with some discrepancy at the growth phase, but converges with the recorded data at the mature phase. Possible reason for the discrepancy is the insufficient record years.

Keywest Comments:

The prediction has a bad fit, possible reason is that the Key West system is quite extreme: mainly in stagnant phase stays at five miles and then a sudden increase at 1907, then back to five miles. S-curve can not fit into this untypical development mode just like the St. Augustine scenario.

2.4 Conclusion
The development of streetcar systems in Florida generally accords with the entire US trend, especially in the major urban regions with track networks that have more than 50 miles, such as Jacksonville and Tampa. And in the cities that have relatively small streetcar networks - track miles less than 20 miles, and small populations such as Key West, St Augustine. The streetcar systems were less in accord with nationwide trends, and more catered to the local special needs such as tourism/sightseeing.

By the US nation trend, it means after the “birthing phase” in the 1890s, the streetcar networks in all major urban cities in the nation entered the rapid growth phase after electrification. And till World War, I in 1914, and the generalization of automobiles, the streetcars systems in Florida entered the mature phase and slowed down in growth rate. Then by the end of 1920, most of these streetcars except Tampa, and Jacksonville all went into a slow decline.

3. Reference
Garrison, W. L., &amp; Levinson, D. M. (2006). The transportation experience: Policy, planning, and deployment. New York: Oxford University Press.

How cable cars work. (n.d.). Retrieved March 22, 2021, from http://www.cablecarmuseum.org/mechanical070714.html

How New YORKERS commuted to work in 1830. (2011, October 27). Retrieved March 22, 2021, from https://ephemeralnewyork.wordpress.com/2011/10/27/manhattans-earliest-form-of-mass-transit/

John Stephenson car Co. - page 3. (2006, April 11). Retrieved March 22, 2021, from https://www.midcontinent.org/rollingstock/builders/stephenson3.htm

Schrag, Z. M. (2000, January). The bus is young and honest. Retrieved March 23, 2021, from https://www.jstor.org/stable/25147453

Schultz, C. (n.d.). Trolley: The cars that built our cities - narration script. Retrieved March 22, 2021, from http://www.transitgloriamundi.com/trolley_videos/trolley/narration.html

Streetcars in The USA (Trains): Definition & amp; history. (n.d.). Retrieved March 22, 2021, from https://www.american-rails.com/streetcars.html

Stromberg, J. (2015, May 07). The real story behind the demise of AMERICA'S once-mighty streetcars. Retrieved March 22, 2021, from https://www.vox.com/2015/5/7/8562007/streetcar-history-demise

Wingler, F. A. (2019, September). From the 1832 Horse pulled Tramway to 21th Century Light Rail Transit/Light Metro Rail - a short History of the Evolution in Pictures. Retrieved March 23, 2021, from http://www.drwingler.com/wp-content/uploads/2019/08/FROM-HORSE-PULLED-TRAMWAY-TO-METROLIGHT.pdf

Young, J. (2015, March 02). Infrastructure: Mass transit IN 19th- and 20th-Century Urban America. Retrieved March 22, 2021, from https://oxfordre.com/americanhistory/view/10.1093/acrefore/9780199329175.001.0001/acrefore-9780199329175-e-28?mediaType=Article

title: User:Jinpeng Li Usyd/sandbox


text:
Transportation Deployment Casebook/2021/Texas Streetcar

Texas Streetcar Overview
The streetcar’s introduction in the late nineteenth century consisted of progressive methods such as horse-drawn, steam, gas and electric pulled carts on a rail-line that brought many positive opportunities communities impacted by them. Before being known as light rail, the streetcar had a major influence on the development of the suburbs and provided a range of services such as the transport of people and goods. . These new networks within communities and cites were called tramways and they shared the spaces between buildings called roads with pedestrians, horses and in the twentieth century, the automobiles. Additionally, improvement to existing road and infrastructure and more recreational areas and faster transport within these cities and communities. The introduction of the first streetcar in Texas was in Dallas in the 1870s and was quickly followed by Austin and many other cities within Texas.

Technology characteristics
The streetcar system was a method of transport that consisted of a singular vehicle’s movement on road bearing steel wheels on a laid-out network of cast iron strap rails tracks. As a result of the introduction of these rails, the capacity of the vehicle could grow from the decreased friction and subsequently better riding conditions for the passengers. The early streetcars within America consist of horse or mule-drawn and steam-powered and after the invention of the generator, the implementation of powered overhead wires and tracks began which resulted in electric streetcars which had a capacity of 40 passengers.

Main advantages & Markets
After the implementation of streetcars, the cities which were called “walking cities”, now had better and easier access for the new and growing communities called suburbs. This is from easy access to the city to work, away from the city its less overcrowded. This resulted in the new ideology of the “American dream” to start a family within the suburbs with more land and a larger home with easy access to the cities. This system also allowed for better access and transport of goods around the city and people would not be resisted to local venders for these goods. The transport investments started to rise from banks and rich individuals finically supporting this new transport network. Promotion to real-estate outside the city creating more wealth, the acceleration of more population growth. This new market of the streetcar predominately existed for the middle-class worker, where these workers started to settle in the outskirts of the cities known as suburbs. These suburbs were more spacious and quieter when compared to the city center. The companies that controlled these street cars raised revenue through fees based on the distance the passenger or goods travelled and high net worth individuals saw protentional in this system scalability of this network.

The Previous Transportation Methods
The previous transportation methods before the streetcar were the Horse car, Omnibus and cable car within America. Omnibuses were implemented and used in the early 19th century with horse/mull drawn carriages, this was then followed by the cable car mid-19th century, this mode of transport involved cables that guided the car between rails with steam-powered trolley powering the drive. This method of transport was invented by Andrew Hallide. There were major logistics and functioning errors such as jamming or breakage of the cables resulting in a halt in the transportation line. These problems were rectified from the introduction of the electric streetcar that began to replace the omnibuses and cable cars in the early 20th century. Before the introduction of the electric streetcar, there was a short-lived early version of the streetcar called dummy engines often having large public backlash over the high levels of pollution and noise coupled with damages caused by horse and mull-drawn carriages resulted in a need for future development of this current transportation system. Furthermore, the use of horse-drawn carriages had major drawbacks such as high maintenance cost, a large degree of risk associated with livestock disease, large waste build-up and capped usage from these animals. This resulted in large inefficiency in the network meaning that was an opening for a better form of transportation within these networks. These limitations incentivized improving and implementing new methods for powering the carriage and the first practical battery-powered electric car was built by French and English inventors; This idea of an electrically powered system solved the high levels of pollution and noise and further development into these electric carriages resulted in fully powered connected carriages. As a result of the limited range, a developing form of gasoline power carriages emerged, and the reliance on powered lines and batteries quickly diminished. This new and evolving market of the streetcars helped the transport industry rise but, this industry became too limited and the rise of government and corporate development through investment and policy help drive the consumer choice for busses and car making trolleys more obsolete[6]. By 1937 almost 50% of the public transport network was busses within America and this new reliance on busses from the great depression the use of automobiles and rail network became more popular and the electric streetcar began to phase out of the transportation system.

Birth of electric streetcar
Previously, the horse-drawn streetcar was popular due to their implantation into a sector that wasn’t there. This was then closely followed by mulls as they were cheaper overall and just as strong as horses. Many transitions into other forms of drive for the streetcar then the birth of the electric battery for the locomotive was in the 1860s but the initial idea began in the 1820s. During the first successful commercial implementation of the electric railroad systems in 1881 made by Ernst Werner von Seimens, but safety factors influenced societies opinions on his technical design by shocking people and animals from the power travelling through the rails, this led to the development of overhead wires to supply these electric streetcars invented by Charles J. Van Depoele. In America engineer, Frank J. Sprague was given credit for the implementation, growth of the current electric streetcar, spring-mounted, two gear-drive motor, independent framed carriages from the existing system especially in New York. After the electric grid was implemented in America, the generation, transmission and storage of electricity made the electric streetcar easily applicable in any scenario. The first successful streetcar line in Texas was found in Austin, this was a horse/mull driven line. In 1891 the first electric line was introduced in Austin by a developer from Kansas, Monroe Shipe, and this rapidly expanded with many more investors building tracks within Texas over the next 20 years. This expansion of the overhead electric streetcar was quickly introduced everywhere, and the first practical method was introduced by Frank J. Sprague in 1888. The rising popularity of this electric streetcar system shows improvement such as the carts themselves being replaced with lighter wooden framed, four-wheeled cars from steel-bodied, eight-wheeled cars.

Market development
In 1897, the total mileage of track within Texas was 192.15, with each city and town having multiple transits companies operating with one rail track as their equity. At this time there was already five times the amount of electric streetcar when compared to horse and mull, 20 year later in 1912, horse and mull powered streetcars were phased out and just over 1100 miles of electric streetcar track are functioning within Texas and this transition was due to the cost and logistic advantage over the horse and mull streetcar. The electric streetcar system had niche variants such as the intercity powerlines called interurbans providing services to the outlying areas which proved to be profitable over railroad networks due to the railroad network prioritization of the long-distance travelling passengers and freight services when compared to the small commuter services. The transition into this era of the electric streetcar showed a more cost-effective, reliable, safer, and quicker method of transport over its predecessor streetcars such as the horse and mull etc.

Policy
The streetcar system was financed by private equity meaning that the streetcar was policy-driven and a form of restricted capitalism. As such large amount of private wealth could be generated from this industry sector, such in the late 1800s for economic and safety the reliance on animals started to vanquish, resulting in the publics agreeance for fossil fuels become relied upon as the main source of energy. The policy was a driving factor for the standards required to provide a streetcar network. When the multiple streetcar system emerged, cities began making policies to guide and ensure fair practices. Including fair policy for both consumer and business. Public policy controlled by local members of the city governed fare pricing being roughly locked in at about 5 cents, safety requirements and controlled the charters which were franchised out to private investors. These policies aided the public usage of the streetcar system to grow for new and existing line distributing into suburbs and with these low fares making cheap, safe and simple to travel around the city and suburbs.

Streetcar lifecycle
The industrial revolution aided the growth of the streetcar to result in easier and quicker methods for the movement of people and goods resulting in the aid in population growth. Many cities and towns adopted the streetcar system as it helped the communities grow and prosper, new streetcar track systems were being formed while existing ones were quickly extended into surrounding suburbs. In Austin Texas, the importance of these streetcar systems was known to the city officials and one a major infrastructure project such as the Congress Avenue Bridge which was built across the Colorado River, Streetcar links were quickly added to expand the network throughout south Austin which wasn’t fully connected [6]. As such, the line around Austin was becoming uniform and connecting to make a large network which resulted in upgraded and double-tracked to increase the service capabilities and better services.

The streetcar system growth in Austin slowed down and peaked by the mid with 23 miles of track for the population of 40,000. Furthermore, this peak and decline were from the competing method of transport the automobiles, once passengers started to deviate from the streetcar system, farebox income wasn’t enough to keep the streetcar system serviceable. Many cities, such as Austin quickly started to shrink their networks, only keeping profitable networks at the time, with San Antonio becoming the first major city to discontinue its electric streetcars in 1933, being replaced by buses. Soon after the city of Austin followed suit and in 1940, Mayor Tom Miller rode the last electric streetcar along Congress Avenue. Most rails that were left in the ground were excavated in 1942 for World War two when there was a storage of metal. Overall the reason for failure with the streetcar system not just in Austin but in most states of America was the increased operating expenses, Low fare prices affecting revenue, Increased usage of the automobile and poor policy affecting this transit model. However, the rise in streetcars in returning with Sydney Australia recreating a better and improved network from the congestion created from personal and road sharing automobiles

Model analysis
This is a Lifecycle analysis of the Texas streetcar system of electric, petrol/gass and horse-driven streetcar between and with a logistic function applied to model the predicted lifecycle of the transport mode. The model will predict the technological advancement of the streetcar and analysis and predict with an s curve for the birthing, growth, maturity, decline.

Model definition
A three-parameter logistic function that were used for the model is shown using the equation below:

S(t) = Smax/[1+exp(-b(t-ti)]

where:

 * S(t) is the status measure, (e.g. miles of completed track)
 * t is time (years),
 * ti is the inflection time (year in which 1/2 Smax is achieved),
 * Smax is saturation status level
 * b is a coefficient to be estimated.

Due to this data involving a short timeframe, not all lifecycle stages would be recorded within each system of streetcar values. A single variable linear regression system was used for the estimates with the Ordinary Least Squares Regression with estimated values of K & b shown in the formulas below.

 * Y = bX + c
 * Y=LN(Miles/(K-Miles))
 * X=Year

Within this model there was missing data and years, so the complete uninterrupted consecutive years was used and estimates for 1915 and 1916; between 1897-1920, this restricted time frame caused some aspects of the lifecycle analysis to be missing as mention previously.

Texas Data
The three streetcar systems found in Texas with more than one year of use was the horse/mull, electric and petrol/Gas streetcars. The measured data is between 1897-1920. Although steam and battery power were an existing system, they did not have more than two consecutive years in this data set. If the data wasn’t included between time spans but had a data point that was the same or more later one, e.g. five year apart with zeros in between those two data points the zero would get filled with the first reference data point. Overall, the electric streetcar showed at least 2 stages of the lifecycle which include birth, growth, maturity and decline within this data set. All graphs display the Miles of track against the year, with a table is coupled with each figure showing the respected parameters which include estimated saturation, the coefficient and inflection time.

Combine Total Miles
The total mileage on all systems showed a clear trend indicating the lifecycle phases of growth and maturity. Although, the data used does not show much birthing of decline stage this is due to the study period being too short. The first figure shows the total measured and predicted track mileage for the combined streetcar systems coupled with the parameters in table 1.

Table 1 Combined streetcar Variables

Electric total Miles
The model recorded both growth and maturity stage for the streetcar lifecycle with the point of inflection in 1908, the inflection is where the rate at which it increases starts to decrease. As such, the growth stage within this model is approximately 1997 to 1908 and the maturity is assumed to be after the time frame. Overall, the time frame used clearly shows two aspects of the life cycle growth and maturity, while the birth and decline is extended past the measured timeframe. Figure 2 shows the total measured and predicted track mileage for the electric streetcar systems coupled with the parameters in table 2.

Table 2 electric streetcar Variables

Horse/Mull Total Miles
The horse/Mull system that is recorded shows the decline stage of the streetcar lifecycle system when compared to the other forms of the streetcar. This is because the other modes of streetcar were slowly replacing this mode. As such, the model indicates the decline stage of the streetcar lifecycle system. Figure 3 shows the total measured and predicted track mileage for the Horse/Mull streetcar systems coupled with the parameters in table 3.

Table 3 Horse/Mull streetcar Variables

Petrol/Gas Total Miles
The petrol/Gas streetcar system model shows some aspects of an S-curve shape similar to the electric system. The birth phase is seen in 1907 with growth seen in 1910. As such, the development of the petrol/gass Lifecycle happened after all other models and the accuracy of the model is analyzed below. Figure 4 shows the total measured and predicted track mileage for the Petrol/Gas streetcar systems coupled with the parameters in table 4.

Table 4: Gas/Petrol streetcar Variables

Accuracy of the model
The data presented show that at least one model exhibits one section of the lifecycle with the electric streetcar actual data that is recorded showing a clear spread of the lifecycle compared to the other models. In terms of the petrol/Gass model, what is shown is the birthing and growth stage in terms of the approximate trend given by the S curve. The horse/Mull model shows the most inaccuracy due to the small spread of data; as such, the data is seen to have a clear decline stage but the K value is set at 95,000, which produces the best line of fix for the estimate with the actual data recorded. Although this K value works with the data presented, the actual total miles of the horse/mull system is almost impossible to be 95,000 miles in Texas. The source of the data could have some inaccuracies due to the missing data and some pages ineligible and cut off sections of the pages resulting in data that can increase the errors in the recorded data for the models developed. The results for the regression in each streetcar system presented in table 5.

Table 5: Regression Results The checks for fitness is found in an R Squared analysis, the closer the values are to 1, the more of the recorded points within the model fall on the regression line, Also, the t stat test determines the statistically significant of the model and in relation to combined, electric and petrol/gass model, all these modes have high values meaning they statistically significant at the 95% confidence level. The combined and the electric mode have small P-values compared to the other 2 models meaning that there estimated coefficients for these tests are reliable and accurate.

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


text: Category:Shelf:Shogi/all books

title: Category:Shelf:Shogi/all books


text: Shelf:Shogi/ancestry

title: Shelf:Shogi/ancestry


text: Category:Book:Shogi Opening Theory

title: Category:Book:Shogi Opening Theory


text:
User talk:Lee2021

Welcome!
Welcome to Wikibooks, Lee2021!

 First steps tutorial Wikibooks is for collaborative development of free textbooks.

You do not need technical skills to contribute. You can easily change most books. Please introduce yourself, and let us know what interests you.

If you already contribute at other Wikimedia projects, our Wikimedia Orientation should quickly get you started. (Would you like to provide feedback on this message?)

  Getting help   Made a mistake?   Goodies, tips and tricks
 * Read the Using Wikibooks book for a friendly introduction to the project, or our help pages for more information.
 * You can get friendly help from the community in the user assistance room or our IRC channel.
 * Upload freely licensed files to Wikimedia Commons. You may request permission to upload fair use files locally. Please include author and source information and a non-free use rationale for non-free files.
 * You can restore a previously saved version.
 * Pages should follow the  naming convention.
 * Need to rename a page? Use the move tab (is available once your account is 4 days old - until then, ask for help).
 * To request a page be deleted, add to the top of the page.
 * Was a page you made deleted? Please read the deletion policy, and check the deletion log to find out why. Also check the RFD archives if applicable. You can request undeletion at WB:RFU, or ask the administrator who deleted the page.
 * Please fill in the edit summary and preview your edits before saving.
 * Sign your name on discussion pages by typing ~~~~
 * User scripts can make many tasks easier. Look at the Gadgets tab of my preferences; check off the boxes for the scripts you want, and hit save!

-- Jules (Mrjulesd) 14:32, 6 April 2021 (UTC)

title: User talk:Lee2021


text:
User:Muhammad Hashim khan kakar

My Name is Dr,

Muhammad Hashim Khan kakar from Barshore Union e.l.la

title: User:Muhammad Hashim khan kakar


text:
User:উজ্জ্ব্ল সিকদার/sandbox

Trigonometry Trigonometry Formulas Limit_(mathematics) Logarithm Derivative Applications_of_Integration Calculus.pdf

authors: উজ্জ্ব্ল সিকদার

title: User:উজ্জ্ব্ল সিকদার/sandbox


text:
User talk:DinosaursRoar

You cannot edit for 1 week due to vandalism. You are welcome to contribute constructively when editing privileges are restored. You may appeal this action with a reasonable argument by adding the text below. -- Jules (Mrjulesd) 20:53, 6 April 2021 (UTC)

title: User talk:DinosaursRoar


text:
User:6669666Project6669666

6669666Project6669666

title: User:6669666Project6669666


text:
User:Harris2300

My name is Tanya. I am from Los Angeles, California. I am an Eligibility Worker with the County of Los Angeles Department of Public Social Services.

title: User:Harris2300


text:
Oberon/ETH Oberon/2.3.7/PPP.Tool

$VCS   6, Edgar@EdgarSchwarz.de, 06.06.00 21:34:10 $ Welcome Version 1.2.0, 06.06.2000 by Edgar@EdgarSchwarz.de - PAP password now set with NetSystem.Setuser. You can configure several providers with different passwords now. Version 1.1.1, 09.05.2000 by Edgar@EdgarSchwarz.de - Running already on Beta 25.04.2000 (just because thats my working system just now :-) - Logging now to a own text. Open with PPPTest.ShowLog. - If server doesn't tell his IP-address ask for it. - Still a problem with at least one ISP with PAP. - Sometimes connection goes down after a while (idle time ?). Not yet clear what happens, because I also have some problems now under windows, since my   provider changed to new nationwide (Germany) phone number. Version 1.1.0 06.09.1999 by Edgar.Schwarz@z.zgs.de. - Logging changed to kernel log (shown interactive with System.OpenKernelLog) - Echo requests without data handled correctly - es.PPP.Tool without outlines - some small corrections/clarifications Version 1.0.0 28.02.1999 - First versioned release. BTW, some technical stuff :-) "<" something ">" means: insert the stuff that's right for you. Stuff between "[" and "]" is optional. For setting up PPP you should read System.Text first. If you then have probems you can use this document for additional information. If you have any comments or proposals for this document just send me a mail. What is PPP PPP means 'Point to Point Protocol' and is basically a specification how two computers can communicate and exchange data. It also specifies how PPP server and client can negotiate certain parameters. Maximum packet size, compression techniques and so on. The PPP packet provides services PPPHDLC.SendPacket and PPPHDLC.ReceivePacket which the can be used e.g. by TCP/IP. This implementation is configured to communicate with a COM port. In principle it's also possible to use Ethernet, ISDN or whatelse. It's just necessary to change the interface to the hardware. PPP is described in RFC (Request for Comment. These are Standards really, just the name is a little misleading) 1584. Also of interest is RFC 1172 on IPCP (PPP Internet Protocol Control Protocol) and RFC 1334 on PPP Authentication Protocols. Creating Release ET.Call System.CopyFiles "es.* => *" ~ VCSPacket.NewPacket PPP.Pkt PPPDebug.Mod PPPTools.Mod PPPHDLC.Mod PPPFSM.Mod PPPIPCP.Mod PPPPAP.Mod PPPLCP.Mod PPPMain.Mod PPPTest.Mod PPP.Tool ~ Compress.Add PPP.1.2.0.Arc ^ Add \s if necessary. Installing PPP Compiler.Compile PPPDebug.Mod PPPTools.Mod PPPHDLC.Mod PPPFSM.Mod PPPIPCP.Mod PPPPAP.Mod PPPLCP.Mod PPPMain.Mod PPPTest.Mod ~ Add \s if necessary. What does PPP do First I will give you a sketch, which parties are involved if you are connected with less detail on the ISP side. ISP																					YOU ---																				  --- 	Web sever															 HTML, Mail, ftp TCP/IP															TCP/IP a device PPP													PPP serial interface modem							modem phone line TCP/IP uses a device. This is by default the device which is set for Oberon.Text:NetSystem.Hosts.Route0 which at the moment means Device0. Now you have to tell PPP which device and which serial interface it should use (set it in Oberon.Text:NetSystem). Finally you have to configure setting up your modem connection to your ISP and starting PPP when done (set it in Oberon.Text:). Using PPP In Oberon.Text you can define profiles for ISPs. My ISP is "StZ". - setup Setting stuff like described in System.Text. Also see chapter 'My setup' below. - initialisation > NetSystem.Start > NetSystem.SetUser dialup:z974hzb@StZ ~ set password for user "z974hzb" - connect > Dialer.Dial StZ device0 ~ After the modem is connected and the script is finished you get a 'IPCP is finally up' in System.Log. Now you can access the WWW. If you don't get the 'IPCP is finally up' then see below. - disconnect > PPPMain.StopInst Some more information in case of problems My setup in Oberon.Text NetSystem = { Hosts = { Domain = { "zgs.de", "" } DNS0 = { "dns0", "195.145.135.1" } DNS1 = { "dns1", "195.145.135.2" } Device0 = {"PPPMain.InstPPP", "COM1"} Route0 = { Device = "Device0" Mode = ""	{* "arp" for LAN, "" for PPP or SLIP *} } 	} 	SMTP = "zmail.zgs.de"	{* outgoing mail server *} POP = "zmail.zgs.de"	{* incoming mail server *} NNTP = "znews.zgs.de"	{* news server *} POPMode = "POP3"	{* POP3 or APOP *} EMail = "Edgar@EdgarSchwarz.de"	{* your return address *} MailSignature = "Mail.Sig.Text"	{* appended to every outgoing mail *} NewsSignature = "News.Sig.Text"{* appended to every outgoing news *} ProxyDomain = "zgs.de" {* optional *} HTTPProxy = "zproxy.zgs.de:8080" NewsThreading = Yes	{* Newsreader keeps message threads together? *} 	NewsFont = Courier10.Scn.Fnt	{* Font for news articles *} HTMLImages = No	{* Download WWW images with background task? *} 	KeepURLs = Yes KeepCache = Yes     {* only valid if KeepURLs = Yes *} } {* profile for my ISP (Stuttgarter Zeitung) *} StZ = { Init = { COM1 38400 }	{* modem port and speed *} Dial = { "ATZ" 10 "OK" "ATD 07111324300" 60 "CONNECT" 10 "Login:" USER 20 "word:" PASSWORD 20 "PPP Mode." CALL PPPMain.StartInst } In case your provider uses PAP (Password Authentication Protocol) you should set the PAP parameters and try the following dial script. Your provider probably uses PAP or CHAP (not yet supported) if you don't receive anything like 'Login' or 'Password'. = { 	Init = { COM1 38400 }	{* modem port and speed *} Dial = { "ATZ" 10 "OK" "ATD " 60 "CONNECT" CALL "PPPMain.StartInst " } } You set your PAP authentication by the usual way with NetSystem: NetSystem.SetUser pap: [: ]@ ~ Some more or less common problems already encountered - A provider had a PPP server which wanted to configure illegal configuration options which I discarded. I changed my code to refuse these options. - Be sure you don't have a typo somewhere in your configuration. Here I remember  a case where somebody couldn't connect to his mailbox because of an error in his email address. - A modem was setup in echo mode on power on so my PPP module tried to talk to itself without much success. - If you get somthing like 'deviceX pending' check whether your settings in Oberon.Text:NetSystem are looking good. Points to keep in mind - If you change your dial script you can just redial. - If you change something in your NetSystem configuration it's probably best to reboot. If you still have problems - PPPTest.LogOn to turn logging on - If it doesn't go through to 'Calling [PPPMain.StartInst]' you have already problem with dialing. Check your dial script. If you don't have an idea send me a step by step description of what you did, your setup for NetSystem and dialing from Oberon.Text and the partial log you got in System.Log. - If you get 'Calling [PPPMain.StartInst]' but not 'IPCP is finally ready. Device opened.' Then you have a problem in PPP setup. This can be errors in the DNS entry, your provider has problems at the moment (this also happens :-) ), your provider wants CHAP (I only support PAP at the moment), problems with modem configuration or much more. So in this case you can do a PPPTest.ShowLog which gives you the PPP log. You can try to understand it yourself (If you read the RFCs :-) ) or send it to Edgar@EdgarSchwarz.de together with the information in the first case. The log I get in System.Log with Dialer.Dial StZ device0 ~ Dial script started Sending [ATZ] Waiting 10s for [OK] {ATZ||OK} Sending [ATD 07111324300] Waiting 60s for [CONNECT] {|ATD 07111324300||CONNECT} Waiting 10s for [Login:] { 38400||*** POP Stuttgart 1 ***|||Login:} Sending USER [z974hzb] Waiting 20s for [word:] { z974hzb|Password:} Sending PASSWORD [***] Waiting 20s for [PPP Mode.] { |   Entering PPP Mode.} Calling [PPPMain.StartInst] End of script IPCP is finally ready. Device opened. How can I see the log ? PPPTest.ShowLog show you what's going on. A PPP log I got ! This log was taken before switching to kernel log for debugging, ! ! so perhaps it changed a little bit. ! Starting receiving-loop Pustekuchen, macht Devicepolling FSM.LowerUp protocol: LCP -  channel: PPP state: Initial FSM.Open protocol: LCP -  channel: PPP state: Closed reset CI FSM.SendConfReq protocol: LCP -  channel: PPP id:   1    state: Closed LCP.AddCI protocol: LCP -  channel: PPP MRU AsyncMap FSM.SendData protocol: LCP -  channel: PPP code: ConfReq state: Closed id:   1 0101000E 010405DC 02060000 0000 11:06:46SendPacket: len =   20 FF03C021 0101000E 010405DC 02060000 00004F35 11:06:46CheckPacket: len=  55 0D0A2020 20204950 20616464 72657373 20697320 3139352E 3134352E 3133322E 3136350D 0A202020 204D5455 20697320 31353234 2E0D0A Checksum failure11:06:46CheckPacket: len=  37 FF03C021 0101001F 010405F4 0206000A 00000702 08021104 05F41309 0300C07B 8056F048 BA FSM.Input new Input protocol: LCP -  channel: PPP state: ReqSent 0101001F 010405F4 0206000A 00000702 08021104 05F41309 0300C07B 8056F0 FSM.ReceiveConfigureRequest protocol: LCP -  channel: PPP id:   1 RejPCCompRejACCompRejLCPConf17RejLCPConf19FSM.SendData protocol: LCP -  channel: PPP code: ConfRej state: ReqSent id:   1 04010015 07020802 110405F4 13090300 C07B8056 F0 11:06:46SendPacket: len =   27 FF03C021 04010015 07020802 110405F4 13090300 C07B8056 F03A1C 11:06:46CheckPacket: len=   0 11:06:46CheckPacket: len=  20 FF03C021 0201000E 010405DC 02060000 000071B6 FSM.Input new Input protocol: LCP -  channel: PPP state: ReqSent 0201000E 010405DC 02060000 0000 FSM.ReceiveConfAck protocol: LCP -  channel: PPP id:   1 11:06:46CheckPacket: len=   0 11:06:46CheckPacket: len=  20 FF03C021 0102000E 010405F4 0206000A 0000ADF5 FSM.Input new Input protocol: LCP -  channel: PPP state: AckRcvd 0102000E 010405F4 0206000A 0000 FSM.ReceiveConfigureRequest protocol: LCP -  channel: PPP id:   2 FSM.SendData protocol: LCP -  channel: PPP code: ConfAck state: AckRcvd id:   2 0202000E 010405F4 0206000A 0000 11:06:46SendPacket: len =   20 FF03C021 0202000E 010405F4 0206000A 00009376 LCP is finally ready!! FSM.LowerUp protocol: IPCP -  channel: PPP state: Initial FSM.Open protocol: IPCP -  channel: PPP state: Closed FSM.SendConfReq protocol: IPCP -  channel: PPP id:   1    state: Closed FSM.SendData protocol: IPCP -  channel: PPP code: ConfReq state: Closed id:   1 0101000A 03060000 0000 11:06:46SendPacket: len =   16 FF038021 0101000A 03060000 00001328 11:06:47CheckPacket: len=   0 11:06:47CheckPacket: len=  22 FF038021 01010010 0206002D 0F010306 C391877B 0C58 FSM.Input new Input protocol: IPCP -  channel: PPP state: ReqSent 01010010 0206002D 0F010306 C391877B FSM.ReceiveConfigureRequest protocol: IPCP -  channel: PPP id:   1 FSM.SendData protocol: IPCP -  channel: PPP code: ConfRej state: ReqSent id:   1 0401000A 0206002D 0F01 11:06:47SendPacket: len =   16 FF038021 0401000A 0206002D 0F0186DE 11:06:47CheckPacket: len=   0 11:06:47CheckPacket: len=  16 FF0380FD 0101000A 11060001 0103CEDF 11:06:47CheckPacket: len=   0 11:06:47CheckPacket: len=  16 FF038021 0301000A 0306C391 84A5E7A4 FSM.Input new Input protocol: IPCP -  channel: PPP state: ReqSent 0301000A 0306C391 84A5 FSM.ReceiveConfigureNak/Reject protocol: IPCP -  channel: PPP id:   1 FSM.SendConfReq protocol: IPCP -  channel: PPP id:   2    state: ReqSent FSM.SendData protocol: IPCP -  channel: PPP code: ConfReq state: ReqSent id:   2 0102000A 0306C391 84A5 11:06:47SendPacket: len =   16 FF038021 0102000A 0306C391 84A5AE2A 11:06:47CheckPacket: len=   0 11:06:47CheckPacket: len=  16 FF038021 0102000A 0306C391 877B353F FSM.Input new Input protocol: IPCP -  channel: PPP state: ReqSent 0102000A 0306C391 877B FSM.ReceiveConfigureRequest protocol: IPCP -  channel: PPP id:   2 FSM.SendData protocol: IPCP -  channel: PPP code: ConfAck state: ReqSent id:   2 0202000A 0306C391 877B 11:06:47SendPacket: len =   16 FF038021 0202000A 0306C391 877B5C4B 11:06:47CheckPacket: len=   0 11:06:47CheckPacket: len=  16 FF038021 0202000A 0306C391 84A5C75E FSM.Input new Input protocol: IPCP -  channel: PPP state: AckSent 0202000A 0306C391 84A5 FSM.ReceiveConfAck protocol: IPCP -  channel: PPP id:   2 OurAddress = C39184A5 HisAddress = C391877B IPCP is finally ready!! Now the lower layers are up and PPP is running. If there are still problems these probably come from the upper layer protocols. Some concluding remarks - In doubt send more information than you think relevant. Sometimes there is an error in an unexpected place. - Also send me errors and proposals for this document. PPP installation should be as painless as possible for a user. Regards, Edgar Schwarz, Edgar@EdgarSchwarz.de

title: Oberon/ETH Oberon/2.3.7/PPP.Tool


text:
Oberon/ETH Oberon/2.3.7/FTPDocs.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 FTPDocs; (** portable *)	(* ejz, 05.01.03 20:13:25, some tips by bh & pm *) IMPORT Files, Objects, Fonts, Display, NetSystem, Strings, HyperDocs, NetTools, Input, Texts, Display3, Oberon, Links, Gadgets, Attributes, TextGadgets, Documents, TextDocs, Desktops, Streams, MIME; (** This module implements an API-interface and a interactive interface to FTP (RFC 959). 		The FTPDocs-modul supports ftp urls. The following line should be added to the LinkSchemes section of the Registry: 			ftp = FTPDocs.NewLinkScheme 		And the following line to the Documents section: 			ftp = FTPDocs.NewDoc 		To ensure that anonymous ftp works correctly your e-mail address should be defined in the NetSystem section of 		the Registry. e.g.: EMail = "me@home" 		To access FTP within a firewall, add the proxy to the NetSystem section of the Registry: 			FTPProxy = host [ ":" port ] . *) CONST DefConPort* = 21; FixedFont = "Courier10.Scn.Fnt"; (** res codes *) Done* = NetTools.Done; NotReady* = 1; NotConnected* = 2; WrongUser* = 3; WrongPassword* = 4; TimedOut* = 5; LocFileNotFound* = 6; Interrupted* = 7; Disconnected* = 8; Failed* = NetTools.Failed; (* systems *) Unknown = -1; UNIX = 0; VMS = 1; TempFile = "Temp.FTP"; Menu = "HyperDocs.Back[Back] FTPDocs.DeleteDocFile[Del] FTPDocs.GetDocFile[Get] FTPDocs.PutDocFile[Put] TextDocs.Search[Search]"; SysMenu = "HyperDocs.Back[Back] FTPDocs.GetDocFile[Get] FTPDocs.PutDocFile[Put]"; MinDataPort = 1100; MaxDataPort = 1500; TYPE (** The connection to an ftp server is controlled by a session handle. *) Session* = POINTER TO SessionDesc; SessionDesc* = RECORD (NetTools.SessionDesc) dataC: NetSystem.Connection; log: Texts.Text; curDir: ARRAY NetTools.PathStrLen OF CHAR; system, dataPort: INTEGER; dataIP: NetSystem.IPAdr; portIPAddress: ARRAY 64 OF CHAR; usr, passw, host: ARRAY NetTools.ServerStrLen OF CHAR; port: INTEGER; ack, bin: BOOLEAN END; EnumProc* = PROCEDURE (entry: ARRAY OF CHAR); Frame = POINTER TO FrameDesc; FrameDesc = RECORD (TextGadgets.FrameDesc) S: Session END; VAR system: INTEGER; W, dirW: Texts.Writer; line, link: ARRAY NetTools.MaxLine OF CHAR; cacheS, curS: Session; curF: Frame; message: BOOLEAN; proxyHost: ARRAY NetTools.ServerStrLen OF CHAR; proxyPort, dataPort: INTEGER; proxy: BOOLEAN; PROCEDURE ReadResponse(S: Session; VAR sline: ARRAY OF CHAR); VAR time, i, j, cpos: LONGINT; code: ARRAY 8 OF CHAR; line: ARRAY NetTools.MaxLine OF CHAR; BEGIN IF ~NetTools.Connected(S.C, NetSystem.in) THEN COPY("Connection closed by server.", sline); COPY(sline, S.reply); S.status := 0; S.res := Disconnected; RETURN END; time := NetSystem.Available(S.C); NetSystem.ReadString(S.C, line); IF S.log # NIL THEN Texts.WriteString(W, line); Texts.WriteLn(W); Texts.Append(S.log, W.buf) END; Strings.StrToInt(line, time); S.status := SHORT(time); Strings.IntToStr(time, code); cpos := 0; WHILE code[cpos] # 0X DO 			INC(cpos) END; i := cpos+1; j := 0; WHILE line[i] # 0X DO 			sline[j] := line[i]; INC(j); INC(i) END; sline[j] := 0X; time := Input.Time; IF line[cpos] = "-" THEN LOOP IF NetSystem.Available(S.C) > 0 THEN line[cpos] := 0X; NetSystem.ReadString(S.C, line); IF S.log # NIL THEN Texts.WriteString(W, line); Texts.WriteLn(W); Texts.Append(S.log, W.buf) END; IF line[cpos] # "-" THEN line[cpos] := 0X; IF line = code THEN EXIT END END; time := Input.Time ELSIF (Input.Time-time) >= NetTools.TimeOut THEN S.res := TimedOut; RETURN ELSIF NetTools.UserBreak THEN S.res := Interrupted; RETURN END END END; S.ack := TRUE END ReadResponse; PROCEDURE SendLine(C: NetSystem.Connection; VAR str: ARRAY OF CHAR); BEGIN NetTools.SendString(C, str); NetSystem.WriteBytes(C, 0, 2, Strings.CRLF) END SendLine; PROCEDURE SendCmd(S: Session; str: ARRAY OF CHAR); BEGIN IF ~S.ack THEN ReadResponse(S, line) ELSE S.ack := FALSE END; SendLine(S.C, str) END SendCmd; (** Close connection for session S. 	res: allways = Done *) PROCEDURE Close*(S: Session); BEGIN S.ack := TRUE; SendCmd(S, "QUIT"); ReadResponse(S, S.reply); NetTools.Disconnect(S.dataC); NetTools.Disconnect(S.C); S.res := Done END Close; PROCEDURE Close2(S: Session); BEGIN S.ack := TRUE; SendCmd(S, "QUIT"); NetTools.Disconnect(S.dataC); NetTools.Disconnect(S.C) 	END Close2; PROCEDURE QuerySystem(S: Session); VAR pos: LONGINT; BEGIN S.system := UNIX; SendCmd(S, "SYST"); ReadResponse(S, line); IF (S.status >= 200) & (S.status < 300) THEN pos := 0; Strings.Search("VMS", line, pos); IF pos >= 0 THEN S.system := VMS END END END QuerySystem; PROCEDURE GetLogin(VAR host, usr, passw: ARRAY OF CHAR); BEGIN IF (usr = "ftp") OR (usr = "anonymous") OR (usr = "") THEN IF ~NetTools.QueryString("EMail", passw) OR (passw[0] = "<") THEN COPY("anonymous@host.nowhere", passw) END; IF usr = "" THEN COPY("anonymous", usr) END ELSIF passw = "" THEN NetSystem.GetPassword("ftp", host, usr, passw) END END GetLogin; (** Open a new ftp session S to server using USER=user and PASS=passwd. 	If user is either ftp or anonymous, passwd defaults to the e-mail address set in the 	Registry (NetSystem.EMail). 	port gives the Telnet-port of the FTP server, most FTP servers use FTPDocs.DefConPort. 	If log # NIL all responses from the server will be appended to log. NetSystem.hostIP 	must be set correctly. 	res: 		Done: all ok 		WrongPassword: the password given is incorrect 		WrongUser: the given user is not allowed to use this server 		NotReady: the server is busy, retry later 		NotConnected: server not found 		Failed: NetSystem.hostIP not set *) PROCEDURE Open*(server, user, passwd: ARRAY OF CHAR; port: INTEGER; log: Texts.Text; VAR S: Session); BEGIN NEW(S); S.dataC := NIL; COPY(server, S.host); S.port := port; S.dataPort := -1; COPY(user, S.usr); COPY(passwd, S.passw); GetLogin(server, S.usr, S.passw); IF NetSystem.hostIP = NetSystem.anyIP THEN S.C := NIL; S.reply := "invalid NetSystem.hostIP"; S.res := Failed; RETURN END; S.system := Unknown; S.reply := "connecting failed"; S.portIPAddress := ""; S.log := log; S.ack := TRUE; IF (S.usr = "") OR (S.passw = "") THEN S.res := Failed; S.reply := "no password or username specified"; RETURN END; IF NetTools.Connect(S.C, port, server, FALSE) THEN ReadResponse(S, S.reply); IF (S.status >= 200) & (S.status < 300) THEN line := "USER "; Strings.Append(line, S.usr); SendCmd(S, line); ReadResponse(S, line); IF (S.status = 330) OR (S.status = 331) THEN line := "PASS "; Strings.Append(line, S.passw); SendCmd(S, line); ReadResponse(S, line); IF (S.status = 230) OR (S.status= 330) THEN S.res := Done ELSE S.res := WrongPassword; COPY(line, S.reply); Close2(S) END ELSIF S.status # 230 THEN S.res := WrongUser; COPY(line, S.reply); Close2(S) ELSE S.res := Done END; IF S.res # Done THEN NetSystem.DelPassword("ftp", S.usr, server) END ELSE S.res := NotReady; Close2(S) END ELSE S.res := NotConnected END; IF S.res = Done THEN SendCmd(S, "TYPE I"); S.bin := TRUE; ReadResponse(S, line); IF S.status # 200 THEN (* should not happen *) END; QuerySystem(S); S.res := Done END END Open; (** Change the current directory. 		res: 			Done: all ok 			Failed: directory not changed *) PROCEDURE ChangeDir*(S: Session; newDir: ARRAY OF CHAR); BEGIN S.reply := "CWD "; Strings.Append(S.reply, newDir); SendCmd(S, S.reply); ReadResponse(S, S.reply); IF S.status = 250 THEN S.res := Done ELSE S.res := Failed END END ChangeDir; PROCEDURE SetDataPort(S: Session); VAR str: ARRAY 4 OF CHAR; p0, p1: LONGINT; i, j, k: INTEGER; done: BOOLEAN; BEGIN SendCmd(S, "PASV"); ReadResponse(S, line); IF (S.status >= 200) & (S.status < 300) THEN S.res := Interrupted; i := 0; WHILE (line[i] # 0X) & ~Strings.IsDigit(line[i]) DO INC(i) END; j := 0; k := 0; WHILE (line[i] # 0X) & (k < 4) DO 				IF line[i] # "," THEN S.portIPAddress[j] := line[i] ELSE S.portIPAddress[j] := "."; INC(k) END; INC(i); INC(j) END; IF (j <= 0) & (k < 4) THEN RETURN END; S.portIPAddress[j-1] := 0X; NetSystem.ToHost(S.portIPAddress, S.dataIP, done); IF ~done THEN RETURN END; WHILE (line[i] # 0X) & ((line[i] <= " ") OR (line[i] = ",")) DO INC(i) END; Strings.StrToIntPos(line, p0, i); WHILE (line[i] # 0X) & ((line[i] <= " ") OR (line[i] = ",")) DO INC(i) END; Strings.StrToIntPos(line, p1, i); S.dataPort := SHORT(256*p0+p1); S.res := Done ELSE S.dataIP := NetSystem.anyIP; S.dataPort := dataPort; REPEAT IF S.dataPort >= MaxDataPort THEN S.dataPort := MinDataPort END; INC(S.dataPort); (* not 100% safe *) NetSystem.OpenConnection(S.dataC, S.dataPort, NetSystem.anyIP, NetSystem.anyport, S. res) UNTIL (S.res = NetSystem.done) OR NetTools.UserBreak; IF S.res = NetSystem.done THEN dataPort := S.dataPort; S.res := Failed; NetSystem.ToNum(NetSystem.hostIP, S.portIPAddress); i := 0; WHILE S.portIPAddress[i] # 0X DO IF S.portIPAddress[i] = "." THEN S.portIPAddress[i] := "," END; INC(i) END; Strings.AppendCh(S.portIPAddress, ","); Strings.IntToStr(S.dataPort DIV 256, str); Strings.Append(S.portIPAddress, str); Strings.AppendCh(S.portIPAddress, ","); Strings.IntToStr(S.dataPort MOD 256, str); Strings.Append(S.portIPAddress, str); line := "PORT "; Strings.Append(line, S.portIPAddress); SendCmd(S, line) ELSE NetTools.Disconnect(S.dataC); S.dataC := NIL; S.reply := "Interrupted"; S.res := Interrupted END END END SetDataPort; PROCEDURE WaitDataCon(S: Session): NetSystem.Connection; VAR C1: NetSystem.Connection; time: LONGINT; BEGIN IF S.dataIP = NetSystem.anyIP THEN time := Input.Time; REPEAT UNTIL NetSystem.Requested(S.dataC) OR ((Input.Time-time) > NetTools.TimeOut) OR NetTools.UserBreak; IF NetSystem.Requested(S.dataC) THEN NetSystem.Accept(S.dataC, C1, S.res); NetTools.Disconnect(S.dataC); IF S.res = NetSystem.done THEN S.res := Done; RETURN C1 				ELSE S.res := Failed END ELSIF (Input.Time-time) > NetTools.TimeOut THEN S.res := TimedOut ELSE S.res := Interrupted END; NetTools.Disconnect(S.dataC) ELSE NetSystem.OpenConnection(C1, NetSystem.anyport, S.dataIP, S.dataPort, S.res); IF S.res = Done THEN RETURN C1 END END; RETURN NIL END WaitDataCon; (** Retrieve a list of the current directory and call enum for each entry in the list. 		res: 			Done: all ok 			TimeOut: server did not answer in time 			Failed: see S.reply(Line) *) PROCEDURE EnumDir*(S: Session; enum: EnumProc); VAR C: NetSystem.Connection; len: LONGINT; BEGIN S.reply := ""; SetDataPort(S); C := NIL; IF S.res = Interrupted THEN RETURN END; IF S.dataIP = NetSystem.anyIP THEN ReadResponse(S, line) ELSE C := WaitDataCon(S); IF S.res = Done THEN S.status := 200 END END; IF S.status = 200 THEN IF S.system = VMS THEN SendCmd(S, "NLST") ELSE SendCmd(S, "LIST") END; ReadResponse(S, S.reply); IF (S.status = 150) OR (S.status = 250) THEN IF S.dataIP = NetSystem.anyIP THEN C := WaitDataCon(S) END; IF S.res = Done THEN S.res := Done; len := NetSystem.Available(C); WHILE ((len > 0) OR NetTools.Connected(C, NetSystem.in)) & ~NetTools.UserBreak DO 						IF len > 0 THEN NetSystem.ReadString(C, line); enum(line) END; len := NetSystem.Available(C) END END; NetTools.Disconnect(C);	(* before ReadResponse *) ReadResponse(S, S.reply) ELSE S.res := Failed END END; IF C # NIL THEN NetTools.Disconnect(C) END; IF S.dataC # NIL THEN NetTools.Disconnect(S.dataC) END END EnumDir; PROCEDURE ScanLen(VAR reply: ARRAY OF CHAR; VAR len: LONGINT); VAR i, d: INTEGER; last: BOOLEAN; BEGIN last := FALSE; d := -1; i := 0; WHILE reply[i] # 0X DO 			IF Strings.IsDigit(reply[i]) THEN IF ~last THEN d := i; last := TRUE END ELSE last := FALSE END; INC(i) END; IF d > 0 THEN Strings.StrToIntPos(reply, len, d) 		ELSE len := 0 END END ScanLen; PROCEDURE GetF(S: Session; remName: ARRAY OF CHAR; VAR R: Files.Rider); VAR C: NetSystem.Connection; BEGIN S.reply := ""; SetDataPort(S); C := NIL; IF S.res = Interrupted THEN RETURN END; IF S.dataIP = NetSystem.anyIP THEN ReadResponse(S, line) ELSE C := WaitDataCon(S); IF S.res = Done THEN S.status := 200 END END; IF S.status = 200 THEN line := "RETR "; Strings.Append(line, remName); SendCmd(S, line); ReadResponse(S, line); COPY(line, S.reply); IF (S.status = 150) OR (S.status = 250) THEN IF S.dataIP = NetSystem.anyIP THEN C := WaitDataCon(S) END; IF S.res = Done THEN ScanLen(S.reply, NetTools.curLen); NetTools.curPos := 0; NetTools.ReadData(C, R, MAX(LONGINT)) END; NetTools.Disconnect(C);	(* before ReadResponse *) ReadResponse(S, S.reply); IF S.res = Interrupted THEN ReadResponse(S, line) END ELSE S.res := Failed END END; IF C # NIL THEN NetTools.Disconnect(C) END; IF S.dataC # NIL THEN NetTools.Disconnect(S.dataC) END END GetF; (** Retrieve the file remName from the server and store it as local file locName. 		res: 			Done: all ok 			TimeOut: server did not answer in time 			Failed: file not found or no permission, see S.reply(Line) *) PROCEDURE GetFile*(S: Session; remName, locName: ARRAY OF CHAR); VAR F: Files.File; R: Files.Rider; BEGIN S.bin := TRUE; F := Files.New(locName); Files.Set(R, F, 0); GetF(S, remName, R); Files.Register(F) END GetFile; (** Retrieve the text file remName from the server and write it to writer W. 		The text is converted from iso-8859-1 to the Oberon-code. 		res: 			Done: all ok 			TimeOut: server did not answer in time 			Failed: file not found or no permission, see S.reply(Line) *) PROCEDURE GetText*(S: Session; remName: ARRAY OF CHAR; VAR W: Texts.Writer); VAR C: NetSystem.Connection; in: Streams.Stream; BEGIN S.reply := ""; C := NIL; SendCmd(S, "TYPE A"); S.bin := FALSE; ReadResponse(S, line); SetDataPort(S); IF S.res = Interrupted THEN SendCmd(S, "TYPE I"); ReadResponse(S, line); RETURN END; IF S.dataIP = NetSystem.anyIP THEN ReadResponse(S, line) ELSE C := WaitDataCon(S); IF S.res = Done THEN S.status := 200 END END; IF S.status = 200 THEN line := "RETR "; Strings.Append(line, remName); SendCmd(S, line); ReadResponse(S, line); COPY(line, S.reply); IF (S.status = 150) OR (S.status = 250) THEN IF S.dataIP = NetSystem.anyIP THEN C := WaitDataCon(S) END; IF S.res = Done THEN ScanLen(S.reply, NetTools.curLen); NetTools.curPos := 0; in := NetTools.OpenStream(C); MIME.textCont.len := MAX(LONGINT); MIME.ReadText(in, W, MIME.textCont, FALSE) END; NetTools.Disconnect(C);	(* before ReadResponse *) ReadResponse(S, S.reply); IF S.res = Interrupted THEN ReadResponse(S, line) END ELSE S.res := Failed END END; IF C # NIL THEN NetTools.Disconnect(C) END; IF S.dataC # NIL THEN NetTools.Disconnect(S.dataC) END; SendCmd(S, "TYPE I"); ReadResponse(S, line) END GetText; (** Store the local file locName as remName on the server. 		res: 			Done: all ok 			TimeOut: server did not answer in time 			Failed: no permission or bad file name 			LocFileNotFound: could not open the local file *) PROCEDURE PutFile*(S: Session; remName, locName: ARRAY OF CHAR); VAR C: NetSystem.Connection; F: Files.File; R: Files.Rider; BEGIN S.reply := ""; S.bin := TRUE; C := NIL; F := Files.Old(locName); IF F # NIL THEN SetDataPort(S); IF S.res = Interrupted THEN RETURN END; IF S.dataIP = NetSystem.anyIP THEN ReadResponse(S, line) ELSE C := WaitDataCon(S); IF S.res = Done THEN S.status := 200 END END; IF S.status = 200 THEN line := "STOR "; Strings.Append(line, remName); SendCmd(S, line); ReadResponse(S, S.reply); IF (S.status = 150) OR (S.status = 250) THEN IF S.dataIP = NetSystem.anyIP THEN C := WaitDataCon(S) END; IF S.res = Done THEN NetTools.curLen := Files.Length(F); NetTools.curPos := 0; Files.Set(R, F, 0); NetTools.WriteData(C, R) 					END; NetTools.Disconnect(C); ReadResponse(S, S.reply) ELSE S.res := Failed END END ELSE COPY(locName, S.reply); Strings.Append(S.reply, " not found"); S.res := LocFileNotFound END; IF C # NIL THEN NetTools.Disconnect(C) END; IF S.dataC # NIL THEN NetTools.Disconnect(S.dataC) END END PutFile; (** Store text as remName on the server. 		The text is converted to iso-8859-1. All none ascii content is ignored (colors, fonts, objects, ...). 		res: 			Done: all ok 			TimeOut: server did not answer in time 			Failed: no permission or bad file name *) PROCEDURE PutText*(S: Session; remName: ARRAY OF CHAR; text: Texts.Text); VAR C: NetSystem.Connection; out: Streams.Stream; BEGIN S.reply := ""; C := NIL; SendCmd(S, "TYPE A"); S.bin := FALSE; ReadResponse(S, line); IF (S.status < 200) OR (S.status >= 300) THEN RETURN END; SetDataPort(S); IF S.res = Interrupted THEN SendCmd(S, "TYPE I"); ReadResponse(S, line); RETURN END; IF S.dataIP = NetSystem.anyIP THEN ReadResponse(S, line) ELSE C := WaitDataCon(S); IF S.res = Done THEN S.status := 200 END END; IF S.status = 200 THEN line := "STOR "; Strings.Append(line, remName); SendCmd(S, line); ReadResponse(S, S.reply); IF (S.status = 150) OR (S.status = 250) THEN IF S.dataIP = NetSystem.anyIP THEN C := WaitDataCon(S) END; IF S.res = Done THEN NetTools.curLen := text.len; NetTools.curPos := 0; out := NetTools.OpenStream(C); MIME.textCont.len := MAX(LONGINT); MIME.WriteText(text, 0, text.len, out, MIME.textCont, FALSE, FALSE) END; NetTools.Disconnect(C); ReadResponse(S, S.reply) ELSE S.res := Failed END END; IF C # NIL THEN NetTools.Disconnect(C) END; IF S.dataC # NIL THEN NetTools.Disconnect(S.dataC) END; SendCmd(S, "TYPE I"); ReadResponse(S, line) END PutText; (** Delete the file remName from the server. 		res: 			Done: all ok 			Failed: file not found or no permission, see S.reply(Line) *) PROCEDURE DeleteFile*(S: Session; remName: ARRAY OF CHAR); BEGIN S.reply := "DELE "; Strings.Append(S.reply, remName); SendCmd(S, S.reply); ReadResponse(S, S.reply); IF S.status = 250 THEN S.res := Done ELSE S.res := Failed END END DeleteFile; (** Query the current dir (path). 		res: 			Done: all ok 			Failed: see S.reply(Line) *) PROCEDURE GetCurDir*(S: Session; VAR curdir: ARRAY OF CHAR); VAR i, j: INTEGER; BEGIN SendCmd(S, "PWD"); ReadResponse(S, S.reply); IF S.status = 257 THEN IF S.system = VMS THEN COPY(S.reply, curdir); i := 0; WHILE curdir[i] > " " DO 					INC(i) END; curdir[i] := 0X ELSE i := 0; WHILE (S.reply[i] # 0X) & (S.reply[i] # 22X) DO 					INC(i) END; j := 0; IF S.reply[i] = 22X THEN INC(i); WHILE (S.reply[i] # 0X) & (S.reply[i] # 22X) DO 						curdir[j] := S.reply[i]; INC(j); INC(i) END END; curdir[j] := 0X END; S.res := Done ELSE COPY("", curdir); S.res := Failed END END GetCurDir; (** Create a new directory. 		res: 			Done: all ok 			Failed: see S.reply(Line) *) PROCEDURE MakeDir*(S: Session; newDir: ARRAY OF CHAR); BEGIN S.reply := "MKD "; Strings.Append(S.reply, newDir); SendCmd(S, S.reply); ReadResponse(S, S.reply); IF S.status = 257 THEN S.res := Done ELSE S.res := Failed END END MakeDir; (** Remove an existing directory. 		res: 			Done: all ok 			Failed: see S.reply(Line) *) PROCEDURE RmDir*(S: Session; dir: ARRAY OF CHAR); BEGIN S.reply := "RMD "; Strings.Append(S.reply, dir); SendCmd(S, S.reply); ReadResponse(S, S.reply); IF S.status = 250 THEN S.res := Done ELSE S.res := Failed END END RmDir; 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 := "FTPDocs.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.FTPDeskMenu", 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.FTPSystemMenu", TRUE); IF M.obj = NIL THEN M.obj := Desktops.NewMenu(SysMenu) END; M.res := 0 ELSIF M.name = "UserMenu" THEN M.obj := Gadgets.CopyPublicObject("NetDocs.FTPUserMenu", 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; (** Register a ftp URL and get a unique key for it. *) PROCEDURE RegisterFTPAdr*(host, path, user, passwd: ARRAY OF CHAR; type: CHAR; port: INTEGER): LONGINT; VAR portS: ARRAY 8 OF CHAR; key: LONGINT; BEGIN COPY("ftp://", line); IF user # "" THEN HyperDocs.ESC(user, "@"); Strings.Append(line, user); IF passwd # "" THEN HyperDocs.ESC(passwd, "@"); Strings.AppendCh(line, ":"); Strings.Append(line, passwd) END; Strings.AppendCh(line, "@") END; Strings.Lower(host, host); Strings.Append(line, host); IF port # DefConPort THEN Strings.AppendCh(line, ":"); Strings.IntToStr(port, portS); Strings.Append(line, portS) END; IF path # "" THEN Strings.Append(line, path); IF type # 0X THEN Strings.Append(line, ";type="); Strings.AppendCh(line, type) END END; key := HyperDocs.RegisterLink(line); RETURN key END RegisterFTPAdr; (** Parsing of an ftp url. *) PROCEDURE SplitFTPAdr*(VAR url, host, path, user, passwd: ARRAY OF CHAR; VAR type: CHAR; VAR port: INTEGER): LONGINT; VAR key, i, j, l: LONGINT; iskey: BOOLEAN; PROCEDURE Blanks; BEGIN WHILE (url[i] # 0X) & (url[i] <= " ") DO 				INC(i) END END Blanks; BEGIN (* Pre: url must be a ftp url *) type := 0X; port := DefConPort; COPY("", user); COPY("", passwd); i := 0; Blanks; (* skip ftp *) WHILE (url[i] # 0X) & (url[i] # ":") DO 			INC(i) END; (* skip :// *) IF url[i] = ":" THEN INC(i) END; Blanks; WHILE (url[i] = "/") & (url[i] # 0X) DO 			INC(i) END; Blanks; (* look ahead for @ *) j := i; 		WHILE (url[j] # 0X) & (url[j] # "@") & (url[j] # "/") DO 			INC(j) END; IF url[j] = "@" THEN (* get user *) l := LEN(user)-1; j := 0; WHILE (url[i] # 0X) & (url[i] # ":") & (url[i] # "@") DO 				IF (j < l) THEN user[j] := url[i]; INC(j) END; INC(i) END; user[j] := 0X; DEC(j); WHILE (j >= 0) & (user[j] <= " ") DO 				user[j] := 0X; DEC(j) END; IF url[i] = ":" THEN (* get password *) l := LEN(passwd); INC(i); Blanks; j := 0; WHILE (url[i] # 0X) & (url[i] # "@") DO 					IF j < l THEN passwd[j] := url[i]; INC(j) END; INC(i) END; passwd[j] := 0X; DEC(j); WHILE (j >= 0) & (passwd[j] <= " ") DO 					passwd[j] := 0X; DEC(j) END END; INC(i); Blanks END; (* get host *) iskey := (user = "") & (passwd = ""); l := LEN(host); j := 0; WHILE (url[i] # 0X) & (url[i] # ":") & (url[i] # "/") DO 			IF (url[i] > " ") & ~Strings.IsDigit(url[i]) THEN iskey := FALSE END; IF j < l THEN host[j] := url[i]; INC(j) END; INC(i) END; host[j] := 0X; DEC(j); WHILE (j >= 0) & (host[j] <= " ") DO 			host[j] := 0X; DEC(j) END; IF (url[i] = 0X) & iskey THEN IF host # "" THEN Strings.StrToInt(host, key); HyperDocs.RetrieveLink(key, line); key := SplitFTPAdr(line, host, path, user, passwd, type, port); RETURN key ELSE RETURN HyperDocs.UndefKey END END; IF url[i] = ":" THEN port := 0; INC(i); WHILE (url[i] # "/") & (url[i] # 0X) DO 				IF Strings.IsDigit(url[i]) THEN port := port*10+ORD(url[i])-ORD("0") END; INC(i) END; IF port <= 0 THEN port := DefConPort END END; (* get path *) l := LEN(path); j := 0; IF url[i] # 0X THEN path[j] := url[i]; INC(j); INC(i); IF url[i] = "~" THEN j := 0 END END; WHILE (url[i] # 0X) & (url[i] # ";") DO 			IF j < l THEN path[j] := url[i]; INC(j) END; INC(i) END; path[j] := 0X; DEC(j); WHILE (j >= 0) & (path[j] <= " ") DO 			path[j] := 0X; DEC(j) END; IF url[i] = ";" THEN INC(i); Blanks; IF CAP(url[i]) # "T" THEN type := CAP(url[i]) ELSE WHILE (url[i] # 0X) & (url[i] # "=") DO 					INC(i) END; IF url[i] = "=" THEN INC(i); Blanks; type := CAP(url[i]) ELSE type := "T" END END END; HyperDocs.UnESC(host); HyperDocs.UnESC(path); HyperDocs.UnESC(user); HyperDocs.UnESC(passwd); key := RegisterFTPAdr(host, path, user, passwd, type, port); RETURN key END SplitFTPAdr; PROCEDURE *LinkSchemeHandler(L: Objects.Object; VAR M: Objects.ObjMsg); VAR usr, passw, host: ARRAY NetTools.ServerStrLen OF CHAR; path: ARRAY NetTools.PathStrLen OF CHAR; port: INTEGER; type: CHAR; BEGIN WITH L: HyperDocs.LinkScheme DO 			IF M IS HyperDocs.RegisterLinkMsg THEN WITH M: HyperDocs.RegisterLinkMsg DO 					IF (M.base = NIL) OR (HyperDocs.CheckPrefix(M.link) >= 0) THEN M.key := SplitFTPAdr(M.link, host, path, usr, passw, type, port) ELSIF M.base.prefix = "ftp" THEN link := "ftp://"; Strings.Append(link, M.base.host); IF M.base.port > 0 THEN Strings.AppendCh(link, ":"); Strings.IntToStr(M.base.port, path); Strings.Append(link, path) END; HyperDocs.Path(M.base, link, M.link); M.key := HyperDocs.RegisterLink(link) ELSE HyperDocs.LinkSchemeHandler(L, M) 					END; IF M.key # HyperDocs.UndefKey THEN M.res := 0 END END ELSIF M IS HyperDocs.FetchMsg THEN WITH M: HyperDocs.FetchMsg DO 					IF M.key # HyperDocs.UndefKey THEN HyperDocs.RetrieveLink(M.key, line); M.key := SplitFTPAdr(line, host, path, usr, passw, type, port); (*GetLogin(host, usr, passw);*) Texts.WriteString(W, "ftp://"); Texts.WriteString(W, host); Texts.WriteString(W, path); Texts.Append(Oberon.Log, W.buf); IF (cacheS # NIL) & ((cacheS.host # host) OR (cacheS.port # port) OR (cacheS.usr # usr) OR (cacheS.passw # passw)) THEN Close(cacheS); cacheS := NIL END; IF cacheS = NIL THEN Open(host, usr, passw, port, NIL, cacheS) END; IF cacheS.res = Done THEN GetF(cacheS, path, M.R); IF cacheS.res # Done THEN Texts.WriteString(W, cacheS.reply) ELSE Texts.WriteString(W, " done"); M.res := 0 END ELSE Texts.WriteString(W, cacheS.reply) END; Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) ELSE IF cacheS # NIL THEN Close(cacheS); cacheS := NIL; END; M.res := 0 END END ELSIF 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 := "FTPDocs.NewLinkScheme"; M.res := 0 ELSE HyperDocs.LinkSchemeHandler(L, M) 					END END ELSE HyperDocs.LinkSchemeHandler(L, M) 			END END END LinkSchemeHandler; PROCEDURE NewLinkScheme*; VAR L: HyperDocs.LinkScheme; BEGIN NEW(L); L.handle := LinkSchemeHandler; L.usePath := TRUE; Objects.NewObj := L 	END NewLinkScheme; PROCEDURE TrimmVMS(VAR name: ARRAY OF CHAR); VAR i: INTEGER; BEGIN i := 0; WHILE (name[i] # 0X) & (name[i] # ";") DO 			INC(i) END; name[i] := 0X END TrimmVMS; PROCEDURE GetDoc(F: Frame; name: ARRAY OF CHAR; type: CHAR): Documents.Document; VAR i, j: LONGINT; D: Documents.Document; tempName: ARRAY 64 OF CHAR; T: Texts.Text; tW: Texts.Writer; obj: Objects.Object; bin: BOOLEAN; BEGIN IF type # 0X THEN bin := ~((type = "A") OR (type = "T")) ELSE obj := Gadgets.FindObj(Gadgets.context, "Ascii"); IF obj # NIL THEN Attributes.GetBool(obj, "Value", bin); bin := ~bin ELSE bin := TRUE END END; IF bin THEN Texts.WriteString(W, "FTPDocs.GetFile ") ELSE Texts.WriteString(W, "FTPDocs.GetText ") END; Texts.WriteString(W, name); Texts.Write(W, " "); Texts.Append(Oberon.Log, W.buf); j := -1; i := 0; WHILE name[i] # 0X DO IF name[i] = "." THEN j := i 			END; INC(i) END; IF ~bin THEN type := "A"; Texts.OpenWriter(tW); GetText(F.S, name, tW); NEW(T); Texts.Open(T, ""); Texts.Append(T, tW.buf) ELSE COPY(TempFile, tempName); IF j > 0 THEN i := 0; WHILE tempName[i] # 0X DO 					INC(i) END; WHILE name[j] # 0X DO 					tempName[i] := name[j]; INC(i); INC(j) END; tempName[i] := 0X; IF F.S.system = VMS THEN TrimmVMS(tempName) END END; GetFile(F.S, name, tempName) END; Texts.WriteLn(W); Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); IF F.S.res = Done THEN IF type = "A" THEN NEW(D); TextDocs.InitDoc(D); D.W := HyperDocs.docW; D.H := HyperDocs.docH; Links.SetLink(D.dsc, "Model", T); COPY(name, D.name) ELSE D := Documents.Open(tempName) END ELSE D := NIL END; RETURN D 	END GetDoc; PROCEDURE *ShowEntry(entry: ARRAY OF CHAR); VAR link: Objects.Object; i, j, beg0, beg1, beg2, begL, key: LONGINT; name: ARRAY 64 OF CHAR; BEGIN begL := -1; IF entry = "" THEN RETURN END; IF system = UNIX THEN i := 0; beg0 := 0; beg1 := 0; beg2 := 0; WHILE entry[i] # 0X DO 				IF entry[i] <= " " THEN beg0 := beg1; beg1 := beg2; beg2 := i 				END; INC(i) END; i := 0; WHILE entry[i] # 0X DO 				IF (i >= beg2) & ((entry[0] = "d") OR (entry[0] = "-")) THEN Texts.SetColor(dirW, SHORT(HyperDocs.linkC)); IF begL < 0 THEN Texts.Append(curF.text, dirW.buf); begL := curF.text.len END ELSIF (i >= beg0) & (entry[0] = "l") THEN Texts.SetColor(dirW, SHORT(HyperDocs.linkC)); IF begL < 0 THEN Texts.Append(curF.text, dirW.buf); begL := curF.text.len END END; Texts.Write(dirW, entry[i]); INC(i) END; Texts.SetColor(dirW, SHORT(Display3.textC)); IF begL >= 0 THEN i := 0; INC(beg2); WHILE (entry[beg2] > " ") & (i < 63) DO 					name[i] := entry[beg2]; INC(i); INC(beg2) END; name[i] := 0X; IF name = ".message" THEN message := TRUE END; IF name[0] # "/" THEN COPY(curS.curDir, line); IF curS.curDir # "/" THEN Strings.AppendCh(line, "/") END; Strings.Append(line, name); IF entry[0] = "d" THEN Strings.AppendCh(line, "/") END ELSE COPY(name, line) END; key := RegisterFTPAdr(curS.host, line, "", "", 0X, curS.port); IF HyperDocs.Visited(key) THEN Texts.Append(curF.text, dirW.buf); Texts.ChangeLooks(curF.text, begL, curF.text.len, {1}, NIL, SHORT(HyperDocs.oldLinkC), 0) END; link := HyperDocs.LinkControl(key); Texts.WriteObj(dirW, link) END; Texts.WriteLn(dirW) ELSIF system = VMS THEN beg0 := 0; Strings.Search(".dir;", entry, beg0); IF beg0 < 0 THEN Strings.Search(".DIR;", entry, beg0) END; i := 0; IF beg0 > 0 THEN Texts.SetColor(dirW, SHORT(HyperDocs.linkC)); WHILE (entry[i] # 0X) & (i < beg0) DO 					Texts.Write(dirW, entry[i]); INC(i) END; Texts.SetColor(dirW, SHORT(Display3.textC)); beg1 := i; entry[beg1] := 0X; COPY(curS.curDir, line); line[0] := "/"; i := 0; WHILE (line[i] # 0X) & (line[i] # "]") DO 					INC(i) END; line[i] := 0X; Strings.AppendCh(line, "."); Strings.Append(line, entry); Strings.AppendCh(line, "]"); key := RegisterFTPAdr(curS.host, line, "", "", 0X, curS.port); link := HyperDocs.LinkControl(key); Texts.WriteObj(dirW, link); entry[beg1] := "."; i := beg1 ELSE beg0 := 0; Strings.Search(";", entry, beg0); IF beg0 > 0 THEN j := 0; Texts.SetColor(dirW, SHORT(HyperDocs.linkC)); WHILE (entry[i] # 0X) & (i < beg0) & (j < 63) DO 						name[j] := entry[i]; INC(j); Texts.Write(dirW, entry[i]); INC(i) END; name[j] := 0X; beg1 := i; 					Texts.SetColor(dirW, SHORT(Display3.textC)); COPY(curS.curDir, line); line[0] := "/"; i := 0; WHILE (line[i] # 0X) & (line[i] # "]") DO 						INC(i) END; line[i] := 0X; Strings.AppendCh(line, "]"); Strings.Append(line, name); key := RegisterFTPAdr(curS.host, line, "", "", 0X, curS.port); link := HyperDocs.LinkControl(key); Texts.WriteObj(dirW, link); i := beg1 END END; WHILE entry[i] # 0X DO 				Texts.Write(dirW, entry[i]); INC(i) END; Texts.WriteLn(dirW) END; Texts.SetColor(W, SHORT(Display3.textC)) END ShowEntry; PROCEDURE HorzRule: Objects.Object; VAR obj: Objects.Object; BEGIN obj := Gadgets.CreateObject("BasicFigures.NewRect3D"); Attributes.SetBool(obj, "Filled", TRUE); Attributes.SetInt(obj, "Color", Display3.textbackC); Gadgets.ModifySize(obj(Display.Frame), Display.Width, 4); RETURN obj END HorzRule; PROCEDURE DoDir(D: Documents.Document; F: Frame); VAR f, o: Objects.Object; pos: LONGINT; msgW: Texts.Writer; U: Gadgets.UpdateMsg; h: INTEGER; oldBin: BOOLEAN; BEGIN Texts.Delete(F.text, 0, F.text.len); system := F.S.system; GetCurDir(F.S, F.S.curDir); f := Gadgets.CreateObject("TextFields.NewTextField"); Attributes.SetString(f, "Value", F.S.curDir); Attributes.SetString(f, "Cmd", "FTPDocs.ChangeDocDir '#Value '"); WITH f: Display.Frame DO 			f.W := 3*f.W; h := f.H 		END; Texts.WriteObj(dirW, f); Texts.Write(dirW, Strings.Tab); o := Gadgets.CreateObject("BasicGadgets.NewInteger"); f := Gadgets.CreateObject("BasicGadgets.NewCheckBox"); WITH f: Gadgets.Frame DO 			f.H := h; f.obj := o 		END; Gadgets.NameObj(f, "Bin"); Attributes.SetInt(f, "SetVal", 0); Attributes.SetString(f, "YesVal", "I"); Texts.WriteObj(dirW, f); Texts.WriteString(dirW, " binary"); Texts.Write(dirW, 09X); f := Gadgets.CreateObject("BasicGadgets.NewCheckBox"); WITH f: Gadgets.Frame DO 			f.H := h; f.obj := o 		END; Gadgets.NameObj(f, "Ascii"); Attributes.SetInt(f, "SetVal", 1); Attributes.SetString(f, "YesVal", "A"); Texts.WriteObj(dirW, f); Attributes.SetBool(f, "Value", ~F.S.bin); Texts.WriteString(dirW, " ascii"); Texts.WriteLn(dirW); Texts.WriteObj(dirW, HorzRule); Texts.WriteLn(dirW); Texts.Append(F.text, dirW.buf); pos := F.text.len-1; message := FALSE; curS := F.S; curF := F; 		EnumDir(F.S, ShowEntry); curS := NIL; curF := NIL; Attributes.SetInt(F, "LinkColor", HyperDocs.linkC); Attributes.SetInt(F, "OldLinkColor", HyperDocs.oldLinkC); F.do := HyperDocs.linkMethods; IF F.S.res # Done THEN Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) ELSE D.name := "ftp://"; Strings.Append(D.name, F.S.host); Strings.Append(D.name, F.S.curDir); Attributes.SetString(D, "DocumentName", D.name); U.obj := D; U.F := NIL; Display.Broadcast(U) END; IF message THEN Texts.OpenWriter(msgW); Texts.WriteObj(msgW, HorzRule); Texts.SetFont(msgW, Fonts.This(FixedFont)); Texts.WriteLn(msgW); oldBin := F.S.bin; GetText(F.S, ".message", msgW); F.S.bin := oldBin; Texts.Insert(F.text, pos-1, msgW.buf) END; Texts.Append(F.text, dirW.buf) END DoDir; PROCEDURE GetContext(VAR F: Frame; VAR D: Documents.Document); BEGIN D := Desktops.CurDoc(Gadgets.context); IF (D.dsc # NIL) & (D.dsc IS Frame) & (D.dsc(Frame).S # NIL) THEN F := D.dsc(Frame) ELSE F := NIL END END GetContext; PROCEDURE ScanName(context: Objects.Object; VAR name: ARRAY OF CHAR; VAR bin: BOOLEAN); VAR R: Texts.Reader; S: Texts.Scanner; obj: Objects.Object; T: Texts.Text; i, beg, end, time: LONGINT; ch: CHAR; BEGIN bin := TRUE; COPY("", name); Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF (S.class = Texts.Char) & (S.c = Oberon.OptionChar) THEN Texts.Scan(S); bin := (CAP(S.s[0]) # "A") & (CAP(S.s[0]) # "T"); Texts.Scan(S) ELSE obj := Gadgets.FindObj(context, "Ascii"); IF obj # NIL THEN Attributes.GetBool(obj, "Value", bin); bin := ~bin ELSE bin := TRUE END END; IF ((S.class = Texts.Char) & (S.c = "^")) OR Desktops.IsInMenu(Gadgets.context)THEN T := NIL; time := -1; Oberon.GetSelection(T, beg, end, time); IF (time >= 0) & (T # NIL) THEN Texts.OpenReader(R, T, beg); Texts.Read(R, ch); WHILE ~R.eot & (~(R.lib IS Fonts.Font) OR (ch <= " ")) DO 					Texts.Read(R, ch) END ELSE COPY("", name); RETURN END; IF ~R.eot & (R.lib IS Fonts.Font) & (ch = 22X) THEN Texts.Read(R, ch) END; i := 0; WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch > " ") & (ch # 22X) DO 				name[i] := ch; INC(i); Texts.Read(R, ch) END; name[i] := 0X ELSIF S.class IN {Texts.Name, Texts.String} THEN COPY(S.s, name) END END ScanName; (** Used by the interactive interface to retrieve the selected file and store it under the same name. *) PROCEDURE GetDocFile*; VAR D: Documents.Document; F: Frame; name: ARRAY NetTools.MaxLine OF CHAR; lname: ARRAY 128 OF CHAR; T: Texts.Text; Wr: Texts.Writer; Fi: Files.File; len: LONGINT; bin: BOOLEAN; BEGIN GetContext(F, D); IF F # NIL THEN ScanName(D.dsc, name, bin); IF name # "" THEN COPY(name, lname); IF F.S.system = VMS THEN TrimmVMS(lname) END; IF bin THEN Texts.WriteString(W, "FTPDocs.GetFile ") ELSE Texts.WriteString(W, "FTPDocs.GetText ") END; Texts.WriteString(W, name); Texts.WriteString(W, " => "); Texts.WriteString(W, lname); Texts.Write(W, " "); Texts.Append(Oberon.Log, W.buf); IF bin THEN GetFile(F.S, name, lname) ELSE NEW(T); Texts.Open(T, ""); Texts.OpenWriter(Wr); GetText(F.S, name, Wr); Texts.Append(T, Wr.buf); Fi := Files.New(lname); Texts.Store(T, Fi, 0, len); Files.Register(Fi) END; Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) END END END GetDocFile; PROCEDURE SkipPath(VAR pname, name: ARRAY OF CHAR); VAR i, j: LONGINT; BEGIN i := 0; j := 0; WHILE (pname[i] # 0X) & (j = 0) DO 			IF (pname[i] = "=") & (pname[i+1] = ">") THEN j := i 			ELSE INC(i) END END; IF j # 0 THEN pname[j] := 0X; INC(j, 2); i := 0; WHILE pname[j] # 0X DO 				name[i] := pname[j]; INC(i); INC(j) END; name[i] := 0X ELSE i := 0; j := 0; WHILE pname[i] # 0X DO 				IF (pname[i] = "/") OR (pname[i] = "\") OR (pname[i] = ":") THEN j := 0 ELSE name[j] := pname[i]; INC(j) END; INC(i) END; name[j] := 0X END END SkipPath; (** Used by the interactive interface to send the selected file and store it under the same name. *) PROCEDURE PutDocFile*; VAR D: Documents.Document; F: Frame; name, rname: ARRAY 128 OF CHAR; T: Texts.Text; bin: BOOLEAN; BEGIN GetContext(F, D); IF F # NIL THEN ScanName(D.dsc, name, bin); IF name # "" THEN IF bin THEN Texts.WriteString(W, "FTPDocs.PutFile ") ELSE Texts.WriteString(W, "FTPDocs.PutText ") END; Texts.WriteString(W, name); Texts.Write(W, " "); Texts.Append(Oberon.Log, W.buf); SkipPath(name, rname); IF bin THEN PutFile(F.S, rname, name) ELSE NEW(T); Texts.Open(T, name); PutText(F.S, rname, T) 				END; Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); DoDir(D, F) 			END END END PutDocFile; (** Used by the interactive interface to delete the selected file. *) PROCEDURE DeleteDocFile*; VAR D: Documents.Document; F: Frame; name: ARRAY NetTools.MaxLine OF CHAR; bin: BOOLEAN; BEGIN GetContext(F, D); IF F # NIL THEN ScanName(D.dsc, name, bin); IF name # "" THEN DeleteFile(F.S, name); Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); DoDir(D, F) 			END END END DeleteDocFile; PROCEDURE TrimmCurDirVMS(VAR curDir: ARRAY OF CHAR); VAR i: LONGINT; BEGIN curDir[0] := "/"; i := 0; WHILE curDir[i] # 0X DO 			INC(i) END; IF i > 0 THEN curDir[i-1] := 0X END END TrimmCurDirVMS; (** Used by the interactive interface to change to directory pointed at *) PROCEDURE ChangeDocDir*; VAR F: Frame; D: Documents.Document; S: Attributes.Scanner; old, new: HyperDocs.Node; key: LONGINT; BEGIN GetContext(F, D); IF F # NIL THEN Attributes.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Attributes.Scan(S); IF S.class IN {Attributes.Name, Attributes.String} THEN ChangeDir(F.S, S.s); IF F.S.res # Done THEN Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) ELSE old := HyperDocs.NodeByDoc(D); DoDir(D, F); IF F.S.system = VMS THEN TrimmCurDirVMS(F.S.curDir) ELSIF F.S.curDir # "/" THEN Strings.AppendCh(F.S.curDir, "/") END; key := RegisterFTPAdr(F.S.host, F.S.curDir, "", "", 0X, F.S.port); IF (old = NIL) OR (old.key # key) THEN HyperDocs.Remember(key, old, new) ELSE new := old END; HyperDocs.LinkNodeToDoc(D, new) END END END END ChangeDocDir; (** Extension of TextGadgets used by the interactive FTPDocs. *) PROCEDURE CopyFrame(VAR C: Objects.CopyMsg; from, to: Frame); BEGIN TextGadgets.CopyFrame(C, from, to); to.S := from.S 	END CopyFrame; PROCEDURE *FrameHandler(F: Objects.Object; VAR M: Objects.ObjMsg); VAR F1: Frame; BEGIN WITH F: Frame DO 			IF 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; CopyFrame(M, F, F1); M.obj := F1 					END END ELSE TextGadgets.FrameHandler(F, M) 			END END END FrameHandler; PROCEDURE CurrentS(VAR S: Session); BEGIN S := NIL; IF (HyperDocs.context # NIL) & (HyperDocs.context.curDoc # NIL) & (HyperDocs.context.curDoc.dsc IS Frame) THEN S := HyperDocs.context.curDoc.dsc(Frame).S 		END END CurrentS; PROCEDURE *LoadDoc(D: Documents.Document); VAR F: Frame; usr, pass, host: ARRAY NetTools.ServerStrLen OF CHAR; path, name: ARRAY NetTools.PathStrLen OF CHAR; i, j, k, key: LONGINT; D2: Documents.Document; T: Texts.Text; new: HyperDocs.Node; port: INTEGER; P: NetTools.ProxyMsg; S: HyperDocs.LinkScheme; type: CHAR; newC: BOOLEAN; BEGIN key := SplitFTPAdr(D.name, host, path, usr, pass, type, port); IF key = HyperDocs.UndefKey THEN D.dsc := NIL; RETURN END; IF proxy & NetTools.UseProxy(host) THEN GetLogin(host, usr, pass); IF (usr = "ftp") OR (usr = "anonymous") THEN usr := ""; pass := "" END; P.key := RegisterFTPAdr(host, path, usr, pass, type, port); P.res := -1; COPY(proxyHost, P.host); P.port := proxyPort; P.D := D; 			S := HyperDocs.LinkSchemeByPrefix("http"); S.handle(S, P); RETURN END; NEW(F); CurrentS(F.S); IF F.S = NIL THEN newC := TRUE; Texts.WriteString(W, host); Texts.Append(Oberon.Log, W.buf); Open(host, usr, pass, port, NIL, F.S); IF F.S.res = Done THEN Texts.WriteString(W, " connected"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) END ELSE newC := FALSE; F.S.res := Done END; IF F.S.res = Done THEN IF F.S.system # VMS THEN j := -1; i := 0; WHILE path[i] # 0X DO 					IF path[i] = "/" THEN j := i 					END; INC(i) END; IF j > 0 THEN k := j; path[j] := 0X; INC(j) ELSE k := -1 END; IF (j > 0) & (path # "") THEN ChangeDir(F.S, path) ELSIF j = 0 THEN ChangeDir(F.S, "/"); j := 1; k := 0 END; IF (j > 0) & (i > j) THEN IF HyperDocs.context # NIL THEN HyperDocs.context.replace := FALSE; HyperDocs.context.history := FALSE END; i := 0; WHILE path[j] # 0X DO 						name[i] := path[j]; INC(i); INC(j) END; name[i] := 0X; D2 := GetDoc(F, name, type); IF D2 # NIL THEN IF newC THEN Close(F.S) 						END; D^ := D2^ ELSE name := ""; path[k] := "/"; ChangeDir(F.S, path) END ELSE name := "" END ELSE i := 0; WHILE (path[i] # 0X) & (path[i] # "]") DO 					INC(i) END; IF path[i] = "]" THEN k := i+1; j := 0; WHILE path[k] # 0X DO 						name[j] := path[k]; INC(j); INC(k) END; name[j] := 0X; path[i+1] := 0X; i := 1; WHILE path[i] # 0X DO 						path[i-1] := path[i]; INC(i) END; path[i-1] := 0X; ChangeDir(F.S, path); IF name # "" THEN IF HyperDocs.context # NIL THEN HyperDocs.context.replace := FALSE; HyperDocs.context.history := FALSE END; D2 := GetDoc(F, name, type); IF D2 # NIL THEN IF newC THEN Close(F.S) 							END; D^ := D2^ ELSE name := "" END END ELSE name := "" END END; IF (F.S.res = Done) & (name = "") THEN TextDocs.InitDoc(D); NEW(T); Texts.Open(T, ""); TextGadgets.Init(F, T, FALSE); DoDir(D, F); IF HyperDocs.context = NIL THEN IF F.S.system = VMS THEN TrimmCurDirVMS(F.S.curDir) END; key := RegisterFTPAdr(host, F.S.curDir, "", "", 0X, port); HyperDocs.Remember(key, NIL, new); HyperDocs.LinkNodeToDoc(D, new) ELSE HyperDocs.context.replace := ~newC; HyperDocs.context.history := TRUE END; D.W := HyperDocs.docW; D.H := HyperDocs.docH; D.dsc := F; D.handle := DocHandler; F.handle := FrameHandler END; IF F.S.res = Done THEN RETURN ELSIF HyperDocs.context # NIL THEN HyperDocs.context.history := FALSE END END; Texts.WriteString(W, " - "); Texts.WriteString(W, F.S.reply); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); F.S := NIL; D.dsc := NIL END LoadDoc; PROCEDURE NewDoc*; VAR D: Documents.Document; BEGIN NEW(D); D.Load := LoadDoc; D.Store := NIL; D.handle := DocHandler; Objects.NewObj := D 	END NewDoc; PROCEDURE Init; BEGIN dataPort := MinDataPort; NetTools.GetHostPort("FTPProxy", proxyHost, proxyPort, 80); proxy := proxyHost # ""; cacheS := NIL; curS := NIL END Init; BEGIN Texts.OpenWriter(W); Texts.OpenWriter(dirW); Texts.SetFont(dirW, Fonts.This(FixedFont)); Init END FTPDocs.

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