diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /system/doc | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'system/doc')
281 files changed, 42733 insertions, 0 deletions
diff --git a/system/doc/Books/src/HOWTO.txt b/system/doc/Books/src/HOWTO.txt new file mode 100644 index 0000000000..1fa47446e3 --- /dev/null +++ b/system/doc/Books/src/HOWTO.txt @@ -0,0 +1,35 @@ +Peter H�gfeldt 2001-04-27 A + +HOWTO for building books for printing +------------------------------------- + +Note: Books are also built automatically by a daily build script. + That is the only safe way to build books. + +Note: Manual handling of dependency files has been removed. + +1. To build a book, ug say, in pdf format with a frame, be sure + to have a clean view, and run + + i) clearmake -V clean + ii) clearmake -V depend + iii) clearmake -V ug.frame.pdf + + You can build the following variants: ug.ps, ug.pdf, ug.frame.ps, + ug.frame.pdf, ug.crop.ps, and ug.crop.pdf. + + To build all frame.pdf and crop.pdf books replace iii) by + + iii) clearmake -V release_books TESTROOT=/some/dest/dir + + and you will get all books in /some/dest/dir. + +2. To change the contents of a book you have to: + + i) Edit the sgml book file, e.g. ug.sgml. + + ii) Do the corresponding changes in the Makefile (if needed). + + + + diff --git a/system/doc/Books/src/Makefile b/system/doc/Books/src/Makefile new file mode 100644 index 0000000000..9d346cb230 --- /dev/null +++ b/system/doc/Books/src/Makefile @@ -0,0 +1,127 @@ +# ---------------------------------------------------- +# Copyright (C) 1997, Ericsson Telecommunications +# Author: Lars Thorsen, Hans Nilsson +# ---------------------------------------------------- +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifeq (ug.dep,$(wildcard ug.dep)) +include ug.dep +include database_management.dep +include orber_ic.dep +include basic_application.dep +include tools.dep +include operation_maintenance.dep +include interfaces.dep +include stdlib.dep +include corba_service.dep +endif + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +BOOKS = \ + ug \ + database_management \ + orber_ic \ + corba_service \ + basic_application \ + tools \ + operation_maintenance \ + interfaces \ + stdlib + +TEX_FILES = $(shell for i in $(BOOKS) ; do (echo $$i.tex); done) + +FRAME_CROP_PDF_FILES = $(BOOKS:%=%.frame.pdf) $(BOOKS:%=%.crop.pdf) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAG_booksty = -booksty otpBOOK +DVIPS_FLAGS += -O '19mm,32.5mm' + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +all: $(FRAME_CROP_PDF_FILES) + +books: all + +clean: + rm -f $(TEX_FILES) + rm -f *.psframe *.pscrop *.ps + rm -f $(TOP_PS_FILES) + rm -f errs core *~ $(LATEX_CLEAN) + rm -f *.dep *.pdf + +dep depend: + @for i in $(BOOKS); do \ + echo "Running docdepend for $$i ..." ; \ + docdepend $$i.xml | \ + sed s/insidecover.tex/insidecover.xml/ > $$i.dep ; \ + done + +# ---------------------------------------------------- +# Rules +# ---------------------------------------------------- +.SUFFIXES: .psframe .pscrop + +# The following rules are for multiple suffixes, e.g. kalle.pdf, +# kalle.frame.pdf. The order of the rules is important. Default rules +# from otp.mk are disabled in order to get it right. + +%.pdf: %.ps + +%.ps: %.dvi + +%.pdf: %.dvi + +%.frame.ps: %.dvi + BOOK=$@ ./make_headers + $(DVI2PS) -frame $(DVIPS_FLAGS) -f $< > $@ + +%.frame.pdf: %.dvi + BOOK=$@ ./make_headers + $(DVI2PS) -frame $(DVIPS_FLAGS) -f $< | \ + $(DISTILL) $(DISTILL_FLAGS) > $@ + +%.crop.ps: %.dvi + BOOK=$@ ./make_headers + $(DVI2PS) -crop $(DVIPS_FLAGS) -f $< > $@ + +%.crop.pdf: %.dvi + BOOK=$@ ./make_headers + $(DVI2PS) -crop $(DVIPS_FLAGS) -f $< | \ + $(DISTILL) $(DISTILL_FLAGS) > $@ + +%.pdf: %.dvi + $(DVI2PS) $(DVIPS_FLAGS) -f $< | \ + $(DISTILL) $(DISTILL_FLAGS) > $@ + +%.ps: %.dvi + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +%.pdf: %.dvi + $(DVI2PS) $(DVIPS_FLAGS) -f $< | \ + $(DISTILL) $(DISTILL_FLAGS) > $@ + +# ---------------------------------------------------- +# Release targets +# ---------------------------------------------------- +# + +ifeq ($(TESTROOT),) +release_books: all + +else +release_books: all + $(INSTALL_DIR) $(TESTROOT)/books + $(INSTALL_DATA) $(FRAME_CROP_PDF_FILES) $(TESTROOT)/books +endif + diff --git a/system/doc/Books/src/basic_application.xml b/system/doc/Books/src/basic_application.xml new file mode 100644 index 0000000000..8097dafd7e --- /dev/null +++ b/system/doc/Books/src/basic_application.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Run-Time System and Basic Applications</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-10-17</date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Run-Time System and Basic Applications</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +This book is a collection of User's Guides for</p> + <list type="bulleted"> + <item>ERTS</item> + <item>SASL</item> + </list> + <p>and of Reference Manuals for</p> + <list type="bulleted"> + <item>ERTS</item> + <item>SASL</item> + <item>Compiler</item> + <item>Kernel</item> + </list> + <p>The Standard Libraries (STDLIB), which are in close + connection with Kernel, are documented in a volume of its + own.</p> + <br></br> + </preface> + </preamble> + <pagetext>ERTS</pagetext> + <parts lift="no"> + <title>ERTS User's Guide</title> + <include file="../../../../erts/erts/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/erts/doc/src/application"></include> + </applications> + <pagetext>SASL</pagetext> + <parts lift="no"> + <title>SASL User's Guide</title> + <include file="../../../../erts/lib/sasl/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/sasl/doc/src/application"></include> + </applications> + <pagetext>Kernel</pagetext> + <applications> + <include file="../../../../erts/lib/kernel/doc/src/application_holder"></include> + </applications> + <pagetext>Compiler</pagetext> + <applications> + <include file="../../../../erts/lib/compiler/doc/src/application"></include> + </applications> + <pagetext>Erlang/OTP Run-Time System and Basic Applications</pagetext> +</book> + diff --git a/system/doc/Books/src/corba_service.xml b/system/doc/Books/src/corba_service.xml new file mode 100644 index 0000000000..dce2894a52 --- /dev/null +++ b/system/doc/Books/src/corba_service.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2001</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 CORBA Services </title> + <prepared></prepared> + <docno>EN/LZT 151 ??? R1</docno> + <date>1997-05-27</date> + <rev></rev> + <abbreviation></abbreviation> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP CORBA Services</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> + + This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +</p> + <p>This book contains documentation about the six applications in Erlang/OTP that + implement the CORBA services. + These applications are:</p> + <list type="bulleted"> + <item><em>cosEvent</em>, an Erlang implementation of the + CORBA service CosEvent.</item> + <item><em>cosEventDomain</em>, an Erlang implementation of the + CORBA service CosEventDomainAdmin.</item> + <item><em>cosFileTransfer</em>, an Erlang implementation of the + CORBA service CosFileTransfer.</item> + <item><em>cosNotificaton</em>, an Erlang implementation of the + CORBA service CosNotification.</item> + <item><em>cosProperty</em>, an Erlang implementation of the + CORBA service CosProperty.</item> + <item><em>cosTime</em>, an Erlang implementation of the + CORBA service CosTime.</item> + <item><em>cosTransaction</em>, an Erlang implementation of the + CORBA service CosTransaction.</item> + </list> + </preface> + </preamble> + <pagetext>cosEvent</pagetext> + <parts lift="no"> + <title>cosEvent User's Guide</title> + <include file="../../../../libraries/cosEvent/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosEvent/doc/src/application"></include> + </applications> + <pagetext>cosEventDomain</pagetext> + <parts lift="no"> + <title>cosEventDomain User's Guide</title> + <include file="../../../../libraries/cosEventDomain/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosEventDomain/doc/src/application"></include> + </applications> + <pagetext>cosFileTransfert</pagetext> + <parts lift="no"> + <title>cosFileTransfer User's Guide</title> + <include file="../../../../libraries/cosFileTransfer/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosFileTransfer/doc/src/application"></include> + </applications> + <pagetext>cosNotification</pagetext> + <parts lift="no"> + <title>cosNotification User's Guide</title> + <include file="../../../../libraries/cosNotification/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosNotification/doc/src/application"></include> + </applications> + <pagetext>cosTime</pagetext> + <parts lift="no"> + <title>cosTime User's Guide</title> + <include file="../../../../libraries/cosTime/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosTime/doc/src/application"></include> + </applications> + <pagetext>cosProperty</pagetext> + <parts lift="no"> + <title>cosProperty User's Guide</title> + <include file="../../../../libraries/cosProperty/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/cosProperty/doc/src/application"></include> + </applications> + <pagetext>Erlang/OTP CORBA Services</pagetext> +</book> + diff --git a/system/doc/Books/src/database_management.xml b/system/doc/Books/src/database_management.xml new file mode 100644 index 0000000000..268612a990 --- /dev/null +++ b/system/doc/Books/src/database_management.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Database Applications </title> + <prepared></prepared> + <docno>EN/LZT 108 194 R2</docno> + <date>1997-05-27</date> + <rev></rev> + <abbreviation></abbreviation> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Database Applications</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +</p> + <p>This book is common for the four applications in Erlang/OTP, which + manage databases. These applications are:</p> + <list type="bulleted"> + <item><em>Mnesia</em>; to be used when + a continuous + operation and soft real-time properties are required.</item> + <item><em>Mnesia_Session</em>; to be used when the Mnesia Database + Management + System has to be accessed from other programming languages than + Erlang.</item> + <item><em>Mnemosyne</em>; to be used as a query language for the + Mnesia Database + Management System. </item> + <item><em>ODBC,</em> Open DataBase Connectivity; to be used when + various SQL + databases will be accessed.</item> + </list> + </preface> + </preamble> + <pagetext>Mnesia</pagetext> + <parts lift="no"> + <title>Mnesia User's Guide</title> + <include file="../../../../libraries/mnesia/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/mnesia/doc/src/application"></include> + </applications> + <pagetext>Mnesia_Session</pagetext> + <parts lift="no"> + <title>Mnesia_Session User's Guide</title> + <include file="../../../../libraries/mnesia_session/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/mnesia_session/doc/src/application"></include> + </applications> + <pagetext>Mnemosyne</pagetext> + <parts lift="no"> + <title>Mnemosyne User's Guide</title> + <include file="../../../../libraries/mnemosyne/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/mnemosyne/doc/src/application"></include> + </applications> + <pagetext>ODBC </pagetext> + <parts lift="no"> + <title>ODBC User's Guide</title> + <include file="../../../../libraries/odbc/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/odbc/doc/src/application"></include> + </applications> + <pagetext>Erlang/OTP Database Applications</pagetext> +</book> + diff --git a/system/doc/Books/src/frame_crop.header.src b/system/doc/Books/src/frame_crop.header.src new file mode 100644 index 0000000000..131045ef8d --- /dev/null +++ b/system/doc/Books/src/frame_crop.header.src @@ -0,0 +1,101 @@ +%% This PostScript file centers the page on an A4 paper and draws a +%% crop marks. dvips is assumed. + +%% DEBUG +%% /mydict 20 dict def mydict begin + +%% Millimeter to postscript points: + +/mm{ 25.4 div 72 mul }def + + +%% The size of the retangle is: + +/papw 172 mm def +/paph 232 mm def + +%% The text area size is: + +%%/txtw{131 mm}def +%%/txth{285 mm}def + + +%% A4 size is: + +/A4w 209 mm def +/A4h 296 mm def + +%% Draw crop marks + +/mkcrop{ + 0.3 setlinewidth + 0 0 mkonecrop + papw 0 mkonecrop + 0 paph mkonecrop + papw paph mkonecrop +} def + +/mkonecrop{gsave + translate + newpath + 0 18 moveto + 0 -18 lineto + stroke + newpath + -18 0 moveto + 18 0 lineto + stroke + grestore } def + +%% Draw a frame + +/mkframe{ + gsave + 0 A4h paph sub moveto + papw 0 rlineto + 0 paph rlineto + papw neg 0 rlineto + 0 paph neg rlineto + stroke + grestore +} def + +/mkmarks{mk@MARKS@} def + +/mkinfo{ gsave + 72 68 moveto (Book: @BOOK@) show + 72 60 moveto (Generated by dvips: @DATE@) show + 72 52 moveto (Config spec: @CSFILE@) show + 72 44 moveto (View: @VIEW@) show + 72 36 moveto (User: @USER@) show + 72 28 moveto (Latex: @LATEX@) show + 72 20 moveto (@DOCBVSN@ @DOCB@) show + 72 12 moveto (@DVIPSVSN@ @DVIPS@) show + 288 68 moveto (Book build: @BOOKBUILD@) show + 288 60 moveto (Build script: @BUILDSCRIPT@) show + grestore +} def + + +%% Beginning-of-page hook (the thing called by dvips): + +/bop-hook{ + gsave + /Helvetica findfont 7 scalefont setfont + gsave + A4w papw sub 2 div + A4h paph sub 2 div neg + translate + mkmarks + grestore + mkinfo + grestore +} def + +%% DEBUG +%%/bop-hook +%%showpage +%%end + + + diff --git a/system/doc/Books/src/insidecover.xml b/system/doc/Books/src/insidecover.xml new file mode 100644 index 0000000000..e6b4b4206c --- /dev/null +++ b/system/doc/Books/src/insidecover.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE bookinsidecover SYSTEM "bookinsidecover.dtd"> + +<bookinsidecover> +Ericsson Utvecklings AB provides this publication ``as is'' without warranty of any kind. In no event shall Ericsson Utvecklings AB be liable for any damage arising from any defect or error in this publication. The contents of this publication is subject to revision without notice due to continued progress in design. <br></br> + <br></br> +Copyright © 1996-2000 Ericsson Utvecklings AB. <br></br> + <br></br> +All rights reserved including the right of reproduction in whole or in part in any form. <br></br> + <vfill></vfill> + <br></br> + <bold>Editors & Layout:</bold> +Anna Fedoriw and Bengt Nilsson <br></br> + <bold>Written and Produced by:</bold> +The Open Telecom Platform Project <br></br> + <bold>Cover by:</bold> +Röjning & Co <br></br> + <br></br> +Fourth revised and restructured edition. <br></br> + <br></br> +Printed in Sweden by XBS Koncerntryck, Stockholm 2000 <br></br> + <br></br> + <vfill></vfill> + <br></br> +For more information: URL <tt>http://www.erlang.se</tt> + <br></br> + <br></br> + <br></br> +Ericsson Utvecklings AB <br></br> +OTP Product Development <br></br> +Box 1505 <br></br> +SE-125 25 ÄLVSJÖ <br></br> +Sweden <br></br> +</bookinsidecover> + diff --git a/system/doc/Books/src/interfaces.xml b/system/doc/Books/src/interfaces.xml new file mode 100644 index 0000000000..b225f9581a --- /dev/null +++ b/system/doc/Books/src/interfaces.xml @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Interface and Communication Applications</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-02-09</date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Interface and Communication </pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +</p> + <p>This book is a collection of the documentation of following applications:</p> + <list type="bulleted"> + <item>Asn1</item> + <item>Comet</item> + <item>Crypto</item> + <item>Erl_Interface</item> + <item>GS</item> + <item>Inets</item> + <item>Jinterface</item> + <item>Megaco</item> + <item>SSL</item> + </list> + </preface> + </preamble> + <pagetext>Asn1</pagetext> + <parts lift="yes"> + <title>Asn1 User's Guide</title> + <include file="../../../../erts/lib/asn1/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/asn1/doc/src/application"></include> + </applications> + <pagetext>Comet </pagetext> + <parts lift="no"> + <title>Comet User's Guide</title> + <include file="../../../../erts/lib/comet/doc/src/users_guide"></include> + </parts> + <applications> + <include file="../../../../erts/lib/comet/doc/src/refman"></include> + </applications> + <pagetext>Crypto</pagetext> + <applications> + <include file="../../../../erts/lib/crypto/doc/src/refman"></include> + </applications> + <pagetext>Erl_Interface</pagetext> + <parts lift="yes"> + <title>Erl_Interface User's Guide</title> + <include file="../../../../erts/lib/erl_interface/doc/src/part_erl_interface"></include> + </parts> + <applications> + <include file="../../../../erts/lib/erl_interface/doc/src/application_erl_interface"></include> + </applications> + <pagetext>GS</pagetext> + <parts lift="no"> + <title>GS User's Guide</title> + <include file="../../../../erts/lib/gs/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/gs/doc/src/application"></include> + </applications> + <pagetext>Inets</pagetext> + <applications> + <include file="../../../../libraries/inets/doc/src/application"></include> + </applications> + <pagetext>Jinterface </pagetext> + <parts lift="yes"> + <title>Jinterface User's Guide</title> + <include file="../../../../erts/lib/jinterface/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/jinterface/doc/src/application"></include> + </applications> + <pagetext>Megaco</pagetext> + <parts lift="no"> + <title>Megaco User's Guide</title> + <include file="../../../../erts/lib/megaco/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/megaco/doc/src/application"></include> + </applications> + <pagetext>SSL </pagetext> + <parts lift="yes"> + <title>SSL Users Guide</title> + <include file="../../../../erts/lib/ssl/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../erts/lib/ssl/doc/src/refman"></include> + </applications> + <pagetext>Erlang/OTP Interface and Communication </pagetext> +</book> + diff --git a/system/doc/Books/src/make_headers b/system/doc/Books/src/make_headers new file mode 100755 index 0000000000..0ec7aca632 --- /dev/null +++ b/system/doc/Books/src/make_headers @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Make Postscript header files (frame and crop marks) +# +# From environment: BOOK CSFILE USER BOOKBUILD + +DATE=`date` +VIEW=`cleartool pwv -s -set` +LATEX=`which latex` +DVIPSVSN=`dvips -version` +DVIPS=`which dvips` +DOCBVSN=`docb_transform -version` +DOCB=`which docb_transform` +for marks in frame crop; do + sed -e "s/@DATE@/$DATE/g" \ + -e "s/@BOOK@/$BOOK/g" \ + -e "s/@MARKS@/$marks/g" \ + -e "s;@CSFILE@;$CSFILE;g" \ + -e "s/@VIEW@/$VIEW/g" \ + -e "s/@USER@/$USER/g" \ + -e "s;@LATEX@;$LATEX;g" \ + -e "s;@DVIPSVSN@;$DVIPSVSN;g" \ + -e "s;@DVIPS@;$DVIPS;g" \ + -e "s/@DOCBVSN@/$DOCBVSN/g" \ + -e "s;@DOCB@;$DOCB;g" \ + -e "s;@BOOKBUILD@;$BOOKBUILD;g" \ + -e "s;@BUILDSCRIPT@;$BUILDSCRIPT;g" \ + frame_crop.header.src > $marks.header +done + diff --git a/system/doc/Books/src/operation_maintenance.xml b/system/doc/Books/src/operation_maintenance.xml new file mode 100644 index 0000000000..41bdd3dff7 --- /dev/null +++ b/system/doc/Books/src/operation_maintenance.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Operation and Maintenance Applications</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-02-09</date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Operation and Maintenance</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> +the documentation is + divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> + + This book is a collection of Erlang application used during Operation and Maintenance. The following applications are covered:</p> + <list type="bulleted"> + <item>EVA</item> + <item>OS_Mon </item> + <item>SNMP</item> + </list> + </preface> + </preamble> + <pagetext>EVA</pagetext> + <parts lift="no"> + <title>EVA User's Guide</title> + <include file="../../../../libraries/eva/doc/src/users_guide"></include> + </parts> + <applications> + <include file="../../../../libraries/eva/doc/src/refman"></include> + <include file="../../../../libraries/eva/doc/src/refman_snmp"></include> + </applications> + <pagetext>OS_Mon</pagetext> + <applications> + <include file="../../../../erts/lib/os_mon/doc/src/application"></include> + </applications> + <pagetext>SNMP</pagetext> + <parts lift="no"> + <title>SNMP User's Guide</title> + <include file="../../../../libraries/snmp/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/snmp/doc/src/application"></include> + </applications> + <pagetext>Erlang/OTP Operation and Maintenance</pagetext> +</book> + diff --git a/system/doc/Books/src/orber_ic.xml b/system/doc/Books/src/orber_ic.xml new file mode 100644 index 0000000000..16eb076dc7 --- /dev/null +++ b/system/doc/Books/src/orber_ic.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>1999</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 CORBA and IDL Applications </title> + <prepared></prepared> + <docno>EN/LZT 151 810 R1</docno> + <date>1997-05-27</date> + <rev></rev> + <abbreviation></abbreviation> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP CORBA and IDL</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> + + This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +</p> + <p>This book contains documentation about the six applications in Erlang/OTP that + implement the CORBA standard. + These applications are:</p> + <list type="bulleted"> + <item> + <p><em>IC</em>, a compiler for OMG Interface Definition + Language (IDL). + The OMG IDL is used for + language-independent interface specifications.</p> + <p>The compiler + is capable of producing;</p> + <list type="bulleted"> + <item>Erlang stub/skeleton code for CORBA (default behavior)</item> + <item>Erlang stub/skeleton code for OTP generic servers</item> + <item>C stub/skeleton code for OTP generic servers</item> + <item>Java stub/skeleton code for OTP generic servers</item> + <item>Erlang code for module interfaces</item> + </list> + </item> + <item><em>Orber</em>, which is an Object Request Broker that can be + used for + accessing distributed services in an + soft real-time environment. It is especially useful for applications + that use a heterogeneous + language environments.</item> + </list> + </preface> + </preamble> + <pagetext>IC</pagetext> + <parts lift="no"> + <title>IC User's Guide </title> + <include file="../../../../libraries/ic/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/ic/doc/src/application"></include> + </applications> + <pagetext>Orber</pagetext> + <parts lift="no"> + <title>Orber User's Guide</title> + <include file="../../../../libraries/orber/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/orber/doc/src/application"></include> + </applications> + <pagetext>Erlang/OTP CORBA and IDL</pagetext> +</book> + diff --git a/system/doc/Books/src/stdlib.xml b/system/doc/Books/src/stdlib.xml new file mode 100644 index 0000000000..31ea0d6962 --- /dev/null +++ b/system/doc/Books/src/stdlib.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Standard Library Application</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-05-30</date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Standard Library Application</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +</p> + <p>This book describes all standard libraries in Erlang/OTP. + It contains modules for manipulating lists, strings, and files etc. + </p> + </preface> + </preamble> + <applications> + <include file="../../../../erts/lib/stdlib/doc/src/application"></include> + </applications> +</book> + diff --git a/system/doc/Books/src/tools.xml b/system/doc/Books/src/tools.xml new file mode 100644 index 0000000000..9d7bf45f31 --- /dev/null +++ b/system/doc/Books/src/tools.xml @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>2000</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 Tool Applications</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-02-09</date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP Tools</pagetext> + <preamble> + <contents level="1"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, + EN/LZT 108 4107 R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> +This book contains User's Guides + and Reference Manuals + for the following applications:</p> + <list type="bulleted"> + <item>Appmon</item> + <item>Debugger</item> + <item>Pman</item> + <item>Toolbar</item> + <item>Tools</item> + <item>TV</item> + </list> + <p>For the following applications, only Reference Manuals are available:</p> + <list type="bulleted"> + <item>Parsetools</item> + <item>Runtime_Tools</item> + </list> + </preface> + </preamble> + <pagetext>Appmon</pagetext> + <parts lift="yes"> + <title>Appmon User's Guide</title> + <include file="../../../../libraries/appmon/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../libraries/appmon/doc/src/application"></include> + </applications> + <pagetext>Debugger</pagetext> + <parts lift="yes"> + <title>Debugger User's Guide</title> + <include file="../../../../tools/debugger/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../tools/debugger/doc/src/application"></include> + </applications> + <pagetext>Pman</pagetext> + <parts lift="yes"> + <title>Pman User's Guide</title> + <include file="../../../../tools/pman/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../tools/pman/doc/src/application"></include> + </applications> + <pagetext>Toolbar</pagetext> + <parts lift="yes"> + <title>Toolbar User's Guide</title> + <include file="../../../../tools/toolbar/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../tools/toolbar/doc/src/application"></include> + </applications> + <pagetext>Tools</pagetext> + <parts lift="no"> + <title>Tools User's Guide</title> + <include file="../../../../tools/tools/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../tools/tools/doc/src/application"></include> + </applications> + <pagetext>TV</pagetext> + <parts lift="yes"> + <title>TV User's Guide</title> + <include file="../../../../tools/tv/doc/src/part"></include> + </parts> + <applications> + <include file="../../../../tools/tv/doc/src/application"></include> + </applications> + <pagetext>Parsetools</pagetext> + <applications> + <include file="../../../../tools/parsetools/doc/src/application"></include> + </applications> + <pagetext>Runtime_Tools</pagetext> + <applications> + <include file="../../../../tools/runtime_tools/doc/src/refman"></include> + </applications> + <pagetext>Erlang/OTP Tools</pagetext> +</book> + diff --git a/system/doc/Books/src/ug.xml b/system/doc/Books/src/ug.xml new file mode 100644 index 0000000000..15b3dc0a31 --- /dev/null +++ b/system/doc/Books/src/ug.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="special"> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang 5.1/OTP R8 System Documentation</title> + <prepared></prepared> + <docno>EN/LZT 151 247 R2</docno> + <date></date> + <rev></rev> + </header> + <insidecover> + <include file="insidecover"></include> + </insidecover> + <pagetext>Erlang/OTP System Documentation</pagetext> + <preamble> + <contents level="2"></contents> + <preface> + <p><em>Introduction</em> <br></br> +This documentation describes the Open + Telecom Platform (Erlang/OTP), a middle-ware based on the Erlang + programming language, aiming at providing time-saving and flexible + development for robust, adaptable telecom systems.</p> + <p><em>Organization of the Documentation</em> <br></br> + + The documentation is divided into eight parts:</p> + <list type="bulleted"> + <item>Erlang 5.0/OTP R7 System Documentation, EN/LZT 1084095 R1</item> + <item>Erlang 5.0/OTP R7 Run-Time System and Basic Applications, + EN/LZT 108 4106 R1</item> + <item>Erlang 5.0/OTP R7 Standard Library Application, EN/LZT 108 4107 + R1</item> + <item>Erlang 5.0/OTP R7 Database Applications, EN/LZT 108 194 R3</item> + <item>Erlang 5.0/OTP R7 CORBA and IDL Applications, + EN/LZT 151 810 R2</item> + <item>Erlang 5.0/OTP R7 Interface and Communication Applications, + EN/LZT 108 4110 R1</item> + <item>Erlang 5.0/OTP R7 Operation and Maintenance Applications, + EN/LZT 108 4108 R1</item> + <item>Erlang 5.0/OTP R7 Tool Applications, EN/LZT 108 4109 R1</item> + </list> + <p><em>About this Book</em> <br></br> + This book is the starting point of the documentation and contains information about the Erlang programming language and runtime system, the OTP design principles, and how to install and configure Erlang/OTP.</p> + <list type="bulleted"> + <item>Chapter 1: Introduction</item> + <item>Chapter 2: "Getting Started with Erlang" gives an introduction to the Erlang runtime system and to tools such as Compiler and Debugger.</item> + <item>Chapter 3: "OTP Design Principles" describes a way to structure Erlang code in terms of applications and supervision trees. The standard behaviors are described and examples illustrate how to apply these behaviors to typical applications.</item> + <item>Chapter 4: "System Principles" describes the strategies + and options, which are available to start an Erlang/OTP system. </item> + <item>Chapter 5: "Operation and Management Principles" describes the model for operation and maintenance of sub-systems.</item> + <item>Chapter 6: "Installation Guide"gives guidelines on how to install Erlang/OTP on UNIX or Windows.</item> + <item>Chapter 7: "Embedded Systems" is a supplement to "Installation Guide", It describes issues that are specific for running Erlang/OTP on an embedded system.</item> + <item>Chapter 8: "Erlang Extensions Since 4.4" lists all extensions to the Erlang programming languages since the latest version of the book <em>Concurrent Programming in ERLANG</em>.</item> + <item>Chapter 9: "Interoperability Tutorial" gives an orientation of the different + interoperability mechanisms, which can be used when integrating an + Erlang program with a program written in an other programming language.</item> + </list> + </preface> + </preamble> + <pagetext>Introduction</pagetext> + <parts lift="yes"> + <title>Introduction</title> + <include file="../../system_architecture_intro/part"></include> + </parts> + <pagetext>Getting Started with Erlang</pagetext> + <parts lift="yes"> + <title>Getting Started with Erlang</title> + <include file="../../getting_started/part"></include> + </parts> + <pagetext>Design Principles</pagetext> + <parts lift="no"> + <title>OTP Design Principles</title> + <include file="../../design_principles/part"></include> + </parts> + <pagetext>System Principles</pagetext> + <parts lift="yes"> + <title>System Principles</title> + <include file="../../system_principles/part"></include> + </parts> + <pagetext>Operation and Management Principles</pagetext> + <parts lift="yes"> + <title>Operation and Management Principles</title> + <include file="../../oam/part"></include> + </parts> + <pagetext>Installation Guide</pagetext> + <parts lift="no"> + <title>Installation Guide</title> + <include file="../../../../system/doc/installation_guide/part"></include> + </parts> + <pagetext>Embedded System</pagetext> + <parts lift="no"> + <title>Embedded System</title> + <include file="../../../../system/doc/embedded/part"></include> + </parts> + <pagetext>Erlang Extensions since 4.4</pagetext> + <parts lift="no"> + <title>Erlang Extensions since 4.4</title> + <include file="../../../../system/doc/extensions/part"></include> + </parts> + <pagetext>Interoperability Tutorial</pagetext> + <parts lift="no"> + <title>Interoperability Tutorial</title> + <include file="../../tutorial/part"></include> + </parts> + <pagetext>Erlang/OTP System Documentation</pagetext> +</book> + diff --git a/system/doc/Makefile b/system/doc/Makefile new file mode 100644 index 0000000000..3f32e35561 --- /dev/null +++ b/system/doc/Makefile @@ -0,0 +1,46 @@ +# ``The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved via the world wide web at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# The Initial Developer of the Original Code is Ericsson Utvecklings AB. +# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +# AB. All Rights Reserved.'' +# +# $Id$ +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# +# Macros +# + +SUB_DIRECTORIES = design_principles \ + getting_started \ + system_architecture_intro \ + embedded \ + system_principles \ + oam \ + installation_guide \ + tutorial \ + efficiency_guide \ + reference_manual \ + programming_examples \ + top + +# pics \ + +SPECIAL_TARGETS = + +# +# Default Subdir Targets +# +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/system/doc/book.xml b/system/doc/book.xml new file mode 100644 index 0000000000..d1ec093019 --- /dev/null +++ b/system/doc/book.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erlang/OTP System Documentation</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2009-08-21</date> + <rev>A</rev> + <file>book.xml</file> + </header> + <insidecover> + </insidecover> + <pagetext></pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="installation_guide/part.xml"/> + <xi:include href="system_principles/part.xml"/> + <xi:include href="embedded/part.xml"/> + <xi:include href="getting_started/part.xml"/> + <xi:include href="reference_manual/part.xml"/> + <xi:include href="getting_started/part.xml"/> + <xi:include href="efficiency_guide/part.xml"/> + <xi:include href="tutorial/part.xml"/> + <xi:include href="design_principles/part.xml"/> + <xi:include href="oam/part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/definitions/cite.defs b/system/doc/definitions/cite.defs new file mode 100644 index 0000000000..41fffc1460 --- /dev/null +++ b/system/doc/definitions/cite.defs @@ -0,0 +1,26 @@ +[ +{"4711","CCITT","CCITT, Red Book Vol.-FASCILE VIII.7, Recomm. X400-X.430, Geneva, 1985","jocke"}, +{"X.680","ITU-T X.680","ITU-T Recommendation X.680 (1994) | ISO/IEC 8824-1: 1995, Abstract Syntax Notation One (ASN.1): Specification of Basic Notation"}, +{"X.682","ITU-T X.682","ITU-T Recommendation X.682 (1994) | ISO/IEC 8824-3: 1995, Abstract Syntax Notation One (ASN.1): Constraint Specification"}, +{"X.690","ITU-T X.690","ITU-T Recommendation X.690 (1994) | ISO/IEC 8825-1: 1995, ASN.1 Encoding Rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)"}, +{"X.691","ITU-T X.691","ITU-T Recommendation X.691 (04/95) | ISO/IEC 8825-2: 1995, ASN.1 Encoding Rules: Specification of Packed Encoding Rules (PER)"}, +{"X.681","ITU-T X.681","ITU-T Recommendation X.681 (1994) | ISO/IEC 8824-2: 1995, Abstract Syntax Notation One (ASN.1): Information Object Specification"}, +{"X.683","ITU-T X.683","ITU-T Recommendation X.683 (1994) | ISO/IEC 8824-4: 1995, Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 Specifications"}, +{ + "DUBUISSON", + "ASN.1 Communication between Heterogeneous Systems", + "Oliver Dubuisson, ASN.1 Communication between Heterogeneous Systems, " + "June 2000 ISBN 0-126333361-0", "nibe" + }, + { + "erlbook2", + "Concurrent Programming in ERLANG", + "J. Armstrong, R. Virding, C. Wikstrom, M. Williams, " + "Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X", + "kent" + }, + {"practsgml", "Practical SGML", + "Eric van Herwijnen: Practical SGML, Kluwer Academic Publishers, 1990.", + "peter" +} +]. diff --git a/system/doc/definitions/cite.defs.xml b/system/doc/definitions/cite.defs.xml new file mode 100644 index 0000000000..e54251fa24 --- /dev/null +++ b/system/doc/definitions/cite.defs.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cites SYSTEM "cites.dtd"> + +<cites> + <cite> + <id>4711</id> + <shortdef>CCITT</shortdef> + <def> +CCITT, Red Book Vol.-FASCILE VIII.7, Recomm. X400-X.430, Geneva, 1985. </def> + <resp>jocke</resp> + </cite> + <cite> + <id>X.680</id> + <shortdef>ITU-T X.680</shortdef> + <def> +ITU-T Recommendation X.680 (1994) | ISO/IEC 8824-1: 1995, Abstract Syntax Notation One (ASN.1): Specification of Basic Notation. </def> + </cite> + <cite> + <id>X.682</id> + <shortdef>ITU-T X.682</shortdef> + <def> +ITU-T Recommendation X.682 (1994) | ISO/IEC 8824-3: 1995, Abstract Syntax Notation One (ASN.1): Constraint Specification. </def> + </cite> + <cite> + <id>X.690</id> + <shortdef>ITU-T X.690</shortdef> + <def> +ITU-T Recommendation X.690 (1994) | ISO/IEC 8825-1: 1995, ASN.1 Encoding Rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER). </def> + </cite> + <cite> + <id>X.691</id> + <shortdef>ITU-T X.691</shortdef> + <def> +ITU-T Recommendation X.691 (04/95) | ISO/IEC 8825-2: 1995, ASN.1 Encoding Rules: Specification of Packed Encoding Rules (PER). </def> + </cite> + <cite> + <id>X.681</id> + <shortdef>ITU-T X.681</shortdef> + <def> +ITU-T Recommendation X.681 (1994) | ISO/IEC 8824-2: 1995, Abstract Syntax Notation One (ASN.1): Information Object Specification. </def> + </cite> + <cite> + <id>X.683</id> + <shortdef>ITU-T X.683</shortdef> + <def> +ITU-T Recommendation X.683 (1994) | ISO/IEC 8824-4: 1995, Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 Specifications. </def> + </cite> + <cite> + <id>DUBUISSON</id> + <shortdef>ASN.1 Communication between Heterogeneous Systems</shortdef> + <def> +Oliver Dubuisson, ASN.1 Communication between Heterogeneous Systems, June 2000 ISBN 0-126333361-0. </def> + <resp>nibe</resp> + </cite> + <cite> + <id>erlbook2</id> + <shortdef>Concurrent Programming in ERLANG</shortdef> + <def> +J. Armstrong, R. Virding, C. Wikstrom, M. Williams, Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X. </def> + <resp>kent</resp> + </cite> + <cite> + <id>practsgml</id> + <shortdef>Practical SGML</shortdef> + <def> +Eric van Herwijnen: Practical SGML, Kluwer Academic Publishers, 1990. </def> + <resp>peter</resp> + </cite> +</cites> + diff --git a/system/doc/definitions/term.defs b/system/doc/definitions/term.defs new file mode 100644 index 0000000000..f3d6f865d2 --- /dev/null +++ b/system/doc/definitions/term.defs @@ -0,0 +1,215 @@ +[{"agent","agent","An entity that terminates a management protocol in the Network Element.","mbj"}, +{"API","API","Application Programming Interface. The interface towards an application. Usually this is a set of functions available, but can also be a set of messages sent to or from an application.","mbj"}, +{"application","application","A collection of resources which is required to offer a specific service.","mbj"}, +{"appmon","Application Monitor","A graphical node and application process tree viewer. See also appmon.","mbj"}, +{"Appmon","Appmon","Application name for the Application Monitor within Erlang/OTP. A graphical node and process viewer.","mbj"}, +{"app callback","application callback module","A module which is called when the application is started, and when it has stopped. Every application has one application callback module.","mbj"}, +{"AC","application controller","A process which coordinates all operations on applications.","mbj"}, +{"app master","application master","The application master is a process that monitors the application. It is provided by the Erlang run-time system. Every application has an application master process.","mbj"}, +{".app file","application resource file","Specifies the resources required by the application and how the application should be started. Every application has one application resource file, called AppName.app.","mbj"}, +{"arity","arity","Denotes the number of arguments to a function.","jocke"}, +{"ASN.1","ASN.1","Abstract Syntax Notation One - an ITU-T and ISO standard notation for describing data formats used in communication protocols.","kenneth"}, +{"ASN.1 Compiler","ASN.1 Compiler","The Erlang/OTP ASN.1 Compiler translates an ASN.1 module into a corresponding Erlang module with encode and decode functions.","kenneth"}, +{"atom","atom","An atom is a constant. Atoms always starts with a lower case letter (a-z) and are terminated by a non-alphanumeric character - otherwise they must be quoted (enclosed in \' \'). An atom is a data type in Erlang, used to enhance the legibility of programs.","kenneth"}, +{"atomicity","atomicity","Atomicity refers to the \"all or nothing\" property. If a transaction succeeds (i.e. commits), then all its effects on the data is captured in the database. If the transaction does not succeed (i.e. aborts), then none of its effect on the data is captured in the database. In other words, the transaction processing algorithm guarantees that the database will not reflect a partitial effect of a transaction.","hakan"}, +{"attach","attach","The debugger may attach to a process. When attached, the debugger may show process details, such as message queues and variable bindings.","olin"}, +{"behaviour","behaviour","A \"pattern of design\" which can be used to build applications and processes in an applications.","mbj"}, +{"BIF","BIF","Built-In Functions which perform operations that are impossible or inefficient to program in Erlang itself. Are defined in +the module Erlang in the application kernel","kenneth"}, +{"binary","binary","A data type in Erlang which is used to store an area of untyped memory. Binaries are used for efficiently handling large quantities of untyped data.","kenneth"}, +{"boolean","boolean","A common data type in programming and specification languages. The value can be either true or false.","kenneth"}, +{"boot file","boot file","A binary file with extension .boot which is read during start of an Erlang node. See SASL User's Guide for more info.","kenneth"}, +{"break point","break point","By setting a break point using the debugger, the user specifies a position in the source code of a module where execution is to be suspended and control transferred to the debugger.","olin"}, +{"CAshort","CA","See Certification Authority.","helen"}, +{"CA certificate","CA certificate","A certificate containing a CA's public key. Network entities use this public key to verify certificates signed with the CA's private key.","helen"}, +{"callback function","callback function","A callback function is a function exported from a callback module, that a generic behaviour calls to perform a specific task.", "mbj"}, +{"callback module","callback module","A callback module is a module that implements the specific parts of a generic behaviour. The generic behaviour specifies which callback functions must be exported from the module.","mbj"}, +{"certificate","certificate","A file used for authenticating network entities under the SSL protocol. A certificate contains information about its owner (called the subject) and issuer, plus the owner's public key and a signature made by a CA. Network entities verify these signatures using CA certificates.","helen"}, +{"CAlong","Certification Authority (CA)","A trusted third party whose purpose is to sign certificates for network entities it has authenticated using secure means. Other network entities can check the signature to verify that a CA has authenticated the bearer of a certificate.","helen"}, +{"CSRlong","Certificate Signing Request (CSR)","An unsigned certificate for submission to a Certification Authority, which signs it with its private key. Once the CSR is signed, it becomes a certificate.","helen"}, +{"child","child","A supervised process. See also permanent, transient, temporary child.","mbj"}, +{"cipher","cipher","A system of encryption.","helen"}, +{"ClearCase","ClearCase","A configuration management system from Rational Software Corporation.","lars"}, +{"client-server model","client-server model","A model where there is a server, which manages some resource, and a number of clients which send requests to the server to access the resource. The client-server model is one of the basic programming techniques for coordinating the activities of several parallel processes.","mbj"}, +{"cover","Coverage Analyser","Module name for the coverage analyser tool, located in the Tools application.","gunilla"}, +{"CORBAlong","Common Object Request Broker Architecture (CORBA)","A specification of an architecture for a distributed object system","lars"},{"CORBA","Common Object Request Broker Architecture (CORBA)","A specification of an architecture for a distributed object system","lars"}, +{"compiler","compiler","A compiler is a translator. A common type of compilers are those who takes source code for a programming language and translates it into code that is executable on a specific platform. E.g. the Erlang compiler translates Erlang source code to an intermediary code that is executable by the Erlang Run Time System.","kenneth"}, +{"consistency","consistency","Consistency refers to the requirement that, given a consistent initial database state, the state of the database after the successful execution of a transaction is also consistent; that is, a transaction transforms the database from a consistent state to another consistent state. Database consistency may be defined as a set of rules or constraints. If the execution of a transaction causes the consistency constraints to be violated, the transaction is not accepted (and thus aborted) by the system.","hakan"}, +{"cookie","cookie","A magic cookie is a secret atom assigned to each Erlang node. The Erlang nodes in a distributed system must know each others cookies in order to authorize each other for communication","kenneth"}, +{"CORBAshort","CORBA","See Common Object RequestBroker Architecture.","lars"}, +{"Coverage Analyser","Coverage Analyser","A tool which provides a set of functions for coverage analysis of Erlang programs, i.e observing how many times each line or function are executed. See also cover.","olin"}, +{"coverage analysis","coverage analysis","The task of determining which lines, or how many lines of code, has actually been executed. Useful for determining the completeness of test suites.","olin"}, +{"cross reference tool","cross reference tool","A tool that can be used for finding dependencies between functions, modules, applications and releases. The Erlang/OTP cross reference tool is called xref and is part of the Tools application.","gunilla"}, +{"CSRshort","CSR","See Certificate Signing Request.","helen"}, +{"data type","data type","The data types in Erlang are numbers, atoms, tuples, lists, pids, funs, records, ports, references and binaries. The values of Erlang data types can be stored in variables.","kenneth"}, +{"DBMSlong","Database Management System (DBMS)","A database is a collection of data and a DBMS is a system which manages the database. Applications accesses the database through the database management system.","hakan"}, +{"DBMSshort","DBMS","See Database Management System.","hakan"}, +{"Debugger","Debugger","An Erlang/OTP tool which provides mechanisms which makes it possible to see what happens during the execution of code in specified modules, or when processes crash.","olin"}, +{"dets","dets","A module within the stdlib application, which provides a term storage, and which is used as the underlying file storage mechanism by the Mnesia DBMS.","hakan"}, +{"dirty operations","dirty operations","Functions which manipulate data in a DBMS, without using transactions.","hakan"}, +{"distributed application","distributed application","An application which runs on one of several nodes. May be restarted on another node. (See local application.)","mbj"}, +{"DNSshort","DNS","See Domain Name System.","lars"}, +{"Docbuilder","Docbuilder","The documentation system used in Erlang/OTP.","jocke"}, +{"DNSlong","Domain Name System (DNS)","DNS is a service that map names to internet addresses","lars"}, +{"DTD","DTD","Document Type Definition as defined in SGML.","jocke"}, +{"durability","durability","If a transaction succeeds, then its effect on the data is persistently captured, and will survive subsequent system failures resulting in loss of data in volatile memory. Durability is usually enforced by first writing modified data to some non-volatile memory (usually disc), before a transaction is allowed to commit. If there is a system failure, the state of the non-volatile memory must be recovered to reflect the effect of all and only committed transactions.","hakan"}, +{"Emacs","Emacs"," A widely used text editor which allows customization of its behaviour. An Erlang mode for Emacs is included in the Erlang deliverables.","kenneth"}, +{"Emacs for Erlang","Emacs for Erlang","A tool which provides a major mode for editing Erlang source files in Emacs.","olin"}, +{"encaps","encapsulation","Data can be encapsulated into another data element.","kent"}, +{"eprof","eprof","A module in the tools application. See Profiler.","olin"}, +{"erl","erl","The command which starts an Erlang run-time system.","kenneth"}, +{"erl_interface","erl_interface library","A thread safe library with C-functions which makes it possible to write a C-program which appears as one of the nodes in a system of distributed Erlang nodes.","kenneth"}, +{"Erlang","Erlang","Erlang is a functional programming language intended for designing large industrial soft real time systems.","kenneth"}, +{"Erlang emulator","Erlang emulator","Another word for Erlang Virtual Machine.","kenneth"}, +{"ERTSlong","Erlang Run Time System","A fundamental part of Erlang/OTP which contains the Erlang Virtual Machine, the kernel and stdlib applications. The Erlang Run Time System is a mandatory part which all other Erlang applications are dependent upon.","kenneth"}, +{"Erlang VM","Erlang Virtual Machine","The virtual machine, which makes Erlang/OTP work together with a specific OS/HW platform. The Erlang Virtual Machine is available on several different platforms. The Erlang Virtual Machine is the glue which makes it possible to run an Erlang application on any platform without change.","kenneth"}, +{"ERTSshort","ERTS","See Erlang Run Time System.","kenneth"}, +{"ETS","ETS","Erlang Term Storage tables.","olin"}, +{"EVAshort","EVA","See Event and Alarm handling application","mbj"}, +{"EVAlong","Event and Alarm handling application (EVA)","An application that consists of Fault Management functionality, such as sending and logging of events and alarms.","mbj"}, +{"event handler","event handler","A module exporting functions which can process events sent to an event manager process. The event handler is a behaviour of type gen_event.","mbj"}, +{"event manager","event manager","A process to which events of a certain category is sent. gen_event handler can be installed in the event manager.","mbj"}, +{"exit signal","exit signal","A signal which is sent from a terminating process to the processes and ports it is linked to. An EXIT signal has the following format: {'EXIT', Exiting_Process_Id, Reason}.","kent"}, +{"foo","foo","Algebraic place holder.","kent"}, +{"FSM","FSM","Finite State Machine.","kenneth"}, +{"fun","fun","A data type, introduced in Erlang 4.4, which represent functional objects.","kenneth"}, +{"function","function","Erlang programs are written entirely in terms of modules with functions. A function can have arguments and does always return a result. A function can be exported which makes it available for calls from other modules. Non exported functions can only be called internally within the module.","kenneth"}, +{"Gateway","gateway","A server which acts as an intermediary for some other server. Unlike a proxy, a gateway receives requests as if it were the origin server for the requested resource; the requesting client may not be aware that it is communicating with a gateway.","jocke"}, +{"gen_event","gen_event","A behaviour used for programming event handling mechanisms, such as alarm handlers, error loggers, and plug-and-play handlers.","mbj"}, +{"gen_fsm","gen_fsm","A behaviour used for programming finite state machines.","mbj"}, +{"gen_server","gen_server","A behaviour used for programming client-server processes.","mbj"}, +{"gterm","Global Glossary Database","A glossary database used to list common acronymns and defintions etc.","jocke"}, +{"xref","xref","A cross reference tool that can be used for finding dependencies between functions, modules, applications and releases. Part of the Tools application.","gunilla"}, +{"GSlong","Graphics System","A library module which provides a graphics interface for Erlang.","mbj"}, +{"grid","grid","A multi-column object which is used to display tables. (Graphics System.)","mbj"}, +{"GSshort","GS","See Graphics System.","olin"}, +{"GS Contributions","GS Contributions","Unsupported user supplied tools which are included with the Erlang/OTP software release.","olin"}, +{"GUI","GUI","Graphical User Interface","mbj"}, +{"Home Directory","Home Directory","The position of a user account in the file system. The Home Directory is automatically passed to the Erlang run-time system at startup. On Unix the contents of the environment variable \"HOME\" is passed. Om Win32 the concatenation of the environment variables \"HOMEDRIVE\" and \"HOMEPATH\" is passed, or if these variables are not set, the value returned by the Win32 API function \"GetWindowsDirectory\" is passed.","kenneth"}, +{"host name","host name","The name of a machine on a network, e.g. erlang.ericsson.se.","kent"}, +{"HTML","HTML","Hypertext Markup Language.","jocke"}, +{"HTTP","HTTP","Hypertext Transfer Protocol.","jocke"}, +{"HTTPS","HTTPS","The Hypertext Transport Protocol, Secure, the standard SSL communication mechanism of the World Wide Web.","helen"}, +{"IDLshort","IDL","See Interface Description Language.","lars"}, +{"IDLlong","Interface Description Language (IDL)","The interface specification language created by OMG.","lars"}, +{"indexing","indexing","Fast lookup using an (usually enumerated) key.","kent"}, +{"I1","INETS","The Internet Services application","jocke"}, +{"initial call","initial call","The first call to an interpreted function (when using the Interpreter).","kent"}, +{"instrumentation function","instrumentation function","A function used to implement a Managed Object, i.e. give access to the real resources behind an MO.","mbj"}, +{"IDLlong","Interface Description Language (IDL)","The interface specification language created by OMG.","lars"}, +{"interpreter","interpreter","An application which provides mechanisms which make it possible to see what happens during the execution of code in specified (interpreted) modules, or when processes crash.","kent"}, +{"isolation","isolation","A transaction executes as if no other concurrent transactions are executing, and thus its execution results are equivalent to those obtained by executing database transactions serially. A system which maintains transaction isolation is also said to be enforcing serializability.","hakan"}, +{"kernel","kernel","An application which contains file servers, code servers and other code necessary for the Erlang run-time system.","kenneth"}, +{"key","key","A file containing the value that must be fed into an algorithm in order to encrypt or decrypt a message.","helen"}, +{"key pair","key pair","A set of two keys used in public key cryptography. One is the public key used to encrypt data, and the other is the private key necessary to decrypt the same data.","helen"}, +{"list","list","Terms separated by commas and enclosed in square brackets [ ] are called lists. A list is a data type in Erlang, used for storing a variable number of terms. It is dynamically sized. The first element of the list is referred to as the head of the list, and the remainer of the list as the tail.","kenneth"}, +{"list box","list box ","A list of labels with optional scroll bars attached. (Graphics System.)","mbj"}, +{"lc","list comprehension","A language construct in Erlang which are analogous to set comprehensions in Zermelo-Frankel set theory. Analogous to the 'setof' and 'findall' predicates in Prolog.","kenneth"}, +{"local application","local application","An application which runs on one node and which are always started at the local node only. (See distributed application.)","mbj"}, +{"manager","manager","An entity that terminates a management protocol in the Network Management Station.","mbj"}, +{"Master Agent","Master Agent","The SNMP agent system consists of one Master Agent which terminates the SNMP protocol","mbj"}, {"MIB","Management Information Base (MIB)","An abstract definition of the management information available through a management interface in a system.","mbj"}, +{"matching","matching","See pattern matching.","kenneth"}, +{"message queue","message queue","The queue of not yet received messages that are in the mailbox of a process.","olin"}, +{"Mnemosyne","Mnemosyne","Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.","hakan"}, +{"Mnesia","Mnesia","Mnesia is a distributed Database Management System, appropriate for telecommunications applications and other applications with need of continuous operation and soft real-time properties.","hakan"}, +{"MIBshort","MIB","See Management Information Base.","mbj"}, +{"MIME","MIME","Multi-purpose Internet Mail Extensions.","jocke"}, +{"MOlong","Managed Object (MO)","The abstract management information defined in a MIB.","mbj"}, {"MO", "MO","Managed Object; The abstract management information defined in a MIB.","nibe"}, +{"MOshort","MO","See Managed Object.","mbj"}, +{"module","module","Module is the unit for compilation and for loading in Erlang. A Module contains a module declaration, export declarations and code representing the functions in the module.","kenneth"}, +{"NCSA","NCSA","The National Center for Supercomputing Applications.","jocke"}, +{"NEshort","NE","See Network Element.","mbj"}, +{"NElong", "Network Element","In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity.","mbj"}, {"NE", "NE","Network Element; In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity.","mbj"}, +{"NMSlong","Network Management Station (NMS)","The place where the operator manages the network.","mbj"}, {"NMS","NMS","Network Management Station; The place where the operator manages the network.","nibe"}, +{"NMSshort","NMS","See Network Management Station.","mbj"}, +{"node","node","An executing Erlang run-time system which can communicate with other Erlang run-time systems.","kenneth"}, +{"node name","node name","A node name is an atom constructed as the concatenation of a name supplied by the user, an \"@\" character, and the name of the host where the node is executing.","kenneth"}, +{"notation","notation","How things are written.","kent"}, +{"notification","notification","Information of an event.","kent"}, +{"NROFF","NROFF","A text formatting language for line printer quality output devices that runs on the UNIX operating system.","jocke"}, +{"number","number","A data type in Erlang. Are subdivided into integers, for storing natural numbers, or floats, for storing real numbers.","kenneth"}, +{"OMGlong","Object Managment Group (OMG)","A standardisation group for all specifications in the area of CORBA.","lars"}, +{"OMGshort","OMG","Object Managment Group.","lars"}, +{"OTP","OTP","Open Telecom Platform","mike"}, +{"os_mon","os_mon","An application which monitors the behaviour of the underlying operating system","mbj"}, +{"parser generator","parser generator","A tool for making compilers which takes a grammar description as input and generates a complete program (a parser) which recognizes input which complies with the grammar. YECC is a parser generator included in the Erlang/OTP.","kenneth"}, +{"pass phrase","pass phrase","The word or phrase which authenticates the user who is authorized to use private key file. The pass phrase prevents unauthorized users from starting, restarting, or reconfiguring the server.","helen"}, +{"pattern matching","pattern matching","A basic mechanism in Erlang for assigning values to variables and for controlling the flow of a program.","kenneth"}, +{"permanent child","permanent child","A supervised process which always is restarted when it dies.","mbj"}, +{"Pid","Pid","Process Identifier. A data type in Erlang for storing process references. The process identity of the process displayed in the line.","kenneth"}, +{"Pman","Pman","Module and application name for the Process Trace Tool.","olin"}, +{"point","point","A unit used to indicate the size of a typeface. Equal to 1/72 inches.","jocke"}, +{"pointer","pointer","A pointer tells where data is stored. Memory pointers are not used in Erlang.","kent"}, +{"port","port","A data type in Erlang. Ports provide the basic mechanism for communication with the external world.","peterl"}, +{"port controller","port controller","An Erlang process which controls a port program. A port has exactly one port controller.","peterl"}, +{"port program","port program","A program that runs as an external program in the operating system and which the Erlang run-time system can start and communicate with by means of the Erlang port mechanism.","kenneth"}, +{"PostScript","PostScript","A language describing a fully laid-out page in terms of fonts, lines, grey scales, and so on, in a way that is interpretable by a printer. The language was developed by Adobe Systems.","jocke"}, +{"pretty-printed","pretty-printed","Nicely formatted code or data, e.g. C or Erlang, with indents and tabs etc.","jocke"}, +{"primitive","primitive","The basic elements in a programming language.","kent"}, +{"private key","private key","The secret key in a pair, used to decrypt incoming messages and sign outgoing ones.","helen"}, +{"process","process","A process is a self-contained separate unit of execution which exists concurrently with other processes in the system. The BIF \"spawn/3\" creates and starts the execution of a new process.","kenneth"}, +{"process dictionary","process dictionary","Each process has an associated dictionary which provides the process with simple destructive storage capabilities.","kenneth"}, +{"Process Manager","Process Manager","Obsolete name for the Process Trace Tool.","olin"}, +{"Process Trace Tool","Process Trace Tool","A tool which gives an overview of the processes in the Erlang run-time system. See also Pman.","olin"}, +{"Profiler","Profiler","Another name for eprof, a tool used to profile a system in order to find out how much time is spent in various segments of a program.","olin"}, +{"program","program","Routines which can be executed by a computer.","kent"}, +{"Proxy","proxy","An intermediary program which acts as both a server and a client for the purpose of making requests on behalf of other clients.","jocke"}, +{"public key","public key","The publicly available key in a key pair, used to encrypt messages bound for its owner and to decrypt signatures made by its owner.","helen"}, +{"query","query","Queries are used for accessing the data in a Database Management System. The query specify a maybe complicated relation that should hold for all of the selected data. This could involve several tables as well as conditions like for instance less then and greater then.","hakan"}, +{"query language","query language","A language which is specially designed to express database queries. Examples of query languages are QLC and SQL.","hakan"}, +{"receive","receive","A primitive for message processing in Erlang, receives a message from a process.","kenneth"}, +{"record","record","A data structure intended for storing a fixed number of related Erlang terms, it is similar to a \"struct\" in C or a \"record\" in Pascal.","kenneth"}, +{"recursion","recursion","A function is recursive if it calls itself until the result desired is attained. Recursion is the heart of functional programming.","kenneth"}, +{"reference","reference","A data type in Erlang for storing system unique references.","kenneth"}, +{"release handler","release handler","A SASL process which handles software upgrade.","mbj"}, +{"relup","release upgrade script","A script with instructions to the release handler of how the release should be installed in the system.","mbj"}, +{"RPC","Remote Proceedure Call","A technique for evaluating a function transparently on a remote node.","kenneth"}, +{"resource","resource","The actual resource to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources.","mbj"},{"resources","resources","The actual resources to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources.","nibe"}, +{"RFC","RFC","A \"Request for Comments\" used as a proposed standard by IETF.","jocke"}, +{"SASLshort","SASL","See System Architecture Support Libraries.","mbj"}, +{"schema","schema","The schema contains the definitions and whereabouts for all tables. In Mnesia it is realized as a special table named \"schema\".","hakan"}, +{"schema functions","schema functions","The functions which are available for managing schemas.","hakan"}, +{"SDL","SDL","Specification and Description Language. A ITU-T standard specification language which is used to specify the behaviour of switching systems.","kenneth"}, +{"send","send","A primitive for message processing in Erlang, sends a message to a process.","kenneth"}, +{"shell","shell"," The shell is an interactive front-end to an Erlang node where Erlang expressions can be evaluated. ","kenneth"}, +{"shell prompt","shell prompt","The text or symbol shown on the screen when the shell is ready to receive commands.","kent"}, +{"SNMPEAlong","Simple Network Management Protocol Extensible Agent (SNMPEA).","An Erlang/OTP application that includes a bilingual extensible SNMP agent.","mbj"}, +{"single assignment","single assignment","Means that once a variable has been assigned a value, the value can never be changed. Erlang is a single assignment language.","kenneth"}, +{"single step","single step","Single stepping is a function provided by the debugger. By single stepping the developer may use the debugger to follow the execution of a process and see what actually happens at each function call.","olin"}, +{"slave","slave","Not in control, can never take over by himself.","kent"}, +{"SSLlong","Secure Sockets Layer (SSL)","A protocol created by Netscape Communications Corporation for authentication and encryption over TCP/IP networks, including Web.","helen"}, +{"signature","signature","An encrypted text block that validates a certificate or other file. A Certification Authority (CA) creates a signature by generating a hash of the public key embedded in a certificate, then encrypting the hash with its own private key. Only the CA's public key can decrypt the signature, verifying that the CA has authenticated the network entity that owns the certificate.","helen"}, +{"SNMPshort","SNMP","Simple Network Management Protocol.","mbj"}, +{"SNMPshort","SNMPEA","See Simple Network Management Protocol Extensible Agent.","mbj"}, +{"spawn","spawn","A primitive for multiprocessing in Erlang, that starts a parallel computation (called a process). The creation of a new process","kenneth"}, +{"SSLshort","SSL","See Secure Sockets Layer.","helen"}, +{"SSLeay","SSLeay","An SSL library developed by Eric Yong ([email protected]).","helen"}, +{"SSLTOP","SSLTOP","The path to your SSL directory, a subdirectory of ServerRoot.","helen"}, +{"start script","start script","A start script is a file with .script extension which is the source when a boot file is created. See SASL User's Guide for more info.","kenneth"}, +{"stdlib","stdlib","An application within Erlang/OTP which contains modules for manipulating lists, strings, files, etc.","kenneth"}, +{"sticky directory","sticky directory","A directory containing Erlang object code that is part of the runtime system.","kent"}, +{"sticky lock","sticky lock","A lock which lingers at a node after the transaction which first acquired the lock has terminated. Once a process has obtained a sticky lock on a node, subsequent locks acquired by processes on the same node, can be set without need of involving remote nodes.","hakan"}, +{"string","string","The ASCII or ISO-8859-1 representation of the list of characters occurring within quotation marks in Erlang code.","kent"}, +{"Subagent","Subagent","The SNMP agent system consists of one Master Agent (See Master Agent) and zero or more Subagents which can be used to distribute the SNMP agent system on several nodes.","mbj"}, +{"supervision tree","supervision tree","A hierarcial tree of processes used to program fault tolerant systems.","mbj"}, +{"supervisor","supervisor","A behaviour to stucture fault tolerant computations, and program supervision trees with.","mbj"}, +{"sup_bridge","supervisor bridge"," A behaviour used to connect a process, or subsystem, to a supervisor tree.","mbj"}, +{"SASLlong","System Architecture Support Libraries (SASL)","An Erlang/OTP application which contains services for error logging, release handling and report browsing.","mbj"}, {".config","system configuration file","A file which specifies configuration parameters for the applications in the system.","mbj"}, +{"table lock","table lock","Table locks are locks which are set on whole tables. They may either be read locks or write locks.","hakan"}, +{"Table Visualizer","Table Visualizer","A tool which enables the user to examine ETS and Mnesia tables.","olin"}, +{"temporary child","temporary child","A supervised process which is never restarted when it dies.","mbj"}, +{"term","term","The super type of all Erlang types.","kenneth"}, +{"Toolbar","Toolbar","A tool that provides an simplistic interface to the other various Erlang/OTP tools","olin"}, +{"tools","tools","An application within Erlang/OTP which contains the tools which are not applications themselves.","olin"}, +{"transaction","transaction","Transactions groups a set of database accesses into an atomic unit. All transactions has the ACID (atomicity, concistency, isolation and durability) properties.","hakan"}, +{"transient child","transient child","A supervised process which is restarted if it dies non-normally.","mbj"}, +{"trigger","trigger","The Interpreter. A break point that is reached by a process triggers if it is active, and the execution of the process is stopped.","olin"}, +{"tty","tty","tty is a simple command line interface program where keystrokes are collected and interpreted. Originally meant teletypewriter equipment. Now it usually means the user console/terminal/shell window.","kent"}, +{"tuple","tuple","A tuple is a data type in Erlang. Tuples are used as place holders for complex data structures. Tuples may contain anything of any size, and are written as sequences of terms separated by commas, and enclosed in curly brackets { }.","kenneth"}, +{"variable","variable","An alias for a memory position, in which a value can be put. Erlang variables always start with an upper case letter.","kenneth"}, +{"workers","workers","The lower nodes in a supervision tree. These are the processes that actually performs some real work, e.g. servers.","mbj"}, +{"YECC","YECC","A LALR-1 parser generator included in Erlang/OTP. It is written in Erlang and generates a parser as an Erlang module.","kenneth"}]. + + + + diff --git a/system/doc/definitions/term.defs.xml b/system/doc/definitions/term.defs.xml new file mode 100644 index 0000000000..28ac0d6eaf --- /dev/null +++ b/system/doc/definitions/term.defs.xml @@ -0,0 +1,1525 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE terms SYSTEM "terms.dtd"> + +<terms> + <term> + <id>agent</id> + <shortdef>agent</shortdef> + <def> +An entity that terminates a management protocol in the Network Element. </def> + <resp>mbj</resp> + </term> + <term> + <id>API</id> + <shortdef>API</shortdef> + <def> +Application Programming Interface. The interface towards an application. Usually this is a set of functions available, but can also be a set of messages sent to or from an application. </def> + <resp>mbj</resp> + </term> + <term> + <id>application</id> + <shortdef>application</shortdef> + <def> +A collection of resources which is required to offer a specific service. </def> + <resp>mbj</resp> + </term> + <term> + <id>appmon</id> + <shortdef>Application Monitor</shortdef> + <def> +A graphical node and application process tree viewer. See also appmon. </def> + <resp>mbj</resp> + </term> + <term> + <id>Appmon</id> + <shortdef>Appmon</shortdef> + <def> +Application name for the Application Monitor within Erlang/OTP. A graphical node and process viewer. </def> + <resp>mbj</resp> + </term> + <term> + <id>app callback</id> + <shortdef>application callback module</shortdef> + <def> +A module which is called when the application is started, and when it has stopped. Every application has one application callback module. </def> + <resp>mbj</resp> + </term> + <term> + <id>AC</id> + <shortdef>application controller</shortdef> + <def> +A process which coordinates all operations on applications. </def> + <resp>mbj</resp> + </term> + <term> + <id>app master</id> + <shortdef>application master</shortdef> + <def> +The application master is a process that monitors the application. It is provided by the Erlang run-time system. Every application has an application master process. </def> + <resp>mbj</resp> + </term> + <term> + <id>.app file</id> + <shortdef>application resource file</shortdef> + <def> +Specifies the resources required by the application and how the application should be started. Every application has one application resource file, called AppName.app. </def> + <resp>mbj</resp> + </term> + <term> + <id>arity</id> + <shortdef>arity</shortdef> + <def> +Denotes the number of arguments to a function. </def> + <resp>jocke</resp> + </term> + <term> + <id>ASN.1</id> + <shortdef>ASN.1</shortdef> + <def> +Abstract Syntax Notation One - an ITU-T and ISO standard notation for describing data formats used in communication protocols. </def> + <resp>kenneth</resp> + </term> + <term> + <id>ASN.1 Compiler</id> + <shortdef>ASN.1 Compiler</shortdef> + <def> +The Erlang/OTP ASN.1 Compiler translates an ASN.1 module into a corresponding Erlang module with encode and decode functions. </def> + <resp>kenneth</resp> + </term> + <term> + <id>atom</id> + <shortdef>atom</shortdef> + <def> +An atom is a constant. Atoms always starts with a lower case letter (a-z) and are terminated by a non-alphanumeric character - otherwise they must be quoted (enclosed in ' '). An atom is a data type in Erlang, used to enhance the legibility of programs. </def> + <resp>kenneth</resp> + </term> + <term> + <id>atomicity</id> + <shortdef>atomicity</shortdef> + <def> +Atomicity refers to the "all or nothing" property. If a transaction succeeds (i.e. commits), then all its effects on the data is captured in the database. If the transaction does not succeed (i.e. aborts), then none of its effect on the data is captured in the database. In other words, the transaction processing algorithm guarantees that the database will not reflect a partitial effect of a transaction. </def> + <resp>hakan</resp> + </term> + <term> + <id>attach</id> + <shortdef>attach</shortdef> + <def> +The debugger may attach to a process. When attached, the debugger may show process details, such as message queues and variable bindings. </def> + <resp>olin</resp> + </term> + <term> + <id>behaviour</id> + <shortdef>behaviour</shortdef> + <def> +A "pattern of design" which can be used to build applications and processes in an applications. </def> + <resp>mbj</resp> + </term> + <term> + <id>BIF</id> + <shortdef>BIF</shortdef> + <def> +Built-In Functions which perform operations that are impossible or inefficient to program in Erlang itself. Are defined in the module Erlang in the application kernel </def> + <resp>kenneth</resp> + </term> + <term> + <id>binary</id> + <shortdef>binary</shortdef> + <def> +A data type in Erlang which is used to store an area of untyped memory. Binaries are used for efficiently handling large quantities of untyped data. </def> + <resp>kenneth</resp> + </term> + <term> + <id>boolean</id> + <shortdef>boolean</shortdef> + <def> +A common data type in programming and specification languages. The value can be either true or false. </def> + <resp>kenneth</resp> + </term> + <term> + <id>boot file</id> + <shortdef>boot file</shortdef> + <def> +A binary file with extension .boot which is read during start of an Erlang node. See SASL User's Guide for more info. </def> + <resp>kenneth</resp> + </term> + <term> + <id>break point</id> + <shortdef>break point</shortdef> + <def> +By setting a break point using the debugger, the user specifies a position in the source code of a module where execution is to be suspended and control transferred to the debugger. </def> + <resp>olin</resp> + </term> + <term> + <id>CAshort</id> + <shortdef>CA</shortdef> + <def> +See Certification Authority. </def> + <resp>helen</resp> + </term> + <term> + <id>CA certificate</id> + <shortdef>CA certificate</shortdef> + <def> +A certificate containing a CA's public key. Network entities use this public key to verify certificates signed with the CA's private key. </def> + <resp>helen</resp> + </term> + <term> + <id>callback function</id> + <shortdef>callback function</shortdef> + <def> +A callback function is a function exported from a callback module, that a generic behaviour calls to perform a specific task. </def> + <resp>mbj</resp> + </term> + <term> + <id>callback module</id> + <shortdef>callback module</shortdef> + <def> +A callback module is a module that implements the specific parts of a generic behaviour. The generic behaviour specifies which callback functions must be exported from the module. </def> + <resp>mbj</resp> + </term> + <term> + <id>certificate</id> + <shortdef>certificate</shortdef> + <def> +A file used for authenticating network entities under the SSL protocol. A certificate contains information about its owner (called the subject) and issuer, plus the owner's public key and a signature made by a CA. Network entities verify these signatures using CA certificates. </def> + <resp>helen</resp> + </term> + <term> + <id>CAlong</id> + <shortdef>Certification Authority (CA)</shortdef> + <def> +A trusted third party whose purpose is to sign certificates for network entities it has authenticated using secure means. Other network entities can check the signature to verify that a CA has authenticated the bearer of a certificate. </def> + <resp>helen</resp> + </term> + <term> + <id>CSRlong</id> + <shortdef>Certificate Signing Request (CSR)</shortdef> + <def> +An unsigned certificate for submission to a Certification Authority, which signs it with its private key. Once the CSR is signed, it becomes a certificate. </def> + <resp>helen</resp> + </term> + <term> + <id>child</id> + <shortdef>child</shortdef> + <def> +A supervised process. See also permanent, transient, temporary child. </def> + <resp>mbj</resp> + </term> + <term> + <id>cipher</id> + <shortdef>cipher</shortdef> + <def> +A system of encryption. </def> + <resp>helen</resp> + </term> + <term> + <id>ClearCase</id> + <shortdef>ClearCase</shortdef> + <def> +A configuration management system from Rational Software Corporation. </def> + <resp>lars</resp> + </term> + <term> + <id>client-server model</id> + <shortdef>client-server model</shortdef> + <def> +A model where there is a server, which manages some resource, and a number of clients which send requests to the server to access the resource. The client-server model is one of the basic programming techniques for coordinating the activities of several parallel processes. </def> + <resp>mbj</resp> + </term> + <term> + <id>cover</id> + <shortdef>Coverage Analyser</shortdef> + <def> +Module name for the coverage analyser tool, located in the Tools application. </def> + <resp>gunilla</resp> + </term> + <term> + <id>CORBAlong</id> + <shortdef>Common Object Request Broker Architecture (CORBA)</shortdef> + <def> +A specification of an architecture for a distributed object system </def> + <resp>lars</resp> + </term> + <term> + <id>CORBA</id> + <shortdef>Common Object Request Broker Architecture (CORBA)</shortdef> + <def> +A specification of an architecture for a distributed object system </def> + <resp>lars</resp> + </term> + <term> + <id>compiler</id> + <shortdef>compiler</shortdef> + <def> +A compiler is a translator. A common type of compilers are those who takes source code for a programming language and translates it into code that is executable on a specific platform. E.g. the Erlang compiler translates Erlang source code to an intermediary code that is executable by the Erlang Run Time System. </def> + <resp>kenneth</resp> + </term> + <term> + <id>consistency</id> + <shortdef>consistency</shortdef> + <def> +Consistency refers to the requirement that, given a consistent initial database state, the state of the database after the successful execution of a transaction is also consistent; that is, a transaction transforms the database from a consistent state to another consistent state. Database consistency may be defined as a set of rules or constraints. If the execution of a transaction causes the consistency constraints to be violated, the transaction is not accepted (and thus aborted) by the system. </def> + <resp>hakan</resp> + </term> + <term> + <id>cookie</id> + <shortdef>cookie</shortdef> + <def> +A magic cookie is a secret atom assigned to each Erlang node. The Erlang nodes in a distributed system must know each others cookies in order to authorize each other for communication </def> + <resp>kenneth</resp> + </term> + <term> + <id>CORBAshort</id> + <shortdef>CORBA</shortdef> + <def> +See Common Object RequestBroker Architecture. </def> + <resp>lars</resp> + </term> + <term> + <id>Coverage Analyser</id> + <shortdef>Coverage Analyser</shortdef> + <def> +A tool which provides a set of functions for coverage analysis of Erlang programs, i.e observing how many times each line or function are executed. See also cover. </def> + <resp>olin</resp> + </term> + <term> + <id>coverage analysis</id> + <shortdef>coverage analysis</shortdef> + <def> +The task of determining which lines, or how many lines of code, has actually been executed. Useful for determining the completeness of test suites. </def> + <resp>olin</resp> + </term> + <term> + <id>cross reference tool</id> + <shortdef>cross reference tool</shortdef> + <def> +A tool that can be used for finding dependencies between functions, modules, applications and releases. The Erlang/OTP cross reference tool is called xref and is part of the Tools application. </def> + <resp>gunilla</resp> + </term> + <term> + <id>CSRshort</id> + <shortdef>CSR</shortdef> + <def> +See Certificate Signing Request. </def> + <resp>helen</resp> + </term> + <term> + <id>data type</id> + <shortdef>data type</shortdef> + <def> +The data types in Erlang are numbers, atoms, tuples, lists, pids, funs, records, ports, references and binaries. The values of Erlang data types can be stored in variables. </def> + <resp>kenneth</resp> + </term> + <term> + <id>DBMSlong</id> + <shortdef>Database Management System (DBMS)</shortdef> + <def> +A database is a collection of data and a DBMS is a system which manages the database. Applications accesses the database through the database management system. </def> + <resp>hakan</resp> + </term> + <term> + <id>DBMSshort</id> + <shortdef>DBMS</shortdef> + <def> +See Database Management System. </def> + <resp>hakan</resp> + </term> + <term> + <id>Debugger</id> + <shortdef>Debugger</shortdef> + <def> +An Erlang/OTP tool which provides mechanisms which makes it possible to see what happens during the execution of code in specified modules, or when processes crash. </def> + <resp>olin</resp> + </term> + <term> + <id>dets</id> + <shortdef>dets</shortdef> + <def> +A module within the stdlib application, which provides a term storage, and which is used as the underlying file storage mechanism by the Mnesia DBMS. </def> + <resp>hakan</resp> + </term> + <term> + <id>dirty operations</id> + <shortdef>dirty operations</shortdef> + <def> +Functions which manipulate data in a DBMS, without using transactions. </def> + <resp>hakan</resp> + </term> + <term> + <id>distributed application</id> + <shortdef>distributed application</shortdef> + <def> +An application which runs on one of several nodes. May be restarted on another node. (See local application.) </def> + <resp>mbj</resp> + </term> + <term> + <id>DNSshort</id> + <shortdef>DNS</shortdef> + <def> +See Domain Name System. </def> + <resp>lars</resp> + </term> + <term> + <id>Docbuilder</id> + <shortdef>Docbuilder</shortdef> + <def> +The documentation system used in Erlang/OTP. </def> + <resp>jocke</resp> + </term> + <term> + <id>DNSlong</id> + <shortdef>Domain Name System (DNS)</shortdef> + <def> +DNS is a service that map names to internet addresses </def> + <resp>lars</resp> + </term> + <term> + <id>DTD</id> + <shortdef>DTD</shortdef> + <def> +Document Type Definition as defined in SGML. </def> + <resp>jocke</resp> + </term> + <term> + <id>durability</id> + <shortdef>durability</shortdef> + <def> +If a transaction succeeds, then its effect on the data is persistently captured, and will survive subsequent system failures resulting in loss of data in volatile memory. Durability is usually enforced by first writing modified data to some non-volatile memory (usually disc), before a transaction is allowed to commit. If there is a system failure, the state of the non-volatile memory must be recovered to reflect the effect of all and only committed transactions. </def> + <resp>hakan</resp> + </term> + <term> + <id>Emacs</id> + <shortdef>Emacs</shortdef> + <def> +A widely used text editor which allows customization of its behaviour. An Erlang mode for Emacs is included in the Erlang deliverables. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Emacs for Erlang</id> + <shortdef>Emacs for Erlang</shortdef> + <def> +A tool which provides a major mode for editing Erlang source files in Emacs. </def> + <resp>olin</resp> + </term> + <term> + <id>encaps</id> + <shortdef>encapsulation</shortdef> + <def> +Data can be encapsulated into another data element. </def> + <resp>kent</resp> + </term> + <term> + <id>eprof</id> + <shortdef>eprof</shortdef> + <def> +A module in the tools application. See Profiler. </def> + <resp>olin</resp> + </term> + <term> + <id>erl</id> + <shortdef>erl</shortdef> + <def> +The command which starts an Erlang run-time system. </def> + <resp>kenneth</resp> + </term> + <term> + <id>erl_interface</id> + <shortdef>erl_interface library</shortdef> + <def> +A thread safe library with C-functions which makes it possible to write a C-program which appears as one of the nodes in a system of distributed Erlang nodes. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Erlang</id> + <shortdef>Erlang</shortdef> + <def> +Erlang is a functional programming language intended for designing large industrial soft real time systems. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Erlang emulator</id> + <shortdef>Erlang emulator</shortdef> + <def> +Another word for Erlang Virtual Machine. </def> + <resp>kenneth</resp> + </term> + <term> + <id>ERTSlong</id> + <shortdef>Erlang Run Time System</shortdef> + <def> +A fundamental part of Erlang/OTP which contains the Erlang Virtual Machine, the kernel and stdlib applications. The Erlang Run Time System is a mandatory part which all other Erlang applications are dependent upon. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Erlang VM</id> + <shortdef>Erlang Virtual Machine</shortdef> + <def> +The virtual machine, which makes Erlang/OTP work together with a specific OS/HW platform. The Erlang Virtual Machine is available on several different platforms. The Erlang Virtual Machine is the glue which makes it possible to run an Erlang application on any platform without change. </def> + <resp>kenneth</resp> + </term> + <term> + <id>ERTSshort</id> + <shortdef>ERTS</shortdef> + <def> +See Erlang Run Time System. </def> + <resp>kenneth</resp> + </term> + <term> + <id>ETS</id> + <shortdef>ETS</shortdef> + <def> +Erlang Term Storage tables. </def> + <resp>olin</resp> + </term> + <term> + <id>EVAshort</id> + <shortdef>EVA</shortdef> + <def> +See Event and Alarm handling application </def> + <resp>mbj</resp> + </term> + <term> + <id>EVAlong</id> + <shortdef>Event and Alarm handling application (EVA)</shortdef> + <def> +An application that consists of Fault Management functionality, such as sending and logging of events and alarms. </def> + <resp>mbj</resp> + </term> + <term> + <id>event handler</id> + <shortdef>event handler</shortdef> + <def> +A module exporting functions which can process events sent to an event manager process. The event handler is a behaviour of type gen_event. </def> + <resp>mbj</resp> + </term> + <term> + <id>event manager</id> + <shortdef>event manager</shortdef> + <def> +A process to which events of a certain category is sent. gen_event handler can be installed in the event manager. </def> + <resp>mbj</resp> + </term> + <term> + <id>exit signal</id> + <shortdef>exit signal</shortdef> + <def> +A signal which is sent from a terminating process to the processes and ports it is linked to. An EXIT signal has the following format: {'EXIT', Exiting_Process_Id, Reason}. </def> + <resp>kent</resp> + </term> + <term> + <id>foo</id> + <shortdef>foo</shortdef> + <def> +Algebraic place holder. </def> + <resp>kent</resp> + </term> + <term> + <id>FSM</id> + <shortdef>FSM</shortdef> + <def> +Finite State Machine. </def> + <resp>kenneth</resp> + </term> + <term> + <id>fun</id> + <shortdef>fun</shortdef> + <def> +A data type, introduced in Erlang 4.4, which represent functional objects. </def> + <resp>kenneth</resp> + </term> + <term> + <id>function</id> + <shortdef>function</shortdef> + <def> +Erlang programs are written entirely in terms of modules with functions. A function can have arguments and does always return a result. A function can be exported which makes it available for calls from other modules. Non exported functions can only be called internally within the module. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Gateway</id> + <shortdef>gateway</shortdef> + <def> +A server which acts as an intermediary for some other server. Unlike a proxy, a gateway receives requests as if it were the origin server for the requested resource; the requesting client may not be aware that it is communicating with a gateway. </def> + <resp>jocke</resp> + </term> + <term> + <id>gen_event</id> + <shortdef>gen_event</shortdef> + <def> +A behaviour used for programming event handling mechanisms, such as alarm handlers, error loggers, and plug-and-play handlers. </def> + <resp>mbj</resp> + </term> + <term> + <id>gen_fsm</id> + <shortdef>gen_fsm</shortdef> + <def> +A behaviour used for programming finite state machines. </def> + <resp>mbj</resp> + </term> + <term> + <id>gen_server</id> + <shortdef>gen_server</shortdef> + <def> +A behaviour used for programming client-server processes. </def> + <resp>mbj</resp> + </term> + <term> + <id>gterm</id> + <shortdef>Global Glossary Database</shortdef> + <def> +A glossary database used to list common acronymns and defintions etc. </def> + <resp>jocke</resp> + </term> + <term> + <id>xref</id> + <shortdef>xref</shortdef> + <def> +A cross reference tool that can be used for finding dependencies between functions, modules, applications and releases. Part of the Tools application. </def> + <resp>gunilla</resp> + </term> + <term> + <id>GSlong</id> + <shortdef>Graphics System</shortdef> + <def> +A library module which provides a graphics interface for Erlang. </def> + <resp>mbj</resp> + </term> + <term> + <id>grid</id> + <shortdef>grid</shortdef> + <def> +A multi-column object which is used to display tables. (Graphics System.) </def> + <resp>mbj</resp> + </term> + <term> + <id>GSshort</id> + <shortdef>GS</shortdef> + <def> +See Graphics System. </def> + <resp>olin</resp> + </term> + <term> + <id>GS Contributions</id> + <shortdef>GS Contributions</shortdef> + <def> +Unsupported user supplied tools which are included with the Erlang/OTP software release. </def> + <resp>olin</resp> + </term> + <term> + <id>GUI</id> + <shortdef>GUI</shortdef> + <def> +Graphical User Interface </def> + <resp>mbj</resp> + </term> + <term> + <id>Home Directory</id> + <shortdef>Home Directory</shortdef> + <def> +The position of a user account in the file system. The Home Directory is automatically passed to the Erlang run-time system at startup. On Unix the contents of the environment variable "HOME" is passed. Om Win32 the concatenation of the environment variables "HOMEDRIVE" and "HOMEPATH" is passed, or if these variables are not set, the value returned by the Win32 API function "GetWindowsDirectory" is passed. </def> + <resp>kenneth</resp> + </term> + <term> + <id>host name</id> + <shortdef>host name</shortdef> + <def> +The name of a machine on a network, e.g. erlang.ericsson.se. </def> + <resp>kent</resp> + </term> + <term> + <id>HTML</id> + <shortdef>HTML</shortdef> + <def> +Hypertext Markup Language. </def> + <resp>jocke</resp> + </term> + <term> + <id>HTTP</id> + <shortdef>HTTP</shortdef> + <def> +Hypertext Transfer Protocol. </def> + <resp>jocke</resp> + </term> + <term> + <id>HTTPS</id> + <shortdef>HTTPS</shortdef> + <def> +The Hypertext Transport Protocol, Secure, the standard SSL communication mechanism of the World Wide Web. </def> + <resp>helen</resp> + </term> + <term> + <id>IDLshort</id> + <shortdef>IDL</shortdef> + <def> +See Interface Description Language. </def> + <resp>lars</resp> + </term> + <term> + <id>IDLlong</id> + <shortdef>Interface Description Language (IDL)</shortdef> + <def> +The interface specification language created by OMG. </def> + <resp>lars</resp> + </term> + <term> + <id>indexing</id> + <shortdef>indexing</shortdef> + <def> +Fast lookup using an (usually enumerated) key. </def> + <resp>kent</resp> + </term> + <term> + <id>I1</id> + <shortdef>INETS</shortdef> + <def> +The Internet Services application </def> + <resp>jocke</resp> + </term> + <term> + <id>initial call</id> + <shortdef>initial call</shortdef> + <def> +The first call to an interpreted function (when using the Interpreter). </def> + <resp>kent</resp> + </term> + <term> + <id>instrumentation function</id> + <shortdef>instrumentation function</shortdef> + <def> +A function used to implement a Managed Object, i.e. give access to the real resources behind an MO. </def> + <resp>mbj</resp> + </term> + <term> + <id>IDLlong</id> + <shortdef>Interface Description Language (IDL)</shortdef> + <def> +The interface specification language created by OMG. </def> + <resp>lars</resp> + </term> + <term> + <id>interpreter</id> + <shortdef>interpreter</shortdef> + <def> +An application which provides mechanisms which make it possible to see what happens during the execution of code in specified (interpreted) modules, or when processes crash. </def> + <resp>kent</resp> + </term> + <term> + <id>isolation</id> + <shortdef>isolation</shortdef> + <def> +A transaction executes as if no other concurrent transactions are executing, and thus its execution results are equivalent to those obtained by executing database transactions serially. A system which maintains transaction isolation is also said to be enforcing serializability. </def> + <resp>hakan</resp> + </term> + <term> + <id>kernel</id> + <shortdef>kernel</shortdef> + <def> +An application which contains file servers, code servers and other code necessary for the Erlang run-time system. </def> + <resp>kenneth</resp> + </term> + <term> + <id>key</id> + <shortdef>key</shortdef> + <def> +A file containing the value that must be fed into an algorithm in order to encrypt or decrypt a message. </def> + <resp>helen</resp> + </term> + <term> + <id>key pair</id> + <shortdef>key pair</shortdef> + <def> +A set of two keys used in public key cryptography. One is the public key used to encrypt data, and the other is the private key necessary to decrypt the same data. </def> + <resp>helen</resp> + </term> + <term> + <id>list</id> + <shortdef>list</shortdef> + <def> +Terms separated by commas and enclosed in square brackets [ ] are called lists. A list is a data type in Erlang, used for storing a variable number of terms. It is dynamically sized. The first element of the list is referred to as the head of the list, and the remainer of the list as the tail. </def> + <resp>kenneth</resp> + </term> + <term> + <id>list box</id> + <shortdef>list box </shortdef> + <def> +A list of labels with optional scroll bars attached. (Graphics System.) </def> + <resp>mbj</resp> + </term> + <term> + <id>lc</id> + <shortdef>list comprehension</shortdef> + <def> +A language construct in Erlang which are analogous to set comprehensions in Zermelo-Frankel set theory. Analogous to the 'setof' and 'findall' predicates in Prolog. </def> + <resp>kenneth</resp> + </term> + <term> + <id>local application</id> + <shortdef>local application</shortdef> + <def> +An application which runs on one node and which are always started at the local node only. (See distributed application.) </def> + <resp>mbj</resp> + </term> + <term> + <id>manager</id> + <shortdef>manager</shortdef> + <def> +An entity that terminates a management protocol in the Network Management Station. </def> + <resp>mbj</resp> + </term> + <term> + <id>Master Agent</id> + <shortdef>Master Agent</shortdef> + <def> +The SNMP agent system consists of one Master Agent which terminates the SNMP protocol </def> + <resp>mbj</resp> + </term> + <term> + <id>MIB</id> + <shortdef>Management Information Base (MIB)</shortdef> + <def> +An abstract definition of the management information available through a management interface in a system. </def> + <resp>mbj</resp> + </term> + <term> + <id>matching</id> + <shortdef>matching</shortdef> + <def> +See pattern matching. </def> + <resp>kenneth</resp> + </term> + <term> + <id>message queue</id> + <shortdef>message queue</shortdef> + <def> +The queue of not yet received messages that are in the mailbox of a process. </def> + <resp>olin</resp> + </term> + <term> + <id>Mnemosyne</id> + <shortdef>Mnemosyne</shortdef> + <def> +Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.</def> + <resp>hakan</resp> + </term> + <term> + <id>Mnesia</id> + <shortdef>Mnesia</shortdef> + <def> +Mnesia is a distributed Database Management System, appropriate for telecommunications applications and other applications with need of continuous operation and soft real-time properties. </def> + <resp>hakan</resp> + </term> + <term> + <id>MIBshort</id> + <shortdef>MIB</shortdef> + <def> +See Management Information Base. </def> + <resp>mbj</resp> + </term> + <term> + <id>MIME</id> + <shortdef>MIME</shortdef> + <def> +Multi-purpose Internet Mail Extensions. </def> + <resp>jocke</resp> + </term> + <term> + <id>MOlong</id> + <shortdef>Managed Object (MO)</shortdef> + <def> +The abstract management information defined in a MIB. </def> + <resp>mbj</resp> + </term> + <term> + <id>MO</id> + <shortdef>MO</shortdef> + <def> +Managed Object; The abstract management information defined in a MIB. </def> + <resp>nibe</resp> + </term> + <term> + <id>MOshort</id> + <shortdef>MO</shortdef> + <def> +See Managed Object. </def> + <resp>mbj</resp> + </term> + <term> + <id>module</id> + <shortdef>module</shortdef> + <def> +Module is the unit for compilation and for loading in Erlang. A Module contains a module declaration, export declarations and code representing the functions in the module. </def> + <resp>kenneth</resp> + </term> + <term> + <id>NCSA</id> + <shortdef>NCSA</shortdef> + <def> +The National Center for Supercomputing Applications. </def> + <resp>jocke</resp> + </term> + <term> + <id>NEshort</id> + <shortdef>NE</shortdef> + <def> +See Network Element. </def> + <resp>mbj</resp> + </term> + <term> + <id>NElong</id> + <shortdef>Network Element</shortdef> + <def> +In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity. </def> + <resp>mbj</resp> + </term> + <term> + <id>NE</id> + <shortdef>NE</shortdef> + <def> +Network Element; In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity. </def> + <resp>mbj</resp> + </term> + <term> + <id>NMSlong</id> + <shortdef>Network Management Station (NMS)</shortdef> + <def> +The place where the operator manages the network. </def> + <resp>mbj</resp> + </term> + <term> + <id>NMS</id> + <shortdef>NMS</shortdef> + <def> +Network Management Station; The place where the operator manages the network. </def> + <resp>nibe</resp> + </term> + <term> + <id>NMSshort</id> + <shortdef>NMS</shortdef> + <def> +See Network Management Station. </def> + <resp>mbj</resp> + </term> + <term> + <id>node</id> + <shortdef>node</shortdef> + <def> +An executing Erlang run-time system which can communicate with other Erlang run-time systems. </def> + <resp>kenneth</resp> + </term> + <term> + <id>node name</id> + <shortdef>node name</shortdef> + <def> +A node name is an atom constructed as the concatenation of a name supplied by the user, an "@" character, and the name of the host where the node is executing. </def> + <resp>kenneth</resp> + </term> + <term> + <id>notation</id> + <shortdef>notation</shortdef> + <def> +How things are written. </def> + <resp>kent</resp> + </term> + <term> + <id>notification</id> + <shortdef>notification</shortdef> + <def> +Information of an event. </def> + <resp>kent</resp> + </term> + <term> + <id>NROFF</id> + <shortdef>NROFF</shortdef> + <def> +A text formatting language for line printer quality output devices that runs on the UNIX operating system. </def> + <resp>jocke</resp> + </term> + <term> + <id>number</id> + <shortdef>number</shortdef> + <def> +A data type in Erlang. Are subdivided into integers, for storing natural numbers, or floats, for storing real numbers. </def> + <resp>kenneth</resp> + </term> + <term> + <id>OMGlong</id> + <shortdef>Object Managment Group (OMG)</shortdef> + <def> +A standardisation group for all specifications in the area of CORBA. </def> + <resp>lars</resp> + </term> + <term> + <id>OMGshort</id> + <shortdef>OMG</shortdef> + <def> +Object Managment Group. </def> + <resp>lars</resp> + </term> + <term> + <id>OTP</id> + <shortdef>OTP</shortdef> + <def> +Open Telecom Platform </def> + <resp>mike</resp> + </term> + <term> + <id>os_mon</id> + <shortdef>os_mon</shortdef> + <def> +An application which monitors the behaviour of the underlying operating system </def> + <resp>mbj</resp> + </term> + <term> + <id>parser generator</id> + <shortdef>parser generator</shortdef> + <def> +A tool for making compilers which takes a grammar description as input and generates a complete program (a parser) which recognizes input which complies with the grammar. YECC is a parser generator included in the Erlang/OTP. </def> + <resp>kenneth</resp> + </term> + <term> + <id>pass phrase</id> + <shortdef>pass phrase</shortdef> + <def> +The word or phrase which authenticates the user who is authorized to use private key file. The pass phrase prevents unauthorized users from starting, restarting, or reconfiguring the server. </def> + <resp>helen</resp> + </term> + <term> + <id>pattern matching</id> + <shortdef>pattern matching</shortdef> + <def> +A basic mechanism in Erlang for assigning values to variables and for controlling the flow of a program. </def> + <resp>kenneth</resp> + </term> + <term> + <id>permanent child</id> + <shortdef>permanent child</shortdef> + <def> +A supervised process which always is restarted when it dies. </def> + <resp>mbj</resp> + </term> + <term> + <id>Pid</id> + <shortdef>Pid</shortdef> + <def> +Process Identifier. A data type in Erlang for storing process references. The process identity of the process displayed in the line. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Pman</id> + <shortdef>Pman</shortdef> + <def> +Module and application name for the Process Trace Tool. </def> + <resp>olin</resp> + </term> + <term> + <id>point</id> + <shortdef>point</shortdef> + <def> +A unit used to indicate the size of a typeface. Equal to 1/72 inches. </def> + <resp>jocke</resp> + </term> + <term> + <id>pointer</id> + <shortdef>pointer</shortdef> + <def> +A pointer tells where data is stored. Memory pointers are not used in Erlang. </def> + <resp>kent</resp> + </term> + <term> + <id>port</id> + <shortdef>port</shortdef> + <def> +A data type in Erlang. Ports provide the basic mechanism for communication with the external world. </def> + <resp>peterl</resp> + </term> + <term> + <id>port controller</id> + <shortdef>port controller</shortdef> + <def> +An Erlang process which controls a port program. A port has exactly one port controller. </def> + <resp>peterl</resp> + </term> + <term> + <id>port program</id> + <shortdef>port program</shortdef> + <def> +A program that runs as an external program in the operating system and which the Erlang run-time system can start and communicate with by means of the Erlang port mechanism. </def> + <resp>kenneth</resp> + </term> + <term> + <id>PostScript</id> + <shortdef>PostScript</shortdef> + <def> +A language describing a fully laid-out page in terms of fonts, lines, grey scales, and so on, in a way that is interpretable by a printer. The language was developed by Adobe Systems. </def> + <resp>jocke</resp> + </term> + <term> + <id>pretty-printed</id> + <shortdef>pretty-printed</shortdef> + <def> +Nicely formatted code or data, e.g. C or Erlang, with indents and tabs etc. </def> + <resp>jocke</resp> + </term> + <term> + <id>primitive</id> + <shortdef>primitive</shortdef> + <def> +The basic elements in a programming language. </def> + <resp>kent</resp> + </term> + <term> + <id>private key</id> + <shortdef>private key</shortdef> + <def> +The secret key in a pair, used to decrypt incoming messages and sign outgoing ones. </def> + <resp>helen</resp> + </term> + <term> + <id>process</id> + <shortdef>process</shortdef> + <def> +A process is a self-contained separate unit of execution which exists concurrently with other processes in the system. The BIF "spawn/3" creates and starts the execution of a new process. </def> + <resp>kenneth</resp> + </term> + <term> + <id>process dictionary</id> + <shortdef>process dictionary</shortdef> + <def> +Each process has an associated dictionary which provides the process with simple destructive storage capabilities. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Process Manager</id> + <shortdef>Process Manager</shortdef> + <def> +Obsolete name for the Process Trace Tool. </def> + <resp>olin</resp> + </term> + <term> + <id>Process Trace Tool</id> + <shortdef>Process Trace Tool</shortdef> + <def> +A tool which gives an overview of the processes in the Erlang run-time system. See also Pman. </def> + <resp>olin</resp> + </term> + <term> + <id>Profiler</id> + <shortdef>Profiler</shortdef> + <def> +Another name for eprof, a tool used to profile a system in order to find out how much time is spent in various segments of a program. </def> + <resp>olin</resp> + </term> + <term> + <id>program</id> + <shortdef>program</shortdef> + <def> +Routines which can be executed by a computer. </def> + <resp>kent</resp> + </term> + <term> + <id>Proxy</id> + <shortdef>proxy</shortdef> + <def> +An intermediary program which acts as both a server and a client for the purpose of making requests on behalf of other clients. </def> + <resp>jocke</resp> + </term> + <term> + <id>public key</id> + <shortdef>public key</shortdef> + <def> +The publicly available key in a key pair, used to encrypt messages bound for its owner and to decrypt signatures made by its owner. </def> + <resp>helen</resp> + </term> + <term> + <id>query</id> + <shortdef>query</shortdef> + <def> +Queries are used for accessing the data in a Database Management System. The query specify a maybe complicated relation that should hold for all of the selected data. This could involve several tables as well as conditions like for instance less then and greater then. </def> + <resp>hakan</resp> + </term> + <term> + <id>query language</id> + <shortdef>query language</shortdef> + <def> +A language which is specially designed to express database queries. Examples of query languages are QLC and SQL. </def> + <resp>hakan</resp> + </term> + <term> + <id>receive</id> + <shortdef>receive</shortdef> + <def> +A primitive for message processing in Erlang, receives a message from a process. </def> + <resp>kenneth</resp> + </term> + <term> + <id>record</id> + <shortdef>record</shortdef> + <def> +A data structure intended for storing a fixed number of related Erlang terms, it is similar to a "struct" in C or a "record" in Pascal. </def> + <resp>kenneth</resp> + </term> + <term> + <id>recursion</id> + <shortdef>recursion</shortdef> + <def> +A function is recursive if it calls itself until the result desired is attained. Recursion is the heart of functional programming. </def> + <resp>kenneth</resp> + </term> + <term> + <id>reference</id> + <shortdef>reference</shortdef> + <def> +A data type in Erlang for storing system unique references. </def> + <resp>kenneth</resp> + </term> + <term> + <id>release handler</id> + <shortdef>release handler</shortdef> + <def> +A SASL process which handles software upgrade. </def> + <resp>mbj</resp> + </term> + <term> + <id>relup</id> + <shortdef>release upgrade script</shortdef> + <def> +A script with instructions to the release handler of how the release should be installed in the system. </def> + <resp>mbj</resp> + </term> + <term> + <id>RPC</id> + <shortdef>Remote Proceedure Call</shortdef> + <def> +A technique for evaluating a function transparently on a remote node. </def> + <resp>kenneth</resp> + </term> + <term> + <id>resource</id> + <shortdef>resource</shortdef> + <def> +The actual resource to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources. </def> + <resp>mbj</resp> + </term> + <term> + <id>resources</id> + <shortdef>resources</shortdef> + <def> +The actual resources to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources. </def> + <resp>nibe</resp> + </term> + <term> + <id>RFC</id> + <shortdef>RFC</shortdef> + <def> +A "Request for Comments" used as a proposed standard by IETF. </def> + <resp>jocke</resp> + </term> + <term> + <id>SASLshort</id> + <shortdef>SASL</shortdef> + <def> +See System Architecture Support Libraries. </def> + <resp>mbj</resp> + </term> + <term> + <id>schema</id> + <shortdef>schema</shortdef> + <def> +The schema contains the definitions and whereabouts for all tables. In Mnesia it is realized as a special table named "schema". </def> + <resp>hakan</resp> + </term> + <term> + <id>schema functions</id> + <shortdef>schema functions</shortdef> + <def> +The functions which are available for managing schemas. </def> + <resp>hakan</resp> + </term> + <term> + <id>SDL</id> + <shortdef>SDL</shortdef> + <def> +Specification and Description Language. A ITU-T standard specification language which is used to specify the behaviour of switching systems. </def> + <resp>kenneth</resp> + </term> + <term> + <id>send</id> + <shortdef>send</shortdef> + <def> +A primitive for message processing in Erlang, sends a message to a process. </def> + <resp>kenneth</resp> + </term> + <term> + <id>shell</id> + <shortdef>shell</shortdef> + <def> +The shell is an interactive front-end to an Erlang node where Erlang expressions can be evaluated. </def> + <resp>kenneth</resp> + </term> + <term> + <id>shell prompt</id> + <shortdef>shell prompt</shortdef> + <def> +The text or symbol shown on the screen when the shell is ready to receive commands. </def> + <resp>kent</resp> + </term> + <term> + <id>SNMPEAlong</id> + <shortdef>Simple Network Management Protocol Extensible Agent (SNMPEA).</shortdef> + <def> +An Erlang/OTP application that includes a bilingual extensible SNMP agent. </def> + <resp>mbj</resp> + </term> + <term> + <id>single assignment</id> + <shortdef>single assignment</shortdef> + <def> +Means that once a variable has been assigned a value, the value can never be changed. Erlang is a single assignment language. </def> + <resp>kenneth</resp> + </term> + <term> + <id>single step</id> + <shortdef>single step</shortdef> + <def> +Single stepping is a function provided by the debugger. By single stepping the developer may use the debugger to follow the execution of a process and see what actually happens at each function call. </def> + <resp>olin</resp> + </term> + <term> + <id>slave</id> + <shortdef>slave</shortdef> + <def> +Not in control, can never take over by himself. </def> + <resp>kent</resp> + </term> + <term> + <id>SSLlong</id> + <shortdef>Secure Sockets Layer (SSL)</shortdef> + <def> +A protocol created by Netscape Communications Corporation for authentication and encryption over TCP/IP networks, including Web. </def> + <resp>helen</resp> + </term> + <term> + <id>signature</id> + <shortdef>signature</shortdef> + <def> +An encrypted text block that validates a certificate or other file. A Certification Authority (CA) creates a signature by generating a hash of the public key embedded in a certificate, then encrypting the hash with its own private key. Only the CA's public key can decrypt the signature, verifying that the CA has authenticated the network entity that owns the certificate. </def> + <resp>helen</resp> + </term> + <term> + <id>SNMPshort</id> + <shortdef>SNMP</shortdef> + <def> +Simple Network Management Protocol. </def> + <resp>mbj</resp> + </term> + <term> + <id>SNMPshort</id> + <shortdef>SNMPEA</shortdef> + <def> +See Simple Network Management Protocol Extensible Agent. </def> + <resp>mbj</resp> + </term> + <term> + <id>spawn</id> + <shortdef>spawn</shortdef> + <def> +A primitive for multiprocessing in Erlang, that starts a parallel computation (called a process). The creation of a new process </def> + <resp>kenneth</resp> + </term> + <term> + <id>SSLshort</id> + <shortdef>SSL</shortdef> + <def> +See Secure Sockets Layer. </def> + <resp>helen</resp> + </term> + <term> + <id>SSLeay</id> + <shortdef>SSLeay</shortdef> + <def> +An SSL library developed by Eric Yong ([email protected]). </def> + <resp>helen</resp> + </term> + <term> + <id>SSLTOP</id> + <shortdef>SSLTOP</shortdef> + <def> +The path to your SSL directory, a subdirectory of ServerRoot. </def> + <resp>helen</resp> + </term> + <term> + <id>start script</id> + <shortdef>start script</shortdef> + <def> +A start script is a file with .script extension which is the source when a boot file is created. See SASL User's Guide for more info. </def> + <resp>kenneth</resp> + </term> + <term> + <id>stdlib</id> + <shortdef>stdlib</shortdef> + <def> +An application within Erlang/OTP which contains modules for manipulating lists, strings, files, etc. </def> + <resp>kenneth</resp> + </term> + <term> + <id>sticky directory</id> + <shortdef>sticky directory</shortdef> + <def> +A directory containing Erlang object code that is part of the runtime system. </def> + <resp>kent</resp> + </term> + <term> + <id>sticky lock</id> + <shortdef>sticky lock</shortdef> + <def> +A lock which lingers at a node after the transaction which first acquired the lock has terminated. Once a process has obtained a sticky lock on a node, subsequent locks acquired by processes on the same node, can be set without need of involving remote nodes. </def> + <resp>hakan</resp> + </term> + <term> + <id>string</id> + <shortdef>string</shortdef> + <def> +The ASCII or ISO-8859-1 representation of the list of characters occurring within quotation marks in Erlang code. </def> + <resp>kent</resp> + </term> + <term> + <id>Subagent</id> + <shortdef>Subagent</shortdef> + <def> +The SNMP agent system consists of one Master Agent (See Master Agent) and zero or more Subagents which can be used to distribute the SNMP agent system on several nodes. </def> + <resp>mbj</resp> + </term> + <term> + <id>supervision tree</id> + <shortdef>supervision tree</shortdef> + <def> +A hierarcial tree of processes used to program fault tolerant systems. </def> + <resp>mbj</resp> + </term> + <term> + <id>supervisor</id> + <shortdef>supervisor</shortdef> + <def> +A behaviour to stucture fault tolerant computations, and program supervision trees with. </def> + <resp>mbj</resp> + </term> + <term> + <id>sup_bridge</id> + <shortdef>supervisor bridge</shortdef> + <def> +A behaviour used to connect a process, or subsystem, to a supervisor tree. </def> + <resp>mbj</resp> + </term> + <term> + <id>SASLlong</id> + <shortdef>System Architecture Support Libraries (SASL)</shortdef> + <def> +An Erlang/OTP application which contains services for error logging, release handling and report browsing. </def> + <resp>mbj</resp> + </term> + <term> + <id>.config</id> + <shortdef>system configuration file</shortdef> + <def> +A file which specifies configuration parameters for the applications in the system. </def> + <resp>mbj</resp> + </term> + <term> + <id>table lock</id> + <shortdef>table lock</shortdef> + <def> +Table locks are locks which are set on whole tables. They may either be read locks or write locks. </def> + <resp>hakan</resp> + </term> + <term> + <id>Table Visualizer</id> + <shortdef>Table Visualizer</shortdef> + <def> +A tool which enables the user to examine ETS and Mnesia tables. </def> + <resp>olin</resp> + </term> + <term> + <id>temporary child</id> + <shortdef>temporary child</shortdef> + <def> +A supervised process which is never restarted when it dies. </def> + <resp>mbj</resp> + </term> + <term> + <id>term</id> + <shortdef>term</shortdef> + <def> +The super type of all Erlang types. </def> + <resp>kenneth</resp> + </term> + <term> + <id>Toolbar</id> + <shortdef>Toolbar</shortdef> + <def> +A tool that provides an simplistic interface to the other various Erlang/OTP tools </def> + <resp>olin</resp> + </term> + <term> + <id>tools</id> + <shortdef>tools</shortdef> + <def> +An application within Erlang/OTP which contains the tools which are not applications themselves. </def> + <resp>olin</resp> + </term> + <term> + <id>transaction</id> + <shortdef>transaction</shortdef> + <def> +Transactions groups a set of database accesses into an atomic unit. All transactions has the ACID (atomicity, concistency, isolation and durability) properties. </def> + <resp>hakan</resp> + </term> + <term> + <id>transient child</id> + <shortdef>transient child</shortdef> + <def> +A supervised process which is restarted if it dies non-normally. </def> + <resp>mbj</resp> + </term> + <term> + <id>trigger</id> + <shortdef>trigger</shortdef> + <def> +The Interpreter. A break point that is reached by a process triggers if it is active, and the execution of the process is stopped. </def> + <resp>olin</resp> + </term> + <term> + <id>tty</id> + <shortdef>tty</shortdef> + <def> +tty is a simple command line interface program where keystrokes are collected and interpreted. Originally meant teletypewriter equipment. Now it usually means the user console/terminal/shell window. </def> + <resp>kent</resp> + </term> + <term> + <id>tuple</id> + <shortdef>tuple</shortdef> + <def> +A tuple is a data type in Erlang. Tuples are used as place holders for complex data structures. Tuples may contain anything of any size, and are written as sequences of terms separated by commas, and enclosed in curly brackets { }. </def> + <resp>kenneth</resp> + </term> + <term> + <id>variable</id> + <shortdef>variable</shortdef> + <def> +An alias for a memory position, in which a value can be put. Erlang variables always start with an upper case letter. </def> + <resp>kenneth</resp> + </term> + <term> + <id>workers</id> + <shortdef>workers</shortdef> + <def> +The lower nodes in a supervision tree. These are the processes that actually performs some real work, e.g. servers. </def> + <resp>mbj</resp> + </term> + <term> + <id>YECC</id> + <shortdef>YECC</shortdef> + <def> +A LALR-1 parser generator included in Erlang/OTP. It is written in Erlang and generates a parser as an Erlang module. </def> + <resp>kenneth</resp> + </term> +</terms> + diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile new file mode 100644 index 0000000000..b3fe136644 --- /dev/null +++ b/system/doc/design_principles/Makefile @@ -0,0 +1,115 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/design_principles + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(DESIGN_PRINCIPLES_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = \ + note.gif \ + clientserver.gif \ + dist1.gif \ + dist2.gif \ + dist3.gif \ + dist4.gif \ + dist5.gif \ + inclappls.gif \ + sup4.gif \ + sup5.gif \ + sup6.gif + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/design_principles + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(HTML_UG_FILE) gifs + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + + +release_spec: + + diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml new file mode 100644 index 0000000000..121c0179c6 --- /dev/null +++ b/system/doc/design_principles/applications.xml @@ -0,0 +1,378 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>applications.xml</file> + </header> + <marker id="appl"></marker> + <p>This chapter should be read in conjunction with <c>app(4)</c> and + <c>application(3)</c>.</p> + + <section> + <title>Application Concept</title> + <p>When we have written code implementing some specific + functionality, we might want to make the code into an + <em>application</em>, that is a component that can be started and + stopped as a unit, and which can be re-used in other systems as + well.</p> + <p>To do this, we create an + <seealso marker="#callback_module">application callback module</seealso>, where we describe how the application should + be started and stopped.</p> + <p>Then, an <em>application specification</em> is needed, which is + put in an <seealso marker="#appl_res_file">application resource file</seealso>. Among other things, we specify which + modules the application consists of and the name of the callback + module.</p> + <p>If we use <c>systools</c>, the Erlang/OTP tools for packaging code + (see <seealso marker="release_structure">Releases</seealso>), + the code for each application is placed in a separate directory + following a pre-defined <seealso marker="#app_dir">directory structure</seealso>.</p> + </section> + + <section> + <marker id="callback_module"></marker> + <title>Application Callback Module</title> + <p>How to start and stop the code for the application, i.e. + the supervision tree, is described by two callback functions:</p> + <code type="none"> +start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} +stop(State)</code> + <p><c>start</c> is called when starting the application and should + create the supervision tree by starting the top supervisor. + It is expected to return the pid of the top supervisor and an + optional term <c>State</c>, which defaults to []. This term is + passed as-is to <c>stop</c>.</p> + <p><c>StartType</c> is usually the atom <c>normal</c>. It has other + values only in the case of a takeover or failover, see + <seealso marker="distributed_applications">Distributed Applications</seealso>. <c>StartArgs</c> is defined by the key + <c>mod</c> in the <seealso marker="#appl_res_file">application resource file</seealso> file.</p> + <p><c>stop/1</c> is called <em>after</em> the application has been + stopped and should do any necessary cleaning up. Note that + the actual stopping of the application, that is the shutdown of + the supervision tree, is handled automatically as described in + <seealso marker="#stopping">Starting and Stopping Applications</seealso>.</p> + <marker id="ch_app"></marker> + <p>Example of an application callback module for packaging + the supervision tree from + the <seealso marker="sup_princ#ex">Supervisor</seealso> chapter:</p> + <code type="none"> +-module(ch_app). +-behaviour(application). + +-export([start/2, stop/1]). + +start(_Type, _Args) -> + ch_sup:start_link(). + +stop(_State) -> + ok.</code> + <p>A library application, which can not be started or stopped, + does not need any application callback module.</p> + </section> + + <section> + <marker id="appl_res_file"></marker> + <title>Application Resource File</title> + <p>To define an application, we create an <em>application specification</em> which is put in an <em>application resource file</em>, or in short <c>.app</c> file:</p> + <code type="none"> +{application, Application, [Opt1,...,OptN]}.</code> + <p><c>Application</c>, an atom, is the name of the application. + The file must be named <c>Application.app</c>.</p> + <p>Each <c>Opt</c> is a tuple <c>{Key, Value}</c> which define a + certain property of the application. All keys are optional. + Default values are used for any omitted keys.</p> + <p>The contents of a minimal <c>.app</c> file for a library + application <c>libapp</c> looks like this:</p> + <code type="none"> +{application, libapp, []}.</code> + <p>The contents of a minimal <c>.app</c> file <c>ch_app.app</c> for + a supervision tree application like <c>ch_app</c> looks like this:</p> + <code type="none"> +{application, ch_app, + [{mod, {ch_app,[]}}]}.</code> + <p>The key <c>mod</c> defines the callback module and start + argument of the application, in this case <c>ch_app</c> and + [], respectively. This means that</p> + <code type="none"> +ch_app:start(normal, [])</code> + <p>will be called when the application should be started and</p> + <code type="none"> +ch_app:stop([])</code> + <p>will be called when the application has been stopped.</p> + <p>When using <c>systools</c>, the Erlang/OTP tools for packaging + code (see <seealso marker="release_structure">Releases</seealso>), + the keys <c>description</c>, <c>vsn</c>, <c>modules</c>, + <c>registered</c> and <c>applications</c> should also be + specified:</p> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {ch_app,[]}} + ]}.</code> + <taglist> + <tag><c>description</c></tag> + <item>A short description, a string. Defaults to "".</item> + <tag><c>vsn</c></tag> + <item>Version number, a string. Defaults to "".</item> + <tag><c>modules</c></tag> + <item>All modules <em>introduced</em> by this application. + <c>systools</c> uses this list when generating boot scripts and + tar files. A module must be defined in one and only one + application. Defaults to [].</item> + <tag><c>registered</c></tag> + <item>All names of registered processes in the application. + <c>systools</c> uses this list to detect name clashes + between applications. Defaults to [].</item> + <tag><c>applications</c></tag> + <item>All applications which must be started before this + application is started. <c>systools</c> uses this list to + generate correct boot scripts. Defaults to [], but note that + all applications have dependencies to at least <c>kernel</c> + and <c>stdlib</c>.</item> + </taglist> + <p>The syntax and contents of of the application resource file + are described in detail in <c>app(4)</c>.</p> + </section> + + <section> + <marker id="app_dir"></marker> + <title>Directory Structure</title> + <p>When packaging code using <c>systools</c>, the code for each + application is placed in a separate directory + <c>lib/Application-Vsn</c>, where <c>Vsn</c> is the version number.</p> + <p>This may be useful to know, even if <c>systools</c> is not used, + since Erlang/OTP itself is packaged according to the OTP principles + and thus comes with this directory structure. The code server + (see <c>code(3)</c>) will automatically use code from + the directory with the highest version number, if there are + more than one version of an application present.</p> + <p>The application directory structure can of course be used in + the development environment as well. The version number may then + be omitted from the name.</p> + <p>The application directory have the following sub-directories:</p> + <list type="bulleted"> + <item><c>src</c></item> + <item><c>ebin</c></item> + <item><c>priv</c></item> + <item><c>include</c></item> + </list> + <taglist> + <tag><c>src</c></tag> + <item>Contains the Erlang source code.</item> + <tag><c>ebin</c></tag> + <item>Contains the Erlang object code, the <c>beam</c> files. + The <c>.app</c> file is also placed here.</item> + <tag><c>priv</c></tag> + <item>Used for application specific files. For example, C + executables are placed here. The function <c>code:priv_dir/1</c> + should be used to access this directory.</item> + <tag><c>include</c></tag> + <item>Used for include files.</item> + </taglist> + </section> + + <section> + <marker id="application_controller"></marker> + <title>Application Controller</title> + <p>When an Erlang runtime system is started, a number of processes + are started as part of the Kernel application. One of these + processes is the <em>application controller</em> process, + registered as <c>application_controller</c>.</p> + <p>All operations on applications are coordinated by the application + controller. It is interfaced through the functions in + the module <c>application</c>, see <c>application(3)</c>. + In particular, applications can be loaded, unloaded, started and + stopped.</p> + </section> + + <section> + <title>Loading and Unloading Applications</title> + <p>Before an application can be started, it must be <em>loaded</em>. + The application controller reads and stores the information from + the <c>.app</c> file.</p> + <pre> +1> <input>application:load(ch_app).</input> +ok +2> <input>application:loaded_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {stdlib,"ERTS CXC 138 10","1.11.4.3"}, + {ch_app,"Channel allocator","1"}]</pre> + <p>An application that has been stopped, or has never been started, + can be unloaded. The information about the application is + erased from the internal database of the application controller.</p> + <pre> +3> <input>application:unload(ch_app).</input> +ok +4> <input>application:loaded_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {stdlib,"ERTS CXC 138 10","1.11.4.3"}]</pre> + <note> + <p>Loading/unloading an application does not load/unload the code + used by the application. Code loading is done the usual way.</p> + </note> + </section> + + <section> + <marker id="stopping"></marker> + <title>Starting and Stopping Applications</title> + <p>An application is started by calling:</p> + <pre> +5> <input>application:start(ch_app).</input> +ok +6> <input>application:which_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {stdlib,"ERTS CXC 138 10","1.11.4.3"}, + {ch_app,"Channel allocator","1"}]</pre> + <p>If the application is not already loaded, the application + controller will first load it using <c>application:load/1</c>. It + will check the value of the <c>applications</c> key, to ensure + that all applications that should be started before this + application are running.</p> + <marker id="application_master"></marker> + <p>The application controller then creates an <em>application master</em> for the application. The application master is + the group leader of all the processes in the application. + The application master starts the application by calling + the application callback function <c>start/2</c> in the module, + and with the start argument, defined by the <c>mod</c> key in + the <c>.app</c> file.</p> + <p>An application is stopped, but not unloaded, by calling:</p> + <pre> +7> <input>application:stop(ch_app).</input> +ok</pre> + <p>The application master stops the application by telling the top + supervisor to shutdown. The top supervisor tells all its child + processes to shutdown etc. and the entire tree is terminated in + reversed start order. The application master then calls + the application callback function <c>stop/1</c> in the module + defined by the <c>mod</c> key.</p> + </section> + + <section> + <title>Configuring an Application</title> + <p>An application can be configured using <em>configuration parameters</em>. These are a list of <c>{Par, Val}</c> tuples + specified by a key <c>env</c> in the <c>.app</c> file.</p> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {ch_app,[]}}, + {env, [{file, "/usr/local/log"}]} + ]}.</code> + <p><c>Par</c> should be an atom, <c>Val</c> is any term. + The application can retrieve the value of a configuration + parameter by calling <c>application:get_env(App, Par)</c> or a + number of similar functions, see <c>application(3)</c>.</p> + <p>Example:</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +ok +2> <input>application:get_env(ch_app, file).</input> +{ok,"/usr/local/log"}</pre> + <p>The values in the <c>.app</c> file can be overridden by values + in a <em>system configuration file</em>. This is a file which + contains configuration parameters for relevant applications:</p> + <code type="none"> +[{Application1, [{Par11,Val11},...]}, + ..., + {ApplicationN, [{ParN1,ValN1},...]}].</code> + <p>The system configuration should be called <c>Name.config</c> and + Erlang should be started with the command line argument + <c>-config Name</c>. See <c>config(4)</c> for more information.</p> + <p>Example: A file <c>test.config</c> is created with the following + contents:</p> + <code type="none"> +[{ch_app, [{file, "testlog"}]}].</code> + <p>The value of <c>file</c> will override the value of <c>file</c> + as defined in the <c>.app</c> file:</p> + <pre> +% <input>erl -config test</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +ok +2> <input>application:get_env(ch_app, file).</input> +{ok,"testlog"}</pre> + <p>If + <seealso marker="release_handling#sys">release handling</seealso> + is used, exactly one system configuration file should be used and + that file should be called <c>sys.config</c></p> + <p>The values in the <c>.app</c> file, as well as the values in a + system configuration file, can be overridden directly from + the command line:</p> + <pre> +% <input>erl -ApplName Par1 Val1 ... ParN ValN</input></pre> + <p>Example:</p> + <pre> +% <input>erl -ch_app file '"testlog"'</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +ok +2> <input>application:get_env(ch_app, file).</input> +{ok,"testlog"}</pre> + </section> + + <section> + <title>Application Start Types</title> + <p>A <em>start type</em> is defined when starting the application:</p> + <code type="none"> +application:start(Application, Type)</code> + <p><c>application:start(Application)</c> is the same as calling + <c>application:start(Application, temporary)</c>. The type can + also be <c>permanent</c> or <c>transient</c>:</p> + <list type="bulleted"> + <item>If a permanent application terminates, all other + applications and the runtime system are also terminated.</item> + <item>If a transient application terminates with reason + <c>normal</c>, this is reported but no other applications are + terminated. If a transient application terminates abnormally, + that is with any other reason than <c>normal</c>, all other + applications and the runtime system are also terminated.</item> + <item>If a temporary application terminates, this is reported but + no other applications are terminated.</item> + </list> + <p>It is always possible to stop an application explicitly by + calling <c>application:stop/1</c>. Regardless of the mode, no + other applications will be affected.</p> + <p>Note that transient mode is of little practical use, since when + a supervision tree terminates, the reason is set to + <c>shutdown</c>, not <c>normal</c>.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/appup_cookbook.xml b/system/doc/design_principles/appup_cookbook.xml new file mode 100644 index 0000000000..bc61578953 --- /dev/null +++ b/system/doc/design_principles/appup_cookbook.xml @@ -0,0 +1,627 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appup Cookbook</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>appup_cookbook.xml</file> + </header> + <p>This chapter contains examples of <c>.appup</c> files for + typical cases of upgrades/downgrades done in run-time.</p> + + <section> + <title>Changing a Functional Module</title> + <p>When a change has been made to a functional module, for example + if a new function has been added or a bug has been corrected, + simple code replacement is sufficient.</p> + <p>Example:</p> + <code type="none"> +{"2", + [{"1", [{load_module, m}]}], + [{"1", [{load_module, m}]}] +}.</code> + </section> + + <section> + <title>Changing a Residence Module</title> + <p>In a system implemented according to the OTP Design Principles, + all processes, except system processes and special processes, + reside in one of the behaviours <c>supervisor</c>, + <c>gen_server</c>, <c>gen_fsm</c> or <c>gen_event</c>. These + belong to the STDLIB application and upgrading/downgrading + normally requires an emulator restart.</p> + <p>OTP thus provides no support for changing residence modules + except in the case of <seealso marker="#spec">special processes</seealso>.</p> + </section> + + <section> + <title>Changing a Callback Module</title> + <p>A callback module is a functional module, and for code + extensions simple code replacement is sufficient.</p> + <p>Example: When adding a function to <c>ch3</c> as described in + the example in <seealso marker="release_handling#appup">Release Handling</seealso>, <c>ch_app.appup</c> looks as follows:</p> + <code type="none"> +{"2", + [{"1", [{load_module, ch3}]}], + [{"1", [{load_module, ch3}]}] +}.</code> + <p>OTP also supports changing the internal state of behaviour + processes, see <seealso marker="#int_state">Changing Internal State</seealso> below.</p> + </section> + + <section> + <marker id="int_state"></marker> + <title>Changing Internal State</title> + <p>In this case, simple code replacement is not sufficient. + The process must explicitly transform its state using the callback + function <c>code_change</c> before switching to the new version + of the callback module. Thus synchronized code replacement is + used.</p> + <p>Example: Consider the gen_server <c>ch3</c> from the chapter + about the <seealso marker="gen_server_concepts#ex">gen_server behaviour</seealso>. The internal state is a term <c>Chs</c> + representing the available channels. Assume we want add a counter + <c>N</c> which keeps track of the number of <c>alloc</c> requests + so far. This means we need to change the format to + <c>{Chs,N}</c>.</p> + <p>The <c>.appup</c> file could look as follows:</p> + <code type="none"> +{"2", + [{"1", [{update, ch3, {advanced, []}}]}], + [{"1", [{update, ch3, {advanced, []}}]}] +}.</code> + <p>The third element of the <c>update</c> instruction is a tuple + <c>{advanced,Extra}</c> which says that the affected processes + should do a state transformation before loading the new version + of the module. This is done by the processes calling the callback + function <c>code_change</c> (see <c>gen_server(3)</c>). The term + <c>Extra</c>, in this case [], is passed as-is to the function:</p> + <marker id="code_change"></marker> + <code type="none"> +-module(ch3). +... +-export([code_change/3]). +... +code_change({down, _Vsn}, {Chs, N}, _Extra) -> + {ok, Chs}; +code_change(_Vsn, Chs, _Extra) -> + {ok, {Chs, 0}}.</code> + <p>The first argument is <c>{down,Vsn}</c> in case of a downgrade, + or <c>Vsn</c> in case of an upgrade. The term <c>Vsn</c> is + fetched from the 'original' version of the module, i.e. + the version we are upgrading from, or downgrading to.</p> + <p>The version is defined by the module attribute <c>vsn</c>, if + any. There is no such attribute in <c>ch3</c>, so in this case + the version is the checksum (a huge integer) of the BEAM file, an + uninteresting value which is ignored.</p> + <p>(The other callback functions of <c>ch3</c> need to be modified + as well and perhaps a new interface function added, this is not + shown here).</p> + </section> + + <section> + <title>Module Dependencies</title> + <p>Assume we extend a module by adding a new interface function, as + in the example in <seealso marker="release_handling#appup">Release Handling</seealso>, where a function <c>available/0</c> is + added to <c>ch3</c>.</p> + <p>If we also add a call to this function, say in the module + <c>m1</c>, a run-time error could occur during release upgrade if + the new version of <c>m1</c> is loaded first and calls + <c>ch3:available/0</c> before the new version of <c>ch3</c> is + loaded.</p> + <p>Thus, <c>ch3</c> must be loaded before <c>m1</c> is, in + the upgrade case, and vice versa in the downgrade case. We say + that <c>m1</c><em>is dependent on</em><c>ch3</c>. In a release + handling instruction, this is expressed by the element + <c>DepMods</c>:</p> + <code type="none"> +{load_module, Module, DepMods} +{update, Module, {advanced, Extra}, DepMods}</code> + <p><c>DepMods</c> is a list of modules, on which <c>Module</c> is + dependent.</p> + <p>Example: The module <c>m1</c> in the application <c>myapp</c> is + dependent on <c>ch3</c> when upgrading from "1" to "2", or + downgrading from "2" to "1":</p> + <code type="none"> +myapp.appup: + +{"2", + [{"1", [{load_module, m1, [ch3]}]}], + [{"1", [{load_module, m1, [ch3]}]}] +}. + +ch_app.appup: + +{"2", + [{"1", [{load_module, ch3}]}], + [{"1", [{load_module, ch3}]}] +}.</code> + <p>If <c>m1</c> and <c>ch3</c> had belonged to the same application, + the <c>.appup</c> file could have looked like this:</p> + <code type="none"> +{"2", + [{"1", + [{load_module, ch3}, + {load_module, m1, [ch3]}]}], + [{"1", + [{load_module, ch3}, + {load_module, m1, [ch3]}]}] +}.</code> + <p>Note that it is <c>m1</c> that is dependent on <c>ch3</c> also + when downgrading. <c>systools</c> knows the difference between + up- and downgrading and will generate a correct <c>relup</c>, + where <c>ch3</c> is loaded before <c>m1</c> when upgrading but + <c>m1</c> is loaded before <c>ch3</c> when downgrading.</p> + </section> + + <section> + <marker id="spec"></marker> + <title>Changing Code For a Special Process</title> + <p>In this case, simple code replacement is not sufficient. + When a new version of a residence module for a special process + is loaded, the process must make a fully qualified call to + its loop function to switch to the new code. Thus synchronized + code replacement must be used.</p> + <note> + <p>The name(s) of the user-defined residence module(s) must be + listed in the <c>Modules</c> part of the child specification + for the special process, in order for the release handler to + find the process.</p> + </note> + <p>Example. Consider the example <c>ch4</c> from the chapter about + <seealso marker="spec_proc#ex">sys and proc_lib</seealso>. + When started by a supervisor, the child specification could look + like this:</p> + <code type="none"> +{ch4, {ch4, start_link, []}, + permanent, brutal_kill, worker, [ch4]}</code> + <p>If <c>ch4</c> is part of the application <c>sp_app</c> and a new + version of the module should be loaded when upgrading from + version "1" to "2" of this application, <c>sp_app.appup</c> could + look like this:</p> + <code type="none"> +{"2", + [{"1", [{update, ch4, {advanced, []}}]}], + [{"1", [{update, ch4, {advanced, []}}]}] +}.</code> + <p>The <c>update</c> instruction must contain the tuple + <c>{advanced,Extra}</c>. The instruction will make the special + process call the callback function <c>system_code_change/4</c>, a + function the user must implement. The term <c>Extra</c>, in this + case [], is passed as-is to <c>system_code_change/4</c>:</p> + <code type="none"> +-module(ch4). +... +-export([system_code_change/4]). +... + +system_code_change(Chs, _Module, _OldVsn, _Extra) -> + {ok, Chs}.</code> + <p>The first argument is the internal state <c>State</c> passed from + the function <c>sys:handle_system_msg(Request, From, Parent, Module, Deb, State)</c>, called by the special process when + a system message is received. In <c>ch4</c>, the internal state is + the set of available channels <c>Chs</c>.</p> + <p>The second argument is the name of the module (<c>ch4</c>).</p> + <p>The third argument is <c>Vsn</c> or <c>{down,Vsn}</c> as + described for + <seealso marker="#code_change">gen_server:code_change/3</seealso>.</p> + <p>In this case, all arguments but the first are ignored and + the function simply returns the internal state again. This is + enough if the code only has been extended. If we had wanted to + change the internal state (similar to the example in + <seealso marker="#int_state">Changing Internal State</seealso>), + it would have been done in this function and + <c>{ok,Chs2}</c> returned.</p> + </section> + + <section> + <marker id="sup"></marker> + <title>Changing a Supervisor</title> + <p>The supervisor behaviour supports changing the internal state, + i.e. changing restart strategy and maximum restart frequency + properties, as well as changing existing child specifications.</p> + <p>Adding and deleting child processes are also possible, but not + handled automatically. Instructions must be given by in + the <c>.appup</c> file.</p> + + <section> + <title>Changing Properties</title> + <p>Since the supervisor should change its internal state, + synchronized code replacement is required. However, + a special <c>update</c> instruction must be used.</p> + <p>The new version of the callback module must be loaded first + both in the case of upgrade and downgrade. Then the new return + value of <c>init/1</c> can be checked and the internal state be + changed accordingly.</p> + <p>The following <c>upgrade</c> instruction is used for + supervisors:</p> + <code type="none"> +{update, Module, supervisor}</code> + <p>Example: Assume we want to change the restart strategy of + <c>ch_sup</c> from the <seealso marker="sup_princ#ex">Supervisor Behaviour</seealso> chapter from one_for_one to one_for_all. + We change the callback function <c>init/1</c> in + <c>ch_sup.erl</c>:</p> + <code type="none"> +-module(ch_sup). +... + +init(_Args) -> + {ok, {{one_for_all, 1, 60}, ...}}.</code> + <p>The file <c>ch_app.appup</c>:</p> + <code type="none"> +{"2", + [{"1", [{update, ch_sup, supervisor}]}], + [{"1", [{update, ch_sup, supervisor}]}] +}.</code> + </section> + + <section> + <title>Changing Child Specifications</title> + <p>The instruction, and thus the <c>.appup</c> file, when + changing an existing child specification, is the same as when + changing properties as described above:</p> + <code type="none"> +{"2", + [{"1", [{update, ch_sup, supervisor}]}], + [{"1", [{update, ch_sup, supervisor}]}] +}.</code> + <p>The changes do not affect existing child processes. For + example, changing the start function only specifies how + the child process should be restarted, if needed later on.</p> + <p>Note that the id of the child specification cannot be changed.</p> + <p>Note also that changing the <c>Modules</c> field of the child + specification may affect the release handling process itself, + as this field is used to identify which processes are affected + when doing a synchronized code replacement.</p> + </section> + <marker id="sup_add"></marker> + + <section> + <title>Adding And Deleting Child Processes</title> + <p>As stated above, changing child specifications does not affect + existing child processes. New child specifications are + automatically added, but not deleted. Also, child processes are + not automatically started or terminated. Instead, this must be + done explicitly using <c>apply</c> instructions.</p> + <p>Example: Assume we want to add a new child process <c>m1</c> to + <c>ch_sup</c> when upgrading <c>ch_app</c> from "1" to "2". + This means <c>m1</c> should be deleted when downgrading from + "2" to "1":</p> + <code type="none"> +{"2", + [{"1", + [{update, ch_sup, supervisor}, + {apply, {supervisor, restart_child, [ch_sup, m1]}} + ]}], + [{"1", + [{apply, {supervisor, terminate_child, [ch_sup, m1]}}, + {apply, {supervisor, delete_child, [ch_sup, m1]}}, + {update, ch_sup, supervisor} + ]}] +}.</code> + <p>Note that the order of the instructions is important.</p> + <p>Note also that the supervisor must be registered as + <c>ch_sup</c> for the script to work. If the supervisor is not + registered, it cannot be accessed directly from the script. + Instead a help function that finds the pid of the supervisor + and calls <c>supervisor:restart_child</c> etc. must be written, + and it is this function that should be called from the script + using the <c>apply</c> instruction.</p> + <p>If the module <c>m1</c> is introduced in version "2" of + <c>ch_app</c>, it must also be loaded when upgrading and + deleted when downgrading:</p> + <code type="none"> +{"2", + [{"1", + [{add_module, m1}, + {update, ch_sup, supervisor}, + {apply, {supervisor, restart_child, [ch_sup, m1]}} + ]}], + [{"1", + [{apply, {supervisor, terminate_child, [ch_sup, m1]}}, + {apply, {supervisor, delete_child, [ch_sup, m1]}}, + {update, ch_sup, supervisor}, + {delete_module, m1} + ]}] +}.</code> + <p>Note again that the order of the instructions is important. + When upgrading, <c>m1</c> must be loaded and the supervisor's + child specification changed, before the new child process can + be started. When downgrading, the child process must be + terminated before child specification is changed and the module + is deleted.</p> + </section> + </section> + + <section> + <title>Adding or Deleting a Module</title> + <p>Example: A new functional module <c>m</c> is added to + <c>ch_app</c>:</p> + <code type="none"> +{"2", + [{"1", [{add_module, m}]}], + [{"1", [{delete_module, m}]}]</code> + </section> + + <section> + <title>Starting or Terminating a Process</title> + <p>In a system structured according to the OTP design principles, + any process would be a child process belonging to a supervisor, + see <seealso marker="#sup_add">Adding and Deleting Child Processes</seealso> above.</p> + </section> + + <section> + <title>Adding or Removing an Application</title> + <p>When adding or removing an application, no <c>.appup</c> file + is needed. When generating <c>relup</c>, the <c>.rel</c> files + are compared and <c>add_application</c> and + <c>remove_application</c> instructions are added automatically.</p> + </section> + + <section> + <title>Restarting an Application</title> + <p>Restarting an application is useful when a change is too + complicated to be made without restarting the processes, for + example if the supervisor hierarchy has been restructured.</p> + <p>Example: When adding a new child <c>m1</c> to <c>ch_sup</c>, as + in the <seealso marker="#sup_add">example above</seealso>, an + alternative to updating the supervisor is to restart the entire + application:</p> + <code type="none"> +{"2", + [{"1", [{restart_application, ch_app}]}], + [{"1", [{restart_application, ch_app}]}] +}.</code> + </section> + + <section> + <marker id="app_spec"></marker> + <title>Changing an Application Specification</title> + <p>When installing a release, the application specifications are + automatically updated before evaluating the <c>relup</c> script. + Hence, no instructions are needed in the <c>.appup</c> file:</p> + <pre> +{"2", + [{"1", []}], + [{"1", []}] +}.</pre> + </section> + + <section> + <title>Changing Application Configuration</title> + <p>Changing an application configuration by updating the <c>env</c> + key in the <c>.app</c> file is an instance of changing an + application specification, <seealso marker="#app_spec">see above</seealso>.</p> + <p>Alternatively, application configuration parameters can be + added or updated in <c>sys.config</c>.</p> + </section> + + <section> + <title>Changing Included Applications</title> + <p>The release handling instructions for adding, removing and + restarting applications apply to primary applications only. + There are no corresponding instructions for included + applications. However, since an included application is really a + supervision tree with a topmost supervisor, started as a child + process to a supervisor in the including application, a + <c>relup</c> file can be manually created.</p> + <p>Example: Assume we have a release containing an application + <c>prim_app</c> which have a supervisor <c>prim_sup</c> in its + supervision tree.</p> + <p>In a new version of the release, our example application + <c>ch_app</c> should be included in <c>prim_app</c>. That is, + its topmost supervisor <c>ch_sup</c> should be started as a child + process to <c>prim_sup</c>.</p> + <p>1) Edit the code for <c>prim_sup</c>:</p> + <code type="none"> +init(...) -> + {ok, {...supervisor flags..., + [..., + {ch_sup, {ch_sup,start_link,[]}, + permanent,infinity,supervisor,[ch_sup]}, + ...]}}.</code> + <p>2) Edit the <c>.app</c> file for <c>prim_app</c>:</p> + <code type="none"> +{application, prim_app, + [..., + {vsn, "2"}, + ..., + {included_applications, [ch_app]}, + ... + ]}.</code> + <p>3) Create a new <c>.rel</c> file, including <c>ch_app</c>:</p> + <code type="none"> +{release, + ..., + [..., + {prim_app, "2"}, + {ch_app, "1"}]}.</code> + + <section> + <title>Application Restart</title> + <p>4a) One way to start the included application is to restart + the entire <c>prim_app</c> application. Normally, we would then + use the <c>restart_application</c> instruction in + the <c>.appup</c> file for <c>prim_app</c>.</p> + <p>However, if we did this and then generated a <c>relup</c> file, + not only would it contain instructions for restarting (i.e. + removing and adding) <c>prim_app</c>, it would also contain + instructions for starting <c>ch_app</c> (and stopping it, in + the case of downgrade). This is due to the fact that + <c>ch_app</c> is included in the new <c>.rel</c> file, but not + in the old one.</p> + <p>Instead, a correct <c>relup</c> file can be created manually, + either from scratch or by editing the generated version. + The instructions for starting/stopping <c>ch_app</c> are + replaced by instructions for loading/unloading the application:</p> + <code type="none"> +{"B", + [{"A", + [], + [{load_object_code,{ch_app,"1",[ch_sup,ch3]}}, + {load_object_code,{prim_app,"2",[prim_app,prim_sup]}}, + point_of_no_return, + {apply,{application,stop,[prim_app]}}, + {remove,{prim_app,brutal_purge,brutal_purge}}, + {remove,{prim_sup,brutal_purge,brutal_purge}}, + {purge,[prim_app,prim_sup]}, + {load,{prim_app,brutal_purge,brutal_purge}}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {load,{ch_sup,brutal_purge,brutal_purge}}, + {load,{ch3,brutal_purge,brutal_purge}}, + {apply,{application,load,[ch_app]}}, + {apply,{application,start,[prim_app,permanent]}}]}], + [{"A", + [], + [{load_object_code,{prim_app,"1",[prim_app,prim_sup]}}, + point_of_no_return, + {apply,{application,stop,[prim_app]}}, + {apply,{application,unload,[ch_app]}}, + {remove,{ch_sup,brutal_purge,brutal_purge}}, + {remove,{ch3,brutal_purge,brutal_purge}}, + {purge,[ch_sup,ch3]}, + {remove,{prim_app,brutal_purge,brutal_purge}}, + {remove,{prim_sup,brutal_purge,brutal_purge}}, + {purge,[prim_app,prim_sup]}, + {load,{prim_app,brutal_purge,brutal_purge}}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {apply,{application,start,[prim_app,permanent]}}]}] +}.</code> + </section> + + <section> + <title>Supervisor Change</title> + <p>4b) Another way to start the included application (or stop it + in the case of downgrade) is by combining instructions for + adding and removing child processes to/from <c>prim_sup</c> with + instructions for loading/unloading all <c>ch_app</c> code and + its application specification.</p> + <p>Again, the <c>relup</c> file is created manually. Either from + scratch or by editing a generated version. Load all code for + <c>ch_app</c> first, and also load the application + specification, before <c>prim_sup</c> is updated. When + downgrading, <c>prim_sup</c> should be updated first, before + the code for <c>ch_app</c> and its application specification + are unloaded.</p> + <code type="none"> +{"B", + [{"A", + [], + [{load_object_code,{ch_app,"1",[ch_sup,ch3]}}, + {load_object_code,{prim_app,"2",[prim_sup]}}, + point_of_no_return, + {load,{ch_sup,brutal_purge,brutal_purge}}, + {load,{ch3,brutal_purge,brutal_purge}}, + {apply,{application,load,[ch_app]}}, + {suspend,[prim_sup]}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {code_change,up,[{prim_sup,[]}]}, + {resume,[prim_sup]}, + {apply,{supervisor,restart_child,[prim_sup,ch_sup]}}]}], + [{"A", + [], + [{load_object_code,{prim_app,"1",[prim_sup]}}, + point_of_no_return, + {apply,{supervisor,terminate_child,[prim_sup,ch_sup]}}, + {apply,{supervisor,delete_child,[prim_sup,ch_sup]}}, + {suspend,[prim_sup]}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {code_change,down,[{prim_sup,[]}]}, + {resume,[prim_sup]}, + {remove,{ch_sup,brutal_purge,brutal_purge}}, + {remove,{ch3,brutal_purge,brutal_purge}}, + {purge,[ch_sup,ch3]}, + {apply,{application,unload,[ch_app]}}]}] +}.</code> + </section> + </section> + + <section> + <title>Changing Non-Erlang Code</title> + <p>Changing code for a program written in another programming + language than Erlang, for example a port program, is very + application dependent and OTP provides no special support for it.</p> + <p>Example, changing code for a port program: Assume that + the Erlang process controlling the port is a gen_server + <c>portc</c> and that the port is opened in the callback function + <c>init/1</c>:</p> + <code type="none"> +init(...) -> + ..., + PortPrg = filename:join(code:priv_dir(App), "portc"), + Port = open_port({spawn,PortPrg}, [...]), + ..., + {ok, #state{port=Port, ...}}.</code> + <p>If the port program should be updated, we can extend the code for + the gen_server with a <c>code_change</c> function which closes + the old port and opens a new port. (If necessary, the gen_server + may first request data that needs to be saved from the port + program and pass this data to the new port):</p> + <code type="none"> +code_change(_OldVsn, State, port) -> + State#state.port ! close, + receive + {Port,close} -> + true + end, + PortPrg = filename:join(code:priv_dir(App), "portc"), + Port = open_port({spawn,PortPrg}, [...]), + {ok, #state{port=Port, ...}}.</code> + <p>Update the application version number in the <c>.app</c> file + and write an <c>.appup</c> file:</p> + <code type="none"> +["2", + [{"1", [{update, portc, {advanced,port}}]}], + [{"1", [{update, portc, {advanced,port}}]}] +].</code> + <p>Make sure the <c>priv</c> directory where the C program is + located is included in the new release package:</p> + <pre> +1> <input>systools:make_tar("my_release", [{dirs,[priv]}]).</input> +...</pre> + </section> + + <section> + <title>Emulator Restart</title> + <p>If the emulator can or should be restarted, the very simple + <c>.relup</c> file can be created manually:</p> + <code type="none"> +{"B", + [{"A", + [], + [restart_new_emulator]}], + [{"A", + [], + [restart_new_emulator]}] +}.</code> + <p>This way, the release handler framework with automatic packing + and unpacking of release packages, automatic path updates etc. can + be used without having to specify <c>.appup</c> files.</p> + <p>If some transformation of persistent data, for example database + contents, needs to be done before installing the new release + version, instructions for this can be added to the <c>.relup</c> + file as well.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/book.xml b/system/doc/design_principles/book.xml new file mode 100644 index 0000000000..615722ac12 --- /dev/null +++ b/system/doc/design_principles/book.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OTP Design Principles</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <insidecover> + </insidecover> + <pagetext>OTP Design Principles</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/design_principles/clientserver.fig b/system/doc/design_principles/clientserver.fig new file mode 100644 index 0000000000..5854169ced --- /dev/null +++ b/system/doc/design_principles/clientserver.fig @@ -0,0 +1,40 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 750 404 404 3150 750 3300 1125 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2175 2025 404 404 2175 2025 2325 2400 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1650 3525 404 404 1650 3525 1800 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5025 2925 404 404 5025 2925 5175 3300 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 3375 1275 4575 2550 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4725 2325 3600 1125 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2550 2400 4275 2925 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4275 2700 2700 2175 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2175 3300 4125 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 1 + 3975 3300 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4050 3300 2250 3450 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 5475 525 7050 525 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6975 1125 5550 1125 +4 0 -1 0 0 2 14 0.0000 4 150 645 5700 3075 Server\001 +4 0 -1 0 0 2 14 0.0000 4 150 675 900 1200 Clients\001 +4 0 -1 0 0 2 14 0.0000 4 195 570 5850 300 Query\001 +4 0 -1 0 0 2 14 0.0000 4 195 570 5850 975 Reply\001 +4 0 -1 0 0 2 14 0.0000 4 150 2370 2400 4500 The Client-server model\001 diff --git a/system/doc/design_principles/clientserver.gif b/system/doc/design_principles/clientserver.gif Binary files differnew file mode 100644 index 0000000000..371ece4c12 --- /dev/null +++ b/system/doc/design_principles/clientserver.gif diff --git a/system/doc/design_principles/clientserver.ps b/system/doc/design_principles/clientserver.ps new file mode 100644 index 0000000000..7e4e98152e --- /dev/null +++ b/system/doc/design_principles/clientserver.ps @@ -0,0 +1,199 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: clientserver.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:48:28 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 370 264 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-54.0 272.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 3150 750 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 2175 2025 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1650 3525 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 5025 2925 404 404 0 360 DrawEllipse gs col-1 s gr + +% Polyline +gs clippath +4496 2422 m 4556 2530 l 4452 2464 l 4563 2581 l 4607 2540 l cp clip +n 3375 1275 m 4575 2550 l gs col-1 s gr gr + +% arrowhead +n 4496 2422 m 4556 2530 l 4452 2464 l 4474 2443 l 4496 2422 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +3679 1253 m 3618 1144 l 3722 1212 l 3612 1094 l 3568 1135 l cp clip +n 4725 2325 m 3600 1125 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 3679 1253 m 3618 1144 l 3722 1212 l 3701 1232 l 3679 1253 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +4143 2853 m 4249 2917 l 4126 2911 l 4281 2958 l 4298 2901 l cp clip +n 2550 2400 m 4275 2925 l gs col-1 s gr gr + +% arrowhead +n 4143 2853 m 4249 2917 l 4126 2911 l 4134 2882 l 4143 2853 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +2830 2250 m 2725 2183 l 2849 2193 l 2695 2142 l 2676 2199 l cp clip +n 4275 2700 m 2700 2175 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 2830 2250 m 2725 2183 l 2849 2193 l 2839 2221 l 2830 2250 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +3976 3131 m 4098 3152 l 3981 3191 l 4142 3179 l 4138 3119 l cp clip +n 2175 3300 m 4125 3150 l gs col-1 s gr gr + +% arrowhead +n 3976 3131 m 4098 3152 l 3981 3191 l 3978 3161 l 3976 3131 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +n 3975 3300 m 3975 3300 l gs col-1 s gr +% Polyline + [66.7] 0 sd +gs clippath +2399 3468 m 2276 3447 l 2394 3408 l 2233 3421 l 2238 3481 l cp clip +n 4050 3300 m 2250 3450 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 2399 3468 m 2276 3447 l 2394 3408 l 2396 3438 l 2399 3468 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +6903 495 m 7023 525 l 6903 555 l 7065 555 l 7065 495 l cp clip +n 5475 525 m 7050 525 l gs col-1 s gr gr + +% arrowhead +n 6903 495 m 7023 525 l 6903 555 l 6903 525 l 6903 495 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +5697 1155 m 5577 1125 l 5697 1095 l 5535 1095 l 5535 1155 l cp clip +n 6975 1125 m 5550 1125 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 5697 1155 m 5577 1125 l 5697 1095 l 5697 1125 l 5697 1155 l cp gs 0.00 setgray ef gr col-1 s +/Times-Bold ff 210.00 scf sf +5700 3075 m +gs 1 -1 sc (Server) col-1 sh gr +/Times-Bold ff 210.00 scf sf +900 1200 m +gs 1 -1 sc (Clients) col-1 sh gr +/Times-Bold ff 210.00 scf sf +5850 300 m +gs 1 -1 sc (Query) col-1 sh gr +/Times-Bold ff 210.00 scf sf +5850 975 m +gs 1 -1 sc (Reply) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2400 4500 m +gs 1 -1 sc (The Client-server model) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml new file mode 100644 index 0000000000..977eda49b5 --- /dev/null +++ b/system/doc/design_principles/des_princ.xml @@ -0,0 +1,285 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Overview</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>des_princ.xml</file> + </header> + <p>The <em>OTP Design Principles</em> is a set of principles for how + to structure Erlang code in terms of processes, modules and + directories.</p> + + <section> + <title>Supervision Trees</title> + <p>A basic concept in Erlang/OTP is the <em>supervision tree</em>. + This is a process structuring model based on the idea of + <em>workers</em> and <em>supervisors</em>.</p> + <list type="bulleted"> + <item>Workers are processes which perform computations, that is, + they do the actual work.</item> + <item>Supervisors are processes which monitor the behaviour of + workers. A supervisor can restart a worker if something goes + wrong.</item> + <item>The supervision tree is a hierarchical arrangement of + code into supervisors and workers, making it possible to + design and program fault-tolerant software.</item> + </list> + <marker id="sup6"></marker> + <image file="../design_principles/sup6.gif"> + <icaption>Supervision Tree</icaption> + </image> + <p>In the figure above, square boxes represents supervisors and + circles represent workers.</p> + </section> + + <section> + <title>Behaviours</title> + <p>In a supervision tree, many of the processes have similar + structures, they follow similar patterns. For example, + the supervisors are very similar in structure. The only difference + between them is which child processes they supervise. Also, many + of the workers are servers in a server-client relation, finite + state machines, or event handlers such as error loggers.</p> + <p><em>Behaviours</em> are formalizations of these common patterns. + The idea is to divide the code for a process in a generic part + (a behaviour module) and a specific part (a <em>callback module</em>).</p> + <p>The behaviour module is part of Erlang/OTP. To implement a + process such as a supervisor, the user only has to implement + the callback module which should export a pre-defined set of + functions, the <em>callback functions</em>.</p> + <p>An example to illustrate how code can be divided into a generic + and a specific part: Consider the following code (written in + plain Erlang) for a simple server, which keeps track of a number + of "channels". Other processes can allocate and free the channels + by calling the functions <c>alloc/0</c> and <c>free/1</c>, + respectively.</p> + <marker id="ch1"></marker> + <code type="none"> +-module(ch1). +-export([start/0]). +-export([alloc/0, free/1]). +-export([init/0]). + +start() -> + spawn(ch1, init, []). + +alloc() -> + ch1 ! {self(), alloc}, + receive + {ch1, Res} -> + Res + end. + +free(Ch) -> + ch1 ! {free, Ch}, + ok. + +init() -> + register(ch1, self()), + Chs = channels(), + loop(Chs). + +loop(Chs) -> + receive + {From, alloc} -> + {Ch, Chs2} = alloc(Chs), + From ! {ch1, Ch}, + loop(Chs2); + {free, Ch} -> + Chs2 = free(Ch, Chs), + loop(Chs2) + end.</code> + <p>The code for the server can be rewritten into a generic part + <c>server.erl</c>:</p> + <code type="none"> +-module(server). +-export([start/1]). +-export([call/2, cast/2]). +-export([init/1]). + +start(Mod) -> + spawn(server, init, [Mod]). + +call(Name, Req) -> + Name ! {call, self(), Req}, + receive + {Name, Res} -> + Res + end. + +cast(Name, Req) -> + Name ! {cast, Req}, + ok. + +init(Mod) -> + register(Mod, self()), + State = Mod:init(), + loop(Mod, State). + +loop(Mod, State) -> + receive + {call, From, Req} -> + {Res, State2} = Mod:handle_call(Req, State), + From ! {Mod, Res}, + loop(Mod, State2); + {cast, Req} -> + State2 = Mod:handle_cast(Req, State), + loop(Mod, State2) + end.</code> + <p>and a callback module <c>ch2.erl</c>:</p> + <code type="none"> +-module(ch2). +-export([start/0]). +-export([alloc/0, free/1]). +-export([init/0, handle_call/2, handle_cast/2]). + +start() -> + server:start(ch2). + +alloc() -> + server:call(ch2, alloc). + +free(Ch) -> + server:cast(ch2, {free, Ch}). + +init() -> + channels(). + +handle_call(alloc, Chs) -> + alloc(Chs). % => {Ch,Chs2} + +handle_cast({free, Ch}, Chs) -> + free(Ch, Chs). % => Chs2</code> + <p>Note the following:</p> + <list type="bulleted"> + <item>The code in <c>server</c> can be re-used to build many + different servers.</item> + <item>The name of the server, in this example the atom + <c>ch2</c>, is hidden from the users of the client functions. + This means the name can be changed without affecting them.</item> + <item>The protcol (messages sent to and received from the server) + is hidden as well. This is good programming practice and allows + us to change the protocol without making changes to code using + the interface functions.</item> + <item>We can extend the functionality of <c>server</c>, without + having to change <c>ch2</c> or any other callback module.</item> + </list> + <p>(In <c>ch1.erl</c> and <c>ch2.erl</c> above, the implementation + of <c>channels/0</c>, <c>alloc/1</c> and <c>free/2</c> has been + intentionally left out, as it is not relevant to the example. + For completeness, one way to write these functions are given + below. Note that this is an example only, a realistic + implementation must be able to handle situations like running out + of channels to allocate etc.)</p> + <code type="none"> +channels() -> + {_Allocated = [], _Free = lists:seq(1,100)}. + +alloc({Allocated, [H|T] = _Free}) -> + {H, {[H|Allocated], T}}. + +free(Ch, {Alloc, Free} = Channels) -> + case lists:member(Ch, Alloc) of + true -> + {lists:delete(Ch, Alloc), [Ch|Free]}; + false -> + Channels + end. </code> + <p>Code written without making use of behaviours may be more + efficient, but the increased efficiency will be at the expense of + generality. The ability to manage all applications in the system + in a consistent manner is very important.</p> + <p>Using behaviours also makes it easier to read and understand + code written by other programmers. Ad hoc programming structures, + while possibly more efficient, are always more difficult to + understand.</p> + <p>The module <c>server</c> corresponds, greatly simplified, + to the Erlang/OTP behaviour <c>gen_server</c>.</p> + <p>The standard Erlang/OTP behaviours are:</p> + <taglist> + <tag><seealso marker="gen_server_concepts">gen_server</seealso></tag> + <item>For implementing the server of a client-server relation.</item> + <tag><seealso marker="fsm">gen_fsm</seealso></tag> + <item>For implementing finite state machines.</item> + <tag><seealso marker="events">gen_event</seealso></tag> + <item>For implementing event handling functionality.</item> + <tag><seealso marker="sup_princ">supervisor</seealso></tag> + <item>For implementing a supervisor in a supervision tree.</item> + </taglist> + <p>The compiler understands the module attribute + <c>-behaviour(Behaviour)</c> and issues warnings about + missing callback functions. Example:</p> + <code type="none"> +-module(chs3). +-behaviour(gen_server). +... + +3> c(chs3). +./chs3.erl:10: Warning: undefined call-back function handle_call/3 +{ok,chs3}</code> + </section> + + <section> + <title>Applications</title> + <p>Erlang/OTP comes with a number of components, each implementing + some specific functionality. Components are with Erlang/OTP + terminology called <em>applications</em>. Examples of Erlang/OTP + applications are Mnesia, which has everything needed for + programming database services, and Debugger which is used to + debug Erlang programs. The minimal system based on Erlang/OTP + consists of the applications Kernel and STDLIB.</p> + <p>The application concept applies both to program structure + (processes) and directory structure (modules).</p> + <p>The simplest kind of application does not have any processes, + but consists of a collection of functional modules. Such an + application is called a <em>library application</em>. An example + of a library application is STDLIB.</p> + <p>An application with processes is easiest implemented as a + supervision tree using the standard behaviours.</p> + <p>How to program applications is described in + <seealso marker="applications">Applications</seealso>.</p> + </section> + + <section> + <title>Releases</title> + <p>A <em>release</em> is a complete system made out from a subset of + the Erlang/OTP applications and a set of user-specific + applications.</p> + <p>How to program releases is described in + <seealso marker="release_structure">Releases</seealso>.</p> + <p>How to install a release in a target environment is described + in the chapter about Target Systems in System Principles.</p> + </section> + + <section> + <title>Release Handling</title> + <p><em>Release handling</em> is upgrading and downgrading between + different versions of a release, in a (possibly) running system. + How to do this is described in + <seealso marker="release_handling">Release Handling</seealso>.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/dist1.fig b/system/doc/design_principles/dist1.fig new file mode 100644 index 0000000000..ffdb112d71 --- /dev/null +++ b/system/doc/design_principles/dist1.fig @@ -0,0 +1,20 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2025 525 2775 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2400 900 318 318 2400 900 2625 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 2272 945 cp2\001 +-6 +6 3375 525 4125 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3750 900 318 318 3750 900 3975 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 3622 945 cp3\001 +-6 +6 675 525 1425 1575 +6 675 525 1425 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1050 900 318 318 1050 900 1275 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 922 945 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 810 1500 myapp\001 +-6 diff --git a/system/doc/design_principles/dist1.gif b/system/doc/design_principles/dist1.gif Binary files differnew file mode 100644 index 0000000000..b2cde85841 --- /dev/null +++ b/system/doc/design_principles/dist1.gif diff --git a/system/doc/design_principles/dist1.ps b/system/doc/design_principles/dist1.ps new file mode 100644 index 0000000000..3b841d2cd4 --- /dev/null +++ b/system/doc/design_principles/dist1.ps @@ -0,0 +1,131 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist1.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:13:44 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 202 58 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-43.0 92.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 2400 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2272 945 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3750 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3622 945 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1050 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +922 945 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +810 1500 m +gs 1 -1 sc (myapp) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist2.fig b/system/doc/design_principles/dist2.fig new file mode 100644 index 0000000000..973cbc4a31 --- /dev/null +++ b/system/doc/design_principles/dist2.fig @@ -0,0 +1,41 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 675 525 1425 1575 +6 675 525 1425 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1050 900 318 318 1050 900 1275 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 922 945 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 810 1500 myapp\001 +-6 +6 2025 525 4125 1275 +6 2025 525 2775 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2400 900 318 318 2400 900 2625 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 2272 945 cp2\001 +-6 +6 3375 525 4125 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3750 900 318 318 3750 900 3975 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 3622 945 cp3\001 +-6 +-6 +6 2700 3300 3450 4050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3075 3675 318 318 3075 3675 3300 3900 +4 0 -1 0 0 0 12 0.0000 4 180 255 2947 3720 cp3\001 +-6 +6 1350 3300 2100 4425 +6 1350 3300 2100 4050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1725 3675 318 318 1725 3675 1950 3900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1597 3720 cp2\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 1485 4350 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 1200 1500 525 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 600 525 1575 1350 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2325 1725 2325 2850 +4 0 -1 0 0 0 12 0.0000 4 135 480 2550 2325 5 secs.\001 diff --git a/system/doc/design_principles/dist2.gif b/system/doc/design_principles/dist2.gif Binary files differnew file mode 100644 index 0000000000..8351e8b7f0 --- /dev/null +++ b/system/doc/design_principles/dist2.gif diff --git a/system/doc/design_principles/dist2.ps b/system/doc/design_principles/dist2.ps new file mode 100644 index 0000000000..6fe592a4fc --- /dev/null +++ b/system/doc/design_principles/dist2.ps @@ -0,0 +1,160 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist2.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:13:55 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 215 233 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-30.0 263.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 1050 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +922 945 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +810 1500 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2400 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2272 945 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3750 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3622 945 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 3075 3675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2947 3720 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1725 3675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1597 3720 m +gs 1 -1 sc (cp2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1485 4350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +n 525 1200 m 1500 525 l gs col-1 s gr +% Polyline +n 600 525 m 1575 1350 l gs col-1 s gr +% Polyline +gs clippath +2355 2703 m 2325 2823 l 2295 2703 l 2295 2865 l 2355 2865 l cp clip +n 2325 1725 m 2325 2850 l gs col-1 s gr gr + +% arrowhead +n 2355 2703 m 2325 2823 l 2295 2703 l col-1 s +/Times-Roman ff 180.00 scf sf +2550 2325 m +gs 1 -1 sc (5 secs.) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist3.fig b/system/doc/design_principles/dist3.fig new file mode 100644 index 0000000000..d7e32d0887 --- /dev/null +++ b/system/doc/design_principles/dist3.fig @@ -0,0 +1,33 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 1275 300 2325 1125 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1275 975 2250 300 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1350 300 2325 1125 +-6 +6 2775 300 3525 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 675 318 318 3150 675 3375 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3022 720 cp3\001 +-6 +6 1425 300 2175 1425 +6 1425 300 2175 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1800 675 318 318 1800 675 2025 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1672 720 cp2\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 1560 1350 myapp\001 +-6 +6 1950 3225 2700 4350 +6 1950 3225 2700 3975 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2325 3600 318 318 2325 3600 2550 3825 +4 0 -1 0 0 0 12 0.0000 4 180 255 2197 3645 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 2085 4275 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2325 1725 2325 2850 +4 0 -1 0 0 0 12 0.0000 4 135 480 2550 2325 5 secs.\001 diff --git a/system/doc/design_principles/dist3.gif b/system/doc/design_principles/dist3.gif Binary files differnew file mode 100644 index 0000000000..e95958cc16 --- /dev/null +++ b/system/doc/design_principles/dist3.gif diff --git a/system/doc/design_principles/dist3.ps b/system/doc/design_principles/dist3.ps new file mode 100644 index 0000000000..3e0e93f5db --- /dev/null +++ b/system/doc/design_principles/dist3.ps @@ -0,0 +1,148 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist3.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:14:01 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 134 242 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-75.0 259.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 1275 975 m 2250 300 l gs col-1 s gr +% Polyline +n 1350 300 m 2325 1125 l gs col-1 s gr +% Ellipse +n 3150 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3022 720 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1800 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1672 720 m +gs 1 -1 sc (cp2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1560 1350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2325 3600 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2197 3645 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +2085 4275 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +gs clippath +2355 2703 m 2325 2823 l 2295 2703 l 2295 2865 l 2355 2865 l cp clip +n 2325 1725 m 2325 2850 l gs col-1 s gr gr + +% arrowhead +n 2355 2703 m 2325 2823 l 2295 2703 l col-1 s +/Times-Roman ff 180.00 scf sf +2550 2325 m +gs 1 -1 sc (5 secs.) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist4.fig b/system/doc/design_principles/dist4.fig new file mode 100644 index 0000000000..d40be27ad6 --- /dev/null +++ b/system/doc/design_principles/dist4.fig @@ -0,0 +1,16 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 1425 300 2175 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1800 675 318 318 1800 675 2025 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1672 720 cp2\001 +-6 +6 2775 300 3525 1500 +6 2775 300 3525 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 675 318 318 3150 675 3375 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3022 720 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 2910 1425 myapp\001 +-6 diff --git a/system/doc/design_principles/dist4.gif b/system/doc/design_principles/dist4.gif Binary files differnew file mode 100644 index 0000000000..b1d996b861 --- /dev/null +++ b/system/doc/design_principles/dist4.gif diff --git a/system/doc/design_principles/dist4.ps b/system/doc/design_principles/dist4.ps new file mode 100644 index 0000000000..9bcf3dd880 --- /dev/null +++ b/system/doc/design_principles/dist4.ps @@ -0,0 +1,125 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist4.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:14:06 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 121 67 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-88.0 88.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 1800 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1672 720 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3150 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3022 720 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +2910 1425 m +gs 1 -1 sc (myapp) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist5.fig b/system/doc/design_principles/dist5.fig new file mode 100644 index 0000000000..77f2d74c59 --- /dev/null +++ b/system/doc/design_principles/dist5.fig @@ -0,0 +1,40 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 750 3000 4200 4050 +6 2100 3000 2850 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2475 3375 318 318 2475 3375 2700 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 2347 3420 cp2\001 +-6 +6 3450 3000 4200 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3825 3375 318 318 3825 3375 4050 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 3697 3420 cp3\001 +-6 +6 750 3000 1500 4050 +6 750 3000 1500 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1125 3375 318 318 1125 3375 1350 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 997 3420 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 885 3975 myapp\001 +-6 +-6 +6 2100 300 2850 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2475 675 318 318 2475 675 2700 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 2347 720 cp2\001 +-6 +6 3450 300 4200 1425 +6 3450 300 4200 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3825 675 318 318 3825 675 4050 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3697 720 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 3585 1350 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2175 2325 1425 2925 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 3600 1350 2775 1950 +4 0 -1 0 0 0 12 0.0000 4 180 3270 750 2175 cp1: application:takeover(myapp, permanent)\001 diff --git a/system/doc/design_principles/dist5.gif b/system/doc/design_principles/dist5.gif Binary files differnew file mode 100644 index 0000000000..3ef5cda3f6 --- /dev/null +++ b/system/doc/design_principles/dist5.gif diff --git a/system/doc/design_principles/dist5.ps b/system/doc/design_principles/dist5.ps new file mode 100644 index 0000000000..daeb56b2b7 --- /dev/null +++ b/system/doc/design_principles/dist5.ps @@ -0,0 +1,165 @@ +%!PS-Adobe-2.0 +%%Title: dist5.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Mon Feb 15 08:40:37 1999 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 203 286 408 506 +%%Pages: 1 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +158.5 527.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +%%Page: 1 1 +7.500 slw +% Ellipse +n 2475 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2347 3420 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3825 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3697 3420 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1125 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +997 3420 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +885 3975 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2475 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2347 720 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3825 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3697 720 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3585 1350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +gs clippath +1559 2857 m 1446 2908 l 1521 2810 l 1395 2911 l 1432 2958 l cp clip +n 2175 2325 m 1425 2925 l gs col-1 s gr gr + +% arrowhead +n 1559 2857 m 1446 2908 l 1521 2810 l col-1 s +% Polyline +gs clippath +2912 1888 m 2796 1934 l 2876 1839 l 2745 1935 l 2781 1983 l cp clip +n 3600 1350 m 2775 1950 l gs col-1 s gr gr + +% arrowhead +n 2912 1888 m 2796 1934 l 2876 1839 l col-1 s +/Times-Roman ff 180.00 scf sf +750 2175 m +gs 1 -1 sc (cp1: application:takeover\(myapp, permanent\)) col-1 sh gr +showpage +$F2psEnd +rs diff --git a/system/doc/design_principles/distributed_applications.xml b/system/doc/design_principles/distributed_applications.xml new file mode 100644 index 0000000000..39a24b3598 --- /dev/null +++ b/system/doc/design_principles/distributed_applications.xml @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Distributed Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>distributed_applications.xml</file> + </header> + + <section> + <title>Definition</title> + <p>In a distributed system with several Erlang nodes, there may be + a need to control applications in a distributed manner. If + the node, where a certain application is running, goes down, + the application should be restarted at another node.</p> + <p>Such an application is called a <em>distributed application</em>. + Note that it is the control of the application which is + distributed, all applications can of course be distributed in + the sense that they, for example, use services on other nodes.</p> + <p>Because a distributed application may move between nodes, some + addressing mechanism is required to ensure that it can be + addressed by other applications, regardless on which node it + currently executes. This issue is not addressed here, but the + Kernel module <c>global</c> or STDLIB module <c>pg</c> can be + used for this purpose.</p> + </section> + + <section> + <title>Specifying Distributed Applications</title> + <p>Distributed applications are controlled by both the application + controller and a distributed application controller process, + <c>dist_ac</c>. Both these processes are part of the <c>kernel</c> + application. Therefore, distributed applications are specified by + configuring the <c>kernel</c> application, using the following + configuration parameter (see also <c>kernel(6)</c>):</p> + <taglist> + <tag><c>distributed = [{Application, [Timeout,] NodeDesc}]</c></tag> + <item> + <p>Specifies where the application <c>Application = atom()</c> + may execute. <c>NodeDesc = [Node | {Node,...,Node}]</c> is + a list of node names in priority order. The order between + nodes in a tuple is undefined.</p> + <p><c>Timeout = integer()</c> specifies how many milliseconds to + wait before restarting the application at another node. + Defaults to 0.</p> + </item> + </taglist> + <p>For distribution of application control to work properly, + the nodes where a distributed application may run must contact + each other and negotiate where to start the application. This is + done using the following <c>kernel</c> configuration parameters:</p> + <taglist> + <tag><c>sync_nodes_mandatory = [Node]</c></tag> + <item>Specifies which other nodes must be started (within + the timeout specified by <c>sync_nodes_timeout</c>.</item> + <tag><c>sync_nodes_optional = [Node]</c></tag> + <item>Specifies which other nodes can be started (within + the timeout specified by <c>sync_nodes_timeout</c>.</item> + <tag><c>sync_nodes_timeout = integer() | infinity</c></tag> + <item>Specifies how many milliseconds to wait for the other nodes + to start.</item> + </taglist> + <p>When started, the node will wait for all nodes specified by + <c>sync_nodes_mandatory</c> and <c>sync_nodes_optional</c> to + come up. When all nodes have come up, or when all mandatory nodes + have come up and the time specified by <c>sync_nodes_timeout</c> + has elapsed, all applications will be started. If not all + mandatory nodes have come up, the node will terminate.</p> + <p>Example: An application <c>myapp</c> should run at the node + <c>cp1@cave</c>. If this node goes down, <c>myapp</c> should + be restarted at <c>cp2@cave</c> or <c>cp3@cave</c>. A system + configuration file <c>cp1.config</c> for <c>cp1@cave</c> could + look like:</p> + <code type="none"> +[{kernel, + [{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]}, + {sync_nodes_mandatory, [cp2@cave, cp3@cave]}, + {sync_nodes_timeout, 5000} + ] + } +].</code> + <p>The system configuration files for <c>cp2@cave</c> and + <c>cp3@cave</c> are identical, except for the list of mandatory + nodes which should be <c>[cp1@cave, cp3@cave]</c> for + <c>cp2@cave</c> and <c>[cp1@cave, cp2@cave]</c> for + <c>cp3@cave</c>.</p> + <note> + <p>All involved nodes must have the same value for + <c>distributed</c> and <c>sync_nodes_timeout</c>, or + the behaviour of the system is undefined.</p> + </note> + </section> + + <section> + <title>Starting and Stopping Distributed Applications</title> + <p>When all involved (mandatory) nodes have been started, + the distributed application can be started by calling + <c>application:start(Application)</c> at <em>all of these nodes.</em></p> + <p>It is of course also possible to use a boot script (see + <seealso marker="release_structure">Releases</seealso>) which + automatically starts the application.</p> + <p>The application will be started at the first node, specified + by the <c>distributed</c> configuration parameter, which is up + and running. The application is started as usual. That is, an + application master is created and calls the application callback + function:</p> + <code type="none"> +Module:start(normal, StartArgs)</code> + <p>Example: Continuing the example from the previous section, + the three nodes are started, specifying the system configuration + file:</p> + <pre> +> <input>erl -sname cp1 -config cp1</input> +> <input>erl -sname cp2 -config cp2</input> +> <input>erl -sname cp3 -config cp3</input></pre> + <p>When all nodes are up and running, <c>myapp</c> can be started. + This is achieved by calling <c>application:start(myapp)</c> at + all three nodes. It is then started at <c>cp1</c>, as shown in + the figure below.</p> + <marker id="dist1"></marker> + <image file="../design_principles/dist1.gif"> + <icaption>Application myapp - Situation 1</icaption> + </image> + <p>Similarly, the application must be stopped by calling + <c>application:stop(Application)</c> at all involved nodes.</p> + </section> + + <section> + <title>Failover</title> + <p>If the node where the application is running goes down, + the application is restarted (after the specified timeout) at + the first node, specified by the <c>distributed</c> configuration + parameter, which is up and running. This is called a + <em>failover</em>.</p> + <p>The application is started the normal way at the new node, + that is, by the application master calling:</p> + <code type="none"> +Module:start(normal, StartArgs)</code> + <p>Exception: If the application has the <c>start_phases</c> key + defined (see <seealso marker="included_applications">Included Applications</seealso>), then the application is instead started + by calling:</p> + <code type="none"> +Module:start({failover, Node}, StartArgs)</code> + <p>where <c>Node</c> is the terminated node.</p> + <p>Example: If <c>cp1</c> goes down, the system checks which one of + the other nodes, <c>cp2</c> or <c>cp3</c>, has the least number of + running applications, but waits for 5 seconds for <c>cp1</c> to + restart. If <c>cp1</c> does not restart and <c>cp2</c> runs fewer + applications than <c>cp3,</c> then <c>myapp</c> is restarted on + <c>cp2</c>.</p> + <marker id="dist2"></marker> + <image file="../design_principles/dist2.gif"> + <icaption>Application myapp - Situation 2</icaption> + </image> + <p>Suppose now that <c>cp2</c> goes down as well and does not + restart within 5 seconds. <c>myapp</c> is now restarted on + <c>cp3</c>.</p> + <marker id="dist3"></marker> + <image file="../design_principles/dist3.gif"> + <icaption>Application myapp - Situation 3</icaption> + </image> + </section> + + <section> + <title>Takeover</title> + <p>If a node is started, which has higher priority according + to <c>distributed</c>, than the node where a distributed + application is currently running, the application will be + restarted at the new node and stopped at the old node. This is + called a <em>takeover</em>.</p> + <p>The application is started by the application master calling:</p> + <code type="none"> +Module:start({takeover, Node}, StartArgs)</code> + <p>where <c>Node</c> is the old node.</p> + <p>Example: If <c>myapp</c> is running at <c>cp3</c>, and if + <c>cp2</c> now restarts, it will not restart <c>myapp</c>, + because the order between nodes <c>cp2</c> and <c>cp3</c> is + undefined.</p> + <marker id="dist4"></marker> + <image file="../design_principles/dist4.gif"> + <icaption>Application myapp - Situation 4</icaption> + </image> + <p>However, if <c>cp1</c> restarts as well, the function + <c>application:takeover/2</c> moves <c>myapp</c> to <c>cp1</c>, + because <c>cp1</c> has a higher priority than <c>cp3</c> for this + application. In this case, + <c>Module:start({takeover, cp3@cave}, StartArgs)</c> is executed + at <c>cp1</c> to start the application.</p> + <marker id="dist5"></marker> + <image file="../design_principles/dist5.gif"> + <icaption>Application myapp - Situation 5</icaption> + </image> + </section> +</chapter> + diff --git a/system/doc/design_principles/events.xml b/system/doc/design_principles/events.xml new file mode 100644 index 0000000000..5579f1e459 --- /dev/null +++ b/system/doc/design_principles/events.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Gen_Event Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>events.xml</file> + </header> + <marker id="gen_event"></marker> + <p>This chapter should be read in conjunction with + <c>gen_event(3)</c>, where all interface functions and callback + functions are described in detail.</p> + + <section> + <title>Event Handling Principles</title> + <p>In OTP, an <em>event manager</em> is a named object to which + events can be sent. An <em>event</em> could be, for example, + an error, an alarm or some information that should be logged.</p> + <p>In the event manager, zero, one or several <em>event handlers</em> are installed. When the event manager is notified + about an event, the event will be processed by all the installed + event handlers. For example, an event manager for handling errors + can by default have a handler installed which writes error + messages to the terminal. If the error messages during a certain + period should be saved to a file as well, the user adds another + event handler which does this. When logging to file is no longer + necessary, this event handler is deleted.</p> + <p>An event manager is implemented as a process and each event + handler is implemented as a callback module.</p> + <p>The event manager essentially maintains a list of + <c>{Module, State}</c> pairs, where each <c>Module</c> is an + event handler, and <c>State</c> the internal state of that event + handler.</p> + </section> + + <section> + <title>Example</title> + <p>The callback module for the event handler writing error messages + to the terminal could look like:</p> + <code type="none"> +-module(terminal_logger). +-behaviour(gen_event). + +-export([init/1, handle_event/2, terminate/2]). + +init(_Args) -> + {ok, []}. + +handle_event(ErrorMsg, State) -> + io:format("***Error*** ~p~n", [ErrorMsg]), + {ok, State}. + +terminate(_Args, _State) -> + ok.</code> + <p>The callback module for the event handler writing error messages + to a file could look like:</p> + <code type="none"> +-module(file_logger). +-behaviour(gen_event). + +-export([init/1, handle_event/2, terminate/2]). + +init(File) -> + {ok, Fd} = file:open(File, read), + {ok, Fd}. + +handle_event(ErrorMsg, Fd) -> + io:format(Fd, "***Error*** ~p~n", [ErrorMsg]), + {ok, Fd}. + +terminate(_Args, Fd) -> + file:close(Fd).</code> + <p>The code is explained in the next sections.</p> + </section> + + <section> + <marker id="mgr"></marker> + <title>Starting an Event Manager</title> + <p>To start an event manager for handling errors, as described in + the example above, call the following function:</p> + <code type="none"> +gen_event:start_link({local, error_man})</code> + <p>This function spawns and links to a new process, an event + manager.</p> + <p>The argument, <c>{local, error_man}</c> specifies the name. In + this case, the event manager will be locally registered as + <c>error_man</c>.</p> + <p>If the name is omitted, the event manager is not registered. + Instead its pid must be used. The name could also be given + as <c>{global, Name}</c>, in which case the event manager is + registered using <c>global:register_name/2</c>.</p> + <p><c>gen_event:start_link</c> must be used if the event manager is + part of a supervision tree, i.e. is started by a supervisor. + There is another function <c>gen_event:start</c> to start a + stand-alone event manager, i.e. an event manager which is not + part of a supervision tree.</p> + </section> + + <section> + <title>Adding an Event Handler</title> + <p>Here is an example using the shell on how to start an event + manager and add an event handler to it:</p> + <pre> +1> <input>gen_event:start({local, error_man}).</input> +{ok,<0.31.0>} +2> <input>gen_event:add_handler(error_man, terminal_logger, []).</input> +ok</pre> + <p>This function sends a message to the event manager registered as + <c>error_man</c>, telling it to add the event handler + <c>terminal_logger</c>. The event manager will call the callback + function <c>terminal_logger:init([])</c>, where the argument [] + is the third argument to <c>add_handler</c>. <c>init</c> is + expected to return <c>{ok, State}</c>, where <c>State</c> is + the internal state of the event handler.</p> + <code type="none"> +init(_Args) -> + {ok, []}.</code> + <p>Here, <c>init</c> does not need any input data and ignores its + argument. Also, for <c>terminal_logger</c> the internal state is + not used. For <c>file_logger</c>, the internal state is used + to save the open file descriptor.</p> + <code type="none"> +init(File) -> + {ok, Fd} = file:open(File, read), + {ok, Fd}.</code> + </section> + + <section> + <title>Notifying About Events</title> + <pre> +3> <input>gen_event:notify(error_man, no_reply).</input> +***Error*** no_reply +ok</pre> + <p><c>error_man</c> is the name of the event manager and + <c>no_reply</c> is the event.</p> + <p>The event is made into a message and sent to the event manager. + When the event is received, the event manager calls + <c>handle_event(Event, State)</c> for each installed event + handler, in the same order as they were added. The function is + expected to return a tuple <c>{ok, State1}</c>, where + <c>State1</c> is a new value for the state of the event handler.</p> + <p>In <c>terminal_logger</c>:</p> + <code type="none"> +handle_event(ErrorMsg, State) -> + io:format("***Error*** ~p~n", [ErrorMsg]), + {ok, State}.</code> + <p>In <c>file_logger</c>:</p> + <code type="none"> +handle_event(ErrorMsg, Fd) -> + io:format(Fd, "***Error*** ~p~n", [ErrorMsg]), + {ok, Fd}.</code> + </section> + + <section> + <title>Deleting an Event Handler</title> + <pre> +4> <input>gen_event:delete_handler(error_man, terminal_logger, []).</input> +ok</pre> + <p>This function sends a message to the event manager registered as + <c>error_man</c>, telling it to delete the event handler + <c>terminal_logger</c>. The event manager will call the callback + function <c>terminal_logger:terminate([], State)</c>, where + the argument [] is the third argument to <c>delete_handler</c>. + <c>terminate</c> should be the opposite of <c>init</c> and do any + necessary cleaning up. Its return value is ignored.</p> + <p>For <c>terminal_logger</c>, no cleaning up is necessary:</p> + <code type="none"> +terminate(_Args, _State) -> + ok.</code> + <p>For <c>file_logger</c>, the file descriptor opened in <c>init</c> + needs to be closed:</p> + <code type="none"> +terminate(_Args, Fd) -> + file:close(Fd).</code> + </section> + + <section> + <title>Stopping</title> + <p>When an event manager is stopped, it will give each of + the installed event handlers the chance to clean up by calling + <c>terminate/2</c>, the same way as when deleting a handler.</p> + + <section> + <title>In a Supervision Tree</title> + <p>If the event manager is part of a supervision tree, no stop + function is needed. The event manager will automatically be + terminated by its supervisor. Exactly how this is done is + defined by a <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p> + </section> + + <section> + <title>Stand-Alone Event Managers</title> + <p>An event manager can also be stopped by calling:</p> + <pre> +> <input>gen_event:stop(error_man).</input> +ok</pre> + </section> + </section> +</chapter> + diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml new file mode 100644 index 0000000000..7cdd62057b --- /dev/null +++ b/system/doc/design_principles/fsm.xml @@ -0,0 +1,313 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Gen_Fsm Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>fsm.xml</file> + </header> + <p>This chapter should be read in conjunction with <c>gen_fsm(3)</c>, + where all interface functions and callback functions are described + in detail.</p> + + <section> + <title>Finite State Machines</title> + <p>A finite state machine, FSM, can be described as a set of + relations of the form:</p> + <pre> +State(S) x Event(E) -> Actions(A), State(S')</pre> + <p>These relations are interpreted as meaning:</p> + <quote> + <p>If we are in state <c>S</c> and the event <c>E</c> occurs, we + should perform the actions <c>A</c> and make a transition to + the state <c>S'</c>.</p> + </quote> + <p>For an FSM implemented using the <c>gen_fsm</c> behaviour, + the state transition rules are written as a number of Erlang + functions which conform to the following convention:</p> + <pre> +StateName(Event, StateData) -> + .. code for actions here ... + {next_state, StateName', StateData'}</pre> + </section> + + <section> + <title>Example</title> + <p>A door with a code lock could be viewed as an FSM. Initially, + the door is locked. Anytime someone presses a button, this + generates an event. Depending on what buttons have been pressed + before, the sequence so far may be correct, incomplete or wrong.</p> + <p>If it is correct, the door is unlocked for 30 seconds (30000 ms). + If it is incomplete, we wait for another button to be pressed. If + it is is wrong, we start all over, waiting for a new button + sequence.</p> + <p>Implementing the code lock FSM using <c>gen_fsm</c> results in + this callback module:</p> + <marker id="ex"></marker> + <code type="none"><![CDATA[ +-module(code_lock). +-behaviour(gen_fsm). + +-export([start_link/1]). +-export([button/1]). +-export([init/1, locked/2, open/2]). + +start_link(Code) -> + gen_fsm:start_link({local, code_lock}, code_lock, Code, []). + +button(Digit) -> + gen_fsm:send_event(code_lock, {button, Digit}). + +init(Code) -> + {ok, locked, {[], Code}}. + +locked({button, Digit}, {SoFar, Code}) -> + case [Digit|SoFar] of + Code -> + do_unlock(), + {next_state, open, {[], Code}, 3000}; + Incomplete when length(Incomplete)<length(Code) -> + {next_state, locked, {Incomplete, Code}}; + _Wrong -> + {next_state, locked, {[], Code}} + end. + +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.]]></code> + <p>The code is explained in the next sections.</p> + </section> + + <section> + <title>Starting a Gen_Fsm</title> + <p>In the example in the previous section, the gen_fsm is started by + calling <c>code_lock:start_link(Code)</c>:</p> + <code type="none"> +start_link(Code) -> + gen_fsm:start_link({local, code_lock}, code_lock, Code, []).</code> + <p><c>start_link</c> calls the function <c>gen_fsm:start_link/4</c>. + This function spawns and links to a new process, a gen_fsm.</p> + <list type="bulleted"> + <item> + <p>The first argument <c>{local, code_lock}</c> specifies + the name. In this case, the gen_fsm will be locally registered + as <c>code_lock</c>.</p> + <p>If the name is omitted, the gen_fsm is not registered. + Instead its pid must be used. The name could also be given as + <c>{global, Name}</c>, in which case the gen_fsm is registered + using <c>global:register_name/2</c>.</p> + </item> + <item> + <p>The second argument, <c>code_lock</c>, is the name of + the callback module, that is the module where the callback + functions are located.</p> + <p>In this case, the interface functions (<c>start_link</c> and + <c>button</c>) are located in the same module as the callback + functions (<c>init</c>, <c>locked</c> and <c>open</c>). This + is normally good programming practice, to have the code + corresponding to one process contained in one module.</p> + </item> + <item> + <p>The third argument, <c>Code</c>, is a term which is passed + as-is to the callback function <c>init</c>. Here, <c>init</c> + gets the correct code for the lock as indata.</p> + </item> + <item> + <p>The fourth argument, [], is a list of options. See + <c>gen_fsm(3)</c> for available options.</p> + </item> + </list> + <p>If name registration succeeds, the new gen_fsm process calls + the callback function <c>code_lock:init(Code)</c>. This function + is expected to return <c>{ok, StateName, StateData}</c>, where + <c>StateName</c> is the name of the initial state of the gen_fsm. + In this case <c>locked</c>, assuming the door is locked to begin + with. <c>StateData</c> is the internal state of the gen_fsm. (For + gen_fsms, the internal state is often referred to 'state data' to + distinguish it from the state as in states of a state machine.) + In this case, the state data is the button sequence so far (empty + to begin with) and the correct code of the lock.</p> + <code type="none"> +init(Code) -> + {ok, locked, {[], Code}}.</code> + <p>Note that <c>gen_fsm:start_link</c> is synchronous. It does not + return until the gen_fsm has been initialized and is ready to + receive notifications.</p> + <p><c>gen_fsm:start_link</c> must be used if the gen_fsm is part of + a supervision tree, i.e. is started by a supervisor. There is + another function <c>gen_fsm:start</c> to start a stand-alone + gen_fsm, i.e. a gen_fsm which is not part of a supervision tree.</p> + </section> + + <section> + <title>Notifying About Events</title> + <p>The function notifying the code lock about a button event is + implemented using <c>gen_fsm:send_event/2</c>:</p> + <code type="none"> +button(Digit) -> + gen_fsm:send_event(code_lock, {button, Digit}).</code> + <p><c>code_lock</c> is the name of the gen_fsm and must agree with + the name used to start it. <c>{button, Digit}</c> is the actual + event.</p> + <p>The event is made into a message and sent to the gen_fsm. When + the event is received, the gen_fsm calls + <c>StateName(Event, StateData)</c> which is expected to return a + tuple <c>{next_state, StateName1, StateData1}</c>. + <c>StateName</c> is the name of the current state and + <c>StateName1</c> is the name of the next state to go to. + <c>StateData1</c> is a new value for the state data of + the gen_fsm.</p> + <code type="none"><![CDATA[ +locked({button, Digit}, {SoFar, Code}) -> + case [Digit|SoFar] of + Code -> + do_unlock(), + {next_state, open, {[], Code}, 30000}; + Incomplete when length(Incomplete)<length(Code) -> + {next_state, locked, {Incomplete, Code}}; + _Wrong -> + {next_state, locked, {[], Code}}; + end. + +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.]]></code> + <p>If the door is locked and a button is pressed, the complete + button sequence so far is compared with the correct code for + the lock and, depending on the result, the door is either unlocked + and the gen_fsm goes to state <c>open</c>, or the door remains in + state <c>locked</c>.</p> + </section> + + <section> + <title>Timeouts</title> + <p>When a correct code has been givened, the door is unlocked and + the following tuple is returned from <c>locked/2</c>:</p> + <code type="none"> +{next_state, open, {[], Code}, 30000};</code> + <p>30000 is a timeout value in milliseconds. After 30000 ms, i.e. + 30 seconds, a timeout occurs. Then <c>StateName(timeout, StateData)</c> is called. In this case, the timeout occurs when + the door has been in state <c>open</c> for 30 seconds. After that + the door is locked again:</p> + <code type="none"> +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.</code> + </section> + + <section> + <title>All State Events</title> + <p>Sometimes an event can arrive at any state of the gen_fsm. + Instead of sending the message with <c>gen_fsm:send_event/2</c> + and writing one clause handling the event for each state function, + the message can be sent with <c>gen_fsm:send_all_state_event/2</c> + and handled with <c>Module:handle_event/3</c>:</p> + <code type="none"> +-module(code_lock). +... +-export([stop/0]). +... + +stop() -> + gen_fsm:send_all_state_event(code_lock, stop). + +... + +handle_event(stop, _StateName, StateData) -> + {stop, normal, StateData}.</code> + </section> + + <section> + <title>Stopping</title> + + <section> + <title>In a Supervision Tree</title> + <p>If the gen_fsm is part of a supervision tree, no stop function + is needed. The gen_fsm will automatically be terminated by its + supervisor. Exactly how this is done is defined by a + <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> + set in the supervisor.</p> + <p>If it is necessary to clean up before termination, the shutdown + strategy must be a timeout value and the gen_fsm must be set to + trap exit signals in the <c>init</c> function. When ordered + to shutdown, the gen_fsm will then call the callback function + <c>terminate(shutdown, StateName, StateData)</c>:</p> + <code type="none"> +init(Args) -> + ..., + process_flag(trap_exit, true), + ..., + {ok, StateName, StateData}. + +... + +terminate(shutdown, StateName, StateData) -> + ..code for cleaning up here.. + ok.</code> + </section> + + <section> + <title>Stand-Alone Gen_Fsms</title> + <p>If the gen_fsm is not part of a supervision tree, a stop + function may be useful, for example:</p> + <code type="none"> +... +-export([stop/0]). +... + +stop() -> + gen_fsm:send_all_state_event(code_lock, stop). +... + +handle_event(stop, _StateName, StateData) -> + {stop, normal, StateData}. + +... + +terminate(normal, _StateName, _StateData) -> + ok.</code> + <p>The callback function handling the <c>stop</c> event returns a + tuple <c>{stop,normal,StateData1}</c>, where <c>normal</c> + specifies that it is a normal termination and <c>StateData1</c> + is a new value for the state data of the gen_fsm. This will + cause the gen_fsm to call + <c>terminate(normal,StateName,StateData1)</c> and then + terminate gracefully:</p> + </section> + </section> + + <section> + <title>Handling Other Messages</title> + <p>If the gen_fsm should be able to receive other messages than + events, the callback function <c>handle_info(Info, StateName, StateData)</c> must be implemented to handle them. Examples of + other messages are exit messages, if the gen_fsm is linked to + other processes (than the supervisor) and trapping exit signals.</p> + <code type="none"> +handle_info({'EXIT', Pid, Reason}, StateName, StateData) -> + ..code to handle exits here.. + {next_state, StateName1, StateData1}.</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml new file mode 100644 index 0000000000..8131c47a69 --- /dev/null +++ b/system/doc/design_principles/gen_server_concepts.xml @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Gen_Server Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>gen_server_concepts.xml</file> + </header> + <marker id="gen_server"></marker> + <p>This chapter should be read in conjunction with + <seealso marker="stdlib:gen_server">gen_server(3)</seealso>, + where all interface functions and callback + functions are described in detail.</p> + + <section> + <title>Client-Server Principles</title> + <p>The client-server model is characterized by a central server + and an arbitrary number of clients. The client-server model is + generally used for resource management operations, where several + different clients want to share a common resource. The server is + responsible for managing this resource.</p> + <marker id="clientserver"></marker> + <image file="../design_principles/clientserver.gif"> + <icaption>Client-Server Model</icaption> + </image> + </section> + + <section> + <title>Example</title> + <p>An example of a simple server written in plain Erlang was + given in <seealso marker="des_princ#ch1">Overview</seealso>. + The server can be re-implemented using <c>gen_server</c>, + resulting in this callback module:</p> + <marker id="ex"></marker> + <code type="none"> +-module(ch3). +-behaviour(gen_server). + +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([init/1, handle_call/3, handle_cast/2]). + +start_link() -> + gen_server:start_link({local, ch3}, ch3, [], []). + +alloc() -> + gen_server:call(ch3, alloc). + +free(Ch) -> + gen_server:cast(ch3, {free, Ch}). + +init(_Args) -> + {ok, channels()}. + +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}. + +handle_cast({free, Ch}, Chs) -> + Chs2 = free(Ch, Chs), + {noreply, Chs2}.</code> + <p>The code is explained in the next sections.</p> + </section> + + <section> + <title>Starting a Gen_Server</title> + <p>In the example in the previous section, the gen_server is started + by calling <c>ch3:start_link()</c>:</p> + <code type="none"> +start_link() -> + gen_server:start_link({local, ch3}, ch3, [], []) => {ok, Pid}</code> + <p><c>start_link</c> calls the function + <c>gen_server:start_link/4</c>. This function spawns and links to + a new process, a gen_server.</p> + <list type="bulleted"> + <item> + <p>The first argument <c>{local, ch3}</c> specifies the name. In + this case, the gen_server will be locally registered as + <c>ch3</c>.</p> + <p>If the name is omitted, the gen_server is not registered. + Instead its pid must be used. The name could also be given + as <c>{global, Name}</c>, in which case the gen_server is + registered using <c>global:register_name/2</c>.</p> + </item> + <item> + <p>The second argument, <c>ch3</c>, is the name of the callback + module, that is the module where the callback functions are + located.</p> + <p>In this case, the interface functions (<c>start_link</c>, + <c>alloc</c> and <c>free</c>) are located in the same module + as the callback functions (<c>init</c>, <c>handle_call</c> and + <c>handle_cast</c>). This is normally good programming + practice, to have the code corresponding to one process + contained in one module.</p> + </item> + <item> + <p>The third argument, [], is a term which is passed as-is to + the callback function <c>init</c>. Here, <c>init</c> does not + need any indata and ignores the argument.</p> + </item> + <item> + <p>The fourth argument, [], is a list of options. See + <c>gen_server(3)</c> for available options.</p> + </item> + </list> + <p>If name registration succeeds, the new gen_server process calls + the callback function <c>ch3:init([])</c>. <c>init</c> is expected + to return <c>{ok, State}</c>, where <c>State</c> is the internal + state of the gen_server. In this case, the state is the available + channels.</p> + <code type="none"> +init(_Args) -> + {ok, channels()}.</code> + <p>Note that <c>gen_server:start_link</c> is synchronous. It does + not return until the gen_server has been initialized and is ready + to receive requests.</p> + <p><c>gen_server:start_link</c> must be used if the gen_server is + part of a supervision tree, i.e. is started by a supervisor. + There is another function <c>gen_server:start</c> to start a + stand-alone gen_server, i.e. a gen_server which is not part of a + supervision tree.</p> + </section> + + <section> + <title>Synchronous Requests - Call</title> + <p>The synchronous request <c>alloc()</c> is implemented using + <c>gen_server:call/2</c>:</p> + <code type="none"> +alloc() -> + gen_server:call(ch3, alloc).</code> + <p><c>ch3</c> is the name of the gen_server and must agree with + the name used to start it. <c>alloc</c> is the actual request.</p> + <p>The request is made into a message and sent to the gen_server. + When the request is received, the gen_server calls + <c>handle_call(Request, From, State)</c> which is expected to + return a tuple <c>{reply, Reply, State1}</c>. <c>Reply</c> is + the reply which should be sent back to the client, and + <c>State1</c> is a new value for the state of the gen_server.</p> + <code type="none"> +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}.</code> + <p>In this case, the reply is the allocated channel <c>Ch</c> and + the new state is the set of remaining available channels + <c>Chs2</c>.</p> + <p>Thus, the call <c>ch3:alloc()</c> returns the allocated channel + <c>Ch</c> and the gen_server then waits for new requests, now + with an updated list of available channels.</p> + </section> + + <section> + <title>Asynchronous Requests - Cast</title> + <p>The asynchronous request <c>free(Ch)</c> is implemented using + <c>gen_server:cast/2</c>:</p> + <code type="none"> +free(Ch) -> + gen_server:cast(ch3, {free, Ch}).</code> + <p><c>ch3</c> is the name of the gen_server. <c>{free, Ch}</c> is + the actual request.</p> + <p>The request is made into a message and sent to the gen_server. + <c>cast</c>, and thus <c>free</c>, then returns <c>ok</c>.</p> + <p>When the request is received, the gen_server calls + <c>handle_cast(Request, State)</c> which is expected to + return a tuple <c>{noreply, State1}</c>. <c>State1</c> is a new + value for the state of the gen_server.</p> + <code type="none"> +handle_cast({free, Ch}, Chs) -> + Chs2 = free(Ch, Chs), + {noreply, Chs2}.</code> + <p>In this case, the new state is the updated list of available + channels <c>Chs2</c>. The gen_server is now ready for new + requests.</p> + </section> + + <section> + <title>Stopping</title> + + <section> + <title>In a Supervision Tree</title> + <p>If the gen_server is part of a supervision tree, no stop + function is needed. The gen_server will automatically be + terminated by its supervisor. Exactly how this is done is + defined by a <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p> + <p>If it is necessary to clean up before termination, the shutdown + strategy must be a timeout value and the gen_server must be set + to trap exit signals in the <c>init</c> function. When ordered + to shutdown, the gen_server will then call the callback function + <c>terminate(shutdown, State)</c>:</p> + <code type="none"> +init(Args) -> + ..., + process_flag(trap_exit, true), + ..., + {ok, State}. + +... + +terminate(shutdown, State) -> + ..code for cleaning up here.. + ok.</code> + </section> + + <section> + <title>Stand-Alone Gen_Servers</title> + <p>If the gen_server is not part of a supervision tree, a stop + function may be useful, for example:</p> + <code type="none"> +... +export([stop/0]). +... + +stop() -> + gen_server:cast(ch3, stop). +... + +handle_cast(stop, State) -> + {stop, normal, State}; +handle_cast({free, Ch}, State) -> + .... + +... + +terminate(normal, State) -> + ok.</code> + <p>The callback function handling the <c>stop</c> request returns + a tuple <c>{stop, normal, State1}</c>, where <c>normal</c> + specifies that it is a normal termination and <c>State1</c> is + a new value for the state of the gen_server. This will cause + the gen_server to call <c>terminate(normal,State1)</c> and then + terminate gracefully.</p> + </section> + </section> + + <section> + <title>Handling Other Messages</title> + <p>If the gen_server should be able to receive other messages than + requests, the callback function <c>handle_info(Info, State)</c> + must be implemented to handle them. Examples of other messages + are exit messages, if the gen_server is linked to other processes + (than the supervisor) and trapping exit signals.</p> + <code type="none"> +handle_info({'EXIT', Pid, Reason}, State) -> + ..code to handle exits here.. + {noreply, State1}.</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/inclappls.fig b/system/doc/design_principles/inclappls.fig new file mode 100644 index 0000000000..03885c72d6 --- /dev/null +++ b/system/doc/design_principles/inclappls.fig @@ -0,0 +1,33 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2700 900 530 530 2700 900 3075 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 750 2400 375 375 750 2400 975 2700 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1950 2400 375 375 1950 2400 2175 2700 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 2475 375 375 3150 2475 3375 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 4425 2475 375 375 4425 2475 4650 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5700 2475 375 375 5700 2475 5925 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3600 3600 375 375 3600 3600 3825 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2625 3600 375 375 2625 3600 2850 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 675 3600 375 375 675 3600 900 3900 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 975 2100 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2025 2025 2475 1425 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3000 2100 2850 1425 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3150 1275 4125 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3225 1050 5400 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 675 2775 675 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3225 2850 3525 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3075 2850 2700 3225 +4 0 -1 0 0 2 14 0.0000 4 195 1905 3525 975 Primary application \001 +4 0 -1 0 0 2 14 0.0000 4 195 1950 6525 2550 Included applications\001 +4 0 -1 0 0 2 14 0.0000 4 195 1950 6525 3675 Included applications\001 diff --git a/system/doc/design_principles/inclappls.gif b/system/doc/design_principles/inclappls.gif Binary files differnew file mode 100644 index 0000000000..8b88d6d23e --- /dev/null +++ b/system/doc/design_principles/inclappls.gif diff --git a/system/doc/design_principles/inclappls.ps b/system/doc/design_principles/inclappls.ps new file mode 100644 index 0000000000..239be1b3b3 --- /dev/null +++ b/system/doc/design_principles/inclappls.ps @@ -0,0 +1,808 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./inclappls.tmp.eps) +%%CreationDate: (Tue Jun 12 17:22:15 2001) +%%BoundingBox: 0 20 377 197 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 20 377 197 +userdict begin +%%BeginData: +DisplayImage +0 20 +377.000000 177.000000 +12 +566 266 +1 +1 +1 +1 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +fffffffffffff000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffff +ffffffffff0fff0fffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffff +fffffff8fffff1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffff +ffffe7fffffe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffff +ff9fffffff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffffe +7fffffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffffdff +fffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffff3ffff +fffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffefffffff +ffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffdfffffffff +ffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffbfffffffffff +dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffffffffffffff7fffffffffffef +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcfffffffffffffffffffffffffffffffffffefffffffffffff7ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffffffffffffffffffffffffffffffffffdfffffffffffffbffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffffffffffffffffffffffffffffffffffbfffffffffffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffffffffffffffffffffffffffffffffffbfffffffffffffdffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcfffffffffffffffffffffffffffffffffff7fffffffffffffeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcffffffffffffffffffffffffffffffffffbfffffffffffffffdfffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +ffffffffffffffffffffffffffffffffffbfffffffffffffffdfffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +fffffffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +fffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +fffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +fffffffffffffffffdfffffffffffffffffbffff01fe7ffffffffffffffc4fffff3fffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +fffffffffffffffdfffffffffffffffffbffff9cfe7ffffffffffffffe4ffffb3fffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +fffffffffffffdfffffffffffffffffbffff9cfffffffffffffffffe7ffff3ffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +fffffffffffdfffffffffffffffffbffff9c9062230c813f0c8c8e0f086038623fffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +fffffffffdfffffffffffffffffbffff9cc871126649be6666664e433333313fffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +fffffffdfffffffffffffffffbffff81ce73326679be6666664e733333333fffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +fffffdfffffffffffffffffbffff9fce7333867d7f8666664e7c3333333fffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffff +fffdfffffffffffffffffbffff9fce7332667c7e6666664e733333333fffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffff +fdfffffffffffffffffbffff9fce7332667c7e6626264e233233333fffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffd +fffffffffffffffffbffff0f842110103efe124e4c07109018611fffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffdff +fffffffffffffffbfffffffffffffffefffe7e7fffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffdffff +fffffffffffffbfffffffffffffff2fffe7e7fffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffff +fffffffffff7fffffffffffffff1fffc3c3fffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffff +fffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffffff +fffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffffffff +fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffff +ffe9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffffff +ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffffffef +9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcffffffffffffffffffffffffffffffffffbfffffffffffffffdfe7 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcffffffffffffffffffffffffffffffffffbfffffffffffffffdffbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbffcffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfff3fffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffcfffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7ffff3ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffffffffffffffffe7fffffffffffffefffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcffffffffffffffffffffffffffffffffff9bfffffffffffffdffffff7fffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcffffffffffffffffffffffffffffffffff7bfffffffffffffdffffff9fffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffffffffffffffffffffffffffffffffefdfffffffffffffbffffffe7ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +fffffffffffffffffffffffffffffff9fefffffffffffff7fffffff9ffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +fffffffffffffffffffffffffffff7ff7fffffffffffeefffffffe7fffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffcfffbfffffffffffdf7fffffffbfffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffbfffdfffffffffffbfbfffffffcfffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffffffffffffffffe7fffefffffffffff7fdffffffff3ffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +fffffffffffffffffffdfffff3fffffffffcffeffffffffcffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +fffffffffffffffffbfffffdfffffffffbfff7ffffffff3fffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffe7fffffe7fffffffe7fffbffffffffdfffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffdfffffff9fffffff9ffffdffffffffe7ffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffff3fffffffe7fffffe7ffffefffffffff9ffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +fffffffefffffffff8fffff1ffffff7ffffffffe7fffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +fffffdffffffffdf0fff0fffffffbfffffffff9fffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +fff3ffffffffbff000efffffffdfffffffffe7ffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +efffffffffbfffffefffffffeffffffffffbffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff9f +ffffffff7ffffff7fffffff7fffffffffcffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff7fff +fffffefffffff7fffffffbffffffffff3fffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffcffffff +fffdfffffff7fffffffdffffffffffcfffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffbffffffff +fdfffffff7fffffffefffffffffff3ffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffff7fffffffffb +fffffffbffffffff7ffffffffffdffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffffffffffffffffffffffffcffffffffff7ff +fffffbffffffffbffffffffffe7fffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffffffffffffffffffffffffbfffffffffefffff +fffbffffffffdfffffffffff9fffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffffffffffffffffffffffffe7fffffffffefffffff +fbffffffffefffffffffffe7ffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffffffffffffffffffffffffdffffffffffdffffffffb +fffffffff7fffffffffff9ffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfffffffffffffffffffffffffbffffffffffbffffffffdff +fffffffbfffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffe7ffffffffff7ffffffffdffff +fffffdffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffffffffffffffffffffffdfffffffffff7ffffffffdffffff +fffeffffffffffffcfffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcffffffffffffffffffffffff3ffffffffffefffffffffdffffffff +ff7ffffffffffff3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffffffffffffffffffffffefffffffffffdfffffffffeffffffffff +bffffffffffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffffffffffffffffffffff9fffffffffffbfffffffffeffffffffffdf +ffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcfffffffffffffffffffffff7fffffffffffbfffffffffeffffffffffefff +ffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffeffffffffffff7fffffffffefffffffffff7ffff +ffffffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffff9fffffffffffeffffffffffefffffffffffbffffff +fffffff9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffff7fffffffffffdfffffffffff7ffffffffffdffffffff +fffffe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffffffffffffffffffffcffffffffffffdfffffffffff7ffffffffffeffffffffff +ffff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffffffffffffffffffbffffffffffffbfffffffffff7fffffffffff7fffffffffff +ffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffffffffffffffffffff7ffffffffffff7fffffffffff7fffffffffffbfffffffffffff +f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffcffffffffffffeffffffffffffbfffffffffffdffffffffffffffc +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffbffffffffffffeffffffffffffbfffffffffffefffffffffffffff3f +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +fffffffffffffe7ffffffffffffdffffffffffffbffffffffffff7ffffffffffffffcfff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +fffffffffffdfffffffffffffbffffffffffffbffffffffffffbfffffffffffffff7ffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffff3fffffffffffff7ffffffffffffbffffffffffffdfffffffffffffff9ffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffeffffffffffffff7ffffffffffffdffffffffffffefffffffffffffffe7fffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffdfffffffffffffefffffffffffffdfffffffffffff7fffffffffffffff9fffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ff3fffffffffffffdfffffffffffffdfffffffffffffbfffffffffffffffe7ffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffffe +ffffffffffffffbfffffffffffffdfffffffffffffdffffffffffffffff9ffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffff9ff +ffffffffffffbfffffffffffffefffffffffffffeffffffffffffffffeffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffff7ffff +ffffffffff7fffffffffffffeffffffffffffff7ffffffffffffffff3fffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffefffffff +fffffffeffffffffffffffeffffffffffffffbffffffffffffffffcfffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff9fffffffff +fffffdffffffffffffffeffffffffffffffdfffffffffffffffff3ffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff7fffffffffff +fffdffffffffffffffeffffffffffffffefffffffffffffffffcffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcfffffffffffffffcffffffffffffff +fbfffffffffffffff7ffffffffffffff7fffffffffffffffff7fffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffe00ffffbffffffffffffe007 +fffffffffffffff7ffffffffffffffbfffffffffffffffff9fffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffe1ff0ffe7fffffffffffe1ff0ff +fffffffffffff7ffffffffffffffdfffffffffffffffffe7ffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffff9ffff3fdffffffffffff9ffff3fff +fffffffffff7ffffffffffffffeffffffffffffffffff9ffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcffffffe7ffffcfbfffffffffffe7ffffcfffff +fffffffffbfffffffffffffff7fffffffffffffffffe7fffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffff9ffffff27fffffffffff9ffffff3ffffff +fffffffbfffffffffffffffbffffffffffffffffffbfffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffff7ffffffdffffffffffff7ffffffdffffffff +fffffbe00ffffffffffffdffffff007fffffffffcffffffff803ffffffffffffffffffff +fffffffffffffffffffffffffffcfffffefffffffefffffffffffefffffffeffffffffff +fffe1ff0fffffffffffefffff0ff87fffffffff3ffffff87fc3fffffffffffffffffffff +fffffffffffffffffffffffffcfffffdffffffff7ffffffffffdffffffff7fffffffffff +f9ffff3fffffffffff7fffcffff9fffffffffcfffffe7fffcfffffffffffffffffffffff +fffffffffffffffffffffffcfffffbffffffffbffffffffffbffffffffbfffffffffffe7 +ffffcfffffffffffbfff3ffffe7fffffffff3ffff9fffff3ffffffffffffffffffffffff +fffffffffffffffffffffcfffff7ffffffffdffffffffff7ffffffffdfffffffffff9fff +fff3ffffffffffdffcffffff9fffffffffcfffe7fffffcffffffffffffffffffffffffff +fffffffffffffffffffcffffefffffffffefffffffffefffffffffefffffffffff7fffff +fdffffffffffeffbffffffeffffffffff7ffdfffffff7fffffffffffffffffffffffffff +fffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7fffffffffefffffffe +fffffffffff7f7fffffff7fffffffff9ffbfffffffbfffffffffffffffffffffffffffff +fffffffffffffffcffffdffffffffff7ffffffffdffffffffff7fffffffffdffffffff7f +fffffffffbeffffffffbfffffffffe7f7fffffffdfffffffffffffffffffffffffffffff +fffffffffffffcffffbffffffffffbffffffffbffffffffffbfffffffffbffffffffbfff +fffffffddffffffffdffffffffff9effffffffefffffffffffffffffffffffffffffffff +fffffffffffcffffbffffffffffbffffffffbffffffffffbfffffffff7ffffffffdfffff +fffffebffffffffeffffffffffe5fffffffff7ffffffffffffffffffffffffffffffffff +fffffffffcffff7ffffffffffdffffffff7ffffffffffdffffffffefffffffffefffffff +ffff7fffffffff7ffffffffffbfffffffffbffffffffffffffffffffffffffffffffffff +fffffffcffff7ffffffffffdffffffff7ffffffffffdffffffffdffffffffff7ffffffff +feffffffffffbffffffffff7fffffffffdffffffffffffffffffffffffffffffffffffff +fffffcfffefffffffffffefffffffefffffffffffeffffffffdffffffffff7fffffffffe +ffffffffffbffffffffff7fffffffffdffffffffffffffffffffffffffffffffffffffff +fffcfffefffffffffffefffffffefffffffffffeffffffffbffffffffffbfffffffffdff +ffffffffdfffffffffeffffffffffeffffffffffffffffffffffffffffffffffffffffff +fcfffefffffffffffefffffffefffffffffffeffffffffbffffffffffbfffffffffdffff +ffffffdfffffffffeffffffffffefffffffffffffffffffffffffffffffffffffffffffc +fffefffffffffffefffffffefffffffffffeffffffff7ffffffffffdfffffffffbffffff +ffffefffffffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffcff +fdffffffffffff7ffffffdffffffffffff7fffffff7ffffffffffdfffffffffbffffffff +ffefffffffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffcfffd +ffffffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7ffffffffff +f7ffffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdff +ffffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7 +ffffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdffff +ffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7ff +ffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdffffff +ffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7ffff +ffffbfffffffffffbfffffff87ffe3ffc7ff1fffffff13ffffcffffffffcfffdffffffff +ffff7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffff +ff7fffffffffffdfffffffcffff3ffe7ff9fffffff93fffecffffffffcfffdffffffffff +ff7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff +7fffffffffffdfffffffcffff3ffe7ff9fffffff9ffffcfffffffffcfffdffffffffffff +7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff7f +ffffffffffdfffffffc88e1223270c9fc3232383c2180e188c3ffcfffdffffffffffff7f +fffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff7fff +ffffffffdfffffffcc4c933246611f9999999390cccccc49bffcfffefffffffffffeffff +fffefffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffff +ffffffdfffffffccccf33266619f999999939cccccccc8fffcfffefffffffffffeffffff +fefffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffff +ffffdfffffffccccf33266019fe19999939f0ccccccc3ffcfffefffffffffffefffffffe +fffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffff +ffdfffffffccccf33266799f999999939ccccccccf3ffcfffefffffffffffefffffffeff +fffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffffff +dfffffffcccc532266719f9989899388cc8ccccbbffcffff7ffffffffffdffffffff7fff +fffffffdfffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffffffdf +ffffff80462111130c4f84939301c4240618407ffcffff7ffffffffffdffffffff7fffff +fffffdfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfff +ffffffffffffffffffff9f9ffffffffffffffffcffffbffffffffffbffffffffbfffffff +fffbfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffff +ffffffffffffffffff9f9ffffffffffffffffcffffbffffffffffbffffffffbfffffffff +fbfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffffff +ffffffffffffffff0f0ffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7 +fffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffffffff +fffffffffffffffffffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7ff +ffffff7ffffffffffdfffffffffbffffffffffefffffffffdfffffffffff7fffffffffff +fffffffffffffffffffffffffffffffcffffefffffffffefffffffffefffffffffefffff +ffff7ffffffffffdfffffffffbffffffffffefffffffffdfffffffffff7fffffffffffff +fffffffffffffffffffffffffffffcfffff7ffffffffdffffffffff7ffffffffdfffffff +ffbffffffffffbfffffffffdffffffffffdfffffffffeffffffffffeffffffffffffffff +fffffffffffffffffffffffffffcfffffbffffffffbffffffffffbffffffffbfffffffff +bffffffffffbfffffffffdffffffffffdfffffffffeffffffffffeffffffffffffffffff +fffffffffffffffffffffffffcfffffdffffffff7ffffffffffdffffffff7fffffffffdf +fffffffff7fffffffffeffffffffffbffffffffff7fffffffffdffffffffffffffffffff +fffffffffffffffffffffffcfffffefffffffefffffffffffefffffffeffffffffffdfff +fffffff7fffffffffeffffffffffbffffffffff7fffffffffdffffffffffffffffffffff +fffffffffffffffffffffcffffff7ffffffdffffffffffff7ffffffdffffffffffefffff +ffffefffffffffff7fffffffff7ffffffffffbfffffffffbffffffffffffffffffffffff +fffffffffffffffffffcffffff9ffffff3ffffffffffff9ffffff3fffffffffff7ffffff +ffdfffffffffffbffffffffefffffffffffdfffffffff7ffffffffffffffffffffffffff +fffffffffffffffffcffffffe7ffffcfffffffffffffe7ffffcffffffffffffbffffffff +bfffffffffffdffffffffdfffffffffffeffffffffefffffffffffffffffffffffffffff +fffffffffffffffcfffffff9ffff3ffffffffffffff9ffff3ffffffffffffdffffffff7f +ffffffffffeffffffffbffffffffffff7fffffffdfffffffffffffffffffffffffffffff +fffffffffffffcfffffffe1ff0fffffffffffffffe1ff0fffffffffffffefffffffeffff +fffffffff7fffffff7ffffffffffffbfffffffbfffffffffffffffffffffffffffffffff +fffffffffffcffffffffc00fffffffffffffffffe00fffffffffffffff7ffffffdffffff +fffffffbffffffefffffffffffffdfffffff7fffffffffffffffffffffffffffffffffff +fffffffffcffffffffdfffffffffffffffffffffffffffffffffffff9ffffff3ffffffff +fffffcffffff9fffffffffffffe7fffffcffffffffffffffffffffffffffffffffffffff +fffffffcffffffffdfffffffffffffffffffffffffffffffffffffe7ffffcfffffffffff +ffff3ffffe7ffffffffffffff9fffff3ffffffffffffffffffffffffffffffffffffffff +fffffcffffffffdffffffffffffffffffffffffffffffffffffff9ffff3fffffffffffff +ffcffff9fffffffffffffffe7fffcfffffffffffffffffffffffffffffffffffffffffff +fffcffffffffdffffffffffffffffffffffffffffffffffffffe1ff0ffffffffffffffff +f0ff87ffffffffffffffff87fc3fffffffffffffffffffffffffffffffffffffffffffff +fcffffffffdfffffffffffffffffffffffffffffffffffffffc007ffffffffffffffffff +007ffffffffffffffffff803fffffffffffffffffffffffffffffffffffffffffffffffc +ffffffffdfffffffffffffffffffffffffffffffffffffffbffbffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffdfffffffffffffffffffffffffffffffffffffff7ffdffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffdffffffffffffffffffffffffffffffffffffffefffdffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffdffffffffffffffffffffffffffffffffffffffdfffeffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +dffffffffffffffffffffffffffffffffffffffbffff7fffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdf +fffffffffffffffffffffffffffffffffffff7ffffbfffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfff +ffffffffffffffffffffffffffffffffffefffffdfffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffff +ffffffffffffffffffffffffffffffffdfffffdfffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffff +ffffffffffffffffffffffffffffffbfffffefffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffff +ffffffffffffffffffffffffffff7ffffff7ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffff +fffffffffffffffffffffffffefffffffbffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffff +fffffffffffffffffffffffdfffffffdffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffff +fffffffffffffffffffffbfffffffdffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffff +fffffffffffffffffff7fffffffeffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffff +ffffffffffffffffefffffffff7fffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffff +ffffffffffffffdfffffffffbfffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffff +ffffffffffffbfffffffffdfffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffff +ffffffffff7fffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffff +fffffffeffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffff +fffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffff +fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffff +f7fffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffffef +fffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffffdfff +fffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfffffffc01ffffffffffffffffffffffffffffff003fffff +ffffffff003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffc3fe1ffffffffffffffffffffffffffff0ff87ffffff +fffff87fc3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffff3fffe7ffffffffffffffffffffffffffcffff9ffffffff +ffe7fffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffffcfffff9ffffffffffffffffffffffffff3ffffe7fffffffff +9fffff3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffff3fffffe7ffffffffffffffffffffffffcffffff9ffffffffe7f +ffffcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcffffefffffffbffffffffffffffffffffffffbffffffeffffffffdffff +fff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffffdfffffffdffffffffffffffffffffffff7fffffff7fffffffbffffff +fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffbfffffffefffffffffffffffffffffffeffffffffbfffffff7fffffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffff7ffffffff7ffffffffffffffffffffffdffffffffdffffffeffffffffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcfffefffffffffbffffffffffffffffffffffbffffffffeffffffdfffffffff7fff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffdfffffffffdffffffffffffffffffffff7fffffffff7fffffbfffffffffbfffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff7fffffffffdfffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffbfffffffffefffffffffffffffffffffeffffffffffbfffff7fffffffffdfffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +f7ffffffffff7ffffffffffffffffffffdffffffffffdffffeffffffffffefffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfff7 +ffffffffff7ffffffffffffffffffffdffffffffffdffffeffffffffffefffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffefff +ffffffffbffffffffffffffffffffbffffffffffeffffdfffffffffff7ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffefffff +ffffffbffffffffffffffffffffbffffffffffeffffdfffffffffff7ffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffff +ffffdffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffff +ffdffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffffff +dffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffffffdf +fffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffffffff +ffffffffffffffffff87ffe3ffc7ff1fffffff13ffffcffffffffcffbfffffffffffefff +ffffffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffff +ffffffffffffffffcffff3ffe7ff9fffffff93fffecffffffffcffbfffffffffffefffff +ffffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffff +ffffffffffffffcffff3ffe7ff9fffffff9ffffcfffffffffcffbfffffffffffefffffff +ffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffff +ffffffffffffc88e1223270c9fc3232383c2180e188c3ffcffbfffffffffffefffffffff +ffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffff +ffffffffffcc4c933246611f9999999390cccccc49bffcffbfffffffffffefffffffffff +ffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffff +ffffffffccccf33266619f999999939cccccccc8fffcffbfffffffffffefffffffffffff +ffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffff +ffffffccccf33266019fe19999939f0ccccccc3ffcffbfffffffffffefffffffffffffff +ffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffff +ffffccccf33266799f999999939ccccccccf3ffcffbfffffffffffefffffffffffffffff +ffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffffff +ffcccc532266719f9989899388cc8ccccbbffcffbfffffffffffefffffffffffffffffff +effffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffffffff +80462111130c4f84939301c4240618407ffcffdfffffffffffdffffffffffffffffffff7 +fffffffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff9f9ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ff +fffffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff9f9ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ffff +fffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0f0ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ffffff +fffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffefffffffffffbffffffffffffffffffffbffffffff +ffeffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffefffffffffffbffffffffffffffffffffbffffffffff +effffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfff7ffffffffff7ffffffffffffffffffffdffffffffffdf +fffeffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcfff7ffffffffff7ffffffffffffffffffffdffffffffffdfff +feffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff +7fffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff7f +ffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffdfffffffffdffffffffffffffffffffff7fffffffff7fffffbfff +ffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffefffffffffbffffffffffffffffffffffbffffffffeffffffdfffff +ffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffff7ffffffff7ffffffffffffffffffffffdffffffffdffffffefffffff +feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffbfffffffefffffffffffffffffffffffeffffffffbfffffff7fffffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffdfffffffdffffffffffffffffffffffff7fffffff7fffffffbfffffffbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffefffffffbffffffffffffffffffffffffbffffffeffffffffdfffffff7ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffff3fffffe7ffffffffffffffffffffffffcffffff9ffffffffe7fffffcfffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffcfffff9ffffffffffffffffffffffffff3ffffe7fffffffff9fffff3fffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +ffffff3fffe7ffffffffffffffffffffffffffcffff9ffffffffffe7fffcffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffc3fe1ffffffffffffffffffffffffffff0ff87fffffffffff87fc3ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +fffc01ffffffffffffffffffffffffffffff007fffffffffffff803fffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffc +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 20 377 197 +%%EOF diff --git a/system/doc/design_principles/included_applications.xml b/system/doc/design_principles/included_applications.xml new file mode 100644 index 0000000000..3adb27ea08 --- /dev/null +++ b/system/doc/design_principles/included_applications.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Included Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>included_applications.xml</file> + </header> + + <section> + <title>Definition</title> + <p>An application can <em>include</em> other applications. + An <em>included application</em> has its own application directory + and <c>.app</c> file, but it is started as part of the supervisor + tree of another application.</p> + <p>An application can only be included by one other application.</p> + <p>An included application can include other applications.</p> + <p>An application which is not included by any other application is + called a <em>primary application</em>.</p> + <marker id="inclappls"></marker> + <image file="../design_principles/inclappls.gif"> + <icaption>Primary Application and Included Applications.</icaption> + </image> + <p>The application controller will automatically load any included + applications when loading a primary application, but not start + them. Instead, the top supervisor of the included application + must be started by a supervisor in the including application.</p> + <p>This means that when running, an included application is in fact + part of the primary application and a process in an included + application will consider itself belonging to the primary + application.</p> + </section> + + <section> + <title>Specifying Included Applications</title> + <p>Which applications to include is defined by + the <c>included_applications</c> key in the <c>.app</c> file.</p> + <pre> +{application, prim_app, + [{description, "Tree application"}, + {vsn, "1"}, + {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, + {registered, [prim_app_server]}, + {included_applications, [incl_app]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {prim_app_cb,[]}}, + {env, [{file, "/usr/local/log"}]} + ]}.</pre> + </section> + + <section> + <title>Synchronizing Processes During Startup</title> + <p>The supervisor tree of an included application is started as + part of the supervisor tree of the including application. + If there is a need for synchronization between processes in + the including and included applications, this can be achieved + by using <em>start phases</em>.</p> + <p>Start phases are defined by the <c>start_phases</c> key in + the <c>.app</c> file as a list of tuples <c>{Phase,PhaseArgs}</c>, + where <c>Phase</c> is an atom and <c>PhaseArgs</c> is a term. + Also, the value of the <c>mod</c> key of the including application + must be set to <c>{application_starter,[Module,StartArgs]}</c>, + where <c>Module</c> as usual is the application callback module + and <c>StartArgs</c> a term provided as argument to the callback + function <c>Module:start/2</c>.</p> + <code type="none"> +{application, prim_app, + [{description, "Tree application"}, + {vsn, "1"}, + {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, + {registered, [prim_app_server]}, + {included_applications, [incl_app]}, + {start_phases, [{init,[]}, {go,[]}]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {application_starter,[prim_app_cb,[]]}}, + {env, [{file, "/usr/local/log"}]} + ]}. + +{application, incl_app, + [{description, "Included application"}, + {vsn, "1"}, + {modules, [incl_app_cb, incl_app_sup, incl_app_server]}, + {registered, []}, + {start_phases, [{go,[]}]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {incl_app_cb,[]}} + ]}.</code> + <p>When starting a primary application with included applications, + the primary application is started the normal way: + The application controller creates an application master for + the application, and the application master calls + <c>Module:start(normal, StartArgs)</c> to start the top + supervisor.</p> + <p>Then, for the primary application and each included application + in top-down, left-to-right order, the application master calls + <c>Module:start_phase(Phase, Type, PhaseArgs)</c> for each phase + defined for for the primary application, in that order. + Note that if a phase is not defined for an included application, + the function is not called for this phase and application.</p> + <p>The following requirements apply to the <c>.app</c> file for + an included application:</p> + <list type="bulleted"> + <item>The <c>{mod, {Module,StartArgs}}</c> option must be + included. This option is used to find the callback module + <c>Module</c> of the application. <c>StartArgs</c> is ignored, + as <c>Module:start/2</c> is called only for the primary + application.</item> + <item>If the included application itself contains included + applications, instead the option + <c>{mod, {application_starter, [Module,StartArgs]}}</c> must be + included.</item> + <item>The <c>{start_phases, [{Phase,PhaseArgs}]}</c> option must + be included, and the set of specified phases must be a subset + of the set of phases specified for the primary application.</item> + </list> + <p>When starting <c>prim_app</c> as defined above, the application + controller will call the following callback functions, before + <c>application:start(prim_app)</c> returns a value:</p> + <code type="none"> +application:start(prim_app) + => prim_app_cb:start(normal, []) + => prim_app_cb:start_phase(init, normal, []) + => prim_app_cb:start_phase(go, normal, []) + => incl_app_cb:start_phase(go, normal, []) +ok</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/make.dep b/system/doc/design_principles/make.dep new file mode 100644 index 0000000000..05dd2333fb --- /dev/null +++ b/system/doc/design_principles/make.dep @@ -0,0 +1,31 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/gandalf/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: applications.tex appup_cookbook.tex book.tex \ + des_princ.tex distributed_applications.tex \ + events.tex fsm.tex gen_server_concepts.tex \ + included_applications.tex part.tex release_handling.tex \ + release_structure.tex spec_proc.tex sup_princ.tex + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: sup6.ps + +book.dvi: dist1.ps dist2.ps dist3.ps dist4.ps dist5.ps + +book.dvi: clientserver.ps + +book.dvi: inclappls.ps + +book.dvi: sup4.ps sup5.ps + diff --git a/system/doc/design_principles/note.gif b/system/doc/design_principles/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/design_principles/note.gif diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml new file mode 100644 index 0000000000..d40b7cb23e --- /dev/null +++ b/system/doc/design_principles/part.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OTP Design Principles</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <xi:include href="des_princ.xml"/> + <xi:include href="gen_server_concepts.xml"/> + <xi:include href="fsm.xml"/> + <xi:include href="events.xml"/> + <xi:include href="sup_princ.xml"/> + <xi:include href="spec_proc.xml"/> + <xi:include href="applications.xml"/> + <xi:include href="included_applications.xml"/> + <xi:include href="distributed_applications.xml"/> + <xi:include href="release_structure.xml"/> + <xi:include href="release_handling.xml"/> + <xi:include href="appup_cookbook.xml"/> +</part> + diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml new file mode 100644 index 0000000000..1d62c242c0 --- /dev/null +++ b/system/doc/design_principles/release_handling.xml @@ -0,0 +1,667 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Release Handling</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>release_handling.xml</file> + </header> + + <section> + <title>Release Handling Principles</title> + <p>An important feature of the Erlang programming language is + the ability to change module code in run-time, <em>code replacement</em>, as described in <em>Erlang Reference Manual</em>.</p> + <p>Based on this feature, the OTP application SASL provides a + framework for upgrading and downgrading between different + versions of an entire release in run-time. This is what we call + <em>release handling</em>.</p> + <p>The framework consists of off-line support (<c>systools</c>) for + generating scripts and building release packages, and on-line + support (<c>release_handler</c>) for unpacking and installing + release packages.</p> + <p>Note that the minimal system based on Erlang/OTP, enabling + release handling, thus consists of Kernel, STDLIB and SASL.</p> + <list type="ordered"> + <item> + <p>A release is created as described in the previous chapter + <seealso marker="release_structure">Releases</seealso>. + The release is transferred to and installed at target + environment. Refer to <em>System Principles</em> for + information of how to install the first target system.</p> + </item> + <item> + <p>Modifications, for example error corrections, are made to + the code in the development environment.</p> + </item> + <item> + <p>At some point it is time to make a new version of release. + The relevant <c>.app</c> files are updated and a new + <c>.rel</c> file is written.</p> + </item> + <item> + <p>For each modified application, an + <seealso marker="#appup">application upgrade file</seealso>, + <c>.appup</c>, is created. In this file, it is described how + to upgrade and/or downgrade between the old and new version of + the application.</p> + </item> + <item> + <p>Based on the <c>.appup</c> files, a + <seealso marker="#relup">release upgrade file</seealso> called + <c>relup</c>, is created. This file describes how to upgrade + and/or downgrade between the old and new version of + the entire release.</p> + </item> + <item> + <p>A new release package is made and transferred to + the target system.</p> + </item> + <item> + <p>The new release package is unpacked using the release + handler.</p> + </item> + <item> + <p>The new version of the release is installed, also using + the release handler. This is done by evaluating + the instructions in <c>relup</c>. Modules may be added, + deleted or re-loaded, applications may be started, stopped or + re-started etc. In some cases, it is even necessary to restart + the entire emulator.</p> + <p>If the installation fails, the system may be rebooted. + The old release version is then automatically used.</p> + </item> + <item> + <p>If the installation succeeds, the new version is made + the default version, which should now be used in case of a + system reboot.</p> + </item> + </list> + <p>The next chapter, <seealso marker="appup_cookbook">Appup Cookbook</seealso>, contains examples of <c>.appup</c> files + for typical cases of upgrades/downgrades that are normally easy + to handle in run-time. However, there are a many aspects that can + make release handling complicated. To name a few examples:</p> + <list type="bulleted"> + <item> + <p>Complicated or circular dependencies can make it difficult + or even impossible to decide in which order things must be + done without risking run-time errors during an upgrade or + downgrade. Dependencies may be:</p> + <list type="bulleted"> + <item>between nodes,</item> + <item>between processes, and</item> + <item>between modules.</item> + </list> + </item> + <item> + <p>During release handling, non-affected processes continue + normal execution. This may lead to timeouts or other problems. + For example, new processes created in the time window between + suspending processes using a certain module and loading a new + version of this module, may execute old code.</p> + </item> + </list> + <p>It is therefore recommended that code is changed in as small + steps as possible, and always kept backwards compatible.</p> + </section> + + <section> + <marker id="req"></marker> + <title>Requirements</title> + <p>For release handling to work properly, the runtime system needs + to have knowledge about which release it is currently running. It + must also be able to change (in run-time) which boot script and + system configuration file should be used if the system is + rebooted, for example by <c>heart</c> after a failure. + Therefore, Erlang must be started as an embedded system, see + <em>Embedded System</em> for information on how to do this.</p> + <p>For system reboots to work properly, it is also required that + the system is started with heart beat monitoring, see + <c>erl(1)</c> and <c>heart(3)</c>.</p> + <p>Other requirements:</p> + <list type="bulleted"> + <item> + <p>The boot script included in a release package must be + generated from the same <c>.rel</c> file as the release + package itself.</p> + <p>Information about applications are fetched from the script + when an upgrade or downgrade is performed.</p> + </item> + <item> + <p>The system must be configured using one and only one system + configuration file, called <c>sys.config</c>.</p> + <p>If found, this file is automatically included when a release + package is created.</p> + </item> + <item> + <p>All versions of a release, except the first one, must + contain a <c>relup</c> file.</p> + <p>If found, this file is automatically included when a release + package is created.</p> + </item> + </list> + </section> + + <section> + <title>Distributed Systems</title> + <p>If the system consists of several Erlang nodes, each node may use + its own version of the release. The release handler is a locally + registered process and must be called at each node where an + upgrade or downgrade is required. There is a release handling + instruction that can be used to synchronize the release handler + processes at a number of nodes: <c>sync_nodes</c>. See + <c>appup(4)</c>.</p> + </section> + + <section> + <marker id="instr"></marker> + <title>Release Handling Instructions</title> + <p>OTP supports a set of <em>release handling instructions</em> + that is used when creating <c>.appup</c> files. The release + handler understands a subset of these, the <em>low-level</em> + instructions. To make it easier for the user, there are also a + number of <em>high-level</em> instructions, which are translated + to low-level instructions by <c>systools:make_relup</c>.</p> + <p>Here, some of the most frequently used instructions are + described. The complete list of instructions is found in + <c>appup(4)</c>.</p> + <p>First, some definitions:</p> + <taglist> + <tag><em>Residence module</em></tag> + <item> + <p>The module where a process has its tail-recursive loop + function(s). If the tail-recursive loop functions are + implemented in several modules, all those modules are residence + modules for the process.</p> + </item> + <tag><em>Functional module</em></tag> + <item> + <p>A module which is not a residence module for any process.</p> + </item> + </taglist> + <p>Note that for a process implemented using an OTP behaviour, + the behaviour module is the residence module for that process. + The callback module is a functional module.</p> + + <section> + <title>load_module</title> + <p>If a simple extension has been made to a functional module, it + is sufficient to simply load the new version of the module into + the system, and remove the old version. This is called + <em>simple code replacement</em> and for this the following + instruction is used:</p> + <code type="none"> +{load_module, Module}</code> + </section> + + <section> + <title>update</title> + <p>If a more complex change has been made, for example a change + to the format of the internal state of a gen_server, simple code + replacement is not sufficient. Instead it is necessary to + suspend the processes using the module (to avoid that they try + to handle any requests before the code replacement is + completed), ask them to transform the internal state format and + switch to the new version of the module, remove the old version + and last, resume the processes. This is called <em>synchronized code replacement</em> and for this the following instructions + are used:</p> + <code type="none"> +{update, Module, {advanced, Extra}} +{update, Module, supervisor}</code> + <p><c>update</c> with argument <c>{advanced,Extra}</c> is used + when changing the internal state of a behaviour as described + above. It will cause behaviour processes to call the callback + function <c>code_change</c>, passing the term <c>Extra</c> and + some other information as arguments. See the man pages for + the respective behaviours and + <seealso marker="appup_cookbook#int_state">Appup Cookbook</seealso>.</p> + <p><c>update</c> with argument <c>supervisor</c> is used when + changing the start specification of a supervisor. See + <seealso marker="appup_cookbook#sup">Appup Cookbook</seealso>.</p> + <p>The release handler finds the processes <em>using</em> a module + to update by traversing the supervision tree of each running + application and checking all the child specifications:</p> + <code type="none"> +{Id, StartFunc, Restart, Shutdown, Type, Modules}</code> + <p>A process is using a module if the name is listed in + <c>Modules</c> in the child specification for the process.</p> + <p>If <c>Modules=dynamic</c>, which is the case for event + managers, the event manager process informs the release handler + about the list of currently installed event handlers (gen_fsm) + and it is checked if the module name is in this list instead.</p> + <p>The release handler suspends, asks for code change, and + resumes processes by calling the functions + <c>sys:suspend/1,2</c>, <c>sys:change_code/4,5</c> and + <c>sys:resume/1,2</c> respectively.</p> + </section> + + <section> + <title>add_module and delete_module</title> + <p>If a new module is introduced, the following instruction is + used:</p> + <code type="none"> +{add_module, Module}</code> + <p>The instruction loads the module and is absolutely necessary + when running Erlang in embedded mode. It is not strictly + required when running Erlang in interactive (default) mode, + since the code server automatically searches for and loads + unloaded modules.</p> + <p>The opposite of <c>add_module</c> is <c>delete_module</c> which + unloads a module:</p> + <code type="none"> +{delete_module, Module}</code> + <p>Note that any process, in any application, with <c>Module</c> + as residence module, is killed when the instruction is + evaluated. The user should therefore ensure that all such + processes are terminated before deleting the module, to avoid + a possible situation with failing supervisor restarts.</p> + </section> + + <section> + <title>Application Instructions</title> + <p>Instruction for adding an application:</p> + <code type="none"> +{add_application, Application}</code> + <p>Adding an application means that the modules defined by + the <c>modules</c> key in the <c>.app</c> file are loaded using + a number of <c>add_module</c> instructions, then the application + is started.</p> + <p>Instruction for removing an application:</p> + <code type="none"> +{remove_application, Application}</code> + <p>Removing an application means that the application is stopped, + the modules are unloaded using a number of <c>delete_module</c> + instructions and then the application specification is unloaded + from the application controller.</p> + <p>Instruction for removing an application:</p> + <code type="none"> +{restart_application, Application}</code> + <p>Restarting an application means that the application is stopped + and then started again similar to using the instructions + <c>remove_application</c> and <c>add_application</c> in + sequence.</p> + </section> + + <section> + <title>apply (low-level)</title> + <p>To call an arbitrary function from the release handler, + the following instruction is used:</p> + <code type="none"> +{apply, {M, F, A}}</code> + <p>The release handler will evalute <c>apply(M, F, A)</c>.</p> + </section> + + <section> + <title>restart_new_emulator (low-level)</title> + <p>This instruction is used when changing to a new emulator + version, or if a system reboot is needed for some other reason. + Requires that the system is started with heart beat + monitoring, see <c>erl(1)</c> and <c>heart(3)</c>.</p> + <p>When the release handler encounters the instruction, it shuts + down the current emulator by calling <c>init:reboot()</c>, see + <c>init(3)</c>. All processes are terminated gracefully and + the system can then be rebooted by the heart program, using + the new release version. This new version must still be made + permanent when the new emulator is up and running. Otherwise, + the old version is used in case of a new system reboot.</p> + <p>On UNIX, the release handler tells the heart program which + command to use to reboot the system. Note that the environment + variable <c>HEART_COMMAND</c>, normally used by the heart + program, in this case is ignored. The command instead defaults + to <c>$ROOT/bin/start</c>. Another command can be set + by using the SASL configuration parameter <c>start_prg</c>, see + <c>sasl(6)</c>.</p> + </section> + </section> + + <section> + <marker id="appup"></marker> + <title>Application Upgrade File</title> + <p>To define how to upgrade/downgrade between the current version + and previous versions of an application, we create an + <em>application upgrade file</em>, or in short <c>.appup</c> file. + The file should be called <c>Application.appup</c>, where + <c>Application</c> is the name of the application:</p> + <code type="none"> +{Vsn, + [{UpFromVsn1, InstructionsU1}, + ..., + {UpFromVsnK, InstructionsUK}], + [{DownToVsn1, InstructionsD1}, + ..., + {DownToVsnK, InstructionsDK}]}.</code> + <p><c>Vsn</c>, a string, is the current version of the application, + as defined in the <c>.app</c> file. Each <c>UpFromVsn</c> + is a previous version of the application to upgrade from, and each + <c>DownToVsn</c> is a previous version of the application to + downgrade to. Each <c>Instructions</c> is a list of release + handling instructions.</p> + <p>The syntax and contents of the <c>appup</c> file are described + in detail in <c>appup(4)</c>.</p> + <p>In the chapter <seealso marker="appup_cookbook">Appup Cookbook</seealso>, examples of <c>.appup</c> files for typical + upgrade/downgrade cases are given.</p> + <p>Example: Consider the release <c>ch_rel-1</c> from + the <seealso marker="release_structure#ch_rel">Releases</seealso> + chapter. Assume we want to add a function <c>available/0</c> to + the server <c>ch3</c> which returns the number of available + channels:</p> + <p>(Hint: When trying out the example, make the changes in a copy of + the original directory, so that the first versions are still + available.)</p> + <code type="none"> +-module(ch3). +-behaviour(gen_server). + +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([available/0]). +-export([init/1, handle_call/3, handle_cast/2]). + +start_link() -> + gen_server:start_link({local, ch3}, ch3, [], []). + +alloc() -> + gen_server:call(ch3, alloc). + +free(Ch) -> + gen_server:cast(ch3, {free, Ch}). + +available() -> + gen_server:call(ch3, available). + +init(_Args) -> + {ok, channels()}. + +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}; +handle_call(available, _From, Chs) -> + N = available(Chs), + {reply, N, Chs}. + +handle_cast({free, Ch}, Chs) -> + Chs2 = free(Ch, Chs), + {noreply, Chs2}.</code> + <p>A new version of the <c>ch_app.app</c> file must now be created, + where the version is updated:</p> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "2"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {ch_app,[]}} + ]}.</code> + <p>To upgrade <c>ch_app</c> from <c>"1"</c> to <c>"2"</c> (and + to downgrade from <c>"2"</c> to <c>"1"</c>), we simply need to + load the new (old) version of the <c>ch3</c> callback module. + We create the application upgrade file <c>ch_app.appup</c> in + the <c>ebin</c> directory:</p> + <code type="none"> +{"2", + [{"1", [{load_module, ch3}]}], + [{"1", [{load_module, ch3}]}] +}.</code> + </section> + + <section> + <marker id="relup"></marker> + <title>Release Upgrade File</title> + <p>To define how to upgrade/downgrade between the new version and + previous versions of a release, we create a <em>release upgrade file</em>, or in short <c>relup</c> file.</p> + <p>This file does not need to be created manually, it can be + generated by <c>systools:make_relup/3,4</c>. The relevant versions + of the <c>.rel</c> file, <c>.app</c> files and <c>.appup</c> files + are used as input. It is deducted which applications should be + added and deleted, and which applications that need to be upgraded + and/or downgraded. The instructions for this is fetched from + the <c>.appup</c> files and transformed into a single list of + low-level instructions in the right order.</p> + <p>If the <c>relup</c> file is relatively simple, it can be created + manually. Remember that it should only contain low-level + instructions.</p> + <p>The syntax and contents of the release upgrade file are + described in detail in <c>relup(4)</c>.</p> + <p>Example, continued from the previous section. We have a new + version "2" of <c>ch_app</c> and an <c>.appup</c> file. We also + need a new version of the <c>.rel</c> file. This time the file is + called <c>ch_rel-2.rel</c> and the release version string is + changed changed from "A" to "B":</p> + <code type="none"> +{release, + {"ch_rel", "B"}, + {erts, "5.3"}, + [{kernel, "2.9"}, + {stdlib, "1.12"}, + {sasl, "1.10"}, + {ch_app, "2"}] +}.</code> + <p>Now the <c>relup</c> file can be generated:</p> + <pre> +1> <input>systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"]).</input> +ok</pre> + <p>This will generate a <c>relup</c> file with instructions for + how to upgrade from version "A" ("ch_rel-1") to version "B" + ("ch_rel-2") and how to downgrade from version "B" to version "A".</p> + <p>Note that both the old and new versions of the <c>.app</c> and + <c>.rel</c> files must be in the code path, as well as + the <c>.appup</c> and (new) <c>.beam</c> files. It is possible + to extend the code path by using the option <c>path</c>:</p> + <pre> +1> <input>systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"],</input> +<input>[{path,["../ch_rel-1",</input> +<input>"../ch_rel-1/lib/ch_app-1/ebin"]}]).</input> +ok</pre> + </section> + + <section> + <marker id="rel_handler"></marker> + <title>Installing a Release</title> + <p>When we have made a new version of a release, a release package + can be created with this new version and transferred to the target + environment.</p> + <p>To install the new version of the release in run-time, + the <em>release handler</em> is used. This is a process belonging + to the SASL application, that handles unpacking, installation, + and removal of release packages. It is interfaced through + the module <c>release_handler</c>, which is described in detail in + <c>release_handler(3)</c>.</p> + <p>Assuming there is a target system up and running with + installation root directory <c>$ROOT</c>, the release package with + the new version of the release should be copied to + <c>$ROOT/releases</c>.</p> + <p>The first action is to <em>unpack</em> the release package, + the files are then extracted from the package:</p> + <code type="none"> +release_handler:unpack_release(ReleaseName) => {ok, Vsn}</code> + <p><c>ReleaseName</c> is the name of the release package except + the <c>.tar.gz</c> extension. <c>Vsn</c> is the version of + the unpacked release, as defined in its <c>.rel</c> file.</p> + <p>A directory <c>$ROOT/lib/releases/Vsn</c> will be created, where + the <c>.rel</c> file, the boot script <c>start.boot</c>, + the system configuration file <c>sys.config</c> and <c>relup</c> + are placed. For applications with new version numbers, + the application directories will be placed under <c>$ROOT/lib</c>. + Unchanged applications are not affected.</p> + <p>An unpacked release can be <em>installed</em>. The release + handler then evaluates the instructions in <c>relup</c>, step by + step:</p> + <code type="none"> +release_handler:install_release(Vsn) => {ok, FromVsn, []}</code> + <p>If an error occurs during the installation, the system is + rebooted using the old version of the release. If installation + succeeds, the system is afterwards using the new version of + the release, but should anything happen and the system is + rebooted, it would start using the previous version again. To be + made the default version, the newly installed release must be made + <em>permanent</em>, which means the previous version becomes + <em>old</em>:</p> + <code type="none"> +release_handler:make_permanent(Vsn) => ok</code> + <p>The system keeps information about which versions are old and + permanent in the files <c>$ROOT/releases/RELEASES</c> and + <c>$ROOT/releases/start_erl.data</c>.</p> + <p>To downgrade from <c>Vsn</c> to <c>FromVsn</c>, + <c>install_release</c> must be called again:</p> + <code type="none"> +release_handler:install_release(FromVsn) => {ok, Vsn, []}</code> + <p>An installed, but not permanent, release can be <em>removed</em>. + Information about the release is then deleted from + <c>$ROOT/releases/RELEASES</c> and the release specific code, + that is the new application directories and + the <c>$ROOT/releases/Vsn</c> directory, are removed.</p> + <code type="none"> +release_handler:remove_release(Vsn) => ok</code> + <p>Example, continued from the previous sections:</p> + <p>1) Create a target system as described in <em>System Principles</em> of the first version <c>"A"</c> of <c>ch_rel</c> + from + the <seealso marker="release_structure#ch_rel">Releases</seealso> + chapter. This time <c>sys.config</c> must be included in + the release package. If no configuration is needed, the file + should contain the empty list:</p> + <code type="none"> +[].</code> + <p>2) Start the system as a simple target system. Note that in + reality, it should be started as an embedded system. However, + using <c>erl</c> with the correct boot script and <c>.config</c> + file is enough for illustration purposes:</p> + <pre> +% <input>cd $ROOT</input> +% <input>bin/erl -boot $ROOT/releases/A/start -config $ROOT/releases/A/sys</input> +...</pre> + <p><c>$ROOT</c> is the installation directory of the target system.</p> + <p>3) In another Erlang shell, generate start scripts and create a + release package for the new version <c>"B"</c>. Remember to + include (a possible updated) <c>sys.config</c> and + the <c>relup</c> file, see <seealso marker="#relup">Release Upgrade File</seealso> above.</p> + <pre> +1> <input>systools:make_script("ch_rel-2").</input> +ok +2> <input>systools:make_tar("ch_rel-2").</input> +ok</pre> + <p>The new release package now contains version "2" of <c>ch_app</c> + and the <c>relup</c> file as well:</p> + <code type="none"> +% tar tf ch_rel-2.tar +lib/kernel-2.9/ebin/kernel.app +lib/kernel-2.9/ebin/application.beam +... +lib/stdlib-1.12/ebin/stdlib.app +lib/stdlib-1.12/ebin/beam_lib.beam +... +lib/sasl-1.10/ebin/sasl.app +lib/sasl-1.10/ebin/sasl.beam +... +lib/ch_app-2/ebin/ch_app.app +lib/ch_app-2/ebin/ch_app.beam +lib/ch_app-2/ebin/ch_sup.beam +lib/ch_app-2/ebin/ch3.beam +releases/B/start.boot +releases/B/relup +releases/B/sys.config +releases/ch_rel-2.rel</code> + <p>4) Copy the release package <c>ch_rel-2.tar.gz</c> to + the <c>$ROOT/releases</c> directory.</p> + <p>5) In the running target system, unpack the release package:</p> + <pre> +1> <input>release_handler:unpack_release("ch_rel-2").</input> +{ok,"B"}</pre> + <p>The new application version <c>ch_app-2</c> is installed under + <c>$ROOT/lib</c> next to <c>ch_app-1</c>. The <c>kernel</c>, + <c>stdlib</c> and <c>sasl</c> directories are not affected, as + they have not changed.</p> + <p>Under <c>$ROOT/releases</c>, a new directory <c>B</c> is created, + containing <c>ch_rel-2.rel</c>, <c>start.boot</c>, + <c>sys.config</c> and <c>relup</c>.</p> + <p>6) Check if the function <c>ch3:available/0</c> is available:</p> + <pre> +2> <input>ch3:available().</input> +** exception error: undefined function ch3:available/0</pre> + <p>7) Install the new release. The instructions in + <c>$ROOT/releases/B/relup</c> are executed one by one, resulting + in the new version of <c>ch3</c> being loaded. The function + <c>ch3:available/0</c> is now available:</p> + <pre> +3> <input>release_handler:install_release("B").</input> +{ok,"A",[]} +4> <input>ch3:available().</input> +3 +5> <input>code:which(ch3).</input> +".../lib/ch_app-2/ebin/ch3.beam" +6> <input>code:which(ch_sup).</input> +".../lib/ch_app-1/ebin/ch_sup.beam"</pre> + <p>Note that processes in <c>ch_app</c> for which code have not + been updated, for example the supervisor, are still evaluating + code from <c>ch_app-1</c>.</p> + <p>8) If the target system is now rebooted, it will use version "A" + again. The "B" version must be made permanent, in order to be + used when the system is rebooted.</p> + <pre> +7> <input>release_handler:make_permanent("B").</input> +ok</pre> + </section> + + <section> + <marker id="sys"></marker> + <title>Updating Application Specifications</title> + <p>When a new version of a release is installed, the application + specifications are automatically updated for all loaded + applications.</p> + <note> + <p>The information about the new application specifications are + fetched from the boot script included in the release package. + It is therefore important that the boot script is generated from + the same <c>.rel</c> file as is used to build the release + package itself.</p> + </note> + <p>Specifically, the application configuration parameters are + automatically updated according to (in increasing priority + order):</p> + <list type="ordered"> + <item>The data in the boot script, fetched from the new + application resource file <c>App.app</c></item> + <item>The new <c>sys.config</c></item> + <item>Command line arguments <c>-App Par Val</c></item> + </list> + <p>This means that parameter values set in the other system + configuration files, as well as values set using + <c>application:set_env/3</c>, are disregarded.</p> + <p>When an installed release is made permanent, the system process + <c>init</c> is set to point out the new <c>sys.config</c>.</p> + <p>After the installation, the application controller will compare + the old and new configuration parameters for all running + applications and call the callback function:</p> + <code type="none"> +Module:config_change(Changed, New, Removed)</code> + <p><c>Module</c> is the application callback module as defined by + the <c>mod</c> key in the <c>.app</c> file. <c>Changed</c> and + <c>New</c> are lists of <c>{Par,Val}</c> for all changed and + added configuration parameters, respectively. <c>Removed</c> is + a list of all parameters <c>Par</c> that have been removed.</p> + <p>The function is optional and may be omitted when implementing an + application callback module.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml new file mode 100644 index 0000000000..2e1daa611a --- /dev/null +++ b/system/doc/design_principles/release_structure.xml @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Releases</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>release_structure.xml</file> + </header> + <p>This chapter should be read in conjuction with <c>rel(4)</c>, + <c>systools(3)</c> and <c>script(4)</c>.</p> + + <section> + <title>Release Concept</title> + <p>When we have written one or more applications, we might want to + create a complete system consisting of these applications and a + subset of the Erlang/OTP applications. This is called a + <em>release</em>.</p> + <p>To do this, we create a <seealso marker="#res_file">release resource file</seealso> which defines which applications + are included in the release.</p> + <p>The release resource file is used to generate + <seealso marker="#boot">boot scripts</seealso> and + <seealso marker="#pack">release packages</seealso>. A system + which is transfered to and installed at another site is called a + <em>target system</em>. How to use a release package to create a + target system is described in System Principles.</p> + </section> + + <section> + <marker id="res_file"></marker> + <title>Release Resource File</title> + <p>To define a release, we create a <em>release resource file</em>, + or in short <c>.rel</c> file, where we specify the name and + version of the release, which ERTS version it is based on, and + which applications it consists of:</p> + <code type="none"> +{release, {Name,Vsn}, {erts, EVsn}, + [{Application1, AppVsn1}, + ... + {ApplicationN, AppVsnN}]}.</code> + <p>The file must be named <c>Rel.rel</c>, where <c>Rel</c> is a + unique name.</p> + <p><c>Name</c>, <c>Vsn</c> and <c>Evsn</c> are strings.</p> + <p>Each <c>Application</c> (atom) and <c>AppVsn</c> (string) is + the name and version of an application included in the release. + Note the the minimal release based on Erlang/OTP consists of + the <c>kernel</c> and <c>stdlib</c> applications, so these + applications must be included in the list.</p> + <marker id="ch_rel"></marker> + <p>Example: We want to make a release of <c>ch_app</c> from + the <seealso marker="applications#ch_app">Applications</seealso> + chapter. It has the following <c>.app</c> file:</p> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {ch_app,[]}} + ]}.</code> + <p>The <c>.rel</c> file must also contain <c>kernel</c>, + <c>stdlib</c> and <c>sasl</c>, since these applications are + required by <c>ch_app</c>. We call the file <c>ch_rel-1.rel</c>:</p> + <code type="none"> +{release, + {"ch_rel", "A"}, + {erts, "5.3"}, + [{kernel, "2.9"}, + {stdlib, "1.12"}, + {sasl, "1.10"}, + {ch_app, "1"}] +}.</code> + </section> + + <section> + <marker id="boot"></marker> + <title>Generating Boot Scripts</title> + <p>There are tools in the SASL module <c>systools</c> available to + build and check releases. The functions read the <c>.rel</c> and + <c>.app</c> files and performs syntax and dependency checks. + The function <c>systools:make_script/1,2</c> is used to generate + a boot script (see System Principles).</p> + <pre> +1> <input>systools:make_script("ch_rel-1", [local]).</input> +ok</pre> + <p>This creates a boot script, both the readable version + <c>ch_rel-1.script</c> and the binary version used by the runtime + system, <c>ch_rel-1.boot</c>. <c>"ch_rel-1"</c> is the name of + the <c>.rel</c> file, minus the extension. <c>local</c> is an + option that means that the directories where the applications are + found are used in the boot script, instead of <c>$ROOT/lib</c>. + (<c>$ROOT</c> is the root directory of the installed release.) + This is a useful way to test a generated boot script locally.</p> + <p>When starting Erlang/OTP using the boot script, all applications + from the <c>.rel</c> file are automatically loaded and started:</p> + <pre> +% <input>erl -boot ch_rel-1</input> +Erlang (BEAM) emulator version 5.3 + +Eshell V5.3 (abort with ^G) +1> +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + supervisor: {local,sasl_safe_sup} + started: [{pid,<0.33.0>}, + {name,alarm_handler}, + {mfa,{alarm_handler,start_link,[]}}, + {restart_type,permanent}, + {shutdown,2000}, + {child_type,worker}] + +... + +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + application: sasl + started_at: nonode@nohost + +... +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + application: ch_app + started_at: nonode@nohost</pre> + </section> + + <section> + <marker id="pack"></marker> + <title>Creating a Release Package</title> + <p>There is a function <c>systools:make_tar/1,2</c> which takes + a <c>.rel</c> file as input and creates a zipped tar-file with + the code for the specified applications, a <em>release package</em>.</p> + <pre> +1> <input>systools:make_script("ch_rel-1").</input> +ok +2> <input>systools:make_tar("ch_rel-1").</input> +ok</pre> + <p>The release package by default contains the <c>.app</c> files and + object code for all applications, structured according to + the <seealso marker="applications#app_dir">application directory structure</seealso>, the binary boot script renamed to + <c>start.boot</c>, and the <c>.rel</c> file.</p> + <pre> +% <input>tar tf ch_rel-1.tar</input> +lib/kernel-2.9/ebin/kernel.app +lib/kernel-2.9/ebin/application.beam +... +lib/stdlib-1.12/ebin/stdlib.app +lib/stdlib-1.12/ebin/beam_lib.beam +... +lib/sasl-1.10/ebin/sasl.app +lib/sasl-1.10/ebin/sasl.beam +... +lib/ch_app-1/ebin/ch_app.app +lib/ch_app-1/ebin/ch_app.beam +lib/ch_app-1/ebin/ch_sup.beam +lib/ch_app-1/ebin/ch3.beam +releases/A/start.boot +releases/ch_rel-1.rel</pre> + <p>Note that a new boot script was generated, without + the <c>local</c> option set, before the release package was made. + In the release package, all application directories are placed + under <c>lib</c>. Also, we do not know where the release package + will be installed, so we do not want any hardcoded absolute paths + in the boot script here.</p> + <p>If a <c>relup</c> file and/or a system configuration file called + <c>sys.config</c> is found, these files are included in + the release package as well. See + <seealso marker="release_handling#req">Release Handling</seealso>.</p> + <p>Options can be set to make the release package include source + code and the ERTS binary as well.</p> + <p>Refer to System Principles for how to install the first target + system, using a release package, and to + <seealso marker="release_handling">Release Handling</seealso> for + how to install a new release package in an existing system.</p> + </section> + + <section> + <marker id="reldir"></marker> + <title>Directory Structure</title> + <p>Directory structure for the code installed by the release handler + from a release package:</p> + <code type="none"> +$ROOT/lib/App1-AVsn1/ebin + /priv + /App2-AVsn2/ebin + /priv + ... + /AppN-AVsnN/ebin + /priv + /erts-EVsn/bin + /releases/Vsn + /bin</code> + <taglist> + <tag><c>lib</c></tag> + <item>Application directories.</item> + <tag><c>erts-EVsn/bin</c></tag> + <item>Erlang runtime system executables.</item> + <tag><c>releases/Vsn</c></tag> + <item><c>.rel</c> file and boot script <c>start.boot</c>. <br></br> + + If present in the release package, <br></br> +<c>relup</c> and/or <c>sys.config</c>.</item> + <tag><c>bin</c></tag> + <item>Top level Erlang runtime system executables.</item> + </taglist> + <p>Applications are not required to be located under the + <c>$ROOT/lib</c> directory. Accordingly, several installation + directories may exist which contain different parts of a + system. For example, the previous example could be extended as + follows:</p> + <pre> +$SECOND_ROOT/.../SApp1-SAVsn1/ebin + /priv + /SApp2-SAVsn2/ebin + /priv + ... + /SAppN-SAVsnN/ebin + /priv + +$THIRD_ROOT/TApp1-TAVsn1/ebin + /priv + /TApp2-TAVsn2/ebin + /priv + ... + /TAppN-TAVsnN/ebin + /priv</pre> + <p>The <c>$SECOND_ROOT</c> and <c>$THIRD_ROOT</c> are introduced as + <c>variables</c> in the call to the <c>systools:make_script/2</c> + function.</p> + + <section> + <title>Disk-Less and/or Read-Only Clients</title> + <p>If a complete system consists of some disk-less and/or + read-only client nodes, a <c>clients</c> directory should be + added to the <c>$ROOT</c> directory. By a read-only node we + mean a node with a read-only file system.</p> + <p>The <c>clients</c> directory should have one sub-directory + per supported client node. The name of each client directory + should be the name of the corresponding client node. As a + minimum, each client directory should contain the <c>bin</c> and + <c>releases</c> sub-directories. These directories are used to + store information about installed releases and to appoint the + current release to the client. Accordingly, the <c>$ROOT</c> + directory contains the following:</p> + <code type="none"> +$ROOT/... + /clients/ClientName1/bin + /releases/Vsn + /ClientName2/bin + /releases/Vsn + ... + /ClientNameN/bin + /releases/Vsn</code> + <p>This structure should be used if all clients are running + the same type of Erlang machine. If there are clients running + different types of Erlang machines, or on different operating + systems, the <c>clients</c> directory could be divided into one + sub-directory per type of Erlang machine. Alternatively, you + can set up one <c>$ROOT</c> per type of machine. For each + type, some of the directories specified for the <c>$ROOT</c> + directory should be included:</p> + <code type="none"> +$ROOT/... + /clients/Type1/lib + /erts-EVsn + /bin + /ClientName1/bin + /releases/Vsn + /ClientName2/bin + /releases/Vsn + ... + /ClientNameN/bin + /releases/Vsn + ... + /TypeN/lib + /erts-EVsn + /bin + ...</code> + <p>With this structure, the root directory for clients of + <c>Type1</c> is <c>$ROOT/clients/Type1</c>.</p> + </section> + </section> +</chapter> + diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml new file mode 100644 index 0000000000..f0f62891b6 --- /dev/null +++ b/system/doc/design_principles/spec_proc.xml @@ -0,0 +1,460 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Sys and Proc_Lib</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>spec_proc.xml</file> + </header> + <p>The module <c>sys</c> contains functions for simple debugging of + processes implemented using behaviours.</p> + <p>There are also functions that, together with functions in + the module <c>proc_lib</c>, can be used to implement a + <em>special process</em>, a process which comply to the OTP design + principles without making use of a standard behaviour. They can + also be used to implement user defined (non-standard) behaviours.</p> + <p>Both <c>sys</c> and <c>proc_lib</c> belong to the STDLIB + application.</p> + + <section> + <title>Simple Debugging</title> + <p>The module <c>sys</c> contains some functions for simple debugging + of processes implemented using behaviours. We use the + <c>code_lock</c> example from + the <seealso marker="fsm#ex">gen_event</seealso> chapter to + illustrate this:</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>code_lock:start_link([1,2,3,4]).</input> +{ok,<0.32.0>} +2> <input>sys:statistics(code_lock, true).</input> +ok +3> <input>sys:trace(code_lock, true).</input> +ok +4> <input>code_lock:button(4).</input> +*DBG* code_lock got event {button,4} in state closed +ok +*DBG* code_lock switched to state closed +5> <input>code_lock:button(3).</input> +*DBG* code_lock got event {button,3} in state closed +ok +*DBG* code_lock switched to state closed +6> <input>code_lock:button(2).</input> +*DBG* code_lock got event {button,2} in state closed +ok +*DBG* code_lock switched to state closed +7> <input>code_lock:button(1).</input> +*DBG* code_lock got event {button,1} in state closed +ok +OPEN DOOR +*DBG* code_lock switched to state open +*DBG* code_lock got event timeout in state open +CLOSE DOOR +*DBG* code_lock switched to state closed +8> <input>sys:statistics(code_lock, get).</input> +{ok,[{start_time,{{2003,6,12},{14,11,40}}}, + {current_time,{{2003,6,12},{14,12,14}}}, + {reductions,333}, + {messages_in,5}, + {messages_out,0}]} +9> <input>sys:statistics(code_lock, false).</input> +ok +10> <input>sys:trace(code_lock, false).</input> +ok +11> <input>sys:get_status(code_lock).</input> +{status,<0.32.0>, + {module,gen_fsm}, + [[{'$ancestors',[<0.30.0>]}, + {'$initial_call',{gen,init_it, + [gen_fsm,<0.30.0>,<0.30.0>, + {local,code_lock}, + code_lock, + [1,2,3,4], + []]}}], + running,<0.30.0>,[], + [code_lock,closed,{[],[1,2,3,4]},code_lock,infinity]]}</pre> + </section> + + <section> + <title>Special Processes</title> + <p>This section describes how to write a process which comply to + the OTP design principles, without making use of a standard + behaviour. Such a process should:</p> + <list type="bulleted"> + <item>be started in a way that makes the process fit into a + supervision tree,</item> + <item>support the <c>sys</c><seealso marker="#debug">debug facilities</seealso>, and</item> + <item>take care of <seealso marker="#msg">system messages</seealso>.</item> + </list> + <p>System messages are messages with special meaning, used in + the supervision tree. Typical system messages are requests for + trace output, and requests to suspend or resume process execution + (used during release handling). Processes implemented using + standard behaviours automatically understand these messages.</p> + + <section> + <title>Example</title> + <p>The simple server from + the <seealso marker="des_princ#ch1">Overview</seealso> chapter, + implemented using <c>sys</c> and <c>proc_lib</c> so it fits into + a supervision tree:</p> + <marker id="ex"></marker> + <pre> +-module(ch4). +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([init/1]). +-export([system_continue/3, system_terminate/4, + write_debug/3]). + +start_link() -> + proc_lib:start_link(ch4, init, [self()]). + +alloc() -> + ch4 ! {self(), alloc}, + receive + {ch4, Res} -> + Res + end. + +free(Ch) -> + ch4 ! {free, Ch}, + ok. + +init(Parent) -> + register(ch4, self()), + Chs = channels(), + Deb = sys:debug_options([]), + proc_lib:init_ack(Parent, {ok, self()}), + loop(Chs, Parent, Deb). + +loop(Chs, Parent, Deb) -> + receive + {From, alloc} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, alloc, From}), + {Ch, Chs2} = alloc(Chs), + From ! {ch4, Ch}, + Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + ch4, {out, {ch4, Ch}, From}), + loop(Chs2, Parent, Deb3); + {free, Ch} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, {free, Ch}}), + Chs2 = free(Ch, Chs), + loop(Chs2, Parent, Deb2); + + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, + ch4, Deb, Chs) + end. + +system_continue(Parent, Deb, Chs) -> + loop(Chs, Parent, Deb). + +system_terminate(Reason, Parent, Deb, Chs) -> + exit(Reason). + +write_debug(Dev, Event, Name) -> + io:format(Dev, "~p event = ~p~n", [Name, Event]).</pre> + <p>Example on how the simple debugging functions in <c>sys</c> can + be used for <c>ch4</c> as well:</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>ch4:start_link().</input> +{ok,<0.30.0>} +2> <input>sys:statistics(ch4, true).</input> +ok +3> <input>sys:trace(ch4, true).</input> +ok +4> <input>ch4:alloc().</input> +ch4 event = {in,alloc,<0.25.0>} +ch4 event = {out,{ch4,ch1},<0.25.0>} +ch1 +5> <input>ch4:free(ch1).</input> +ch4 event = {in,{free,ch1}} +ok +6> <input>sys:statistics(ch4, get).</input> +{ok,[{start_time,{{2003,6,13},{9,47,5}}}, + {current_time,{{2003,6,13},{9,47,56}}}, + {reductions,109}, + {messages_in,2}, + {messages_out,1}]} +7> <input>sys:statistics(ch4, false).</input> +ok +8> <input>sys:trace(ch4, false).</input> +ok +9> <input>sys:get_status(ch4).</input> +{status,<0.30.0>, + {module,ch4}, + [[{'$ancestors',[<0.25.0>]},{'$initial_call',{ch4,init,[<0.25.0>]}}], + running,<0.25.0>,[], + [ch1,ch2,ch3]]}</pre> + </section> + + <section> + <title>Starting the Process</title> + <p>A function in the <c>proc_lib</c> module should be used to + start the process. There are several possible functions, for + example <c>spawn_link/3,4</c> for asynchronous start and + <c>start_link/3,4,5</c> for synchronous start.</p> + <p>A process started using one of these functions will store + information that is needed for a process in a supervision tree, + for example about the ancestors and initial call.</p> + <p>Also, if the process terminates with another reason than + <c>normal</c> or <c>shutdown</c>, a crash report (see SASL + User's Guide) is generated.</p> + <p>In the example, synchronous start is used. The process is + started by calling <c>ch4:start_link()</c>:</p> + <code type="none"> +start_link() -> + proc_lib:start_link(ch4, init, [self()]).</code> + <p><c>ch4:start_link</c> calls the function + <c>proc_lib:start_link</c>. This function takes a module name, + a function name and an argument list as arguments and spawns + and links to a new process. The new process starts by executing + the given function, in this case <c>ch4:init(Pid)</c>, where + <c>Pid</c> is the pid (<c>self()</c>) of the first process, that + is the parent process.</p> + <p>In <c>init</c>, all initialization including name registration + is done. The new process must also acknowledge that it has been + started to the parent:</p> + <code type="none"> +init(Parent) -> + ... + proc_lib:init_ack(Parent, {ok, self()}), + loop(...).</code> + <p><c>proc_lib:start_link</c> is synchronous and does not return + until <c>proc_lib:init_ack</c> has been called.</p> + </section> + + <section> + <marker id="debug"></marker> + <title>Debugging</title> + <p>To support the debug facilites in <c>sys</c>, we need a + <em>debug structure</em>, a term <c>Deb</c> which is + initialized using <c>sys:debug_options/1</c>:</p> + <code type="none"> +init(Parent) -> + ... + Deb = sys:debug_options([]), + ... + loop(Chs, Parent, Deb).</code> + <p><c>sys:debug_options/1</c> takes a list of options as argument. + Here the list is empty, which means no debugging is enabled + initially. See <c>sys(3)</c> for information about possible + options.</p> + <p>Then for each <em>system event</em> that we want to be logged + or traced, the following function should be called.</p> + <code type="none"> +sys:handle_debug(Deb, Func, Info, Event) => Deb1</code> + <list type="bulleted"> + <item> + <p><c>Deb</c> is the debug structure.</p> + </item> + <item> + <p><c>Func</c> is a tuple <c>{Module, Name}</c> (or a fun) and + should specify a (user defined) function used to format + trace output. For each system event, the format function is + called as <c>Module:Name(Dev, Event, Info)</c>, where:</p> + <list type="bulleted"> + <item> + <p><c>Dev</c> is the IO device to which the output should + be printed. See <c>io(3)</c>.</p> + </item> + <item> + <p><c>Event</c> and <c>Info</c> are passed as-is from + <c>handle_debug</c>.</p> + </item> + </list> + </item> + <item> + <p><c>Info</c> is used to pass additional information to + <c>Func</c>, it can be any term and is passed as-is.</p> + </item> + <item> + <p><c>Event</c> is the system event. It is up to the user to + define what a system event is and how it should be + represented, but typically at least incoming and outgoing + messages are considered system events and represented by + the tuples <c>{in,Msg[,From]}</c> and <c>{out,Msg,To}</c>, + respectively.</p> + </item> + </list> + <p><c>handle_debug</c> returns an updated debug structure + <c>Deb1</c>.</p> + <p>In the example, <c>handle_debug</c> is called for each incoming + and outgoing message. The format function <c>Func</c> is + the function <c>ch4:write_debug/3</c> which prints the message + using <c>io:format/3</c>.</p> + <code type="none"> +loop(Chs, Parent, Deb) -> + receive + {From, alloc} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, alloc, From}), + {Ch, Chs2} = alloc(Chs), + From ! {ch4, Ch}, + Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + ch4, {out, {ch4, Ch}, From}), + loop(Chs2, Parent, Deb3); + {free, Ch} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, {free, Ch}}), + Chs2 = free(Ch, Chs), + loop(Chs2, Parent, Deb2); + ... + end. + +write_debug(Dev, Event, Name) -> + io:format(Dev, "~p event = ~p~n", [Name, Event]).</code> + </section> + + <section> + <marker id="msg"></marker> + <title>Handling System Messages</title> + <p><em>System messages</em> are received as:</p> + <code type="none"> +{system, From, Request}</code> + <p>The content and meaning of these messages do not need to be + interpreted by the process. Instead the following function + should be called:</p> + <code type="none"> +sys:handle_system_msg(Request, From, Parent, Module, Deb, State)</code> + <p>This function does not return. It will handle the system + message and then call:</p> + <code type="none"> +Module:system_continue(Parent, Deb, State)</code> + <p>if process execution should continue, or:</p> + <code type="none"> +Module:system_terminate(Reason, Parent, Deb, State)</code> + <p>if the process should terminate. Note that a process in a + supervision tree is expected to terminate with the same reason as + its parent.</p> + <list type="bulleted"> + <item><c>Request</c> and <c>From</c> should be passed as-is from + the system message to the call to <c>handle_system_msg</c>.</item> + <item><c>Parent</c> is the pid of the parent.</item> + <item><c>Module</c> is the name of the module.</item> + <item><c>Deb</c> is the debug structure.</item> + <item><c>State</c> is a term describing the internal state and + is passed to <c>system_continue</c>/<c>system_terminate</c>.</item> + </list> + <p>In the example:</p> + <code type="none"> +loop(Chs, Parent, Deb) -> + receive + ... + + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, + ch4, Deb, Chs) + end. + +system_continue(Parent, Deb, Chs) -> + loop(Chs, Parent, Deb). + +system_terminate(Reason, Parent, Deb, Chs) -> + exit(Reason).</code> + <p>If the special process is set to trap exits, note that if + the parent process terminates, the expected behavior is to + terminate with the same reason:</p> + <code type="none"> +init(...) -> + ..., + process_flag(trap_exit, true), + ..., + loop(...). + +loop(...) -> + receive + ... + + {'EXIT', Parent, Reason} -> + ..maybe some cleaning up here.. + exit(Reason); + ... + end.</code> + </section> + </section> + + <section> + <title>User-Defined Behaviours</title> + <p>To implement a user-defined behaviour, write code similar to + code for a special process but calling functions in a callback + module for handling specific tasks.</p> + <p>If it is desired that the compiler should warn for missing + callback functions, as it does for the OTP behaviours, implement + and export the function:</p> + <code type="none"> +behaviour_info(callbacks) -> + [{Name1,Arity1},...,{NameN,ArityN}].</code> + <p>where each <c>{Name,Arity}</c> specifies the name and arity of + a callback function.</p> + <p>When the compiler encounters the module attribute + <c>-behaviour(Behaviour).</c> in a module <c>Mod</c>, it will call + <c>Behaviour:behaviour_info(callbacks)</c> and compare the result + with the set of functions actually exported from <c>Mod</c>, and + issue a warning if any callback function is missing.</p> + <p>Example:</p> + <code type="none"> +%% User-defined behaviour module +-module(simple_server). +-export([start_link/2,...]). +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{init,1}, + {handle_req,1}, + {terminate,0}]. + +start_link(Name, Module) -> + proc_lib:start_link(?MODULE, init, [self(), Name, Module]). + +init(Parent, Name, Module) -> + register(Name, self()), + ..., + Dbg = sys:debug_options([]), + proc_lib:init_ack(Parent, {ok, self()}), + loop(Parent, Module, Deb, ...). + +...</code> + <p>In a callback module:</p> + <code type="none"> +-module(db). +-behaviour(simple_server). + +-export([init/0, handle_req/1, terminate/0]). + +...</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/sup4.fig b/system/doc/design_principles/sup4.fig new file mode 100644 index 0000000000..9127f9797c --- /dev/null +++ b/system/doc/design_principles/sup4.fig @@ -0,0 +1,32 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2100 750 2550 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +4 0 -1 0 0 2 14 0.0000 4 150 105 2250 1050 1\001 +-6 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 4762 2700 293 293 4575 2475 4950 2925 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 3112 2775 293 293 2925 2550 3300 3000 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 1987 2775 293 293 1800 2550 2175 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 675 2550 1125 2550 1125 3000 675 3000 675 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 900 2550 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1950 2475 2325 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3000 2475 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 1200 4500 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2625 2325 3450 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2625 3225 3525 2325 +4 0 -1 0 0 2 14 0.0000 4 150 240 1875 2850 P1\001 +4 0 -1 0 0 2 14 0.0000 4 150 240 3000 2850 P2\001 +4 0 -1 0 0 2 14 0.0000 4 150 255 4650 2775 Pn\001 +4 0 -1 0 0 0 14 0.0000 4 195 2025 3450 975 One for one supervision\001 +4 0 -1 0 0 0 14 0.0000 4 195 2490 3450 1200 If any child dies it is restarted\001 diff --git a/system/doc/design_principles/sup4.gif b/system/doc/design_principles/sup4.gif Binary files differnew file mode 100644 index 0000000000..fc099f9b06 --- /dev/null +++ b/system/doc/design_principles/sup4.gif diff --git a/system/doc/design_principles/sup4.ps b/system/doc/design_principles/sup4.ps new file mode 100644 index 0000000000..2507fcc36e --- /dev/null +++ b/system/doc/design_principles/sup4.ps @@ -0,0 +1,153 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup4.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:21 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 322 151 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-39.0 195.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (1) col-1 sh gr +% Ellipse +n 4762 2700 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3112 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1987 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 675 2550 m 1125 2550 l 1125 3000 l 675 3000 l cp gs col-1 s gr +% Polyline +n 900 2550 m 2250 1200 l gs col-1 s gr +% Polyline +n 1950 2475 m 2325 1200 l gs col-1 s gr +% Polyline +n 2400 1200 m 3000 2475 l gs col-1 s gr +% Polyline +n 2475 1200 m 4500 2550 l gs col-1 s gr +% Polyline +n 2625 2325 m 3450 3150 l gs col-1 s gr +% Polyline +n 2625 3225 m 3525 2325 l gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1875 2850 m +gs 1 -1 sc (P1) col-1 sh gr +/Times-Bold ff 210.00 scf sf +3000 2850 m +gs 1 -1 sc (P2) col-1 sh gr +/Times-Bold ff 210.00 scf sf +4650 2775 m +gs 1 -1 sc (Pn) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3450 975 m +gs 1 -1 sc (One for one supervision) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3450 1200 m +gs 1 -1 sc (If any child dies it is restarted) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup5.fig b/system/doc/design_principles/sup5.fig new file mode 100644 index 0000000000..554ab28ba0 --- /dev/null +++ b/system/doc/design_principles/sup5.fig @@ -0,0 +1,43 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 4762 2700 293 293 4575 2475 4950 2925 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 3112 2775 293 293 2925 2550 3300 3000 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 1987 2775 293 293 1800 2550 2175 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 675 2550 1125 2550 1125 3000 675 3000 675 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 900 2550 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1950 2475 2325 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3000 2475 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 1200 4500 2550 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2775 2325 3450 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2775 3150 3525 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4350 3075 5100 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4425 2175 5100 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1650 2325 2325 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1650 3150 2325 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 2325 1350 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 3150 1350 2325 +4 0 -1 0 0 2 14 0.0000 4 150 240 1875 2850 P1\001 +4 0 -1 0 0 2 14 0.0000 4 150 240 3000 2850 P2\001 +4 0 -1 0 0 2 14 0.0000 4 150 255 4650 2775 Pn\001 +4 0 -1 0 0 0 14 0.0000 4 195 2310 3525 1005 If any child dies all children\001 +4 0 -1 0 0 0 14 0.0000 4 150 3015 3525 1260 are terminated and all are restarted\001 +4 0 -1 0 0 2 14 0.0000 4 105 105 2250 1050 a\001 +4 0 -1 0 0 0 14 0.0000 4 195 2040 3525 750 all-for-one supervision\001 diff --git a/system/doc/design_principles/sup5.gif b/system/doc/design_principles/sup5.gif Binary files differnew file mode 100644 index 0000000000..1197278f63 --- /dev/null +++ b/system/doc/design_principles/sup5.gif diff --git a/system/doc/design_principles/sup5.ps b/system/doc/design_principles/sup5.ps new file mode 100644 index 0000000000..40eb07a132 --- /dev/null +++ b/system/doc/design_principles/sup5.ps @@ -0,0 +1,168 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup5.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:29 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 368 160 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-30.0 195.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 4762 2700 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3112 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1987 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 675 2550 m 1125 2550 l 1125 3000 l 675 3000 l cp gs col-1 s gr +% Polyline +n 900 2550 m 2250 1200 l gs col-1 s gr +% Polyline +n 1950 2475 m 2325 1200 l gs col-1 s gr +% Polyline +n 2400 1200 m 3000 2475 l gs col-1 s gr +% Polyline +n 2475 1200 m 4500 2550 l gs col-1 s gr +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +% Polyline +n 2775 2325 m 3450 3225 l gs col-1 s gr +% Polyline +n 2775 3150 m 3525 2400 l gs col-1 s gr +% Polyline +n 4350 3075 m 5100 2250 l gs col-1 s gr +% Polyline +n 4425 2175 m 5100 3150 l gs col-1 s gr +% Polyline +n 1650 2325 m 2325 3150 l gs col-1 s gr +% Polyline +n 1650 3150 m 2325 2400 l gs col-1 s gr +% Polyline +n 525 2325 m 1350 3150 l gs col-1 s gr +% Polyline +n 525 3150 m 1350 2325 l gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1875 2850 m +gs 1 -1 sc (P1) col-1 sh gr +/Times-Bold ff 210.00 scf sf +3000 2850 m +gs 1 -1 sc (P2) col-1 sh gr +/Times-Bold ff 210.00 scf sf +4650 2775 m +gs 1 -1 sc (Pn) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 1005 m +gs 1 -1 sc (If any child dies all children) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 1260 m +gs 1 -1 sc (are terminated and all are restarted) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (a) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 750 m +gs 1 -1 sc (all-for-one supervision) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup6.fig b/system/doc/design_principles/sup6.fig new file mode 100644 index 0000000000..9947cbb67c --- /dev/null +++ b/system/doc/design_principles/sup6.fig @@ -0,0 +1,46 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2100 750 2550 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +4 0 -1 0 0 2 14 0.0000 4 150 105 2250 1050 1\001 +-6 +6 1200 1650 1650 2100 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 1650 1650 1650 1650 2100 1200 2100 1200 1650 +4 0 -1 0 0 2 14 0.0000 4 150 105 1350 1950 1\001 +-6 +6 3975 2850 4425 3300 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3975 2850 4425 2850 4425 3300 3975 3300 3975 2850 +4 0 -1 0 0 2 14 0.0000 4 150 105 4125 3150 1\001 +-6 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5025 4125 270 270 5025 4125 5175 4350 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1425 3075 270 270 1425 3075 1575 3300 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2250 4125 270 270 2250 4125 2400 4350 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3900 4125 270 270 3900 4125 4050 4350 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2325 1200 1425 1650 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3300 1650 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3300 2100 2550 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3375 2100 4125 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 3300 2325 3825 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4200 3300 3900 3825 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4275 3300 4875 3900 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1425 2775 1425 2100 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3075 1650 3525 1650 3525 2100 3075 2100 3075 1650 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2325 2850 2775 2850 2775 3300 2325 3300 2325 2850 +4 0 -1 0 0 2 14 0.0000 4 105 105 3225 1950 a\001 +4 0 -1 0 0 2 14 0.0000 4 105 105 2475 3150 a\001 diff --git a/system/doc/design_principles/sup6.gif b/system/doc/design_principles/sup6.gif Binary files differnew file mode 100644 index 0000000000..2016f5bf67 --- /dev/null +++ b/system/doc/design_principles/sup6.gif diff --git a/system/doc/design_principles/sup6.ps b/system/doc/design_principles/sup6.ps new file mode 100644 index 0000000000..3e8a8d2ed4 --- /dev/null +++ b/system/doc/design_principles/sup6.ps @@ -0,0 +1,163 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup6.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:34 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 251 221 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-68.0 265.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (1) col-1 sh gr +% Polyline +n 1200 1650 m 1650 1650 l 1650 2100 l 1200 2100 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1350 1950 m +gs 1 -1 sc (1) col-1 sh gr +% Polyline +n 3975 2850 m 4425 2850 l 4425 3300 l 3975 3300 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +4125 3150 m +gs 1 -1 sc (1) col-1 sh gr +% Ellipse +n 5025 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1425 3075 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 2250 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3900 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 2325 1200 m 1425 1650 l gs col-1 s gr +% Polyline +n 2400 1200 m 3300 1650 l gs col-1 s gr +% Polyline +n 3300 2100 m 2550 2850 l gs col-1 s gr +% Polyline +n 3375 2100 m 4125 2850 l gs col-1 s gr +% Polyline +n 2475 3300 m 2325 3825 l gs col-1 s gr +% Polyline +n 4200 3300 m 3900 3825 l gs col-1 s gr +% Polyline +n 4275 3300 m 4875 3900 l gs col-1 s gr +% Polyline +n 1425 2775 m 1425 2100 l gs col-1 s gr +% Polyline +n 3075 1650 m 3525 1650 l 3525 2100 l 3075 2100 l cp gs col-1 s gr +% Polyline +n 2325 2850 m 2775 2850 l 2775 3300 l 2325 3300 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +3225 1950 m +gs 1 -1 sc (a) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2475 3150 m +gs 1 -1 sc (a) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml new file mode 100644 index 0000000000..067fd31961 --- /dev/null +++ b/system/doc/design_principles/sup_princ.xml @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Supervisor Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>sup_princ.xml</file> + </header> + <p>This section should be read in conjunction with + <c>supervisor(3)</c>, where all details about the supervisor + behaviour is given.</p> + + <section> + <title>Supervision Principles</title> + <p>A supervisor is responsible for starting, stopping and + monitoring its child processes. The basic idea of a supervisor is + that it should keep its child processes alive by restarting them + when necessary.</p> + <p>Which child processes to start and monitor is specified by a + list of <seealso marker="#spec">child specifications</seealso>. + The child processes are started in the order specified by this + list, and terminated in the reversed order.</p> + </section> + + <section> + <title>Example</title> + <p>The callback module for a supervisor starting the server from + the <seealso marker="gen_server_concepts#ex">gen_server chapter</seealso> + could look like this:</p> + <marker id="ex"></marker> + <code type="none"> +-module(ch_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link(ch_sup, []). + +init(_Args) -> + {ok, {{one_for_one, 1, 60}, + [{ch3, {ch3, start_link, []}, + permanent, brutal_kill, worker, [ch3]}]}}.</code> + <p><c>one_for_one</c> is the <seealso marker="#strategy">restart strategy</seealso>.</p> + <p>1 and 60 defines the <seealso marker="#frequency">maximum restart frequency</seealso>.</p> + <p>The tuple <c>{ch3, ...}</c> is a <seealso marker="#spec">child specification</seealso>.</p> + </section> + + <section> + <marker id="strategy"></marker> + <title>Restart Strategy</title> + + <section> + <title>one_for_one</title> + <p>If a child process terminates, only that process is restarted.</p> + <marker id="sup4"></marker> + <image file="../design_principles/sup4.gif"> + <icaption>One_For_One Supervision</icaption> + </image> + </section> + + <section> + <title>one_for_all</title> + <p>If a child process terminates, all other child processes are + terminated and then all child processes, including + the terminated one, are restarted.</p> + <marker id="sup5"></marker> + <image file="../design_principles/sup5.gif"> + <icaption>One_For_All Supervision</icaption> + </image> + </section> + + <section> + <title>rest_for_one</title> + <p>If a child process terminates, the 'rest' of the child + processes -- i.e. the child processes after the terminated + process in start order -- are terminated. Then the terminated + child process and the rest of the child processes are restarted.</p> + </section> + </section> + + <section> + <marker id="frequency"></marker> + <title>Maximum Restart Frequency</title> + <p>The supervisors have a built-in mechanism to limit the number of + restarts which can occur in a given time interval. This is + determined by the values of the two parameters <c>MaxR</c> and + <c>MaxT</c> in the start specification returned by the callback + function <c>init</c>:</p> + <code type="none"> +init(...) -> + {ok, {{RestartStrategy, MaxR, MaxT}, + [ChildSpec, ...]}}.</code> + <p>If more than <c>MaxR</c> number of restarts occur in the last + <c>MaxT</c> seconds, then the supervisor terminates all the child + processes and then itself.</p> + <p>When the supervisor terminates, then the next higher level + supervisor takes some action. It either restarts the terminated + supervisor, or terminates itself.</p> + <p>The intention of the restart mechanism is to prevent a situation + where a process repeatedly dies for the same reason, only to be + restarted again.</p> + </section> + + <section> + <marker id="spec"></marker> + <title>Child Specification</title> + <p>This is the type definition for a child specification:</p> + <code type="none"><![CDATA[ +{Id, StartFunc, Restart, Shutdown, Type, Modules} + Id = term() + StartFunc = {M, F, A} + M = F = atom() + A = [term()] + Restart = permanent | transient | temporary + Shutdown = brutal_kill | integer() >=0 | infinity + Type = worker | supervisor + Modules = [Module] | dynamic + Module = atom()]]></code> + <list type="bulleted"> + <item> + <p><c>Id</c> is a name that is used to identify the child + specification internally by the supervisor.</p> + </item> + <item> + <p><c>StartFunc</c> defines the function call used to start + the child process. It is a module-function-arguments tuple + used as <c>apply(M, F, A)</c>.</p> + <p>It should be (or result in) a call to + <c>supervisor:start_link</c>, <c>gen_server:start_link</c>, + <c>gen_fsm:start_link</c> or <c>gen_event:start_link</c>. + (Or a function compliant with these functions, see + <c>supervisor(3)</c> for details.</p> + </item> + <item> + <p><c>Restart</c> defines when a terminated child process should + be restarted.</p> + <list type="bulleted"> + <item>A <c>permanent</c> child process is always restarted.</item> + <item>A <c>temporary</c> child process is never restarted.</item> + <item>A <c>transient</c> child process is restarted only if it + terminates abnormally, i.e. with another exit reason than + <c>normal</c>.</item> + </list> + </item> + <item> + <marker id="shutdown"></marker> + <p><c>Shutdown</c> defines how a child process should be + terminated.</p> + <list type="bulleted"> + <item><c>brutal_kill</c> means the child process is + unconditionally terminated using <c>exit(Child, kill)</c>.</item> + <item>An integer timeout value means that the supervisor tells + the child process to terminate by calling + <c>exit(Child, shutdown)</c> and then waits for an exit + signal back. If no exit signal is received within + the specified time, the child process is unconditionally + terminated using <c>exit(Child, kill)</c>.</item> + <item>If the child process is another supervisor, it should be + set to <c>infinity</c> to give the subtree enough time to + shutdown.</item> + </list> + </item> + <item> + <p><c>Type</c> specifies if the child process is a supervisor or + a worker.</p> + </item> + <item> + <p><c>Modules</c> should be a list with one element + <c>[Module]</c>, where <c>Module</c> is the name of + the callback module, if the child process is a supervisor, + gen_server or gen_fsm. If the child process is a gen_event, + <c>Modules</c> should be <c>dynamic</c>.</p> + <p>This information is used by the release handler during + upgrades and downgrades, see + <seealso marker="release_handling">Release Handling</seealso>.</p> + </item> + </list> + <p>Example: The child specification to start the server <c>ch3</c> + in the example above looks like:</p> + <code type="none"> +{ch3, + {ch3, start_link, []}, + permanent, brutal_kill, worker, [ch3]}</code> + <p>Example: A child specification to start the event manager from + the chapter about + <seealso marker="events#mgr">gen_event</seealso>:</p> + <code type="none"> +{error_man, + {gen_event, start_link, [{local, error_man}]}, + permanent, 5000, worker, dynamic}</code> + <p>Both the server and event manager are registered processes which + can be expected to be accessible at all times, thus they are + specified to be <c>permanent</c>.</p> + <p><c>ch3</c> does not need to do any cleaning up before + termination, thus no shutdown time is needed but + <c>brutal_kill</c> should be sufficient. <c>error_man</c> may + need some time for the event handlers to clean up, thus + <c>Shutdown</c> is set to 5000 ms.</p> + <p>Example: A child specification to start another supervisor:</p> + <code type="none"> +{sup, + {sup, start_link, []}, + transient, infinity, supervisor, [sup]}</code> + </section> + + <section> + <marker id="super_tree"></marker> + <title>Starting a Supervisor</title> + <p>In the example above, the supervisor is started by calling + <c>ch_sup:start_link()</c>:</p> + <code type="none"> +start_link() -> + supervisor:start_link(ch_sup, []).</code> + <p><c>ch_sup:start_link</c> calls the function + <c>supervisor:start_link/2</c>. This function spawns and links to + a new process, a supervisor.</p> + <list type="bulleted"> + <item>The first argument, <c>ch_sup</c>, is the name of + the callback module, that is the module where the <c>init</c> + callback function is located.</item> + <item>The second argument, [], is a term which is passed as-is to + the callback function <c>init</c>. Here, <c>init</c> does not + need any indata and ignores the argument.</item> + </list> + <p>In this case, the supervisor is not registered. Instead its pid + must be used. A name can be specified by calling + <c>supervisor:start_link({local, Name}, Module, Args)</c> or + <c>supervisor:start_link({global, Name}, Module, Args)</c>.</p> + <p>The new supervisor process calls the callback function + <c>ch_sup:init([])</c>. <c>init</c> is expected to return + <c>{ok, StartSpec}</c>:</p> + <code type="none"> +init(_Args) -> + {ok, {{one_for_one, 1, 60}, + [{ch3, {ch3, start_link, []}, + permanent, brutal_kill, worker, [ch3]}]}}.</code> + <p>The supervisor then starts all its child processes according to + the child specifications in the start specification. In this case + there is one child process, <c>ch3</c>.</p> + <p>Note that <c>supervisor:start_link</c> is synchronous. It does + not return until all child processes have been started.</p> + </section> + + <section> + <title>Adding a Child Process</title> + <p>In addition to the static supervision tree, we can also add + dynamic child processes to an existing supervisor with + the following call:</p> + <code type="none"> +supervisor:start_child(Sup, ChildSpec)</code> + <p><c>Sup</c> is the pid, or name, of the supervisor. + <c>ChildSpec</c> is a <seealso marker="#spec">child specification</seealso>.</p> + <p>Child processes added using <c>start_child/2</c> behave in + the same manner as the other child processes, with the following + important exception: If a supervisor dies and is re-created, then + all child processes which were dynamically added to the supervisor + will be lost.</p> + </section> + + <section> + <title>Stopping a Child Process</title> + <p>Any child process, static or dynamic, can be stopped in + accordance with the shutdown specification:</p> + <code type="none"> +supervisor:terminate_child(Sup, Id)</code> + <p>The child specification for a stopped child process is deleted + with the following call:</p> + <code type="none"> +supervisor:delete_child(Sup, Id)</code> + <p><c>Sup</c> is the pid, or name, of the supervisor. + <c>Id</c> is the id specified in the <seealso marker="#spec">child specification</seealso>.</p> + <p>As with dynamically added child processes, the effects of + deleting a static child process is lost if the supervisor itself + restarts.</p> + </section> + + <section> + <title>Simple-One-For-One Supervisors</title> + <p>A supervisor with restart strategy <c>simple_one_for_one</c> is + a simplified one_for_one supervisor, where all child processes are + dynamically added instances of the same process.</p> + <p>Example of a callback module for a simple_one_for_one supervisor:</p> + <code type="none"> +-module(simple_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link(simple_sup, []). + +init(_Args) -> + {ok, {{simple_one_for_one, 0, 1}, + [{call, {call, start_link, []}, + temporary, brutal_kill, worker, [call]}]}}.</code> + <p>When started, the supervisor will not start any child processes. + Instead, all child processes are added dynamically by calling:</p> + <code type="none"> +supervisor:start_child(Sup, List)</code> + <p><c>Sup</c> is the pid, or name, of the supervisor. + <c>List</c> is an arbitrary list of terms which will be added to + the list of arguments specified in the child specification. If + the start function is specified as <c>{M, F, A}</c>, then + the child process is started by calling + <c>apply(M, F, A++List)</c>.</p> + <p>For example, adding a child to <c>simple_sup</c> above:</p> + <code type="none"> +supervisor:start_child(Pid, [id1])</code> + <p>results in the child process being started by calling + <c>apply(call, start_link, []++[id1])</c>, or actually:</p> + <code type="none"> +call:start_link(id1)</code> + </section> + + <section> + <title>Stopping</title> + <p>Since the supervisor is part of a supervision tree, it will + automatically be terminated by its supervisor. When asked to + shutdown, it will terminate all child processes in reversed start + order according to the respective shutdown specifications, and + then terminate itself.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/warning.gif b/system/doc/design_principles/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/design_principles/warning.gif diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk new file mode 100644 index 0000000000..f34d1c9a0f --- /dev/null +++ b/system/doc/design_principles/xmlfiles.mk @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +DESIGN_PRINCIPLES_CHAPTER_FILES = \ + applications.xml \ + appup_cookbook.xml \ + des_princ.xml \ + distributed_applications.xml \ + events.xml \ + fsm.xml \ + gen_server_concepts.xml \ + included_applications.xml \ + release_handling.xml \ + release_structure.xml \ + spec_proc.xml \ + sup_princ.xml diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile new file mode 100644 index 0000000000..f51313de84 --- /dev/null +++ b/system/doc/efficiency_guide/Makefile @@ -0,0 +1,117 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/efficiency_guide + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES = $(EFF_GUIDE_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +PS_FILES = digger.ps + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +C_FILES = \ + +ERL_FILES = all.erl\ + bench.erl\ + call_bm.erl + +HRL_FILES = bench.hrl + + +MISC_FILES = call_result.html\ + README + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/efficiency_guide + +EXTRA_FILES = $(ERL_FILES) \ + $(HRL_FILES) \ + $(MISC_FILES) + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + + +release_spec: + + + diff --git a/system/doc/efficiency_guide/README b/system/doc/efficiency_guide/README new file mode 100644 index 0000000000..6830a46d9e --- /dev/null +++ b/system/doc/efficiency_guide/README @@ -0,0 +1,122 @@ +Benchmark framework +------------------- + +This benchmark framework consists of the files: +bench.erl - see bench module below +bench.hrl - Defines some useful macros +all.erl - see all module below + +bench module +----------- + +The module bench is a generic module that measures execution time +of functions in callback modules and writes an html-report on the outcome. + +When you execute the function bench:run/0 it will compile and run all +benchmark modules in the current directory. + +all module +----------- + +In the all module there is a function called releases/0 that you can +edit to contain all your erlang installations and then you can +run your benchmarks on several erlang versions using only one command i.e. +all:run(). + +Requirements on callback modules +--------------------------------- + +* A callback module must be named <callbackModuleName>_bm.erl + +* The module must export the function benchmarks/0 that must return: + {Iterations, [Name1,Name2...]} where Iterations is the number of + times each benchmark should be run. Name1, Name2 and so one are the + name of exported functions in the module. + +* The exported functions Name1 etc. must take one argument i.e. the number + of iterations and should return the atom ok. + +* The functions in a benchmark module should represent different + ways/different sequential algorithms for doing something. And the + result will be how fast they are compared to each other. + +Files created +-------------- + +Files that are created in the current directory are *.bmres and +index.html. The file(s) with the extension "bmres" are an intermediate +representation of the benchmark results and is only meant to be read +by the reporting mechanism defined in bench.erl. The index.html file +is the report telling you how good the benchmarks are in comparison to +each other. If you run your test on several erlang releases the +html-file will include the result for all versions. + + +Pitfalls +--------- +To get meaningful measurements, you should make sure that: + +* The total execution time is at least several seconds. + +* That any time spent in setup before entering the measurement loop is very + small compared to the total time. + +* That time spent by the loop itself is small compared to the total execution + time + +Consider the following example of a benchmark function that does +a local function call. + +local_call(0) -> ok; +local_call(Iter) -> + foo(), % Local function call + local_call(Iter-1). + +The problem is that both "foo()" and "local_call(Iter-1)" takes about +the same amount of time. To get meaningful figures you'll need to make +sure that the loop overhead will not be visible. In this case we can +take help of a macro in bench.hrl to repeat the local function call +many times, making sure that time spent calling the local function is +relatively much longer than the time spent iterating. Of course, all +benchmarks in the same module must be repeated the same number of +times; thus external_call will look like + +external_call(0) -> ok; +external_call(Iter) -> + ?rep20(?MODULE:foo()), + external_call(Iter-1). + +This technique is only necessary if the operation we are testing executes +really fast. + +If you for instance want to test a sort routine we can keep it simple: + +sorted(Iter) -> + do_sort(Iter, lists:seq(0, 63)). + +do_sort(0, List) -> ok; +do_sort(Iter, List) -> + lists:sort(List), + do_sort(Iter-1, List). + +The call to lists:seq/2 is only done once. The loop overhead in the +do_sort/2 function is small compared to the execution time of lists:sort/1. + +Error handling +--------------- + +Any error enforced by a callback module will result in exit of the benchmark +program and an errormessage that should give a good idea of what is wrong. + + + + + + + + + + + + + diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml new file mode 100644 index 0000000000..0ec3afbd59 --- /dev/null +++ b/system/doc/efficiency_guide/advanced.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Advanced</title> + <prepared>Kenneth Lundin</prepared> + <docno></docno> + <date>2001-08-21</date> + <rev></rev> + <file>advanced.xml</file> + </header> + + <section> + <title>Memory</title> + <p>A good start when programming efficiently is to have knowledge about + how much memory different data types and operations require. It is + implementation-dependent how much memory the Erlang data types and + other items consume, but here are some figures for + erts-5.2 system (OTP release R9B). (There have been no significant + changes in R13.)</p> + + <p>The unit of measurement is memory words. There exists both a 32-bit + and a 64-bit implementation, and a word is therefore, 4 bytes or + 8 bytes, respectively.</p> + <table> + <row> + <cell align="center" valign="middle">Data type</cell> + <cell align="center" valign="middle">Memory size</cell> + </row> + <row> + <cell align="left" valign="middle">Integer (-16#7FFFFFF < i <16#7FFFFFF)</cell> + <cell align="left" valign="middle">1 word</cell> + </row> + <row> + <cell align="left" valign="middle">Integer (big numbers)</cell> + <cell align="left" valign="middle">3..N words</cell> + </row> + <row> + <cell align="left" valign="middle">Atom</cell> + <cell align="left" valign="middle">1 word. Note: an atom refers into + an atom table which also consumes memory. + The atom text is stored once for each unique atom in this table. + The atom table is <em>not</em> garbage-collected.</cell> + </row> + <row> + <cell align="left" valign="middle">Float</cell> + <cell align="left" valign="middle">On 32-bit architectures: 4 words <br></br> +On 64-bit architectures: 3 words</cell> + </row> + <row> + <cell align="left" valign="middle">Binary</cell> + <cell align="left" valign="middle">3..6 + data (can be shared)</cell> + </row> + <row> + <cell align="left" valign="middle">List</cell> + <cell align="left" valign="middle">1 word per element + the size of each element</cell> + </row> + <row> + <cell align="left" valign="middle">String (is the same as a list of integers)</cell> + <cell align="left" valign="middle">2 words per character</cell> + </row> + <row> + <cell align="left" valign="middle">Tuple</cell> + <cell align="left" valign="middle">2 words + the size of each element</cell> + </row> + <row> + <cell align="left" valign="middle">Pid</cell> + <cell align="left" valign="middle">1 word for a process identifier from the current local node, and 5 words for a process identifier from another node. Note: a process identifier refers into a process table and a node table which also consumes memory.</cell> + </row> + <row> + <cell align="left" valign="middle">Port</cell> + <cell align="left" valign="middle">1 word for a port identifier from the current local node, and 5 words for a port identifier from another node. Note: a port identifier refers into a port table and a node table which also consumes memory.</cell> + </row> + <row> + <cell align="left" valign="middle">Reference</cell> + <cell align="left" valign="middle">On 32-bit architectures: 5 words for a reference from the current local node, and 7 words for a reference from another node. <br></br> +On 64-bit architectures: 4 words for a reference from the current local node, and 6 words for a reference from another node. Note: a reference refers into a node table which also consumes memory.</cell> + </row> + <row> + <cell align="left" valign="middle">Fun</cell> + <cell align="left" valign="middle">9..13 words + size of environment. Note: a fun refers into a fun table which also consumes memory.</cell> + </row> + <row> + <cell align="left" valign="middle">Ets table</cell> + <cell align="left" valign="middle">Initially 768 words + the size of each element (6 words + size of Erlang data). The table will grow when necessary.</cell> + </row> + <row> + <cell align="left" valign="middle">Erlang process</cell> + <cell align="left" valign="middle">327 words when spawned including a heap of 233 words.</cell> + </row> + <tcaption>Memory size of different data types</tcaption> + </table> + </section> + + <section> + <title>System limits</title> + <p>The Erlang language specification puts no limits on number of processes, + length of atoms etc., but for performance and memory saving reasons, + there will always be limits in a practical implementation of the Erlang + language and execution environment.</p> + <taglist> + <tag><em>Processes</em></tag> + <item> + <p>The maximum number of simultaneously alive Erlang processes is + by default 32768. This limit can be raised up to at most 268435456 + processes at startup (see documentation of the system flag + <seealso marker="erts:erl#max_processes">+P</seealso> in the + <seealso marker="erts:erl">erl(1)</seealso> documentation). + The maximum limit of 268435456 processes will at least on a 32-bit + architecture be impossible to reach due to memory shortage.</p> + </item> + <tag><em>Distributed nodes</em></tag> + <item> + <taglist> + <tag>Known nodes</tag> + <item> + <p>A remote node Y has to be known to node X if there exist + any pids, ports, references, or funs (Erlang data types) from Y + on X, or if X and Y are connected. The maximum number of remote + nodes simultaneously/ever known to a node is limited by the + <seealso marker="#atoms">maximum number of atoms</seealso> + available for node names. All data concerning remote nodes, + except for the node name atom, are garbage-collected.</p> + </item> + <tag>Connected nodes</tag> + <item>The maximum number of simultaneously connected nodes is limited by + either the maximum number of simultaneously known remote nodes, + <seealso marker="#ports">the maximum number of (Erlang) ports</seealso> + available, or + <seealso marker="#files_sockets">the maximum number of sockets</seealso> + available.</item> + </taglist> + </item> + <tag><em>Characters in an atom</em></tag> + <item>255</item> + <tag><em>Atoms </em></tag> + <item> <marker id="atoms"></marker> +The maximum number of atoms is 1048576. </item> + <tag><em>Ets-tables</em></tag> + <item>The default is 1400, can be changed with the environment variable <c>ERL_MAX_ETS_TABLES</c>.</item> + <tag><em>Elements in a tuple</em></tag> + <item>The maximum number of elements in a tuple is 67108863 (26 bit unsigned integer). Other factors + such as the available memory can of course make it hard to create a tuple of that size. </item> + <tag><em>Size of binary</em></tag> + <item>In the 32-bit implementation of Erlang, 536870911 bytes is the + largest binary that can be constructed or matched using the bit syntax. + (In the 64-bit implementation, the maximum size is 2305843009213693951 bytes.) + If the limit is exceeded, bit syntax construction will fail with a + <c>system_limit</c> exception, while any attempt to match a binary that is + too large will fail. + This limit is enforced starting with the R11B-4 release; in earlier releases, + operations on too large binaries would in general either fail or give incorrect + results. + In future releases of Erlang/OTP, other operations that create binaries (such as + <c>list_to_binary/1</c>) will probably also enforce the same limit.</item> + <tag><em>Total amount of data allocated by an Erlang node</em></tag> + <item>The Erlang runtime system can use the complete 32 (or 64) bit address space, + but the operating system often limits a single process to use less than that.</item> + <tag><em>length of a node name</em></tag> + <item>An Erlang node name has the form host@shortname or host@longname. The node name is + used as an atom within the system so the maximum size of 255 holds for the node name too.</item> + <tag><em>Open ports</em></tag> + <item> + <marker id="ports"></marker> + <p>The maximum number of simultaneously open Erlang ports is + by default 1024. This limit can be raised up to at most 268435456 + at startup (see environment variable + <seealso marker="erts:erlang#ERL_MAX_PORTS">ERL_MAX_PORTS</seealso> + in <seealso marker="erts:erlang">erlang(3)</seealso>) + The maximum limit of 268435456 open ports will at least on a 32-bit + architecture be impossible to reach due to memory shortage.</p> + </item> + <tag><em>Open files, and sockets</em></tag> + <item> <marker id="files_sockets"></marker> + + The maximum number of simultaneously open files and sockets + depend on + <seealso marker="#ports">the maximum number of Erlang ports</seealso> + available, and operating system specific settings and limits.</item> + <tag><em>Number of arguments to a function or fun</em></tag> + <item>256</item> + </taglist> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/all.erl b/system/doc/efficiency_guide/all.erl new file mode 100644 index 0000000000..a0f7809422 --- /dev/null +++ b/system/doc/efficiency_guide/all.erl @@ -0,0 +1,106 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(all). + +%% User interface +-export([run/0]). + +%% Interna constants +-define(NORMAL, 0). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Interface +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------------------------------------------------------------------- +%% run() -> _ +%% +%% Runs all benchmark modules in the current directory on all erlang +%% installations specified by releases/0 +%%--------------------------------------------------------------------------- +run() -> + %% Delete previous intermediate test result files. + lists:foreach(fun(F) -> file:delete(F) end, filelib:wildcard("*.bmres")), + lists:foreach(fun run/1, releases()). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Internal functions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------------------------------------------------------------------- +%% run(Release) -> _ +%% Release = string() - Erlang release +%% Help functions to run/0 +%%--------------------------------------------------------------------------- +run(Release) -> + command(Release ++ " -noshell -compile bench -s erlang halt"), + command(Release ++ " -noshell -s bench run -s erlang halt"). +%%--------------------------------------------------------------------------- +%% command(Command) -> _ +%% Command = string() - is the name and arguments of the external +%% program which will be run +%%--------------------------------------------------------------------------- +command(Command) -> + io:format("~s\n", [Command]), % Progress info to user + Port = open_port({spawn,Command}, [exit_status, in]), + print_output(Port). +%%--------------------------------------------------------------------------- +%% print_output(Port) -> _ +%% Port = port() +%% Print data from the port i.e. output from external program, +%% on standard out. +%%--------------------------------------------------------------------------- +print_output(Port) -> + receive + {Port, {data,Bytes}} -> + io:put_chars(Bytes), + print_output(Port); + {Port, {exit_status, ?NORMAL}} -> + ok + end. +%%--------------------------------------------------------------------------- +%% run() -> Releases +%% Releases = [Release |_] +%% Release = string() - Erlang release +%% Defines which erlang releases to run on +%% --- Change this function to reflect your own erlang installations --- +%%--------------------------------------------------------------------------- +releases() -> + ["/usr/local/otp/releases/otp_beam_sunos5_r7b01_patched/bin/erl", + "/usr/local/otp/releases/otp_beam_sunos5_r8b_patched/bin/erl"]. + + + + + + + + + + + + + + + + + + + + + diff --git a/system/doc/efficiency_guide/appendix.xml b/system/doc/efficiency_guide/appendix.xml new file mode 100644 index 0000000000..631ef9bee7 --- /dev/null +++ b/system/doc/efficiency_guide/appendix.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2002</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Appendix - Programs</title> + <prepared>Ingela Anderton</prepared> + <docno></docno> + <date>2002-09-23</date> + <rev></rev> + <file>appendix.sgml</file> + </header> + <p>This appendix contains the programs referred to in the previous + chapters within the Efficiency Guide.</p> + + <section> + <marker id="bench"></marker> + <title>bench.erl</title> + <codeinclude file="bench.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="bench_hrl"></marker> + <title>bench.hrl</title> + <codeinclude file="bench.hrl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="all"></marker> + <title>all.erl</title> + <codeinclude file="all.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="readme"></marker> + <title>README</title> + <codeinclude file="README" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="call_bm"></marker> + <title>call_bm.erl</title> + <codeinclude file="call_bm.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="call_result"></marker> + <title>index.html</title> + <codeinclude file="call_result.html" tag="" type="none"></codeinclude> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/bench.erl b/system/doc/efficiency_guide/bench.erl new file mode 100644 index 0000000000..8f26b8d0af --- /dev/null +++ b/system/doc/efficiency_guide/bench.erl @@ -0,0 +1,488 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% + +-module(bench). + +%% User interface +-export([run/0]). + +%% Exported to be used in spawn +-export([measure/4]). + +%% Internal constants +-define(MAX, 999999999999999). +-define(RANGE_MAX, 16#7ffffff). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Interface +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------------------------------------------------------------------- +%% run() -> _ +%% +%% Compiles and runs all benchmarks in the current directory, +%% and creates a report +%%--------------------------------------------------------------------------- +run() -> + run(compiler_options()). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Generic Benchmark functions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------------------------------------------------------------------- +%% compiler_options() -> OptionsList +%% OptionsList = list() - See Erlang/OTP module compile +%%--------------------------------------------------------------------------- +compiler_options() -> + [report_errors, report_warnings]. + +%%--------------------------------------------------------------------------- +%% run(OptionsList) -> +%% OptionsList = list() - See Erlang/OTP module compile +%% +%% Help function to run/0. +%%--------------------------------------------------------------------------- +run(OptionsList) -> + Bms = compile_benchmarks(OptionsList), + run_benchmarks(Bms), + report(). + +%%--------------------------------------------------------------------------- +%% compile_benchmarks(OptionsList) -> [BmInfo| _] +%% OptionsList = list() - See Erlang/OTP module compile +%% BmInfo = {Module, Iterations, [BmFunctionName| _]} +%% Module = atom() +%% Iterations = integer() +%% BmFunctionName = atom() +%% +%% Compiles all benchmark modules in the current directory and +%% returns info about the benchmarks. +%%--------------------------------------------------------------------------- +compile_benchmarks(OptionsList) -> + {ok, FilesInCurrentDir} = file:list_dir("."), + ErlFiles = [ErlFile || ErlFile <- lists:sort(FilesInCurrentDir), + lists:suffix(".erl", ErlFile)], + lists:foldr(fun(File, BmInfoAcc) -> + case lists:suffix("_bm.erl", File) of + true -> + BmInfo = bm_compile(File, OptionsList), + [BmInfo | BmInfoAcc]; + false -> + just_compile(File, OptionsList), + BmInfoAcc + end + end, [], ErlFiles). + +%%--------------------------------------------------------------------------- +%% just_compile(FileName, OptionsList) -> ok +%% FileName = string() +%% OptionsList = list() - See Erlang/OTP module compile +%% +%% Compiles a support module. +%%--------------------------------------------------------------------------- +just_compile(FileName, OptionsList) -> + io:format("Compiling ~s...\n", [FileName]), % Progress info to user + case c:c(FileName, OptionsList) of + {ok, _Mod} -> + ok; + %% If compilation fails there is no point in trying to continue + error -> + Reason = + lists:flatten( + io_lib:format("Could not compile file ~s", [FileName])), + exit(self(), Reason) + end. +%%--------------------------------------------------------------------------- +%% bm_compile(FileName, OptionsList) -> BmInfo +%% FileName = string() +%% OptionsList = list() - See Erlang/OTP module compile +%% BmInfo = {Module, Iterations, [BmFunctionName| _]} +%% Iterations = integer() +%% Module = atom() +%% BmFunctionName = atom() +%% +%% Compiles the benchmark module implemented in <FileName> and returns +%% information about the benchmark tests. +%%--------------------------------------------------------------------------- +bm_compile(FileName, OptionsList) -> + io:format("Compiling ~s...\n", [FileName]), % Progress info to user + case c:c(FileName, OptionsList) of + {ok, Mod} -> + bm_cases(Mod); + %% If compilation fails there is no point in trying to continue + error -> + Reason = + lists:flatten( + io_lib:format("Could not compile file ~s", [FileName])), + exit(self(), Reason) + end. +%%--------------------------------------------------------------------------- +%% bm_cases(Module) -> {Module, Iter, [BmFunctionName |_]} +%% Module = atom() +%% Iter = integer() +%% BmFunctionName = atom() +%% +%% Fetches the number of iterations and the names of the benchmark +%% functions for the module <Module>. +%%--------------------------------------------------------------------------- +bm_cases(Module) -> + case catch Module:benchmarks() of + {Iter, BmList} when integer(Iter), list(BmList) -> + {Module, Iter, BmList}; + %% The benchmark is incorrect implemented there is no point in + %% trying to continue + Other -> + Reason = + lists:flatten( + io_lib:format("Incorrect return value: ~p " + "from ~p:benchmarks()", + [Other, Module])), + exit(self(), Reason) + end. +%%--------------------------------------------------------------------------- +%% run_benchmarks(Bms) -> +%% Bms = [{Module, Iter, [BmFunctionName |_]} | _] +%% Module = atom() +%% Iter = integer() +%% BmFunctionName = atom() +%% +%% Runs all the benchmark tests described in <Bms>. +%%--------------------------------------------------------------------------- +run_benchmarks(Bms) -> + Ver = erlang:system_info(version), + Machine = erlang:system_info(machine), + SysInfo = {Ver,Machine}, + + Res = [bms_run(Mod, Tests, Iter, SysInfo) || {Mod,Iter,Tests} <- Bms], + + %% Create an intermediate file that is later used to generate a bench + %% mark report. + Name = Ver ++ [$.|Machine] ++ ".bmres", + {ok, IntermediatFile} = file:open(Name, [write]), + + %% Create mark that identifies version of the benchmark modules + io:format(IntermediatFile, "~p.\n", [erlang:phash(Bms, ?RANGE_MAX)]), + + io:format(IntermediatFile, "~p.\n", [Res]), + file:close(IntermediatFile). + +%%--------------------------------------------------------------------------- +%% bms_run(Module, BmTests, Iter, Info) -> +%% Module = atom(), +%% BmTests = [BmFunctionName|_], +%% BmFunctionName = atom() +%% Iter = integer(), +%% SysInfo = {Ver, Machine} +%% Ver = string() +%% Machine = string() +%% +%% Runs all benchmark tests in module <Module>. +%%--------------------------------------------------------------------------- +bms_run(Module, BmTests, Iter, SysInfo) -> + io:format("Running ~s:", [Module]), % Progress info to user + Res = + {Module,{SysInfo,[{Bm, bm_run(Module, Bm, Iter)} || Bm <- BmTests]}}, + io:nl(), + Res. +%%--------------------------------------------------------------------------- +%% bm_run(Module, BmTest, Iter) -> Elapsed +%% Module = atom(), +%% BmTest = atom(), +%% Iter = integer() +%% Elapsed = integer() - elapsed time in milliseconds. +%% +%% Runs the benchmark Module:BmTest(Iter) +%%--------------------------------------------------------------------------- +bm_run(Module, BmTest, Iter) -> + io:format(" ~s", [BmTest]), % Progress info to user + spawn_link(?MODULE, measure, [self(), Module, BmTest, Iter]), + receive + {Elapsed, ok} -> + Elapsed; + {_Elapsed, Fault} -> + io:nl(), + Reason = + lists:flatten( + io_lib:format("~w", [Fault])), + exit(self(), Reason) + end. +%%--------------------------------------------------------------------------- +%% measure(Parent, Module, BmTest, Iter) -> _ +%% Parent = pid(), +%% Module = atom(), +%% BmTest = atom(), +%% Iter = integer() +%% +%% Measures the time it take to execute Module:Bm(Iter) +%% and send the result to <Parent>. +%%--------------------------------------------------------------------------- +measure(Parent, Module, BmTest, Iter) -> + statistics(runtime), + Res = (catch apply(Module, BmTest, [Iter])), + {_TotalRunTime, TimeSinceLastCall} = statistics(runtime), + Parent ! {TimeSinceLastCall, Res}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Report functions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------------------------------------------------------------------- +%% report() -> _ +%% +%% Creates a report of the bench marking test that appeals to a human. +%% Currently this means creating a html-file. (Other formats could be added) +%%--------------------------------------------------------------------------- +report() -> + {ok, AllFiles} = file:list_dir("."), + BmResultFiles = [File || File <- AllFiles, lists:suffix(".bmres", File)], + + Results = fetch_bmres_data(BmResultFiles), + create_report(Results). + +%%--------------------------------------------------------------------------- +%% fetch_bmres_data(BmResultFiles) -> Results +%% BmResultFiles = [FileName | _] +%% FileName = string() +%% Results = [[{Bm, Res} | _]] +%% Bm = atom() - Name of benchmark module +%% Res = [{VersionInfo, [{Test, Time} | _]}] +%% VersionInfo = {Ver, Machine} +%% Ver = string() +%% Machine = string() +%% Test = atom() +%% Time = integer() +%% +%% Reads result data from intermediate files +%%--------------------------------------------------------------------------- +fetch_bmres_data(BmResultFiles) -> + fetch_bmres_data(BmResultFiles, [], undefined). + +%%--------------------------------------------------------------------------- +%% fetch_bmres_data(BmResultFiles, AccResData, Check) -> Results +%% BmResultFiles = [FileName | _] +%% FileName = string() +%% AccResData = see Results fetch_bmres_data/1 +%% Check = integer() | undefined (first time) +%% +%% Help function to fetch_bmres_data/1 +%%--------------------------------------------------------------------------- +fetch_bmres_data([], AccResData, _Check) -> + AccResData; + +fetch_bmres_data([Name | BmResultFiles], AccResData, Check) -> + {DataList, NewCheck} = read_bmres_file(Name, Check), + fetch_bmres_data(BmResultFiles, [DataList| AccResData], NewCheck). + +%%--------------------------------------------------------------------------- +%% read_bmres_file(Name, Check) -> +%% Name = string() +%% Check = integer() | undefined +%% +%% Reads the data from the result files. Checks that all result +%% files where created with the same set of tests. +%%--------------------------------------------------------------------------- +read_bmres_file(Name, Check) -> + case file:consult(Name) of + {ok, [Check1, List]} when Check =:= undefined, integer(Check1) -> + {List, Check1}; + {ok, [Check, List]} when integer(Check) -> + {List, Check}; + {ok, [Check1, _List]} when integer(Check1) -> + Reason = + lists:flatten( + io_lib:format("Different test setup, remove old setup " + "result by removing *.bmres files and " + "try again", [])), + exit(self(), Reason); + {error, Reason} when atom(Reason) -> + exit(self(), Reason); + {error, Reason} -> + exit(self(), file:format(Reason)) + end. + +%%--------------------------------------------------------------------------- +%% create_report(Results) -> +%% Results = see Results fetch_bmres_data/1 +%% +%% Organizes <Result> so it will be right for create_html_report/1 +%% i.e. group results for the same benchmark test, run on different versions +%% of erlang. +%%--------------------------------------------------------------------------- +create_report(Results) -> + Dictionary = + lists:foldl(fun(BmResultList, Dict0) -> + lists:foldl(fun({Bm, VerResult}, Dict1) -> + dict:append(Bm, VerResult, + Dict1) + end,Dict0, BmResultList) + end, + dict:new(), Results), + + create_html_report(dict:to_list(Dictionary)). +%%--------------------------------------------------------------------------- +%% create_html_report(ResultList) -> _ +%% ResultList = [{Bm, Res} | _] +%% Bm = atom() - Name of benchmark module +%% Res = [{VersionInfo, [{Test, Time} | _]} | _] +%% VersionInfo = {Ver, Machine} +%% Ver = string() +%% Machine = string() +%% Test = atom() +%% Time = integer() +%% +%% Writes the result to an html-file +%%--------------------------------------------------------------------------- +create_html_report(ResultList) -> + + {ok, OutputFile} = file:open("index.html", [write]), + + %% Create the begining of the result html-file. + Head = Title = "Benchmark Results", + io:put_chars(OutputFile, "<html>\n"), + io:put_chars(OutputFile, "<head>\n"), + io:format(OutputFile, "<title>~s</title>\n", [Title]), + io:put_chars(OutputFile, "</head>\n"), + io:put_chars(OutputFile, "<body bgcolor=\"#FFFFFF\" text=\"#000000\"" ++ + " link=\"#0000FF\" vlink=\"#800080\" alink=\"#FF0000\">\n"), + io:format(OutputFile, "<h1>~s</h1>\n", [Head]), + + %% Add the result tables + lists:foreach(fun(Element) -> + create_html_table(OutputFile, Element) end, + ResultList), + + %% Put in the end-html tags + io:put_chars(OutputFile, "</body>\n"), + io:put_chars(OutputFile, "</html>\n"), + + file:close(OutputFile). + +%%--------------------------------------------------------------------------- +%% create_html_table(File, {Bm, Res}) -> _ +%% File = file() - html file to write data to. +%% Bm = atom() - Name of benchmark module +%% Res = [{VersionInfo, [{Test, Time} | _]}] +%% VersionInfo = {Ver, Machine} +%% Ver = string() +%% Machine = string() +%% Test = atom() +%% Time = integer() +%% +%% Creates a html table that displays the result of the benchmark <Bm>. +%%--------------------------------------------------------------------------- +create_html_table(File, {Bm, Res}) -> + + {MinTime, Order} = min_time_and_sort(Res), + + io:format(File, "<h2>~s</h2>\n" , [Bm]), + + %% Fun that calculates relative measure values and puts them in + %% a dictionary + RelativeMesureFun = fun({TestName, Time}, Dict1) -> + dict:append(TestName, Time/MinTime, Dict1) + end, + + %% For all erlang versions that the benchmark tests has been run, + %% calculate the relative measure values and put them in a dictionary. + ResultDict = + lists:foldl(fun({_VerInfo, Bms}, Dict0) -> + lists:foldl(RelativeMesureFun, Dict0, Bms) end, + dict:new(), Res), + + %% Create the table and its headings + io:put_chars(File, "<table border=0 cellpadding=1><tr>" + "<td bgcolor=\"#000000\">\n"), + io:put_chars(File, "<table cellpadding=3 border=0 cellspacing=1>\n"), + io:put_chars(File, "<tr bgcolor=white>"), + io:put_chars(File, "<td>Test</td>"), + Heads = table_headers(Res), + lists:foreach(fun({Ver,Machine}) -> io:format(File, "<td>~s<br>~s</td>", + [Ver,Machine]) end, Heads), + io:put_chars(File, "</tr>\n"), + + %% Create table rows + lists:foreach(fun(Name) -> + create_html_row(File, Name, ResultDict) + end, Order), + + %% Tabel end-tags + io:put_chars(File, "</table></td></tr></table>\n"), + + %% Create link to benchmark source code + io:format(File, "<p><a href=\"~s.erl\">Source for ~s.erl</a>\n", + [Bm,Bm]). + +%%--------------------------------------------------------------------------- +%% create_html_row(File, Name, Dict) -> _ +%% File = file() - html file to write data to. +%% Name = atom() - Name of benchmark test +%% Dict = dict() - Dictonary where the relative time measures for +%% the test can be found. +%% +%% Creates an actual html table-row. +%%--------------------------------------------------------------------------- +create_html_row(File, Name, Dict) -> + ReletiveTimes = dict:fetch(Name, Dict), + io:put_chars(File, "<tr bgcolor=white>\n"), + io:format(File, "<td>~s</td>", [Name]), + lists:foreach(fun(Time) -> + io:format(File, "<td>~-8.2f</td>", [Time]) end, + ReletiveTimes), + io:put_chars(File, "</tr>\n"). + +%%--------------------------------------------------------------------------- +%% min_time_and_sort(ResultList) -> {MinTime, Order} +%% ResultList = [{VersionInfo, [{Test, Time} | _]}] +%% MinTime = integer() - The execution time of the fastes test +%% Order = [BmFunctionName|_] - the order of the testcases in +%% increasing execution time. +%% BmFunctionName = atom() +%%--------------------------------------------------------------------------- +min_time_and_sort(ResultList) -> + + %% Use the results from the run on the highest version + %% of Erlang as norm. + {_, TestRes} = + lists:foldl(fun ({{Ver, _}, ResList}, + {CurrentVer, _}) when Ver > CurrentVer -> + {Ver, ResList}; + (_, VerAndRes) -> + VerAndRes + end, {"0", []}, ResultList), + + {lists:foldl(fun ({_, Time0}, Min1) when Time0 < Min1 -> + Time0; + (_, Min1) -> + Min1 + end, ?MAX, TestRes), + [Name || {Name, _} <- lists:keysort(2, TestRes)]}. + +%%--------------------------------------------------------------------------- +%% table_headers(VerResultList) -> SysInfo +%% VerResultList = [{{Ver, Machine},[{BmFunctionName, Time}]} | _] +%% Ver = string() +%% Machine = string() +%% BmFunctionName = atom() +%% Time = integer() +%% SysInfo = {Ver, Machine} +%%--------------------------------------------------------------------------- +table_headers(VerResultList) -> + [SysInfo || {SysInfo, _} <- VerResultList]. diff --git a/system/doc/efficiency_guide/bench.hrl b/system/doc/efficiency_guide/bench.hrl new file mode 100644 index 0000000000..a98ca1c89e --- /dev/null +++ b/system/doc/efficiency_guide/bench.hrl @@ -0,0 +1,22 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-define(rep5(X), X, X, X, X, X). +-define(rep10(X), ?rep5(X), ?rep5(X)). +-define(rep20(X), ?rep10(X), ?rep10(X)). +-define(rep40(X), ?rep20(X), ?rep20(X)). +-define(rep80(X), ?rep40(X), ?rep40(X)). diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml new file mode 100644 index 0000000000..8746de4b60 --- /dev/null +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -0,0 +1,528 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2007</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Constructing and matching binaries</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-10-12</date> + <rev></rev> + <file>binaryhandling.xml</file> + </header> + + <p>In R12B, the most natural way to write binary construction and matching is now + significantly faster than in earlier releases.</p> + + <p>To construct at binary, you can simply write</p> + + <p><em>DO</em> (in R12B) / <em>REALLY DO NOT</em> (in earlier releases)</p> + <code type="erl"><![CDATA[ +my_list_to_binary(List) -> + my_list_to_binary(List, <<>>). + +my_list_to_binary([H|T], Acc) -> + my_list_to_binary(T, <<Acc/binary,H>>); +my_list_to_binary([], Acc) -> + Acc.]]></code> + + <p>In releases before R12B, <c>Acc</c> would be copied in every iteration. + In R12B, <c>Acc</c> will be copied only in the first iteration and extra + space will be allocated at the end of the copied binary. In the next iteration, + <c>H</c> will be written in to the extra space. When the extra space runs out, + the binary will be reallocated with more extra space.</p> + + <p>The extra space allocated (or reallocated) will be twice the size of the + existing binary data, or 256, whichever is larger.</p> + + <p>The most natural way to match binaries is now the fastest:</p> + + <p><em>DO</em> (in R12B)</p> + <code type="erl"><![CDATA[ +my_binary_to_list(<<H,T/binary>>) -> + [H|my_binary_to_list(T)]; +my_binary_to_list(<<>>) -> [].]]></code> + + <section> + <title>How binaries are implemented</title> + + <p>Internally, binaries and bitstrings are implemented in the same way. + In this section, we will call them <em>binaries</em> since that is what + they are called in the emulator source code.</p> + + <p>There are four types of binary objects internally. Two of them are + containers for binary data and two of them are merely references to + a part of a binary.</p> + + <p>The binary containers are called <em>refc binaries</em> + (short for <em>reference-counted binaries</em>) and <em>heap binaries</em>.</p> + + <p><marker id="refc_binary"></marker><em>Refc binaries</em> + consist of two parts: an object stored on + the process heap, called a <em>ProcBin</em>, and the binary object itself + stored outside all process heaps.</p> + + <p>The binary object can be referenced by any number of ProcBins from any + number of processes; the object contains a reference counter to keep track + of the number of references, so that it can be removed when the last + reference disappears.</p> + + <p>All ProcBin objects in a process are part of a linked list, so that + the garbage collector can keep track of them and decrement the reference + counters in the binary when a ProcBin disappears.</p> + + <p><marker id="heap_binary"></marker><em>Heap binaries</em> are small binaries, + up to 64 bytes, that are stored directly on the process heap. + They will be copied when the process + is garbage collected and when they are sent as a message. They don't + require any special handling by the garbage collector.</p> + + <p>There are two types of reference objects that can reference part of + a refc binary or heap binary. They are called <em>sub binaries</em> and + <em>match contexts</em>.</p> + + <p><marker id="sub_binary"></marker>A <em>sub binary</em> + is created by <c>split_binary/2</c> and when + a binary is matched out in a binary pattern. A sub binary is a reference + into a part of another binary (refc or heap binary, never into a another + sub binary). Therefore, matching out a binary is relatively cheap because + the actual binary data is never copied.</p> + + <p><marker id="match_context"></marker>A <em>match context</em> is + similar to a sub binary, but is optimized + for binary matching; for instance, it contains a direct pointer to the binary + data. For each field that is matched out of a binary, the position in the + match context will be incremented.</p> + + <p>In R11B, a match context was only using during a binary matching + operation.</p> + + <p>In R12B, the compiler tries to avoid generating code that + creates a sub binary, only to shortly afterwards create a new match + context and discard the sub binary. Instead of creating a sub binary, + the match context is kept.</p> + + <p>The compiler can only do this optimization if it can know for sure + that the match context will not be shared. If it would be shared, the + functional properties (also called referential transparency) of Erlang + would break.</p> + </section> + + <section> + <title>Constructing binaries</title> + + <p>In R12B, appending to a binary or bitstring</p> + + <code type="erl"><![CDATA[ +<<Binary/binary, ...>> +<<Binary/bitstring, ...>>]]></code> + + <p>is specially optimized by the <em>run-time system</em>. + Because the run-time system handles the optimization (instead of + the compiler), there are very few circumstances in which the optimization + will not work.</p> + + <p>To explain how it works, we will go through this code</p> + + <code type="erl"><![CDATA[ +Bin0 = <<0>>, %% 1 +Bin1 = <<Bin0/binary,1,2,3>>, %% 2 +Bin2 = <<Bin1/binary,4,5,6>>, %% 3 +Bin3 = <<Bin2/binary,7,8,9>>, %% 4 +Bin4 = <<Bin1/binary,17>>, %% 5 !!! +{Bin4,Bin3} %% 6]]></code> + + <p>line by line.</p> + + <p>The first line (marked with the <c>%% 1</c> comment), assigns + a <seealso marker="#heap_binary">heap binary</seealso> to + the variable <c>Bin0</c>.</p> + + <p>The second line is an append operation. Since <c>Bin0</c> + has not been involved in an append operation, + a new <seealso marker="#refc_binary">refc binary</seealso> + will be created and the contents of <c>Bin0</c> will be copied + into it. The <em>ProcBin</em> part of the refc binary will have + its size set to the size of the data stored in the binary, while + the binary object will have extra space allocated. + The size of the binary object will be either twice the + size of <c>Bin0</c> or 256, whichever is larger. In this case + it will be 256.</p> + + <p>It gets more interesting in the third line. + <c>Bin1</c> <em>has</em> been used in an append operation, + and it has 255 bytes of unused storage at the end, so the three new bytes + will be stored there.</p> + + <p>Same thing in the fourth line. There are 252 bytes left, + so there is no problem storing another three bytes.</p> + + <p>But in the fifth line something <em>interesting</em> happens. + Note that we don't append to the previous result in <c>Bin3</c>, + but to <c>Bin1</c>. We expect that <c>Bin4</c> will be assigned + the value <c><<0,1,2,3,17>></c>. We also expect that + <c>Bin3</c> will retain its value + (<c><<0,1,2,3,4,5,6,7,8,9>></c>). + Clearly, the run-time system cannot write the byte <c>17</c> into the binary, + because that would change the value of <c>Bin3</c> to + <c><<0,1,2,3,4,17,6,7,8,9>></c>.</p> + + <p>What will happen?</p> + + <p>The run-time system will see that <c>Bin1</c> is the result + from a previous append operation (not from the latest append operation), + so it will <em>copy</em> the contents of <c>Bin1</c> to a new binary + and reserve extra storage and so on. (We will not explain here how the + run-time system can know that it is not allowed to write into <c>Bin1</c>; + it is left as an exercise to the curious reader to figure out how it is + done by reading the emulator sources, primarily <c>erl_bits.c</c>.)</p> + + <section> + <title>Circumstances that force copying</title> + + <p>The optimization of the binary append operation requires that + there is a <em>single</em> ProcBin and a <em>single reference</em> to the + ProcBin for the binary. The reason is that the binary object can be + moved (reallocated) during an append operation, and when that happens + the pointer in the ProcBin must be updated. If there would be more than + on ProcBin pointing to the binary object, it would not be possible to + find and update all of them.</p> + + <p>Therefore, certain operations on a binary will mark it so that + any future append operation will be forced to copy the binary. + In most cases, the binary object will be shrunk at the same time + to reclaim the extra space allocated for growing.</p> + + <p>When appending to a binary</p> + + <code type="erl"><![CDATA[ +Bin = <<Bin0,...>>]]></code> + + <p>only the binary returned from the latest append operation will + support further cheap append operations. In the code fragment above, + appending to <c>Bin</c> will be cheap, while appending to <c>Bin0</c> + will force the creation of a new binary and copying of the contents + of <c>Bin0</c>.</p> + + <p>If a binary is sent as a message to a process or port, the binary + will be shrunk and any further append operation will copy the binary + data into a new binary. For instance, in the following code fragment</p> + + <code type="erl"><![CDATA[ +Bin1 = <<Bin0,...>>, +PortOrPid ! Bin1, +Bin = <<Bin1,...>> %% Bin1 will be COPIED +]]></code> + + <p><c>Bin1</c> will be copied in the third line.</p> + + <p>The same thing happens if you insert a binary into an <em>ets</em> + table or send it to a port using <c>erlang:port_command/2</c>.</p> + + <p>Matching a binary will also cause it to shrink and the next append + operation will copy the binary data:</p> + + <code type="erl"><![CDATA[ +Bin1 = <<Bin0,...>>, +<<X,Y,Z,T/binary>> = Bin1, +Bin = <<Bin1,...>> %% Bin1 will be COPIED +]]></code> + + <p>The reason is that a <seealso marker="#match_context">match context</seealso> + contains a direct pointer to the binary data.</p> + + <p>If a process simply keeps binaries (either in "loop data" or in the process + dictionary), the garbage collector may eventually shrink the binaries. + If only one such binary is kept, it will not be shrunk. If the process later + appends to a binary that has been shrunk, the binary object will be reallocated + to make place for the data to be appended.</p> + </section> + + </section> + + <section> + <title>Matching binaries</title> + + <p>We will revisit the example shown earlier</p> + + <p><em>DO</em> (in R12B)</p> + <code type="erl"><![CDATA[ +my_binary_to_list(<<H,T/binary>>) -> + [H|my_binary_to_list(T)]; +my_binary_to_list(<<>>) -> [].]]></code> + + <p>too see what is happening under the hood.</p> + + <p>The very first time <c>my_binary_to_list/1</c> is called, + a <seealso marker="#match_context">match context</seealso> + will be created. The match context will point to the first + byte of the binary. One byte will be matched out and the match context + will be updated to point to the second byte in the binary.</p> + + <p>In R11B, at this point a <seealso marker="#sub_binary">sub binary</seealso> + would be created. In R12B, + the compiler sees that there is no point in creating a sub binary, + because there will soon be a call to a function (in this case, + to <c>my_binary_to_list/1</c> itself) that will immediately + create a new match context and discard the sub binary.</p> + + <p>Therefore, in R12B, <c>my_binary_to_list/1</c> will call itself + with the match context instead of with a sub binary. The instruction + that initializes the matching operation will basically do nothing + when it sees that it was passed a match context instead of a binary.</p> + + <p>When the end of the binary is reached and second clause matches, + the match context will simply be discarded (removed in the next + garbage collection, since there is no longer any reference to it).</p> + + <p>To summarize, <c>my_binary_to_list/1</c> in R12B only needs to create + <em>one</em> match context and no sub binaries. In R11B, if the binary + contains <em>N</em> bytes, <em>N+1</em> match contexts and <em>N</em> + sub binaries will be created.</p> + + <p>In R11B, the fastest way to match binaries is:</p> + + <p><em>DO NOT</em> (in R12B)</p> + <code type="erl"><![CDATA[ +my_complicated_binary_to_list(Bin) -> + my_complicated_binary_to_list(Bin, 0). + +my_complicated_binary_to_list(Bin, Skip) -> + case Bin of + <<_:Skip/binary,Byte,_/binary>> -> + [Byte|my_complicated_binary_to_list(Bin, Skip+1)]; + <<_:Skip/binary>> -> + [] + end.]]></code> + + <p>This function cleverly avoids building sub binaries, but it cannot + avoid building a match context in each recursion step. Therefore, in both R11B and R12B, + <c>my_complicated_binary_to_list/1</c> builds <em>N+1</em> match + contexts. (In a future release, the compiler might be able to generate code + that reuses the match context, but don't hold your breath.)</p> + + <p>Returning to <c>my_binary_to_list/1</c>, note that the match context was + discarded when the entire binary had been traversed. What happens if + the iteration stops before it has reached the end of the binary? Will + the optimization still work?</p> + + <code type="erl"><![CDATA[ +after_zero(<<0,T/binary>>) -> + T; +after_zero(<<_,T/binary>>) -> + after_zero(T); +after_zero(<<>>) -> + <<>>. + ]]></code> + + <p>Yes, it will. The compiler will remove the building of the sub binary in the + second clause</p> + + <code type="erl"><![CDATA[ +. +. +. +after_zero(<<_,T/binary>>) -> + after_zero(T); +. +. +.]]></code> + + <p>but will generate code that builds a sub binary in the first clause</p> + + <code type="erl"><![CDATA[ +after_zero(<<0,T/binary>>) -> + T; +. +. +.]]></code> + + <p>Therefore, <c>after_zero/1</c> will build one match context and one sub binary + (assuming it is passed a binary that contains a zero byte).</p> + + <p>Code like the following will also be optimized:</p> + + <code type="erl"><![CDATA[ +all_but_zeroes_to_list(Buffer, Acc, 0) -> + {lists:reverse(Acc),Buffer}; +all_but_zeroes_to_list(<<0,T/binary>>, Acc, Remaining) -> + all_but_zeroes_to_list(T, Acc, Remaining-1); +all_but_zeroes_to_list(<<Byte,T/binary>>, Acc, Remaining) -> + all_but_zeroes_to_list(T, [Byte|Acc], Remaining-1).]]></code> + + <p>The compiler will remove building of sub binaries in the second and third clauses, + and it will add an instruction to the first clause that will convert <c>Buffer</c> + from a match context to a sub binary (or do nothing if <c>Buffer</c> already is a binary).</p> + + <p>Before you begin to think that the compiler can optimize any binary patterns, + here is a function that the compiler (currently, at least) is not able to optimize:</p> + + <code type="erl"><![CDATA[ +non_opt_eq([H|T1], <<H,T2/binary>>) -> + non_opt_eq(T1, T2); +non_opt_eq([_|_], <<_,_/binary>>) -> + false; +non_opt_eq([], <<>>) -> + true.]]></code> + + <p>It was briefly mentioned earlier that the compiler can only delay creation of + sub binaries if it can be sure that the binary will not be shared. In this case, + the compiler cannot be sure.</p> + + <p>We will soon show how to rewrite <c>non_opt_eq/2</c> so that the delayed sub binary + optimization can be applied, and more importantly, we will show how you can find out + whether your code can be optimized.</p> + + <section> + <title>The bin_opt_info option</title> + + <p>Use the <c>bin_opt_info</c> option to have the compiler print a lot of + information about binary optimizations. It can be given either to the compiler or + <c>erlc</c></p> + + <code type="erl"><![CDATA[ +erlc +bin_opt_info Mod.erl]]></code> + + <p>or passed via an environment variable</p> + + <code type="erl"><![CDATA[ +export ERL_COMPILER_OPTIONS=bin_opt_info]]></code> + + <p>Note that the <c>bin_opt_info</c> is not meant to be a permanent option added + to your <c>Makefile</c>s, because it is not possible to eliminate all messages that + it generates. Therefore, passing the option through the environment is in most cases + the most practical approach.</p> + + <p>The warnings will look like this:</p> + + <code type="erl"><![CDATA[ +./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: sub binary is used or returned +./efficiency_guide.erl:62: Warning: OPTIMIZED: creation of sub binary delayed]]></code> + + <p>To make it clearer exactly what code the warnings refer to, + in the examples that follow, the warnings are inserted as comments + after the clause they refer to:</p> + + <code type="erl"><![CDATA[ +after_zero(<<0,T/binary>>) -> + %% NOT OPTIMIZED: sub binary is used or returned + T; +after_zero(<<_,T/binary>>) -> + %% OPTIMIZED: creation of sub binary delayed + after_zero(T); +after_zero(<<>>) -> + <<>>.]]></code> + + <p>The warning for the first clause tells us that it is not possible to + delay the creation of a sub binary, because it will be returned. + The warning for the second clause tells us that a sub binary will not be + created (yet).</p> + + <p>It is time to revisit the earlier example of the code that could not + be optimized and find out why:</p> + + <code type="erl"><![CDATA[ +non_opt_eq([H|T1], <<H,T2/binary>>) -> + %% INFO: matching anything else but a plain variable to + %% the left of binary pattern will prevent delayed + %% sub binary optimization; + %% SUGGEST changing argument order + %% NOT OPTIMIZED: called function non_opt_eq/2 does not + %% begin with a suitable binary matching instruction + non_opt_eq(T1, T2); +non_opt_eq([_|_], <<_,_/binary>>) -> + false; +non_opt_eq([], <<>>) -> + true.]]></code> + + <p>The compiler emitted two warnings. The <c>INFO</c> warning refers to the function + <c>non_opt_eq/2</c> as a callee, indicating that any functions that call <c>non_opt_eq/2</c> + will not be able to make delayed sub binary optimization. + There is also a suggestion to change argument order. + The second warning (that happens to refer to the same line) refers to the construction of + the sub binary itself.</p> + + <p>We will soon show another example that should make the distinction between <c>INFO</c> + and <c>NOT OPTIMIZED</c> warnings somewhat clearer, but first we will heed the suggestion + to change argument order:</p> + + <code type="erl"><![CDATA[ +opt_eq(<<H,T1/binary>>, [H|T2]) -> + %% OPTIMIZED: creation of sub binary delayed + opt_eq(T1, T2); +opt_eq(<<_,_/binary>>, [_|_]) -> + false; +opt_eq(<<>>, []) -> + true.]]></code> + + <p>The compiler gives a warning for the following code fragment:</p> + + <code type="erl"><![CDATA[ +match_body([0|_], <<H,_/binary>>) -> + %% INFO: matching anything else but a plain variable to + %% the left of binary pattern will prevent delayed + %% sub binary optimization; + %% SUGGEST changing argument order + done; +. +. +.]]></code> + + <p>The warning means that <em>if</em> there is a call to <c>match_body/2</c> + (from another clause in <c>match_body/2</c> or another function), the + delayed sub binary optimization will not be possible. There will be additional + warnings for any place where a sub binary is matched out at the end of and + passed as the second argument to <c>match_body/2</c>. For instance:</p> + + <code type="erl"><![CDATA[ +match_head(List, <<_:10,Data/binary>>) -> + %% NOT OPTIMIZED: called function match_body/2 does not + %% begin with a suitable binary matching instruction + match_body(List, Data).]]></code> + + </section> + + <section> + <title>Unused variables</title> + + <p>The compiler itself figures out if a variable is unused. The same + code is generated for each of the following functions</p> + + <code type="erl"><![CDATA[ +count1(<<_,T/binary>>, Count) -> count1(T, Count+1); +count1(<<>>, Count) -> Count. + +count2(<<H,T/binary>>, Count) -> count2(T, Count+1); +count2(<<>>, Count) -> Count. + +count3(<<_H,T/binary>>, Count) -> count3(T, Count+1); +count3(<<>>, Count) -> Count.]]></code> + + <p>In each iteration, the first 8 bits in the binary will be skipped, not matched out.</p> + + </section> + + </section> + +</chapter> + diff --git a/system/doc/efficiency_guide/book.xml b/system/doc/efficiency_guide/book.xml new file mode 100644 index 0000000000..5df40695bb --- /dev/null +++ b/system/doc/efficiency_guide/book.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Efficiency Guide</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2001-08-07</date> + <rev>R8A</rev> + </header> + <insidecover> + </insidecover> + <pagetext>Efficiency Guide</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/efficiency_guide/call_bm.erl b/system/doc/efficiency_guide/call_bm.erl new file mode 100644 index 0000000000..389814f11f --- /dev/null +++ b/system/doc/efficiency_guide/call_bm.erl @@ -0,0 +1,75 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% + +-module(call_bm). + +-include("bench.hrl"). + +-export([benchmarks/0]). +-export([local_call/1,external_call/1,fun_call/1,apply_fun/1, + apply_mfa_implicit/1, apply_mfa_explicit/1]). +-export([foo/0]). + +benchmarks() -> + {400000,[local_call,external_call,fun_call,apply_fun, + apply_mfa_implicit, apply_mfa_explicit]}. + +local_call(0) -> + ok; +local_call(Iter) -> + ?rep40(foo()), + local_call(Iter-1). + +external_call(0) -> + ok; +external_call(Iter) -> + ?rep40(?MODULE:foo()), + external_call(Iter-1). + +fun_call(Iter) -> + fun_call(Iter, fun() -> ok end). +fun_call(0, _) -> + ok; +fun_call(Iter, Fun) -> + ?rep40(Fun()), + fun_call(Iter-1, Fun). + +apply_fun(Iter) -> + apply_fun(Iter, fun() -> ok end). +apply_fun(0, _) -> + ok; +apply_fun(Iter, Fun) -> + ?rep40(apply(Fun, [])), + apply_fun(Iter-1, Fun). + +apply_mfa_explicit(0) -> + ok; +apply_mfa_explicit(Iter) -> + ?rep40(apply(?MODULE, foo, [])), + apply_mfa_explicit(Iter-1). + +apply_mfa_implicit(Iter) -> + apply_mfa_implicit(?MODULE, foo, Iter). + +apply_mfa_implicit(_, _, 0) -> + ok; +apply_mfa_implicit(Module, Function, Iter) -> + ?rep40(Module:Function()), + apply_mfa_implicit(Module, Function, Iter-1). + +foo() -> ok. diff --git a/system/doc/efficiency_guide/call_result.html b/system/doc/efficiency_guide/call_result.html new file mode 100644 index 0000000000..37b8931cdf --- /dev/null +++ b/system/doc/efficiency_guide/call_result.html @@ -0,0 +1,26 @@ +<html> +<head> +<title>Benchmark Results</title> +</head> +<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"> +<h1>Benchmark Results</h1> +<h2>call_bm</h2> +<table border=0 cellpadding=1><tr><td bgcolor="#000000"> +<table cellpadding=3 border=0 cellspacing=1> +<tr bgcolor=white><td>Test</td><td>5.4<br>BEAM</td></tr> +<tr bgcolor=white> +<td>local_call</td><td>1.00 </td></tr> +<tr bgcolor=white> +<td>external_call</td><td>1.08 </td></tr> +<tr bgcolor=white> +<td>fun_call</td><td>2.79 </td></tr> +<tr bgcolor=white> +<td>apply_fun</td><td>3.54 </td></tr> +<tr bgcolor=white> +<td>apply_mfa_implicit</td><td>7.76 </td></tr> +<tr bgcolor=white> +<td>apply_mfa_explicit</td><td>8.21 </td></tr> +</table></td></tr></table> +<p><a href="call_bm.erl">Source for call_bm.erl</a> +</body> +</html> diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml new file mode 100644 index 0000000000..e18e5aa510 --- /dev/null +++ b/system/doc/efficiency_guide/commoncaveats.xml @@ -0,0 +1,239 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Common Caveats</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2001-08-08</date> + <rev></rev> + <file>commoncaveats.xml</file> + </header> + + <p>Here we list a few modules and BIFs to watch out for, and not only + from a performance point of view.</p> + + <section> + <title>The regexp module</title> + + <p>The regular expression functions in the + <seealso marker="stdlib:regexp">regexp</seealso> + module are written in Erlang, not in C, and were + meant for occasional use on small amounts of data, + for instance for validation of configuration files + when starting an application.</p> + + <p>Use the <seealso marker="stdlib:re">re</seealso> module + (introduced in R13A) instead, especially in time-critical code.</p> + </section> + + <section> + <title>The timer module</title> + + <p>Creating timers using <seealso + marker="erts:erlang#erlang:send_after/3">erlang:send_after/3</seealso> + and <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso> + is much more efficient than using the timers provided by the + <seealso marker="stdlib:timer">timer</seealso> module. The + <c>timer</c> module uses a separate process to manage the timers, + and that process can easily become overloaded if many processes + create and cancel timers frequently (especially when using the + SMP emulator).</p> + + <p>The functions in the <c>timer</c> module that do not manage timers (such as + <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the timer-server process + and are therefore harmless.</p> + </section> + + <section> + <title>list_to_atom/1</title> + + <p>Atoms are not garbage-collected. Once an atom is created, it will never + be removed. The emulator will terminate if the limit for the number + of atoms (1048576) is reached.</p> + + <p>Therefore, converting arbitrary input strings to atoms could be + dangerous in a system that will run continuously. + If only certain well-defined atoms are allowed as input, you can use + <seealso marker="erts:erlang#list_to_existing_atom/1">list_to_existing_atom/1</seealso> + to guard against a denial-of-service attack. (All atoms that are allowed + must have been created earlier, for instance by simply using all of them + in a module and loading that module.)</p> + + <p>Using <c>list_to_atom/1</c> to construct an atom that is passed to + <c>apply/3</c> like this</p> + + <code type="erl"> +apply(list_to_atom("some_prefix"++Var), foo, Args)</code> + + <p>is quite expensive and is not recommended in time-critical code.</p> + </section> + + <section> + <title>length/1</title> + + <p>The time for calculating the length of a list is proportional to the + length of the list, as opposed to <c>tuple_size/1</c>, <c>byte_size/1</c>, + and <c>bit_size/1</c>, which all execute in constant time.</p> + + <p>Normally you don't have to worry about the speed of <c>length/1</c>, + because it is efficiently implemented in C. In time critical-code, though, + you might want to avoid it if the input list could potentially be very long.</p> + + <p>Some uses of <c>length/1</c> can be replaced by matching. + For instance, this code</p> + + <code type="erl"> +foo(L) when length(L) >= 3 -> + ...</code> + + <p>can be rewritten to</p> + <code type="erl"> +foo([_,_,_|_]=L) -> + ...</code> + + <p>(One slight difference is that <c>length(L)</c> will fail if the <c>L</c> + is an improper list, while the pattern in the second code fragment will + accept an improper list.)</p> + </section> + + <section> + <title>setelement/3</title> + + <p><seealso marker="erts:erlang#setelement/3">setelement/3</seealso> + copies the tuple it modifies. Therefore, updating a tuple in a loop + using <c>setelement/3</c> will create a new copy of the tuple every time.</p> + + <p>There is one exception to the rule that the tuple is copied. + If the compiler clearly can see that destructively updating the tuple would + give exactly the same result as if the tuple was copied, the call to + <c>setelement/3</c> will be replaced with a special destructive setelement + instruction. In the following code sequence</p> + + <code type="erl"> +multiple_setelement(T0) -> + T1 = setelement(9, T0, bar), + T2 = setelement(7, T1, foobar), + setelement(5, T2, new_value).</code> + + <p>the first <c>setelement/3</c> call will copy the tuple and modify the + ninth element. The two following <c>setelement/3</c> calls will modify + the tuple in place.</p> + + <p>For the optimization to be applied, <em>all</em> of the followings conditions + must be true:</p> + + <list type="bulleted"> + <item>The indices must be integer literals, not variables or expressions.</item> + <item>The indices must be given in descending order.</item> + <item>There must be no calls to other function in between the calls to + <c>setelement/3</c>.</item> + <item>The tuple returned from one <c>setelement/3</c> call must only be used + in the subsequent call to <c>setelement/3</c>.</item> + </list> + + <p>If it is not possible to structure the code as in the <c>multiple_setelement/1</c> + example, the best way to modify multiple elements in a large tuple is to + convert the tuple to a list, modify the list, and convert the list back to + a tuple.</p> + </section> + + <section> + <title>size/1</title> + + <p><c>size/1</c> returns the size for both tuples and binary.</p> + + <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c> introduced + in R12B gives the compiler and run-time system more opportunities for + optimization. A further advantage is that the new BIFs could help Dialyzer + find more bugs in your program.</p> + </section> + + <section> + <title>split_binary/2</title> + <p>It is usually more efficient to split a binary using matching + instead of calling the <c>split_binary/2</c> function. + Furthermore, mixing bit syntax matching and <c>split_binary/2</c> + may prevent some optimizations of bit syntax matching.</p> + + <p><em>DO</em></p> + <code type="none"><![CDATA[ + <<Bin1:Num/binary,Bin2/binary>> = Bin,]]></code> + <p><em>DO NOT</em></p> + <code type="none"> + {Bin1,Bin2} = split_binary(Bin, Num) + </code> + </section> + + <section> + <title>The '--' operator</title> + <p>Note that the '<c>--</c>' operator has a complexity + proportional to the product of the length of its operands, + meaning that it will be very slow if both of its operands + are long lists:</p> + + <p><em>DO NOT</em></p> + <code type="none"><![CDATA[ + HugeList1 -- HugeList2]]></code> + + <p>Instead use the <seealso marker="stdlib:ordsets">ordsets</seealso> + module:</p> + + <p><em>DO</em></p> + <code type="none"> + HugeSet1 = ordsets:from_list(HugeList1), + HugeSet2 = ordsets:from_list(HugeList2), + ordsets:subtract(HugeSet1, HugeSet2) + </code> + + <p>Obviously, that code will not work if the original order + of the list is important. If the order of the list must be + preserved, do like this:</p> + + <p><em>DO</em></p> + <code type="none"><![CDATA[ + Set = gb_sets:from_list(HugeList2), + [E || E <- HugeList1, not gb_sets:is_element(E, Set)]]]></code> + + <p>Subtle note 1: This code behaves differently from '<c>--</c>' + if the lists contain duplicate elements. (One occurrence + of an element in HugeList2 will remove <em>all</em> + occurrences in HugeList1.)</p> + + <p>Subtle note 2: This code compares lists elements using the + '<c>==</c>' operator, while '<c>--</c>' uses the '<c>=:=</c>'. If + that difference is important, <c>sets</c> can be used instead of + <c>gb_sets</c>, but note that <c>sets:from_list/1</c> is much + slower than <c>gb_sets:from_list/1</c> for long lists.</p> + + <p>Using the '<c>--</c>' operator to delete an element + from a list is not a performance problem:</p> + + <p><em>OK</em></p> + <code type="none"> + HugeList1 -- [Element] + </code> + + </section> + +</chapter> + diff --git a/system/doc/efficiency_guide/digger.ps b/system/doc/efficiency_guide/digger.ps new file mode 100644 index 0000000000..07ac8e2fa9 --- /dev/null +++ b/system/doc/efficiency_guide/digger.ps @@ -0,0 +1,197 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: /clearcase/otp/system/doc/efficiency_guide/digger.ps +%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley +%%BoundingBox: 290 380 322 412 +%%Pages: 1 +%%DocumentFonts: +%%EndComments +%%EndProlog + +%%Page: 1 1 + +% remember original state +/origstate save def + +% build a temporary dictionary +20 dict begin + +% define string to hold a scanline's worth of data +/pix 96 string def + +% define space for color conversions +/grays 32 string def % space for gray scale line +/npixls 0 def +/rgbindx 0 def + +% lower left corner +290 380 translate + +% size of image (on paper, in 1/72inch coords) +31.96800 31.96800 scale + +% define 'colorimage' if it isn't defined +% ('colortogray' and 'mergeprocs' come from xwd2ps +% via xgrab) +/colorimage where % do we know about 'colorimage'? + { pop } % yes: pop off the 'dict' returned + { % no: define one + /colortogray { % define an RGB->I function + /rgbdata exch store % call input 'rgbdata' + rgbdata length 3 idiv + /npixls exch store + /rgbindx 0 store + 0 1 npixls 1 sub { + grays exch + rgbdata rgbindx get 20 mul % Red + rgbdata rgbindx 1 add get 32 mul % Green + rgbdata rgbindx 2 add get 12 mul % Blue + add add 64 idiv % I = .5G + .31R + .18B + put + /rgbindx rgbindx 3 add store + } for + grays 0 npixls getinterval + } bind def + + % Utility procedure for colorimage operator. + % This procedure takes two procedures off the + % stack and merges them into a single procedure. + + /mergeprocs { % def + dup length + 3 -1 roll + dup + length + dup + 5 1 roll + 3 -1 roll + add + array cvx + dup + 3 -1 roll + 0 exch + putinterval + dup + 4 2 roll + putinterval + } bind def + + /colorimage { % def + pop pop % remove 'false 3' operands + {colortogray} mergeprocs + image + } bind def + } ifelse % end of 'false' case + + + +32 32 8 % dimensions of data +[32 0 0 -32 0 32] % mapping matrix +{currentfile pix readhexstring pop} +false 3 colorimage + +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00000000000000000000000000ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000000000000000000000000000ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000000000000000000000000000ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000000000000000000000000000ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000000000000000000000000000ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000000000000000000000000000000000 +000000000000ffff00000000000000000000000000ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000ffff00ffff00ffff00ffff00000000 +000000000000000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000ffff00ffff00ffff00000000000000 +000000000000000000000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000ffff00000000000000000000000000 +000000000000ffff00000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000ffff00000000000000000000000000 +000000ffff00ffff00000000ffff00ffff00ffff00ffff00ffff00000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000000000000000000000000000000000 +ffff00ffff00ffff00000000ffff00ffff00ffff00ffff00ffff00000000000000000000 +000000000000ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00000000000000ffff00000000000000000000000000000000 +ffff00ffff00ffff00000000ffff00ffff00ffff00ffff00ffff00000000000000000000 +000000000000ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000000000000000 +000000000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00000000 +000000000000000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00000000000000ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00ffff00 +000000000000000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00ffff00 +000000000000000000ffff00ffff00ffff00ffff00ffff00000000000000ffff00ffff00 +000000ffff00000000ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00ffff00 +000000000000000000ffff00ffff00ffff00ffff00000000000000000000000000ffff00 +ffff00ffff00000000ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000ffff00ffff00ffff00 +000000000000ffff00ffff00ffff00ffff00000000000000000000000000000000000000 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00ffff00 +000000000000000000ffff00ffff00000000000000000000000000000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000000000000000ffff00ffff00 +000000000000000000ffff00ffff00000000000000000000000000000000000000000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ffff00ffff00000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000 + +showpage + +% stop using temporary dictionary +end + +% restore original state +origstate restore + +%%Trailer diff --git a/system/doc/efficiency_guide/drivers.xml b/system/doc/efficiency_guide/drivers.xml new file mode 100644 index 0000000000..9fe54fb19a --- /dev/null +++ b/system/doc/efficiency_guide/drivers.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2009</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Drivers</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2009-11-16</date> + <rev></rev> + <file>drivers.xml</file> + </header> + + <p>This chapter provides a (very) brief overview on how to write efficient + drivers. It is assumed that you already have a good understanding of + drivers.</p> + + <section> + <title>Drivers and concurrency</title> + + <p>The run-time system will always take a lock before running + any code in a driver.</p> + + <p>By default, that lock will be at the driver level, meaning that + if several ports has been opened to the same driver, only code for + one port at the same time can be running.</p> + + <p>A driver can be configured to instead have one lock for each port.</p> + + <p>If a driver is used in a functional way (i.e. it holds no state, + but only does some heavy calculation and returns a result), several + ports with registered names can be opened beforehand and the port to + be used can be chosen based on the scheduler ID like this:</p> + + <code type="none"> +-define(PORT_NAMES(), + {some_driver_01, some_driver_02, some_driver_03, some_driver_04, + some_driver_05, some_driver_06, some_driver_07, some_driver_08, + some_driver_09, some_driver_10, some_driver_11, some_driver_12, + some_driver_13, some_driver_14, some_driver_15, some_driver_16}). + +client_port() -> + element(erlang:system_info(scheduler_id) rem tuple_size(?PORT_NAMES()) + 1, + ?PORT_NAMES()).</code> + + <p>As long as there are no more than 16 schedulers, there will never + be any lock contention on the port lock for the driver.</p> + + </section> + + <section> + <title>Avoiding copying of binaries when calling a driver</title> + + <p>There are basically two ways to avoid copying a binary that is + sent to a driver.</p> + + <p>If the <c>Data</c> argument for + <seealso marker="erts:erlang#port_control/3">port_control/3</seealso> + is a binary, the driver will be passed a pointer to the contents of + the binary and the binary will not be copied. + If the <c>Data</c> argument is an iolist (list of binaries and lists), + all binaries in the iolist will be copied.</p> + + <p>Therefore, if you want to send both a pre-existing binary and some + additional data to a driver without copying the binary, you must call + <c>port_control/3</c> twice; once with the binary and once with the + additional data. However, that will only work if there is only one + process communicating with the port (because otherwise another process + could call the driver in-between the calls).</p> + + <p>Another way to avoid copying binaries is to implement an <c>outputv</c> + callback (instead of an <c>output</c> callback) in the driver. + If a driver has an <c>outputv</c> callback, refc binaries passed + in an iolist in the <c>Data</c> argument for + <seealso marker="erts:erlang#port_command/2">port_command/2</seealso> + will be passed as references to the driver.</p> + </section> + + <section> + <title>Returning small binaries from a driver</title> + + <p>The run-time system can represent binaries up to 64 bytes as + heap binaries. They will always be copied when sent in a messages, + but they will require less memory if they are not sent to another + process and garbage collection is cheaper.</p> + + <p>If you know that the binaries you return are always small, + you should use driver API calls that do not require a pre-allocated + binary, for instance + <seealso marker="erts:erl_driver#int driver_output-3">driver_output()</seealso> + or + <seealso marker="erts:erl_driver#int driver_output_term-3">driver_output_term()</seealso> + using the <c>ERL_DRV_BUF2BINARY</c> format, + to allow the run-time to construct a heap binary.</p> + + </section> + + <section> + <title>Returning big binaries without copying from a driver</title> + + <p>To avoid copying data when a big binary is sent or returned from + the driver to an Erlang process, the driver must first allocate the + binary and then send it to an Erlang process in some way.</p> + + <p>Use <seealso marker="erts:erl_driver#ErlDrvBinary* driver_alloc_binary-1">driver_alloc_binary()</seealso> to allocate a binary.</p> + + <p>There are several ways to send a binary created with + <c>driver_alloc_binary()</c>.</p> + + <list type="bulleted"> + <item><p>From the <c>control</c> callback, a binary can be returned provided + that + <seealso marker="erts:erl_driver#void set_port_control_flags-2">set_port_control()</seealso> + has been called with the flag value <c>PORT_CONTROL_FLAG_BINARY</c>.</p> + </item> + + <item><p>A single binary can be sent with + <seealso marker="erts:erl_driver#int driver_output_binary-6">driver_output_binary()</seealso>.</p></item> + + <item><p>Using + <seealso marker="erts:erl_driver#int driver_output_term-3">driver_output_term()</seealso> + or + <seealso marker="erts:erl_driver#int driver_send_term-4">driver_send_term()</seealso>, + a binary can be included in an Erlang term.</p> + </item> + </list> + + </section> + +</chapter> diff --git a/system/doc/efficiency_guide/efficiency_guide.erl b/system/doc/efficiency_guide/efficiency_guide.erl new file mode 100644 index 0000000000..e982bdae65 --- /dev/null +++ b/system/doc/efficiency_guide/efficiency_guide.erl @@ -0,0 +1,214 @@ +-module(efficiency_guide). +-compile(export_all). + +%% DO NOT +naive_reverse([H|T]) -> + naive_reverse(T)++[H]; +naive_reverse([]) -> + []. + +%% OK +naive_but_ok_reverse([H|T], Acc) -> + naive_but_ok_reverse(T, [H]++Acc); +naive_but_ok_reverse([], Acc) -> + Acc. + +%% DO +vanilla_reverse([H|T], Acc) -> + vanilla_reverse(T, [H|Acc]); +vanilla_reverse([], Acc) -> + Acc. + + +multiple_setelement(T0) -> + T1 = setelement(9, T0, bar), + T2 = setelement(7, T1, foobar), + setelement(5, T2, new_value). + + +my_list_to_binary(List) -> + my_list_to_binary(List, <<>>). + +my_list_to_binary([H|T], Acc) -> + my_list_to_binary(T, <<Acc/binary,H>>); +my_list_to_binary([], Acc) -> + Acc. + +my_old_list_to_binary(List) -> + my_old_list_to_binary(List, []). + +my_old_list_to_binary([H|T], Acc) -> + my_old_list_to_binary(T, [Acc,H]); +my_old_list_to_binary([], Acc) -> + list_to_binary(Acc). + +my_binary_to_list(<<H,T/binary>>) -> + [H|my_binary_to_list(T)]; +my_binary_to_list(<<>>) -> []. + +my_complicated_binary_to_list(Bin) -> + my_complicated_binary_to_list(Bin, 0). + +my_complicated_binary_to_list(Bin, Skip) -> + case Bin of + <<_:Skip/binary,Byte,_/binary>> -> + [Byte|my_complicated_binary_to_list(Bin, Skip+1)]; + <<_:Skip/binary>> -> + [] + end. + +after_zero(<<0,T/binary>>) -> + T; +after_zero(<<_,T/binary>>) -> + after_zero(T); +after_zero(<<>>) -> + <<>>. + +all_but_zeroes_to_list(Buffer, Acc, 0) -> + {lists:reverse(Acc),Buffer}; +all_but_zeroes_to_list(<<0,T/binary>>, Acc, Remaining) -> + all_but_zeroes_to_list(T, Acc, Remaining-1); +all_but_zeroes_to_list(<<Byte,T/binary>>, Acc, Remaining) -> + all_but_zeroes_to_list(T, [Byte|Acc], Remaining-1). + +non_opt_eq([H|T1], <<H,T2/binary>>) -> + non_opt_eq(T1, T2); +non_opt_eq([_|_], <<_,_/binary>>) -> + false; +non_opt_eq([], <<>>) -> + true. + +opt_eq(<<H,T1/binary>>, [H|T2]) -> + opt_eq(T1, T2); +opt_eq(<<_,_/binary>>, [_|_]) -> + false; +opt_eq(<<>>, []) -> + true. + +match_head(List, <<_:10,Data/binary>>) -> + match_body(List, Data). + +match_body([0|_], <<H,_/binary>>) -> + done; +match_body([H|T1], <<H,T2/binary>>) -> + {T1,T2}. + +count1(<<_,T/binary>>, Count) -> count1(T, Count+1); +count1(<<>>, Count) -> Count. + +count2(<<H,T/binary>>, Count) -> count2(T, Count+1); +count2(<<>>, Count) -> Count. + +count3(<<_H,T/binary>>, Count) -> count3(T, Count+1); +count3(<<>>, Count) -> Count. + +fib(N) -> + fib(N, 0, 1, []). + +fib(0, _Current, _Next, Fibs) -> + lists:reverse(Fibs); +fib(N, Current, Next, Fibs) -> + fib(N - 1, Next, Current + Next, [Current|Fibs]). + +recursive_fib(N) -> + recursive_fib(N, 0, 1). + +recursive_fib(0, _Current, _Next) -> + []; +recursive_fib(N, Current, Next) -> + [Current|recursive_fib(N - 1, Next, Current + Next)]. + +bad_fib(N) -> + bad_fib(N, 0, 1, []). + +bad_fib(0, _Current, _Next, Fibs) -> + Fibs; +bad_fib(N, Current, Next, Fibs) -> + bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]). + +tail_recursive_fib(N) -> + tail_recursive_fib(N, 0, 1, []). + +tail_recursive_fib(0, _Current, _Next, Fibs) -> + lists:reverse(Fibs); +tail_recursive_fib(N, Current, Next, Fibs) -> + tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]). + +append([H|T], Tail) -> + [H|append(T, Tail)]; +append([], Tail) -> + Tail. + +kilo_byte() -> + kilo_byte(10, [42]). + +kilo_byte(0, Acc) -> + Acc; +kilo_byte(N, Acc) -> + kilo_byte(N-1, [Acc|Acc]). + +recursive_sum([H|T]) -> + H+recursive_sum(T); +recursive_sum([]) -> 0. + +sum(L) -> sum(L, 0). + +sum([H|T], Sum) -> sum(T, Sum + H); +sum([], Sum) -> Sum. + +days_in_month(M) -> + element(M, {31,28,31,30,31,30,31,31,30,31,30,31}). + +atom_map1(one) -> 1; +atom_map1(two) -> 2; +atom_map1(three) -> 3; +atom_map1(Int) when is_integer(Int) -> Int; +atom_map1(four) -> 4; +atom_map1(five) -> 5; +atom_map1(six) -> 6. + +atom_map2(one) -> 1; +atom_map2(two) -> 2; +atom_map2(three) -> 3; +atom_map2(four) -> 4; +atom_map2(five) -> 5; +atom_map2(six) -> 6; +atom_map2(Int) when is_integer(Int) -> Int. + +atom_map3(Int) when is_integer(Int) -> Int; +atom_map3(one) -> 1; +atom_map3(two) -> 2; +atom_map3(three) -> 3; +atom_map3(four) -> 4; +atom_map3(five) -> 5; +atom_map3(six) -> 6. + + +map_pairs1(_Map, [], Ys) -> + Ys; +map_pairs1(_Map, Xs, [] ) -> + Xs; +map_pairs1(Map, [X|Xs], [Y|Ys]) -> + [Map(X, Y)|map_pairs1(Map, Xs, Ys)]. + +map_pairs2(_Map, [], Ys) -> + Ys; +map_pairs2(_Map, [_|_]=Xs, [] ) -> + Xs; +map_pairs2(Map, [X|Xs], [Y|Ys]) -> + [Map(X, Y)|map_pairs2(Map, Xs, Ys)]. + +explicit_map_pairs(Map, Xs0, Ys0) -> + case Xs0 of + [X|Xs] -> + case Ys0 of + [Y|Ys] -> + [Map(X, Y)|explicit_map_pairs(Map, Xs, Ys)]; + [] -> + Xs0 + end; + [] -> + Ys0 + end. + + diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml new file mode 100644 index 0000000000..d55b60e39c --- /dev/null +++ b/system/doc/efficiency_guide/functions.xml @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Functions</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-11-22</date> + <rev></rev> + <file>functions.xml</file> + </header> + + <section> + <title>Pattern matching</title> + <p>Pattern matching in function head and in <c>case</c> and <c>receive</c> + clauses are optimized by the compiler. With a few exceptions, there is nothing + to gain by rearranging clauses.</p> + + <p>One exception is pattern matching of binaries. The compiler + will not rearrange clauses that match binaries. Placing the + clause that matches against the empty binary <em>last</em> will usually + be slightly faster than placing it <em>first</em>.</p> + + <p>Here is a rather contrived example to show another exception:</p> + + <p><em>DO NOT</em></p> + <code type="erl"> +atom_map1(one) -> 1; +atom_map1(two) -> 2; +atom_map1(three) -> 3; +atom_map1(Int) when is_integer(Int) -> Int; +atom_map1(four) -> 4; +atom_map1(five) -> 5; +atom_map1(six) -> 6.</code> + + <p>The problem is the clause with the variable <c>Int</c>. + Since a variable can match anything, including the atoms + <c>four</c>, <c>five</c>, and <c>six</c> that the following clauses + also will match, the compiler must generate sub-optimal code that will + execute as follows:</p> + + <p>First the input value is compared to <c>one</c>, <c>two</c>, and + <c>three</c> (using a single instruction that does a binary search; + thus, quite efficient even if there are many values) to select which + one of the first three clauses to execute (if any).</p> + + <p>If none of the first three clauses matched, the fourth clause + will match since a variable always matches. If the guard test + <c>is_integer(Int)</c> succeeds, the fourth clause will be + executed.</p> + + <p>If the guard test failed, the input value is compared to + <c>four</c>, <c>five</c>, and <c>six</c>, and the appropriate clause + is selected. (There will be a <c>function_clause</c> exception if + none of the values matched.)</p> + + <p>Rewriting to either</p> + + <p><em>DO</em></p> + <code type="erl"><![CDATA[ +atom_map2(one) -> 1; +atom_map2(two) -> 2; +atom_map2(three) -> 3; +atom_map2(four) -> 4; +atom_map2(five) -> 5; +atom_map2(six) -> 6; +atom_map2(Int) when is_integer(Int) -> Int.]]></code> + + <p>or</p> + + <p><em>DO</em></p> + <code type="erl"><![CDATA[ +atom_map3(Int) when is_integer(Int) -> Int; +atom_map3(one) -> 1; +atom_map3(two) -> 2; +atom_map3(three) -> 3; +atom_map3(four) -> 4; +atom_map3(five) -> 5; +atom_map3(six) -> 6.]]></code> + + <p>will give slightly more efficient matching code.</p> + + <p>Here is a less contrived example:</p> + + <p><em>DO NOT</em></p> + <code type="erl"><![CDATA[ +map_pairs1(_Map, [], Ys) -> + Ys; +map_pairs1(_Map, Xs, [] ) -> + Xs; +map_pairs1(Map, [X|Xs], [Y|Ys]) -> + [Map(X, Y)|map_pairs1(Map, Xs, Ys)].]]></code> + + <p>The first argument is <em>not</em> a problem. It is variable, but it + is a variable in all clauses. The problem is the variable in the second + argument, <c>Xs</c>, in the middle clause. Because the variable can + match anything, the compiler is not allowed to rearrange the clauses, + but must generate code that matches them in the order written.</p> + + <p>If the function is rewritten like this</p> + + <p><em>DO</em></p> + <code type="erl"><![CDATA[ +map_pairs2(_Map, [], Ys) -> + Ys; +map_pairs2(_Map, [_|_]=Xs, [] ) -> + Xs; +map_pairs2(Map, [X|Xs], [Y|Ys]) -> + [Map(X, Y)|map_pairs2(Map, Xs, Ys)].]]></code> + + <p>the compiler is free rearrange the clauses. It will generate code + similar to this</p> + + <p><em>DO NOT (already done by the compiler)</em></p> + <code type="erl"><![CDATA[ +explicit_map_pairs(Map, Xs0, Ys0) -> + case Xs0 of + [X|Xs] -> + case Ys0 of + [Y|Ys] -> + [Map(X, Y)|explicit_map_pairs(Map, Xs, Ys)]; + [] -> + Xs0 + end; + [] -> + Ys0 + end.]]></code> + + <p>which should be slightly faster for presumably the most common case + that the input lists are not empty or very short. + (Another advantage is that Dialyzer is able to deduce a better type + for the variable <c>Xs</c>.)</p> + </section> + + <section> + <title>Function Calls </title> + + <p>Here is an intentionally rough guide to the relative costs of + different kinds of calls. It is based on benchmark figures run on + Solaris/Sparc:</p> + + <list type="bulleted"> + <item>Calls to local or external functions (<c>foo()</c>, <c>m:foo()</c>) + are the fastest kind of calls.</item> + <item>Calling or applying a fun (<c>Fun()</c>, <c>apply(Fun, [])</c>) + is about <em>three times</em> as expensive as calling a local function.</item> + <item>Applying an exported function (<c>Mod:Name()</c>, + <c>apply(Mod, Name, [])</c>) is about twice as expensive as calling a fun, + or about <em>six times</em> as expensive as calling a local function.</item> + </list> + + <section> + <title>Notes and implementation details</title> + + <p>Calling and applying a fun does not involve any hash-table lookup. + A fun contains an (indirect) pointer to the function that implements + the fun.</p> + + <warning><p><em>Tuples are not fun(s)</em>. + A "tuple fun", <c>{Module,Function}</c>, is not a fun. + The cost for calling a "tuple fun" is similar to that + of <c>apply/3</c> or worse. Using "tuple funs" is <em>strongly discouraged</em>, + as they may not be supported in a future release.</p></warning> + + <p><c>apply/3</c> must look up the code for the function to execute + in a hash table. Therefore, it will always be slower than a + direct call or a fun call.</p> + + <p>It no longer matters (from a performance point of view) + whether you write</p> + + <code type="erl"> +Module:Function(Arg1, Arg2)</code> + + <p>or</p> + + <code type="erl"> +apply(Module, Function, [Arg1,Arg2])</code> + + <p>(The compiler internally rewrites the latter code into the former.)</p> + + <p>The following code</p> + + <code type="erl"> +apply(Module, Function, Arguments)</code> + + <p>is slightly slower because the shape of the list of arguments + is not known at compile time.</p> + </section> + </section> + + <section> + <title>Memory usage in recursion</title> + <p>When writing recursive functions it is preferable to make them + tail-recursive so that they can execute in constant memory space.</p> + <p><em>DO</em></p> + <code type="none"> +list_length(List) -> + list_length(List, 0). + +list_length([], AccLen) -> + AccLen; % Base case + +list_length([_|Tail], AccLen) -> + list_length(Tail, AccLen + 1). % Tail-recursive</code> + <p><em>DO NOT</em></p> + <code type="none"> +list_length([]) -> + 0. % Base case +list_length([_ | Tail]) -> + list_length(Tail) + 1. % Not tail-recursive</code> + </section> + +</chapter> + diff --git a/system/doc/efficiency_guide/introduction.xml b/system/doc/efficiency_guide/introduction.xml new file mode 100644 index 0000000000..ba942c75c2 --- /dev/null +++ b/system/doc/efficiency_guide/introduction.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-11-21</date> + <rev></rev> + <file>introduction.xml</file> + </header> + + <section> + <title>Purpose</title> + + <quote><p>Premature optimization is the root of all evil. -- D.E. Knuth</p></quote> + + <p>Efficient code can be well-structured and clean code, based on + on a sound overall architecture and sound algorithms. + Efficient code can be highly implementation-code that bypasses + documented interfaces and takes advantage of obscure quirks in + the current implementation.</p> + + <p>Ideally, your code should only contain the first kind of efficient + code. If that turns out to be too slow, you should profile the application + to find out where the performance bottlenecks are and optimize only the + bottlenecks. Other code should stay as clean as possible.</p> + + <p>Fortunately, compiler and run-time optimizations introduced in + R12B makes it easier to write code that is both clean and + efficient. For instance, the ugly workarounds needed in R11B and earlier + releases to get the most speed out of binary pattern matching are + no longer necessary. In fact, the ugly code is slower + than the clean code (because the clean code has become faster, not + because the uglier code has become slower).</p> + + <p>This Efficiency Guide cannot really learn you how to write efficient + code. It can give you a few pointers about what to avoid and what to use, + and some understanding of how certain language features are implemented. + We have generally not included general tips about optimization that will + work in any language, such as moving common calculations out of loops.</p> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language and concepts of OTP.</p> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/listhandling.xml b/system/doc/efficiency_guide/listhandling.xml new file mode 100644 index 0000000000..e9d2dfe556 --- /dev/null +++ b/system/doc/efficiency_guide/listhandling.xml @@ -0,0 +1,241 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>List handling</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-11-16</date> + <rev></rev> + <file>listHandling.xml</file> + </header> + + <section> + <title>Creating a list</title> + + <p>Lists can only be built starting from the end and attaching + list elements at the beginning. If you use the <c>++</c> operator + like this</p> + + <code type="erl"> +List1 ++ List2</code> + + <p>you will create a new list which is copy of the elements in <c>List1</c>, + followed by <c>List2</c>. Looking at how <c>lists:append/1</c> or <c>++</c> would be + implemented in plain Erlang, it can be seen clearly that the first list + is copied:</p> + + <code type="erl"> +append([H|T], Tail) -> + [H|append(T, Tail)]; +append([], Tail) -> + Tail.</code> + + <p>So the important thing when recursing and building a list is to + make sure that you attach the new elements to the beginning of the list, + so that you build <em>a</em> list, and not hundreds or thousands of + copies of the growing result list.</p> + + <p>Let us first look at how it should not be done:</p> + + <p><em>DO NOT</em></p> + <code type="erl"><![CDATA[ +bad_fib(N) -> + bad_fib(N, 0, 1, []). + +bad_fib(0, _Current, _Next, Fibs) -> + Fibs; +bad_fib(N, Current, Next, Fibs) -> + bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]).]]></code> + + <p>Here we are not a building a list; in each iteration step we + create a new list that is one element longer than the new previous list.</p> + + <p>To avoid copying the result in each iteration, we must build the list in + reverse order and reverse the list when we are done:</p> + + <p><em>DO</em></p> + <code type="erl"><![CDATA[ +tail_recursive_fib(N) -> + tail_recursive_fib(N, 0, 1, []). + +tail_recursive_fib(0, _Current, _Next, Fibs) -> + lists:reverse(Fibs); +tail_recursive_fib(N, Current, Next, Fibs) -> + tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]).]]></code> + + </section> + + <section> + <title>List comprehensions</title> + + <p>Lists comprehensions still have a reputation for being slow. + They used to be implemented using funs, which used to be slow.</p> + + <p>In recent Erlang/OTP releases (including R12B), a list comprehension</p> + + <code type="erl"><![CDATA[ +[Expr(E) || E <- List]]]></code> + + <p>is basically translated to a local function</p> + + <code type="erl"> +'lc^0'([E|Tail], Expr) -> + [Expr(E)|'lc^0'(Tail, Expr)]; +'lc^0'([], _Expr) -> [].</code> + + <p>In R12B, if the result of the list comprehension will <em>obviously</em> not be used, + a list will not be constructed. For instance, in this code</p> + + <code type="erl"><![CDATA[ +[io:put_chars(E) || E <- List], +ok.]]></code> + + <p>or in this code</p> + + <code type="erl"><![CDATA[ +. +. +. +case Var of + ... -> + [io:put_chars(E) || E <- List]; + ... -> +end, +some_function(...), +. +. +.]]></code> + + <p>the value is neither assigned to a variable, nor passed to another function, + nor returned, so there is no need to construct a list and the compiler will simplify + the code for the list comprehension to</p> + + <code type="erl"> +'lc^0'([E|Tail], Expr) -> + Expr(E), + 'lc^0'(Tail, Expr); +'lc^0'([], _Expr) -> [].</code> + + </section> + + <section> + <title>Deep and flat lists</title> + + <p><seealso marker="stdlib:lists#flatten/1">lists:flatten/1</seealso> + builds an entirely new list. Therefore, it is expensive, and even + <em>more</em> expensive than the <c>++</c> (which copies its left argument, + but not its right argument).</p> + + <p>In the following situations, you can easily avoid calling <c>lists:flatten/1</c>:</p> + + <list type="bulleted"> + <item>When sending data to a port. Ports understand deep lists + so there is no reason to flatten the list before sending it to + the port.</item> + <item>When calling BIFs that accept deep lists, such as + <seealso marker="erts:erlang#list_to_binary/1">list_to_binary/1</seealso> or + <seealso marker="erts:erlang#iolist_to_binary/1">iolist_to_binary/1</seealso>.</item> + <item>When you know that your list is only one level deep, you can can use + <seealso marker="stdlib:lists#append/1">lists:append/1</seealso>.</item> + </list> + + <p><em>Port example</em></p> + <p><em>DO</em></p> + <pre> + ... + port_command(Port, DeepList) + ...</pre> + <p><em>DO NOT</em></p> + <pre> + ... + port_command(Port, lists:flatten(DeepList)) + ...</pre> + + <p>A common way to send a zero-terminated string to a port is the following:</p> + + <p><em>DO NOT</em></p> + <pre> + ... + TerminatedStr = String ++ [0], % String="foo" => [$f, $o, $o, 0] + port_command(Port, TerminatedStr) + ...</pre> + + <p>Instead do like this:</p> + + <p><em>DO</em></p> + <pre> + ... + TerminatedStr = [String, 0], % String="foo" => [[$f, $o, $o], 0] + port_command(Port, TerminatedStr) + ...</pre> + + <p><em>Append example</em></p> + <p><em>DO</em></p> + <pre> + > lists:append([[1], [2], [3]]). + [1,2,3] + ></pre> + <p><em>DO NOT</em></p> + <pre> + > lists:flatten([[1], [2], [3]]). + [1,2,3] + ></pre> + </section> + + <section> + <title>Why you should not worry about recursive lists functions</title> + + <p>In the performance myth chapter, the following myth was exposed: + <seealso marker="myths#tail_recursive">Tail-recursive functions + are MUCH faster than recursive functions</seealso>.</p> + + <p>To summarize, in R12B there is usually not much difference between + a body-recursive list function and tail-recursive function that reverses + the list at the end. Therefore, concentrate on writing beautiful code + and forget about the performance of your list functions. In the time-critical + parts of your code (and only there), <em>measure</em> before rewriting + your code.</p> + + <p><em>Important note</em>: This section talks about lists functions that + <em>construct</em> lists. A tail-recursive function that does not construct + a list runs in constant space, while the corresponding body-recursive + function uses stack space proportional to the length of the list. + For instance, a function that sums a list of integers, should <em>not</em> be + written like this</p> + + <p><em>DO NOT</em></p> + <code type="erl"> +recursive_sum([H|T]) -> H+recursive_sum(T); +recursive_sum([]) -> 0.</code> + + <p>but like this</p> + + <p><em>DO</em></p> + <code type="erl"> +sum(L) -> sum(L, 0). + +sum([H|T], Sum) -> sum(T, Sum + H); +sum([], Sum) -> Sum.</code> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/make.dep b/system/doc/efficiency_guide/make.dep new file mode 100644 index 0000000000..afa3bd0516 --- /dev/null +++ b/system/doc/efficiency_guide/make.dep @@ -0,0 +1,16 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: advanced.tex binaryhandling.tex book.tex commoncaveats.tex \ + drivers.tex functions.tex introduction.tex listhandling.tex \ + myths.tex part.tex processes.tex profiling.tex \ + tablesDatabases.tex + diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml new file mode 100644 index 0000000000..76a72368bb --- /dev/null +++ b/system/doc/efficiency_guide/myths.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2007</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>The Eight Myths of Erlang Performance</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-11-10</date> + <rev></rev> + <file>myths.xml</file> + </header> + + <p>Some truths seem to live on well beyond their best-before date, + perhaps because "information" spreads more rapidly from person-to-person + faster than a single release note that notes, for instance, that funs + have become faster.</p> + + <p>Here we try to kill the old truths (or semi-truths) that have + become myths.</p> + + <section> + <title>Myth: Funs are slow</title> + <p>Yes, funs used to be slow. Very slow. Slower than <c>apply/3</c>. + Originally, funs were implemented using nothing more than + compiler trickery, ordinary tuples, <c>apply/3</c>, and a great + deal of ingenuity.</p> + + <p>But that is ancient history. Funs was given its own data type + in the R6B release and was further optimized in the R7B release. + Now the cost for a fun call falls roughly between the cost for a call to + local function and <c>apply/3</c>.</p> + </section> + + <section> + <title>Myth: List comprehensions are slow</title> + + <p>List comprehensions used to be implemented using funs, and in the + bad old days funs were really slow.</p> + + <p>Nowadays the compiler rewrites list comprehensions into an ordinary + recursive function. Of course, using a tail-recursive function with + a reverse at the end would be still faster. Or would it? + That leads us to the next myth.</p> + </section> + + <section> + <title>Myth: Tail-recursive functions are MUCH faster + than recursive functions</title> + + <p><marker id="tail_recursive"></marker>According to the myth, + recursive functions leave references + to dead terms on the stack and the garbage collector will have to + copy all those dead terms, while tail-recursive functions immediately + discard those terms.</p> + + <p>That used to be true before R7B. In R7B, the compiler started + to generate code that overwrites references to terms that will never + be used with an empty list, so that the garbage collector would not + keep dead values any longer than necessary.</p> + + <p>Even after that optimization, a tail-recursive function would + still most of the time be faster than a body-recursive function. Why?</p> + + <p>It has to do with how many words of stack that are used in each + recursive call. In most cases, a recursive function would use more words + on the stack for each recursion than the number of words a tail-recursive + would allocate on the heap. Since more memory is used, the garbage + collector will be invoked more frequently, and it will have more work traversing + the stack.</p> + + <p>In R12B and later releases, there is an optimization that will + in many cases reduces the number of words used on the stack in + body-recursive calls, so that a body-recursive list function and + tail-recursive function that calls <seealso + marker="stdlib:lists#reverse/1">lists:reverse/1</seealso> at the + end will use exactly the same amount of memory. + <c>lists:map/2</c>, <c>lists:filter/2</c>, list comprehensions, + and many other recursive functions now use the same amount of space + as their tail-recursive equivalents.</p> + + <p>So which is faster?</p> + + <p>It depends. On Solaris/Sparc, the body-recursive function seems to + be slightly faster, even for lists with very many elements. On the x86 + architecture, tail-recursion was up to about 30 percent faster.</p> + + <p>So the choice is now mostly a matter of taste. If you really do need + the utmost speed, you must <em>measure</em>. You can no longer be + absolutely sure that the tail-recursive list function will be the fastest + in all circumstances.</p> + + <p>Note: A tail-recursive function that does not need to reverse the + list at the end is, of course, faster than a body-recursive function, + as are tail-recursive functions that do not construct any terms at all + (for instance, a function that sums all integers in a list).</p> + </section> + + <section> + <title>Myth: '++' is always bad</title> + + <p>The <c>++</c> operator has, somewhat undeservedly, got a very bad reputation. + It probably has something to do with code like</p> + + <p><em>DO NOT</em></p> + <code type="erl"> +naive_reverse([H|T]) -> + naive_reverse(T)++[H]; +naive_reverse([]) -> + [].</code> + + <p>which is the most inefficient way there is to reverse a list. + Since the <c>++</c> operator copies its left operand, the result + will be copied again and again and again... leading to quadratic + complexity.</p> + + <p>On the other hand, using <c>++</c> like this</p> + + <p><em>OK</em></p> + <code type="erl"> +naive_but_ok_reverse([H|T], Acc) -> + naive_but_ok_reverse(T, [H]++Acc); +naive_but_ok_reverse([], Acc) -> + Acc.</code> + + <p>is not bad. Each list element will only be copied once. + The growing result <c>Acc</c> is the right operand + for the <c>++</c> operator, and it will <em>not</em> be copied.</p> + + <p>Of course, experienced Erlang programmers would actually write</p> + + <p><em>DO</em></p> + <code type="erl"> +vanilla_reverse([H|T], Acc) -> + vanilla_reverse(T, [H|Acc]); +vanilla_reverse([], Acc) -> + Acc.</code> + + <p>which is slightly more efficient because you don't build a + list element only to directly copy it. (Or it would be more efficient + if the the compiler did not automatically rewrite <c>[H]++Acc</c> + to <c>[H|Acc]</c>.)</p> + </section> + + <section> + <title>Myth: Strings are slow</title> + + <p>Actually, string handling could be slow if done improperly. + In Erlang, you'll have to think a little more about how the strings + are used and choose an appropriate representation and use + the <seealso marker="stdlib:re">re</seealso> instead of the obsolete + <c>regexp</c> module if you are going to use regualr expressions.</p> + </section> + + <section> + <title>Myth: Repairing a Dets file is very slow</title> + + <p>The repair time is still proportional to the number of records + in the file, but Dets repairs used to be much, much slower in the past. + Dets has been massively rewritten and improved.</p> + </section> + + <section> + <title>Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)</title> + + <p>BEAM is a register-based virtual machine. It has 1024 virtual registers + that are used for holding temporary values and for passing arguments when + calling functions. Variables that need to survive a function call are saved + to the stack.</p> + + <p>BEAM is a threaded-code interpreter. Each instruction is word pointing + directly to executable C-code, making instruction dispatching very fast.</p> + </section> + + <section> + <title>Myth: Use '_' to speed up your program when a variable is not used</title> + + <p>That was once true, but since R6B the BEAM compiler is quite capable of seeing itself + that a variable is not used.</p> + </section> + +</chapter> + diff --git a/system/doc/efficiency_guide/part.xml b/system/doc/efficiency_guide/part.xml new file mode 100644 index 0000000000..2b78f35e2a --- /dev/null +++ b/system/doc/efficiency_guide/part.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Efficiency Guide </title> + <prepared>Ingela Anderton</prepared> + <docno></docno> + <date>2002-09-23</date> + <rev></rev> + </header> + <xi:include href="introduction.xml"/> + <xi:include href="myths.xml"/> + <xi:include href="commoncaveats.xml"/> + <xi:include href="binaryhandling.xml"/> + <xi:include href="listhandling.xml"/> + <xi:include href="functions.xml"/> + <xi:include href="tablesDatabases.xml"/> + <xi:include href="processes.xml"/> + <xi:include href="drivers.xml"/> + <xi:include href="advanced.xml"/> + <xi:include href="profiling.xml"/> +</part> + diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml new file mode 100644 index 0000000000..a25ec53370 --- /dev/null +++ b/system/doc/efficiency_guide/processes.xml @@ -0,0 +1,264 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Processes</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2007-11-21</date> + <rev></rev> + <file>processes.xml</file> + </header> + + <section> + <title>Creation of an Erlang process</title> + + <p>An Erlang process is lightweight compared to operating + systems threads and processes.</p> + + <p>A newly spawned Erlang process uses 309 words of memory + in the non-SMP emulator without HiPE support. (SMP support + and HiPE support will both add to this size.) The size can + be found out like this:</p> + + <pre> +Erlang (BEAM) emulator version 5.6 [async-threads:0] [kernel-poll:false] + +Eshell V5.6 (abort with ^G) +1> <input>Fun = fun() -> receive after infinity -> ok end end.</input> +#Fun<...> +2> <input>{_,Bytes} = process_info(spawn(Fun), memory).</input> +{memory,1232} +3> <input>Bytes div erlang:system_info(wordsize).</input> +309</pre> + + <p>The size includes 233 words for the heap area (which includes the stack). + The garbage collector will increase the heap as needed.</p> + + <p>The main (outer) loop for a process <em>must</em> be tail-recursive. + If not, the stack will grow until the process terminates.</p> + + <p><em>DO NOT</em></p> + <code type="erl"> +loop() -> + receive + {sys, Msg} -> + handle_sys_msg(Msg), + loop(); + {From, Msg} -> + Reply = handle_msg(Msg), + From ! Reply, + loop() + end, + io:format("Message is processed~n", []).</code> + + <p>The call to <c>io:format/2</c> will never be executed, but a + return address will still be pushed to the stack each time + <c>loop/0</c> is called recursively. The correct tail-recursive + version of the function looks like this:</p> + + <p><em>DO</em></p> +<code type="erl"> + loop() -> + receive + {sys, Msg} -> + handle_sys_msg(Msg), + loop(); + {From, Msg} -> + Reply = handle_msg(Msg), + From ! Reply, + loop() + end.</code> + + <section> + <title>Initial heap size</title> + + <p>The default initial heap size of 233 words is quite conservative + in order to support Erlang systems with hundreds of thousands or + even millions of processes. The garbage collector will grow and + shrink the heap as needed.</p> + + <p>In a system that use comparatively few processes, performance + <em>might</em> be improved by increasing the minimum heap size using either + the <c>+h</c> option for + <seealso marker="erts:erl">erl</seealso> or on a process-per-process + basis using the <c>min_heap_size</c> option for + <seealso marker="erts:erlang#spawn_opt/4">spawn_opt/4</seealso>.</p> + + <p>The gain is twofold: Firstly, although the garbage collector will + grow the heap, it will it grow it step by step, which will be more + costly than directly establishing a larger heap when the process + is spawned. Secondly, the garbage collector may also shrink the + heap if it is much larger than the amount of data stored on it; + setting the minimum heap size will prevent that.</p> + + <warning><p>The emulator will probably use more memory, and because garbage + collections occur less frequently, huge binaries could be + kept much longer.</p></warning> + + <p>In systems with many processes, computation tasks that run + for a short time could be spawned off into a new process with + a higher minimum heap size. When the process is done, it will + send the result of the computation to another process and terminate. + If the minimum heap size is calculated properly, the process may not + have to do any garbage collections at all. + <em>This optimization should not be attempted + without proper measurements.</em></p> + </section> + + </section> + + <section> + <title>Process messages</title> + + <p>All data in messages between Erlang processes is copied, with + the exception of + <seealso marker="binaryhandling#refc_binary">refc binaries</seealso> + on the same Erlang node.</p> + + <p>When a message is sent to a process on another Erlang node, + it will first be encoded to the Erlang External Format before + being sent via an TCP/IP socket. The receiving Erlang node decodes + the message and distributes it to the right process.</p> + + <section> + <title>The constant pool</title> + + <p>Constant Erlang terms (also called <em>literals</em>) are now + kept in constant pools; each loaded module has its own pool. + The following function</p> + + <p><em>DO</em> (in R12B and later)</p> + <code type="erl"> +days_in_month(M) -> + element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code> + + <p>will no longer build the tuple every time it is called (only + to have it discarded the next time the garbage collector was run), but + the tuple will be located in the module's constant pool.</p> + + <p>But if a constant is sent to another process (or stored in + an ETS table), it will be <em>copied</em>. + The reason is that the run-time system must be able + to keep track of all references to constants in order to properly + unload code containing constants. (When the code is unloaded, + the constants will be copied to the heap of the processes that refer + to them.) The copying of constants might be eliminated in a future + release.</p> + </section> + + <section> + <title>Loss of sharing</title> + + <p>Shared sub-terms are <em>not</em> preserved when a term is sent + to another process, passed as the initial process arguments in + the <c>spawn</c> call, or stored in an ETS table. + That is an optimization. Most applications do not send message + with shared sub-terms.</p> + + <p>Here is an example of how a shared sub-term can be created:</p> + + <code type="erl"> +kilo_byte() -> + kilo_byte(10, [42]). + +kilo_byte(0, Acc) -> + Acc; +kilo_byte(N, Acc) -> + kilo_byte(N-1, [Acc|Acc]).</code> + + <p><c>kilo_byte/1</c> creates a deep list. If we call + <c>list_to_binary/1</c>, we can convert the deep list to a binary + of 1024 bytes:</p> + + <pre> +1> <input>byte_size(list_to_binary(efficiency_guide:kilo_byte())).</input> +1024</pre> + + <p>Using the <c>erts_debug:size/1</c> BIF we can see that the + deep list only requires 22 words of heap space:</p> + + <pre> +2> <input>erts_debug:size(efficiency_guide:kilo_byte()).</input> +22</pre> + + <p>Using the <c>erts_debug:flat_size/1</c> BIF, we can calculate + the size of the deep list if sharing is ignored. It will be + the size of the list when it has been sent to another process + or stored in an ETS table:</p> + + <pre> +3> <input>erts_debug:flat_size(efficiency_guide:kilo_byte()).</input> +4094</pre> + + <p>We can verify that sharing will be lost if we insert the + data into an ETS table:</p> + + <pre> +4> <input>T = ets:new(tab, []).</input> +17 +5> <input>ets:insert(T, {key,efficiency_guide:kilo_byte()}).</input> +true +6> <input>erts_debug:size(element(2, hd(ets:lookup(T, key)))).</input> +4094 +7> <input>erts_debug:flat_size(element(2, hd(ets:lookup(T, key)))).</input> +4094</pre> + + <p>When the data has passed through an ETS table, + <c>erts_debug:size/1</c> and <c>erts_debug:flat_size/1</c> + return the same value. Sharing has been lost.</p> + + <p>In a future release of Erlang/OTP, we might implement a + way to (optionally) preserve sharing. We have no plans to make + preserving of sharing the default behaviour, since that would + penalize the vast majority of Erlang applications.</p> + </section> + </section> + + <section> + <title>The SMP emulator</title> + + <p>The SMP emulator (introduced in R11B) will take advantage of + multi-core or multi-CPU computer by running several Erlang schedulers + threads (typically, the same as the number of cores). Each scheduler + thread schedules Erlang processes in the same way as the Erlang scheduler + in the non-SMP emulator.</p> + + <p>To gain performance by using the SMP emulator, your application + <em>must have more than one runnable Erlang process</em> most of the time. + Otherwise, the Erlang emulator can still only run one Erlang process + at the time, but you must still pay the overhead for locking. Although + we try to reduce the locking overhead as much as possible, it will never + become exactly zero.</p> + + <p>Benchmarks that may seem to be concurrent are often sequential. + The estone benchmark, for instance, is entirely sequential. So is also + the most common implementation of the "ring benchmark"; usually one process + is active, while the others wait in a <c>receive</c> statement.</p> + + <p>The <seealso marker="percept:percept">percept</seealso> application + can be used to profile your application to see how much potential (or lack + thereof) it has for concurrency.</p> + </section> + +</chapter> + diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml new file mode 100644 index 0000000000..65d13408bc --- /dev/null +++ b/system/doc/efficiency_guide/profiling.xml @@ -0,0 +1,258 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Profiling</title> + <prepared>Ingela Anderton</prepared> + <docno></docno> + <date>2001-11-02</date> + <rev></rev> + <file>profiling.xml</file> + </header> + + <section> + <title>Do not guess about performance - profile</title> + + <p>Even experienced software developers often guess wrong about where + the performance bottlenecks are in their programs.</p> + + <p>Therefore, profile your program to see where the performance + bottlenecks are and concentrate on optimizing them.</p> + + <p>Erlang/OTP contains several tools to help finding bottlenecks.</p> + + <p><c>fprof</c> and <c>eprof</c> provide the most detailed information + about where the time is spent, but they significantly slow downs the + programs they profile.</p> + + <p>If the program is too big to be profiled by <c>fprof</c> or <c>eprof</c>, + <c>cover</c> and <c>cprof</c> could be used to locate parts of the + code that should be more thoroughly profiled using <c>fprof</c> or + <c>eprof</c>.</p> + + <p><c>cover</c> provides execution counts per line per process, + with less overhead than <c>fprof/eprof</c>. Execution counts can + with some caution be used to locate potential performance bottlenecks. + The most lightweight tool is <c>cprof</c>, but it only provides execution + counts on a function basis (for all processes, not per process).</p> + </section> + + <section> + <title>Big systems</title> + <p>If you have a big system it might be interesting to run profiling + on a simulated and limited scenario to start with. But bottlenecks + have a tendency to only appear or cause problems when + there are many things going on at the same time, and when there + are many nodes involved. Therefore it is desirable to also run + profiling in a system test plant on a real target system.</p> + <p>When your system is big you do not want to run the profiling + tools on the whole system. You want to concentrate on processes + and modules that you know are central and stand for a big part of the + execution.</p> + </section> + + <section> + <title>What to look for</title> + <p>When analyzing the result file from the profiling activity + you should look for functions that are called many + times and have a long "own" execution time (time excluded calls + to other functions). Functions that just are called very + many times can also be interesting, as even small things can add + up to quite a bit if they are repeated often. Then you need to + ask yourself what can I do to reduce this time. Appropriate + types of questions to ask yourself are: </p> + <list type="bulleted"> + <item>Can I reduce the number of times the function is called?</item> + <item>Are there tests that can be run less often if I change + the order of tests?</item> + <item>Are there redundant tests that can be removed? </item> + <item>Is there some expression calculated giving the same result + each time? </item> + <item>Is there other ways of doing this that are equivalent and + more efficient?</item> + <item>Can I use another internal data representation to make + things more efficient? </item> + </list> + <p>These questions are not always trivial to answer. You might + need to do some benchmarks to back up your theory, to avoid + making things slower if your theory is wrong. See <seealso marker="#benchmark">benchmarking</seealso>.</p> + </section> + + <section> + <title>Tools</title> + + <section> + <title>fprof</title> + <p><c>fprof</c> measures the execution time for each function, + both own time i.e how much time a function has used for its + own execution, and accumulated time i.e. including called + functions. The values are displayed per process. You also get + to know how many times each function has been + called. <c>fprof</c> is based on trace to file in order to + minimize runtime performance impact. Using fprof is just a + matter of calling a few library functions, see fprof manual + page under the application tools.</p> + <p><c>fprof</c> was introduced in version R8 of Erlang/OTP. Its + predecessor <c>eprof</c> that is based on the Erlang trace BIFs, + is still available, see eprof manual page under the + application tools. Eprof shows how much time has been used by + each process, and in which function calls this time has been + spent. Time is shown as percentage of total time, not as + absolute time.</p> + </section> + + <section> + <title>cover</title> + <p><c>cover</c>'s primary use is coverage analysis to verify + test cases, making sure all relevant code is covered. + <c>cover</c> counts how many times each executable line of + code is executed when a program is run. This is done on a per + module basis. Of course this information can be used to + determine what code is run very frequently and could therefore + be subject for optimization. Using cover is just a matter of + calling a few library functions, see cover manual + page under the application tools.</p> + </section> + + <section> + <title>cprof</title> + <p><c>cprof</c> is something in between <c>fprof</c> and + <c>cover</c> regarding features. It counts how many times each + function is called when the program is run, on a per module + basis. <c>cprof</c> has a low performance degradation (versus + <c>fprof</c> and <c>eprof</c>) and does not need to recompile + any modules to profile (versus <c>cover</c>).</p> + </section> + + <section> + <title>Tool summarization</title> + <table> + <row> + <cell align="center" valign="middle">Tool</cell> + <cell align="center" valign="middle">Results</cell> + <cell align="center" valign="middle">Size of result</cell> + <cell align="center" valign="middle">Effects on program execution time</cell> + <cell align="center" valign="middle">Records number of calls</cell> + <cell align="center" valign="middle">Records Execution time</cell> + <cell align="center" valign="middle">Records called by</cell> + <cell align="center" valign="middle">Records garbage collection</cell> + </row> + <row> + <cell align="left" valign="middle"><c>fprof </c></cell> + <cell align="left" valign="middle">per process to screen/file </cell> + <cell align="left" valign="middle">large </cell> + <cell align="left" valign="middle">significant slowdown </cell> + <cell align="left" valign="middle">yes </cell> + <cell align="left" valign="middle">total and own</cell> + <cell align="left" valign="middle">yes </cell> + <cell align="left" valign="middle">yes </cell> + </row> + <row> + <cell align="left" valign="middle"><c>eprof </c></cell> + <cell align="left" valign="middle">per process/function to screen/file </cell> + <cell align="left" valign="middle">medium </cell> + <cell align="left" valign="middle">significant slowdown </cell> + <cell align="left" valign="middle">yes </cell> + <cell align="left" valign="middle">only total </cell> + <cell align="left" valign="middle">no </cell> + <cell align="left" valign="middle">no </cell> + </row> + <row> + <cell align="left" valign="middle"><c>cover </c></cell> + <cell align="left" valign="middle">per module to screen/file</cell> + <cell align="left" valign="middle">small </cell> + <cell align="left" valign="middle">moderate slowdown</cell> + <cell align="left" valign="middle">yes, per line </cell> + <cell align="left" valign="middle">no </cell> + <cell align="left" valign="middle">no </cell> + <cell align="left" valign="middle">no </cell> + </row> + <row> + <cell align="left" valign="middle"><c>cprof </c></cell> + <cell align="left" valign="middle">per module to caller</cell> + <cell align="left" valign="middle">small </cell> + <cell align="left" valign="middle">small slowdown </cell> + <cell align="left" valign="middle">yes </cell> + <cell align="left" valign="middle">no </cell> + <cell align="left" valign="middle">no </cell> + <cell align="left" valign="middle">no </cell> + </row> + <tcaption></tcaption> + </table> + </section> + </section> + + <section> + <marker id="benchmark"></marker> + <title>Benchmarking</title> + + <p>The main purpose of benchmarking is to find out which + implementation of a given algorithm or function is the fastest. + Benchmarking is far from an exact science. Today's operating systems + generally run background tasks that are difficult to turn off. + Caches and multiple CPU cores doesn't make it any easier. + It would be best to run Unix-computers in single-user mode when + benchmarking, but that is inconvenient to say the least for casual + testing.</p> + + <p>Benchmarks can measure wall-clock time or CPU time.</p> + + <p><seealso marker="stdlib:timer#tc/3">timer:tc/3</seealso> measures + wall-clock time. The advantage with wall-clock time is that I/O, + swapping, and other activities in the operating-system kernel are + included in the measurements. The disadvantage is that the + the measurements will vary wildly. Usually it is best to run the + benchmark several times and note the shortest time - that time should + be the minimum time that is possible to achieve under the best of + circumstances.</p> + + <p><seealso marker="erts:erlang#statistics/1">statistics/1</seealso> + with the argument <c>runtime</c> measures CPU time spent in the Erlang + virtual machine. The advantage is that the results are more + consistent from run to run. The disadvantage is that the time + spent in the operating system kernel (such as swapping and I/O) + are not included. Therefore, measuring CPU time is misleading if + any I/O (file or sockets) are involved.</p> + + <p>It is probably a good idea to do both wall-clock measurements and + CPU time measurements.</p> + + <p>Some additional advice:</p> + + <list type="bulleted"> + <item>The granularity of both types measurement could be quite + high so you should make sure that each individual measurement + lasts for at least several seconds.</item> + + <item>To make the test fair, each new test run should run in its own, + newly created Erlang process. Otherwise, if all tests runs in the + same process, the later tests would start out with larger heap sizes + and therefore probably does less garbage collections. You could + also consider restarting the Erlang emulator between each test.</item> + + <item>Do not assume that the fastest implementation of a given algorithm + on computer architecture X also is the fast on computer architecture Y.</item> + + </list> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/tablesDatabases.xml b/system/doc/efficiency_guide/tablesDatabases.xml new file mode 100644 index 0000000000..4b53348c4c --- /dev/null +++ b/system/doc/efficiency_guide/tablesDatabases.xml @@ -0,0 +1,379 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Tables and databases</title> + <prepared>Ingela Anderton</prepared> + <docno></docno> + <date>2001-08-07</date> + <rev></rev> + <file>tablesDatabases.xml</file> + </header> + + <section> + <title>Ets, Dets and Mnesia</title> + <p>Every example using Ets has a corresponding example in + Mnesia. In general all Ets examples also apply to Dets tables.</p> + + <section> + <title>Select/Match operations</title> + <p>Select/Match operations on Ets and Mnesia tables can become + very expensive operations. They usually need to scan the complete + table. You should try to structure your + data so that you minimize the need for select/match + operations. However, if you really need a select/match operation, + it will still be more efficient than using <c>tab2list</c>. + Examples of this and also of ways to avoid select/match will be provided in + some of the following sections. The functions + <c>ets:select/2</c> and <c>mnesia:select/3</c> should be preferred over + <c>ets:match/2</c>,<c>ets:match_object/2</c>, and <c>mnesia:match_object/3</c>.</p> + <note> + <p>There are exceptions when the complete table is not + scanned, for instance if part of the key is bound when searching an + <c>ordered_set</c> table, or if it is a Mnesia + table and there is a secondary index on the field that is + selected/matched. If the key is fully bound there will, of course, be + no point in doing a select/match, unless you have a bag table and + you are only interested in a sub-set of the elements with + the specific key.</p> + </note> + <p>When creating a record to be used in a select/match operation you + want most of the fields to have the value '_'. The easiest and fastest way + to do that is as follows:</p> + <pre> +#person{age = 42, _ = '_'}. </pre> + </section> + + <section> + <title>Deleting an element</title> + <p>The delete operation is considered + successful if the element was not present in the table. Hence + all attempts to check that the element is present in the + Ets/Mnesia table before deletion are unnecessary. Here follows + an example for Ets tables.</p> + <p><em>DO</em></p> + <pre> +... +ets:delete(Tab, Key), +...</pre> + <p><em>DO NOT</em></p> + <pre> +... +case ets:lookup(Tab, Key) of + [] -> + ok; + [_|_] -> + ets:delete(Tab, Key) +end, +...</pre> + </section> + + <section> + <title>Data fetching</title> + <p>Do not fetch data that you already have! Consider that you + have a module that handles the abstract data type Person. You + export the interface function <c>print_person/1</c> that uses the internal functions + <c>print_name/1</c>, <c>print_age/1</c>, <c>print_occupation/1</c>.</p> + <note> + <p>If the functions <c>print_name/1</c> and so on, had been interface + functions the matter comes in to a whole new light, as you + do not want the user of the interface to know about the + internal data representation. </p> + </note> + <p><em>DO</em></p> + <code type="erl"> +%%% Interface function +print_person(PersonId) -> + %% Look up the person in the named table person, + case ets:lookup(person, PersonId) of + [Person] -> + print_name(Person), + print_age(Person), + print_occupation(Person); + [] -> + io:format("No person with ID = ~p~n", [PersonID]) + end. + +%%% Internal functions +print_name(Person) -> + io:format("No person ~p~n", [Person#person.name]). + +print_age(Person) -> + io:format("No person ~p~n", [Person#person.age]). + +print_occupation(Person) -> + io:format("No person ~p~n", [Person#person.occupation]).</code> + <p><em>DO NOT</em></p> + <code type="erl"> +%%% Interface function +print_person(PersonId) -> + %% Look up the person in the named table person, + case ets:lookup(person, PersonId) of + [Person] -> + print_name(PersonID), + print_age(PersonID), + print_occupation(PersonID); + [] -> + io:format("No person with ID = ~p~n", [PersonID]) + end. + +%%% Internal functionss +print_name(PersonID) -> + [Person] = ets:lookup(person, PersonId), + io:format("No person ~p~n", [Person#person.name]). + +print_age(PersonID) -> + [Person] = ets:lookup(person, PersonId), + io:format("No person ~p~n", [Person#person.age]). + +print_occupation(PersonID) -> + [Person] = ets:lookup(person, PersonId), + io:format("No person ~p~n", [Person#person.occupation]).</code> + </section> + + <section> + <title>Non-persistent data storage </title> + <p>For non-persistent database storage, prefer Ets tables over + Mnesia local_content tables. Even the Mnesia <c>dirty_write</c> + operations carry a fixed overhead compared to Ets writes. + Mnesia must check if the table is replicated or has indices, + this involves at least one Ets lookup for each + <c>dirty_write</c>. Thus, Ets writes will always be faster than + Mnesia writes.</p> + </section> + + <section> + <title>tab2list</title> + <p>Assume we have an Ets-table, which uses <c>idno</c> as key, + and contains:</p> + <pre> +[#person{idno = 1, name = "Adam", age = 31, occupation = "mailman"}, + #person{idno = 2, name = "Bryan", age = 31, occupation = "cashier"}, + #person{idno = 3, name = "Bryan", age = 35, occupation = "banker"}, + #person{idno = 4, name = "Carl", age = 25, occupation = "mailman"}]</pre> + <p>If we <em>must</em> return all data stored in the Ets-table we + can use <c>ets:tab2list/1</c>. However, usually we are only + interested in a subset of the information in which case + <c>ets:tab2list/1</c> is expensive. If we only want to extract + one field from each record, e.g., the age of every person, we + should use:</p> + <p><em>DO</em></p> + <pre> +... +ets:select(Tab,[{ #person{idno='_', + name='_', + age='$1', + occupation = '_'}, + [], + ['$1']}]), +...</pre> + <p><em>DO NOT</em></p> + <pre> +... +TabList = ets:tab2list(Tab), +lists:map(fun(X) -> X#person.age end, TabList), +...</pre> + <p>If we are only interested in the age of all persons named + Bryan, we should:</p> + <p><em>DO</em></p> + <pre> +... +ets:select(Tab,[{ #person{idno='_', + name="Bryan", + age='$1', + occupation = '_'}, + [], + ['$1']}]), +...</pre> + <p><em>DO NOT</em></p> + <pre> +... +TabList = ets:tab2list(Tab), +lists:foldl(fun(X, Acc) -> case X#person.name of + "Bryan" -> + [X#person.age|Acc]; + _ -> + Acc + end + end, [], TabList), +...</pre> + <p><em>REALLY DO NOT</em></p> + <pre> +... +TabList = ets:tab2list(Tab), +BryanList = lists:filter(fun(X) -> X#person.name == "Bryan" end, + TabList), +lists:map(fun(X) -> X#person.age end, BryanList), +...</pre> + <p>If we need all information stored in the Ets table about + persons named Bryan we should:</p> + <p><em>DO</em></p> + <pre> +... +ets:select(Tab, [{#person{idno='_', + name="Bryan", + age='_', + occupation = '_'}, [], ['$_']}]), +...</pre> + <p><em>DO NOT</em></p> + <pre> +... +TabList = ets:tab2list(Tab), +lists:filter(fun(X) -> X#person.name == "Bryan" end, TabList), +...</pre> + </section> + + <section> + <title>Ordered_set tables</title> + <p>If the data in the table should be accessed so that the order + of the keys in the table is significant, the table type + <c>ordered_set</c> could be used instead of the more usual + <c>set</c> table type. An <c>ordered_set</c> is always + traversed in Erlang term order with regard to the key field + so that return values from functions such as <c>select</c>, + <c>match_object</c>, and <c>foldl</c> are ordered by the key + values. Traversing an <c>ordered_set</c> with the <c>first</c> and + <c>next</c> operations also returns the keys ordered.</p> + <note> + <p>An <c>ordered_set</c> only guarantees that + objects are processed in <em>key</em> order. Results from functions as + <c>ets:select/2</c> appear in the <em>key</em> order even if + the key is not included in the result.</p> + </note> + </section> + </section> + + <section> + <title>Ets specific</title> + + <section> + <title>Utilizing the keys of the Ets table</title> + <p>An Ets table is a single key table (either a hash table or a + tree ordered by the key) and should be used as one. In other + words, use the key to look up things whenever possible. A + lookup by a known key in a set Ets table is constant and for a + ordered_set Ets table it is O(logN). A key lookup is always + preferable to a call where the whole table has to be + scanned. In the examples above, the field <c>idno</c> is the + key of the table and all lookups where only the name is known + will result in a complete scan of the (possibly large) table + for a matching result.</p> + <p>A simple solution would be to use the <c>name</c> field as + the key instead of the <c>idno</c> field, but that would cause + problems if the names were not unique. A more general solution + would be create a second table with name as key and idno as + data, i.e. to index (invert) the table with regards to the + <c>name</c> field. The second table would of course have to be + kept consistent with the master table. Mnesia could do this + for you, but a home brew index table could be very efficient + compared to the overhead involved in using Mnesia.</p> + <p>An index table for the table in the previous examples would + have to be a bag (as keys would appear more than once) and could + have the following contents:</p> + <pre> + +[#index_entry{name="Adam", idno=1}, + #index_entry{name="Bryan", idno=2}, + #index_entry{name="Bryan", idno=3}, + #index_entry{name="Carl", idno=4}]</pre> + <p>Given this index table a lookup of the <c>age</c> fields for + all persons named "Bryan" could be done like this:</p> + <pre> +... +MatchingIDs = ets:lookup(IndexTable,"Bryan"), +lists:map(fun(#index_entry{idno = ID}) -> + [#person{age = Age}] = ets:lookup(PersonTable, ID), + Age + end, + MatchingIDs), +...</pre> + <p>Note that the code above never uses <c>ets:match/2</c> but + instead utilizes the <c>ets:lookup/2</c> call. The + <c>lists:map/2</c> call is only used to traverse the <c>idno</c>s + matching the name "Bryan" in the table; therefore the number of lookups + in the master table is minimized.</p> + <p>Keeping an index table introduces some overhead when + inserting records in the table, therefore the number of operations + gained from the table has to be weighted against the number of + operations inserting objects in the table. However, note that the gain when + the key can be used to lookup elements is significant.</p> + </section> + </section> + + <section> + <title>Mnesia specific</title> + + <section> + <title>Secondary index</title> + <p>If you frequently do a lookup on a field that is not the + key of the table, you will lose performance using + "mnesia:select/match_object" as this function will traverse the + whole table. You may create a secondary index instead and + use "mnesia:index_read" to get faster access, however this + will require more memory. Example:</p> + <pre> +-record(person, {idno, name, age, occupation}). + ... +{atomic, ok} = +mnesia:create_table(person, [{index,[#person.age]}, + {attributes, + record_info(fields, person)}]), +{atomic, ok} = mnesia:add_table_index(person, age), +... + +PersonsAge42 = + mnesia:dirty_index_read(person, 42, #person.age), +...</pre> + </section> + + <section> + <title>Transactions </title> + <p>Transactions is a way to guarantee that the distributed + Mnesia database remains consistent, even when many different + processes update it in parallel. However if you have + real time requirements it is recommended to use dirty + operations instead of transactions. When using the dirty + operations you lose the consistency guarantee, this is usually + solved by only letting one process update the table. Other + processes have to send update requests to that process.</p> + <pre> +... +% Using transaction + +Fun = fun() -> + [mnesia:read({Table, Key}), + mnesia:read({Table2, Key2})] + end, + +{atomic, [Result1, Result2]} = mnesia:transaction(Fun), +... + +% Same thing using dirty operations +... + +Result1 = mnesia:dirty_read({Table, Key}), +Result2 = mnesia:dirty_read({Table2, Key2}), +...</pre> + </section> + </section> +</chapter> + diff --git a/system/doc/efficiency_guide/xmlfiles.mk b/system/doc/efficiency_guide/xmlfiles.mk new file mode 100644 index 0000000000..fa2fe44eec --- /dev/null +++ b/system/doc/efficiency_guide/xmlfiles.mk @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +EFF_GUIDE_CHAPTER_FILES = \ + advanced.xml \ + commoncaveats.xml \ + binaryhandling.xml \ + functions.xml \ + introduction.xml \ + listhandling.xml \ + myths.xml \ + part.xml \ + processes.xml \ + profiling.xml \ + tablesDatabases.xml \ + drivers.xml + diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile new file mode 100644 index 0000000000..5e68917fc2 --- /dev/null +++ b/system/doc/embedded/Makefile @@ -0,0 +1,103 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/embedded + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(EMBEDDED_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +PS_FILES = + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/embedded + + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + diff --git a/system/doc/embedded/book.xml b/system/doc/embedded/book.xml new file mode 100644 index 0000000000..7dc43e36bf --- /dev/null +++ b/system/doc/embedded/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Embedded Systems</title> + <prepared>Kenneth Lundin</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file></file> + </header> + <insidecover> + </insidecover> + <pagetext>Embedded Systems</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/embedded/embedded_nt.xml b/system/doc/embedded/embedded_nt.xml new file mode 100644 index 0000000000..8e594b1951 --- /dev/null +++ b/system/doc/embedded/embedded_nt.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Windows NT</title> + <prepared>Kenneth Lundin</prepared> + <responsible>Kenneth Lundin</responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>1997-11-25</date> + <rev>PA2</rev> + <file>embedded_nt.xml</file> + </header> + <p>This chapter describes the OS specific parts of OTP which relate + to Windows NT. + </p> + + <section> + <title>Introduction</title> + <p>A normal installation of NT 4.0, with service pack 4 or later, + is required for an embedded Windows NT running OTP.</p> + </section> + + <section> + <title>Memory Usage</title> + <p>RAM memory of 96 MBytes is recommended to run OTP on NT. + A system with less than 64 Mbytes of RAM is not recommended.</p> + </section> + + <section> + <title>Disk Space Usage</title> + <p>A minimum NT installation with networking needs 250 MB, and + an additional 130 MB for the swap file. </p> + </section> + + <section> + <title>Installation</title> + <p>Normal NT installation is performed. No additional application + programs are needed, such as Internet explorer or web server. Networking + with TCP/IP is required. <br></br> + + Service pack 4 or later must be installed.</p> + + <section> + <title>Hardware Watchdog</title> + <p>For Windows NT running on standard PCs with ISA and/or PCI bus + there is a possibility to install an extension card with a hardware + watchdog. + </p> + <p>See also the <c>heart(3)</c> reference manual page in + <em>Kernel</em>. + </p> + </section> + </section> + + <section> + <title>Starting Erlang</title> + <p>On an embedded system, the <c>erlsrv</c> module should be used, + to install the erlang process as a Windows system service. + This service can start + after NT has booted. See documentation for <c>erlsrv</c>.</p> + </section> +</chapter> + diff --git a/system/doc/embedded/embedded_solaris.xml b/system/doc/embedded/embedded_solaris.xml new file mode 100644 index 0000000000..93532da8e6 --- /dev/null +++ b/system/doc/embedded/embedded_solaris.xml @@ -0,0 +1,734 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Embedded Solaris</title> + <prepared>Fredrik Tillman</prepared> + <responsible></responsible> + <docno>ETX/B/SFP/TILLMAN:96-001</docno> + <approved></approved> + <checked></checked> + <date>2000-10-17</date> + <rev>B</rev> + <file>embedded_solaris.xml</file> + </header> + <p>This chapter describes the OS specific parts of OTP which relate + to Solaris. + </p> + + <section> + <title>Memory Usage</title> + <p>Solaris takes about 17 Mbyte of RAM on a system with 64 Mbyte of + total RAM. This leaves about 47 Mbyte for the applications. If + the system utilizes swapping, these figures cannot be improved + because unnecessary daemon processes are swapped out. However, + if swapping is disabled, or if the swap space is of limited + resource in the system, it becomes necessary to kill off + unnecessary daemon processes. + </p> + </section> + + <section> + <title>Disk Space Usage</title> + <p>The disk space required by Solaris can be minimized by using the + Core User support installation. It requires about 80 Mbyte of + disk space. This installs only the minimum software required to + boot and run Solaris. The disk space can be further reduced by + deleting unnecessary individual files. However, unless disk + space is a critical resource the effort required and the risks + involved may not be justified.</p> + </section> + + <section> + <title>Installation</title> + <p>This section is about installing an embedded system. + The following topics are considered, + </p> + <list type="bulleted"> + <item> + <p>Creation of user and installation directory,</p> + </item> + <item> + <p>Installation of embedded system,</p> + </item> + <item> + <p>Configuration for automatic start at reboot,</p> + </item> + <item> + <p>Making a hardware watchdog available,</p> + </item> + <item> + <p>Changing permission for reboot,</p> + </item> + <item> + <p>Patches,</p> + </item> + <item> + <p>Configuration of the OS_Mon application.</p> + </item> + </list> + <p>Several of the procedures described below require expert + knowledge of the Solaris 2 operating system. For most of them + super user privilege is needed. + </p> + + <section> + <title>Creation of User and Installation Directory</title> + <p>It is recommended that the Embedded Environment is run by an + ordinary user, i.e. a user who does not have super user + privileges. + </p> + <p>Throughout this section we assume that the user name is + <c>otpuser</c>, and that the home directory of that user is, + </p> + <pre> + /export/home/otpuser</pre> + <p>Furthermore, we assume that in the home directory of + <c>otpuser</c>, there is a directory named <c>otp</c>, the + full path of which is, + </p> + <pre> + /export/home/otpuser/otp</pre> + <p>This directory is the <em>installation directory</em> of the + Embedded Environment. + </p> + </section> + + <section> + <title>Installation of an Embedded System</title> + <p>The procedure for installation of an embedded system does + not differ from that of an ordinary system (see the + <em>Installation Guide</em>), + except for the following: + </p> + <list type="bulleted"> + <item> + <p>the (compressed) tape archive file should be + extracted in the installation directory as defined above, + and,</p> + </item> + <item> + <p>there is no need to link the start script to a + standard directory like <c>/usr/local/bin</c>.</p> + </item> + </list> + </section> + + <section> + <title>Configuration for Automatic Start at Boot</title> + <p>A true embedded system has to start when the system + boots. This section accounts for the necessary configurations + needed to achieve that. + </p> + <p>The embedded system and all the applications will start + automatically if the script file shown below is added to the + <c>/etc/rc3.d</c> directory. The file must be owned and + readable by <c>root</c>, and its name cannot be arbitrarily + assigned. The following name is recommended, + </p> + <pre> + S75otp.system</pre> + <p>For further details on initialization (and termination) + scripts, and naming thereof, see the Solaris documentation. + </p> + <pre> +#!/bin/sh +# +# File name: S75otp.system +# Purpose: Automatically starts Erlang and applications when the +# system starts +# Author: [email protected] +# Resides in: /etc/rc3.d +# + +if [ ! -d /usr/bin ] +then # /usr not mounted + exit +fi + +killproc() { # kill the named process(es) + pid=`/usr/bin/ps -e | + /usr/bin/grep -w $1 | + /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + [ "$pid" != "" ] && kill $pid +} + +# Start/stop processes required for Erlang + +case "$1" in +'start') + # Start the Erlang emulator + # + su - otpuser -c "/export/home/otpuser/otp/bin/start" & + ;; +'stop') + killproc beam + ;; +*) + echo "Usage: $0 { start | stop }" + ;; +esac</pre> + <p>The file <c>/export/home/otpuser/otp/bin/start</c> referred to + in the above script, is precisely the script <c>start</c> + described in the section <em>Starting Erlang</em> below. The + script variable <c>OTP_ROOT</c> in that <c>start</c> script + corresponds to the example path + </p> + <pre> + /export/home/otpuser/otp</pre> + <p>used in this section. The <c>start</c> script should be edited + accordingly. + </p> + <p>Use of the <c>killproc</c> procedure in the above script could + be combined with a call to <c>erl_call</c>, e.g. + </p> + <pre> + $SOME_PATH/erl_call -n Node init stop</pre> + <p>In order to take Erlang down gracefully see the + <c>erl_call(1)</c> reference manual page for further details + on the use of <c>erl_call</c>. That however requires that + Erlang runs as a distributed node which is not always the + case. + </p> + <p>The <c>killproc</c> procedure should not be removed: the + purpose is here to move from run level 3 (multi-user mode with + networking resources) to run level 2 (multi-user mode without + such resources), in which Erlang should not run. + </p> + </section> + + <section> + <title>Hardware Watchdog</title> + <p>For Solaris running on VME boards from Force Computers, + there is a possibility to activate the onboard hardware + watchdog, provided a VME bus driver is added to the operating + system (see also <em>Installation Problems</em> below). + </p> + <p>See also the <c>heart(3)</c> reference manual page in + <em>Kernel</em>. + </p> + </section> + + <section> + <title>Changing Permissions for Reboot</title> + <p>If the <c>HEART_COMMAND</c> environment variable is to be set + in the <c>start</c> script in the section, <em>Starting Erlang</em>, and if the value shall be set to the + path of the Solaris <c>reboot</c> command, i.e. + </p> + <pre> + HEART_COMMAND=/usr/sbin/reboot</pre> + <p>the ownership and file permissions for <c>/usr/sbin/reboot</c> + must be changed as follows, + </p> + <pre> + chown 0 /usr/sbin/reboot + chmod 4755 /usr/sbin/reboot</pre> + <p>See also the <c>heart(3)</c> reference manual page in + <em>Kernel</em>. + </p> + </section> + + <section> + <title>The TERM Environment Variable</title> + <p>When the Erlang runtime system is automatically started from the + <c>S75otp.system</c> script the <c>TERM</c> environment + variable has to be set. The following is a minimal setting, + </p> + <pre> + TERM=sun</pre> + <p>which should be added to the <c>start</c> script described in + the section. + </p> + </section> + + <section> + <title>Patches</title> + <p>For proper functioning of flushing file system data to disk on + Solaris 2.5.1, the version specific patch with number + 103640-02 must be added to the operating system. There may be + other patches needed, see the release README file + <c><![CDATA[<ERL_INSTALL_DIR>/README]]></c>. + </p> + </section> + + <section> + <title>Installation of Module os_sup in Application OS_Mon</title> + <p>The following four installation procedures require super user + privilege. + </p> + + <section> + <title>Installation</title> + <list type="ordered"> + <item> + <p><em>Make a copy the Solaris standard configuration file for syslogd.</em></p> + <list type="bulleted"> + <item> + <p>Make a copy the Solaris standard configuration + file for syslogd. This file is usually named + <c>syslog.conf</c> and found in the <c>/etc</c> + directory.</p> + </item> + <item> + <p>The file name of the copy must be + <c>syslog.conf.ORIG</c> but the directory location + is optional. Usually it is <c>/etc</c>. + </p> + <p>A simple way to do this is to issue the command</p> + <code type="none"> +cp /etc/syslog.conf /etc/syslog.conf.ORIG</code> + </item> + </list> + </item> + <item> + <p><em>Make an Erlang specific configuration file for syslogd.</em></p> + <list type="bulleted"> + <item> + <p>Make an edited copy of the back-up copy previously + made.</p> + </item> + <item> + <p>The file name must be <c>syslog.conf.OTP</c> and the + path must be the same as the back-up copy.</p> + </item> + <item> + <p>The format of the configuration file is found in the + man page for <c>syslog.conf(5)</c>, by issuing the + command <c>man syslog.conf</c>.</p> + </item> + <item> + <p>Usually a line is added which should state:</p> + <list type="bulleted"> + <item> + <p>which types of information that will be + supervised by Erlang,</p> + </item> + <item> + <p>the name of the file (actually a named pipe) + that should receive the information.</p> + </item> + </list> + </item> + <item> + <p>If e.g. only information originating from the + unix-kernel should be supervised, the line should + begin with <c>kern.LEVEL</c> (for the possible + values of <c>LEVEL</c> see <c>syslog.conf(5)</c>).</p> + </item> + <item> + <p>After at least one tab-character, the line added + should contain the full name of the named pipe where + syslogd writes its information. The path must be the + same as for the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files. The file name must be + <c>syslog.otp</c>.</p> + </item> + <item> + <p>If the directory for the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files is <c>/etc</c> the line + in <c>syslog.conf.OTP</c> will look like:</p> + <code type="none"> +kern.LEVEL /etc/syslog.otp</code> + </item> + </list> + </item> + <item> + <p><em>Check the file privileges of the configuration files.</em></p> + <list type="bulleted"> + <item> + <p>The configuration files should have <c>rw-r--r--</c> + file privileges and be owned by root.</p> + </item> + <item> + <p>A simple way to do this is to issue the commands</p> + <code type="none"> +chmod 644 /etc/syslog.conf +chmod 644 /etc/syslog.conf.ORIG +chmod 644 /etc/syslog.conf.OTP</code> + </item> + <item> + <p><em>Note:</em> If the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files are not in the + <c>/etc</c> directory, the file path in the second + and third command must be modified.</p> + </item> + </list> + </item> + <item> + <p><em>Modify file privileges and ownership of the mod_syslog utility.</em></p> + <list type="bulleted"> + <item> + <p>The file privileges and ownership of the + <c>mod_syslog</c> utility must be modified.</p> + </item> + <item> + <p>The full name of the binary executable file is + derived from the position of the <c>os_mon</c> + application if the file system by adding + <c>/priv/bin/mod_syslog</c>. The generic full name + of the binary executable file is thus</p> + <code type="none"><![CDATA[ +<OTP_ROOT>/lib/os_mon-<REV>/priv/bin/mod_syslog]]></code> + <p><em>Example:</em> If the path to the otp-root is + <c>/usr/otp</c>, thus the path to the <c>os_mon</c> + application is <c>/usr/otp/lib/os_mon-1.0</c> + (assuming revision 1.0) and the full name of the + binary executable file is + <c>/usr/otp/lib/os_mon-1.0/priv/bin/mod_syslog</c>.</p> + </item> + <item> + <p>The binary executable file must be owned by root, + have <c>rwsr-xr-x</c> file privileges, in particular + the setuid bit of user must be set. + </p> + </item> + <item> + <p>A simple way to do this is to issue the commands</p> + <code type="none"><![CDATA[ +cd <OTP_ROOT>/lib/os_mon-<REV>/priv/bin/mod_syslog +chmod 4755 mod_syslog +chown root mod_syslog]]></code> + </item> + </list> + </item> + </list> + </section> + + <section> + <title>Testing the Application Configuration File</title> + <p>The following procedure does not require root privilege. + </p> + <list type="bulleted"> + <item> + <p>Ensure that the configuration parameters for the + <c>os_sup</c> module in the <c>os_mon</c> application + are correct.</p> + </item> + <item> + <p>Browse the application configuration file (do + <em>not</em> edit it). The full name of the application + configuration file is derived from the position of the + OS_Mon application if the file system by adding + <c>/ebin/os_mon.app</c>. + </p> + <p>The generic full name of the file is thus</p> + <code type="none"><![CDATA[ +<OTP_ROOT>/lib/os_mon-<REV>/ebin/os_mon.app.]]></code> + <p><em>Example:</em> If the path to the otp-root is + <c>/usr/otp</c>, thus the path to the <c>os_mon</c> + application is <c>/usr/otp/lib/os_mon-1.0 </c> (assuming + revision 1.0) and the full name of the binary executable + file is <c>/usr/otp/lib/os_mon-1.0/ebin/os_mon.app</c>.</p> + </item> + <item> + <p>Ensure that the following configuration parameters are + bound to the correct values.</p> + </item> + </list> + <table> + <row> + <cell align="left" valign="top"><em>Parameter</em></cell> + <cell align="left" valign="top"><em>Function</em></cell> + <cell align="left" valign="top"><em>Standard value</em></cell> + </row> + <row> + <cell align="left" valign="middle">start_os_sup</cell> + <cell align="left" valign="middle">Specifies if os_sup will be started or not.</cell> + <cell align="left" valign="middle"><c>true</c>for the first instance on the hardware; <c>false</c>for the other instances.</cell> + </row> + <row> + <cell align="left" valign="middle">os_sup_own</cell> + <cell align="left" valign="middle">The directory for (1)the back-up copy, (2) the Erlang specific configuration file for syslogd.</cell> + <cell align="left" valign="middle"><c>"/etc"</c></cell> + </row> + <row> + <cell align="left" valign="middle">os_sup_syslogconf</cell> + <cell align="left" valign="middle">The full name for the Solaris standard configuration file for syslogd </cell> + <cell align="left" valign="middle"><c>"/etc/syslog.conf"</c></cell> + </row> + <row> + <cell align="left" valign="middle">error_tag</cell> + <cell align="left" valign="middle">The tag for the messages that are sent to the error logger in the Erlang runtime system.</cell> + <cell align="left" valign="middle"><c>std_error</c></cell> + </row> + <tcaption>Configuration Parameters</tcaption> + </table> + <p>If the values listed in the <c>os_mon.app</c> do not suit + your needs, you should <c>not</c> edit that file. Instead + you should <em>override</em> values in a <em>system configuration file</em>, the full pathname of which is given + on the command line to <c>erl</c>. + </p> + <p><em>Example:</em> The following is an example of the + contents of an application configuration file.</p> + <p></p> + <pre> + [{os_mon, [{start_os_sup, true}, {os_sup_own, "/etc"}, + {os_sup_syslogconf, "/etc/syslog.conf"}, {os_sup_errortag, std_error}]}].</pre> + </section> + + <section> + <title>Related Documents</title> + <p>See also the <c>os_mon(3)</c>, <c>application(3)</c> and + <c>erl(1)</c> reference manual pages.</p> + </section> + </section> + + <section> + <title>Installation Problems</title> + <p>The hardware watchdog timer which is controlled by the + <c>heart</c> port program requires the <c>FORCEvme</c> + package, which contains the VME bus driver, to be + installed. This driver, however, may clash with the Sun + <c>mcp</c> driver and cause the system to completely refuse to + boot. To cure this problem, the following lines should be + added to <c>/etc/system</c>: + </p> + <list type="bulleted"> + <item><c>exclude: drv/mcp</c></item> + <item><c>exclude: drv/mcpzsa</c></item> + <item><c>exclude: drv/mcpp</c></item> + </list> + <warning> + <p>It is recommended that these lines be added to avoid the + clash described, which may make it completely impossible to + boot the system.</p> + </warning> + </section> + </section> + + <section> + <title>Starting Erlang</title> + <p>This section describes how an embedded system is started. There + are four programs involved, and they all normally reside in the + directory <c><![CDATA[<ERL_INSTALL_DIR>/bin]]></c>. The only exception is + the program <c>start</c>, which may be located anywhere, and + also is the only program that must be modified by the user. + </p> + <p>In an embedded system there usually is no interactive shell. + However, it is possible for an operator to attach to the Erlang + system by giving the command <c>to_erl</c>. He is then + connected to the Erlang shell, and may give ordinary Erlang + commands. All interaction with the system through this shell is + logged in a special directory. + </p> + <p>Basically, the procedure is as follows. The program + <c>start</c> is called when the machine is started. It calls + <c>run_erl</c>, which sets things up so the operator can attach + to the system. It calls <c>start_erl</c> which calls the + correct version of <c>erlexec</c> (which is located in + <c><![CDATA[<ERL_INSTALL_DIR>/erts-EVsn/bin]]></c>) with the correct + <c>boot</c> and <c>config</c> files. + </p> + </section> + + <section> + <title>Programs</title> + + <section> + <title>start</title> + <p>This program is called when the machine is started. It may + be modified or re-written to suit a special system. By + default, it must be called <c>start</c> and reside in + <c><![CDATA[<ERL_INSTALL_DIR>/bin]]></c>. Another start program can be + used, by using the configuration parameter <c>start_prg</c> in + the application <c>sasl</c>.</p> + <p>The start program must call <c>run_erl</c> as shown below. + It must also take an optional parameter which defaults to + <c><![CDATA[<ERL_INSTALL_DIR>/releases/start_erl.data]]></c>. + </p> + <p>This program should set static parameters and environment + variables such as <c>-sname Name</c> and <c>HEART_COMMAND</c> + to reboot the machine. + </p> + <p>The <c><![CDATA[<RELDIR>]]></c> directory is where new release packets + are installed, and where the release handler keeps information + about releases. See <c>release_handler(3)</c> in the + application <c>sasl</c> for further information. + </p> + <p>The following script illustrates the default behaviour of the + program. + </p> + <code type="none"><![CDATA[ +#!/bin/sh +# Usage: start [DataFile] +# +ROOTDIR=/usr/local/otp + +if [ -z "$RELDIR" ] +then + RELDIR=$ROOTDIR/releases +fi + +START_ERL_DATA=${1:-$RELDIR/start_erl.data} + +$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl \\ + $ROOTDIR $RELDIR $START_ERL_DATA" > /dev/null 2>&1 &]]></code> + <p>The following script illustrates a modification where the node + is given the name <c>cp1</c>, and the environment variables + <c>HEART_COMMAND</c> and <c>TERM</c> have been added to the + above script. + </p> + <code type="none"><![CDATA[ +#!/bin/sh +# Usage: start [DataFile] +# +HEART_COMMAND=/usr/sbin/reboot +TERM=sun +export HEART_COMMAND TERM + +ROOTDIR=/usr/local/otp + +if [ -z "$RELDIR" ] +then + RELDIR=$ROOTDIR/releases +fi + +START_ERL_DATA=${1:-$RELDIR/start_erl.data} + +$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl \\ + $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname cp1" > /dev/null 2>&1 &]]></code> + <p>If a diskless and/or read-only client node is about to start the + <c>start_erl.data</c> file is located in the client directory at + the master node. Thus, the <c>START_ERL_DATA</c> line should look + like: + </p> + <code type="none"> +CLIENTDIR=$ROOTDIR/clients/clientname +START_ERL_DATA=${1:-$CLIENTDIR/bin/start_erl.data}</code> + </section> + + <section> + <title>run_erl</title> + <p>This program is used to start the emulator, but you will not + be connected to the shell. <c>to_erl</c> is used to connect to + the Erlang shell. + </p> + <code type="none"> +Usage: run_erl pipe_dir/ log_dir "exec command [parameters ...]"</code> + <p>Where <c>pipe_dir/</c> should be <c>/tmp/</c> (<c>to_erl</c> + uses this name by default) and <c>log_dir</c> is where the log + files are written. <c>command [parameters]</c> is executed, + and everything written to stdin and stdout is logged in the + <c>log_dir</c>. + </p> + <p>In the <c>log_dir</c>, log files are written. Each logfile + has a name of the form: <c>erlang.log.N</c> where N is a + generation number, ranging from 1 to 5. Each logfile holds up + to 100kB text. As time goes by the following logfiles will be + found in the logfile directory</p> + <code type="none"> +erlang.log.1 +erlang.log.1, erlang.log.2 +erlang.log.1, erlang.log.2, erlang.log.3 +erlang.log.1, erlang.log.2, erlang.log.3, erlang.log.4 +erlang.log.2, erlang.log.3, erlang.log.4, erlang.log.5 +erlang.log.3, erlang.log.4, erlang.log.5, erlang.log.1 +...</code> + <p>with the most recent logfile being the right most in each row + of the above list. That is, the most recent file is the one + with the highest number, or if there are already four files, + the one before the skip. + </p> + <p>When a logfile is opened (for appending or created) a time + stamp is written to the file. If nothing has been written to + the log files for 15 minutes, a record is inserted that says + that we're still alive. + </p> + </section> + + <section> + <title>to_erl</title> + <p>This program is used to attach to a running Erlang runtime + system, started with <c>run_erl</c>. + </p> + <code type="none"> +Usage: to_erl [pipe_name | pipe_dir]</code> + <p>Where <c>pipe_name</c> defaults to <c>/tmp/erlang.pipe.N</c>. + </p> + <p>To disconnect from the shell without exiting the Erlang + system, type <c>Ctrl-D</c>. + </p> + </section> + + <section> + <title>start_erl</title> + <p>This program starts the Erlang emulator with parameters + <c>-boot</c> and <c>-config</c> set. It reads data about + where these files are located from a file called + <c>start_erl.data</c> which is located in the <c><![CDATA[<RELDIR>]]></c>. + Each new release introduces a new data file. This file is + automatically generated by the release handler in Erlang. + </p> + <p>The following script illustrates the behaviour of the + program. + </p> + <code type="none"> +#!/bin/sh +# +# This program is called by run_erl. It starts +# the Erlang emulator and sets -boot and -config parameters. +# It should only be used at an embedded target system. +# +# Usage: start_erl RootDir RelDir DataFile [ErlFlags ...] +# +ROOTDIR=$1 +shift +RELDIR=$1 +shift +DataFile=$1 +shift + +ERTS_VSN=`awk '{print $1}' $DataFile` +VSN=`awk '{print $2}' $DataFile` + +BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin +EMU=beam +PROGNAME=`echo $0 | sed 's/.*\\///'` +export EMU +export ROOTDIR +export BINDIR +export PROGNAME +export RELDIR + +exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $*</code> + <p>If a diskless and/or read-only client node with the + <c>sasl</c> configuration parameter <c>static_emulator</c> set + to <c>true</c> is about to start the <c>-boot</c> and + <c>-config</c> flags must be changed. As such a client cannot + read a new <c>start_erl.data</c> file (the file is not + possible to change dynamically) the boot and config files are + always fetched from the same place (but with new contents if + a new release has been installed). The <c>release_handler</c> + copies this files to the <c>bin</c> directory in the client + directory at the master nodes whenever a new release is made + permanent. + </p> + <p>Assuming the same <c>CLIENTDIR</c> as above the last line + should look like: + </p> + <code type="none"> +exec $BINDIR/erlexec -boot $CLIENTDIR/bin/start \\ + -config $CLIENTDIR/bin/sys $*</code> + </section> + </section> +</chapter> + diff --git a/system/doc/embedded/intro.xml b/system/doc/embedded/intro.xml new file mode 100644 index 0000000000..3eafffd6fa --- /dev/null +++ b/system/doc/embedded/intro.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang on embedded systems</title> + <prepared>Fredrik Tillman</prepared> + <responsible></responsible> + <docno>ETX/B/SFP/TILLMAN:96-001</docno> + <approved></approved> + <checked></checked> + <date>1997-11-12</date> + <rev>PA1</rev> + <file>intro.sgml</file> + </header> + <p>This manual is a complement to the other manuals and describes how + to install, run and maintain Erlang on an embedded system. + </p> + <p>For more informaton about how to install and start Erlang read + XXXXXXXX. + </p> + + <section> + <title>Memory Usage</title> + <p>Solaris takes about 17 Mbyte of RAM on a system with 64 Mbyte of + total RAM. This leaves about 47 Mbyte for the applications. If + the system utilizes swapping, these figures cannot be improved + because unnecessary daemon processes are swapped out. However, + if swapping is disabled, or if the swap space is a precious + resource in the system, it becomes necessary to kill off + unnecessary daemon processes. + </p> + <p>The following start-scripts can be deleted to + prevent unnecessary daemons from starting: + </p> + <list type="bulleted"> + <item><c>/etc/rc2.d/S72autoinstall</c></item> + <item><c>/etc/rc2.d/S74autofs</c></item> + <item><c>/etc/rc2.d/S76nscd</c></item> + <item><c>/etc/rc2.d/S80PRESERVE</c></item> + <item><c>/etc/rc2.d/S80lp</c></item> + <item><c>/etc/rc2.d/S88sendmail</c></item> + <item><c>/etc/rc2.d/S92volmgt</c></item> + <item><c>/etc/rc2.d/S93cacheos.finish</c></item> + <item><c>/etc/rc3.d/S15nfs.server</c></item> + </list> + <p>More information is expected from Sun on how to modify the + kernel in order to reduce the memory consumption. This will be + performed by modifying the <c>/etc/system</c> file.</p> + </section> + + <section> + <title>Disk Space Usage</title> + <p>The disk space required by Solaris can be minimized by using the + Core User support installation. It requires about 80 Mbyte of + disk space. This installs only the minimum software required to + boot and run Solaris. The disk space can be further reduced by + deleting unnecessary individual files. However, unless disk + space is a critical resource the effort required and the risks + involved may not be justified.</p> + </section> + + <section> + <title>Other Issues</title> + <p>Future releases of OTP will include more information on how + Solaris can be configured for use with embedded systems to get + maximum performance. Issues which will be investigated include: + </p> + <list type="bulleted"> + <item>how disabling swapping affects the system</item> + <item>how locking processes in memory may yield performance benefits.</item> + </list> + </section> +</chapter> + diff --git a/system/doc/embedded/make.dep b/system/doc/embedded/make.dep new file mode 100644 index 0000000000..9949a3ac96 --- /dev/null +++ b/system/doc/embedded/make.dep @@ -0,0 +1,14 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex embedded_nt.tex embedded_solaris.tex \ + part.tex vxworks.tex + diff --git a/system/doc/embedded/note.gif b/system/doc/embedded/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/embedded/note.gif diff --git a/system/doc/embedded/part.xml b/system/doc/embedded/part.xml new file mode 100644 index 0000000000..abedce46d6 --- /dev/null +++ b/system/doc/embedded/part.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Embedded Systems User's Guide</title> + <prepared>Kenneth Lundin, Fredrik Tillman</prepared> + <responsible>UAB/F (Kenneth Lundin)</responsible> + <docno></docno> + <approved>UAB/F (Kenneth Lundin)</approved> + <checked></checked> + <date>2000-10-17</date> + <rev>C</rev> + <file></file> + </header> + <description> + <p>This manual describes the issues that are specific + for running Erlang on an embedded system. + It describes the differences in installing and starting + Erlang compared to how it is done for a non-embedded system. + </p> + <p>Note that this is a supplementary document. You still need to + read the Installation Guide. + </p> + <p>There is also target architecture specific information in + the top level README file of the Erlang distribution.</p> + </description> + <xi:include href="embedded_solaris.xml"/> + <xi:include href="embedded_nt.xml"/> + <xi:include href="vxworks.xml"/> +</part> + diff --git a/system/doc/embedded/starting.xml b/system/doc/embedded/starting.xml new file mode 100644 index 0000000000..ddeaeb8bdf --- /dev/null +++ b/system/doc/embedded/starting.xml @@ -0,0 +1,249 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Starting an Embedded System</title> + <prepared>Martin Björklund</prepared> + <responsible>Bjarne Däcker</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>1997-10-17</date> + <rev>D</rev> + <file>starting.sgml</file> + </header> + + <section> + <title>Introduction</title> + <p>This chapter describes how an embedded system is started. + There are four programs involved, and they all normally reside + in the directory <c><![CDATA[<ERL_INSTALL_DIR>/bin]]></c>. The only + exception is the program <c>start</c>, which may be located + anywhere, and also is the only program that must be modified by + the user. + </p> + <p>In an embedded system there usually is no interactive shell. + However, it is possible for an operator to attach to the + Erlang runtime system by giving the command <c>to_erl</c>. He is + then connected to the Erlang shell, and may give ordinary Erlang + commands. All interaction with the system through this shell is + logged in a special directory. + </p> + <p>Basically, the procedure is as follows. The program + <c>start</c> is called when the machine is started. It calls + <c>run_erl</c>, which sets things up so the operator can attach + to the system. It calls <c>start_erl</c> which calls the + correct version of <c>erlexec</c> (which is located in + <c><![CDATA[<ERL_INSTALL_DIR>/erts-EVsn/bin]]></c>) with the correct + <c>boot</c> and <c>config</c> files. + </p> + </section> + + <section> + <title>Programs</title> + + <section> + <title>start</title> + <p>This program is called when the machine is started. It may + be modified or re-written to suit a special system. By + default, it must be called <c>start</c> and reside in + <c><![CDATA[<ERL_INSTALL_DIR>/bin]]></c>. Another start program can be + used, by using the configuration parameter <c>start_prg</c> in + the application <c>sasl</c>.</p> + <p>The start program must call <c>run_erl</c> as shown below. + It must also take an optional parameter which defaults to + <c><![CDATA[<ERL_INSTALL_DIR>/bin/start_erl.data]]></c>. + </p> + <p>This program should set static parameters and environment + variables such as <c>-sname Name</c> and <c>HEART_COMMAND</c> + to reboot the machine. + </p> + <p>The <c><![CDATA[<RELDIR>]]></c> directory is where new release packets + are installed, and where the release handler keeps information + about releases. See <c>release_handler(3)</c> in the + application <c>sasl</c> for further information. + </p> + <p>The following script illustrates the default behaviour of the + program. + </p> + <code type="none"><![CDATA[ +#!/bin/sh +# Usage: start [DataFile] +# +ROOTDIR=/usr/local/otp + +if [ -z "$RELDIR" ] +then + RELDIR=$ROOTDIR/releases +fi + +START_ERL_DATA=${1:-$RELDIR/start_erl.data} + +$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl @@@ + $ROOTDIR $RELDIR $START_ERL_DATA" > /dev/null 2>&1 &]]></code> + <p>The following script illustrates a modification where the + node is given the name <c>cp1</c>, and the environment variables + <c>HEART_COMMAND</c> and <c>TERM</c> have been added to the + above script. + </p> + <code type="none"><![CDATA[ +#!/bin/sh +# Usage: start [DataFile] +# +HEART_COMMAND=/usr/sbin/reboot +TERM=sun +export HEART_COMMAND TERM + +ROOTDIR=/usr/local/otp + +if [ -z "$RELDIR" ] +then + RELDIR=$ROOTDIR/releases +fi + +START_ERL_DATA=${1:-$RELDIR/start_erl.data} + +$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl @@@ + $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname cp1" > /dev/null 2>&1 &]]></code> + <p>If a diskless and/or read-only client node is about to start the + <c>start_erl.data</c> file is located in the client directory at + the master node. Thus, the <c>START_ERL_DATA</c> line should look + like: + </p> + <code type="none"> +CLIENTDIR=$ROOTDIR/clients/clientname +START_ERL_DATA=${1:-$CLIENTDIR/bin/start_erl.data}</code> + </section> + + <section> + <title>run_erl</title> + <p>This program is used to start the emulator, but you will not + be connected to the shell. <c>to_erl</c> is used to connect to the + Erlang shell. + </p> + <code type="none"> +Usage: run_erl pipe_dir/ log_dir "exec command [parameters ...]"</code> + <p>Where <c>pipe_dir/</c> should be <c>/tmp/</c> + (<c>to_erl</c> uses this name by default) and <c>log_dir</c> is + where the log files are written. <c>command [parameters]</c> is + executed, and everything written to stdin and stdout is logged in + the <c>log_dir</c>. + </p> + <p>In the <c>log_dir</c>, log files are written. Each logfile + has a name of the form: <c>erlang.log.N</c> where N is a + generation number, ranging from 1 to 5. Each logfile holds up to + 100kB text. As time goes by the following logfiles will be found + in the logfile directory</p> + <code type="none"> +erlang.log.1 +erlang.log.1, erlang.log.2 +erlang.log.1, erlang.log.2, erlang.log.3 +erlang.log.1, erlang.log.2, erlang.log.3, erlang.log.4 +erlang.log.2, erlang.log.3, erlang.log.4, erlang.log.5 +erlang.log.3, erlang.log.4, erlang.log.5, erlang.log.1 +... </code> + <p>with the most recent logfile being the right most in each row + of the above list. That is, the most recent file is the one with + the highest number, or if there are already four files, the one + before the skip. + </p> + <p>When a logfile is opened (for appending or created) a time + stamp is written to the file. If nothing has been written to + the log files for 15 minutes, a record is inserted that says + that we're still alive. + </p> + </section> + + <section> + <title>to_erl</title> + <p>This program is used to attach to a running Erlang runtime system, + started with <c>run_erl</c>. + </p> + <code type="none"> +Usage: to_erl [pipe_name | pipe_dir]</code> + <p>Where <c>pipe_name</c> defaults to <c>/tmp/erlang.pipe.N</c>. + </p> + <p>To disconnect from the shell without exiting the Erlang + runtime system, type <c>Ctrl-D</c>. + </p> + </section> + + <section> + <title>start_erl</title> + <p>This program starts the Erlang emulator with parameters + <c>-boot</c> and <c>-config</c> set. It reads data about where + these files are located from a file called <c>start_erl.data</c> + which is located in the <c><![CDATA[<RELDIR>]]></c>. Each new release + introduces a new data file. This file is automatically + generated by the release handler in Erlang. + </p> + <p>The following script illustrates the behaviour of the + program.</p> + <code type="none"> +#!/bin/sh +# +# This program is called by run_erl. It starts +# the Erlang emulator and sets -boot and -config parameters. +# It should only be used at an embedded target system. +# +# Usage: start_erl RootDir RelDir DataFile [ErlFlags ...] +# +ROOTDIR=$1 +shift +RELDIR=$1 +shift +DataFile=$1 +shift + +ERTS_VSN=`awk '{print $1}' $DataFile` +VSN=`awk '{print $2}' $DataFile` + +BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin +EMU=beam +PROGNAME=`echo $0 | sed 's/.*\\///'` +export EMU +export ROOTDIR +export BINDIR +export PROGNAME +export RELDIR + +exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $* </code> + <p>If a diskless and/or read-only client node with the <c>sasl</c> + configuration parameter <c>static_emulator</c> set to <c>true</c> + is about to start the <c>-boot</c> and <c>-config</c> flags must be + changed. As such a client can not read a new <c>start_erl.data</c> + file (the file is not possible to change dynamically) the boot and + config files is always fetched from the same place (but with a new + contents if a new release has been installed). The + <c>release_handler</c> copies this files to the <c>bin</c> directory + in the client directory at the master nodes whenever a new release + is made permanent. + </p> + <p>Assuming the same <c>CLIENTDIR</c> as above the last line should + look like:</p> + <code type="none"> +exec $BINDIR/erlexec -boot $CLIENTDIR/bin/start @@@ + -config $CLIENTDIR/bin/sys $* </code> + </section> + </section> +</chapter> + diff --git a/system/doc/embedded/target.xml b/system/doc/embedded/target.xml new file mode 100644 index 0000000000..4408e6ee48 --- /dev/null +++ b/system/doc/embedded/target.xml @@ -0,0 +1,414 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installation of Embedded Environment</title> + <prepared>Peter Högfeldt</prepared> + <responsible>Peter Högfeldt</responsible> + <docno></docno> + <approved>(Peter Högfeldt</approved> + <checked></checked> + <date>1997-05-26</date> + <rev>C</rev> + <file>target.sgml</file> + </header> + <p>This chapter is about installing a Embedded Environment. Solaris + 2.5.1 is the only UNIX operating system supported for embedded systems. + The following topics are considered,</p> + <list type="bulleted"> + <item> + <p>Creation of user and installation directory,</p> + </item> + <item> + <p>Installation of Embedded Environment,</p> + </item> + <item> + <p>Configuration for automatic start at reboot,</p> + </item> + <item> + <p>Making a hardware watchdog available,</p> + </item> + <item> + <p>Changing permission for reboot,</p> + </item> + <item> + <p>Patches for Solaris 2.5.1,</p> + </item> + <item> + <p>Configuration of the os_mon application.</p> + </item> + </list> + <p>Several of the procedures described below require expert knowledge of + the Solaris 2 operating system. For most of them super user privilege is + needed.</p> + + <section> + <title>Creation of user and installation directory</title> + <p>It is recommended that the Embedded Environment is run by an ordinary + user, i.e. a user which does not have super user privileges. </p> + <p>Throughout this chapter we assume that the user name is <c>otpuser</c>, + and that the home directory of that user is,</p> + <pre> +/export/home/otpuser </pre> + <p>Furthermore, we assume that in the home directory of <c>otpuser</c>, + there is a directory named <c>otp</c>, the full path of which is,</p> + <pre> +/export/home/otpuser/otp </pre> + <p>This directory is the <em>installation directory</em> of the Embedded + Environment.</p> + </section> + + <section> + <title>Installation of Embedded Environment</title> + <p>The procedure for installation of a Embedded Environment does not differ + from that of a Development Environment (see the chapter <em>Installation of Development Environment</em>), except for the following,</p> + <list type="bulleted"> + <item> + <p>the (compressed) tape archive file should be extracted in + the installation directory as defined above, and,</p> + </item> + <item> + <p>there is no need to link the start script to a standard directory + like <c>/usr/local/bin</c>.</p> + </item> + </list> + <p>The details for extracting the tape archive file is not repeated here.</p> + </section> + + <section> + <title>Configuration for Automatic Start at Boot</title> + <p>A true Embedded Environment has to start when the system boots. This + section accounts for the necessary configurations needed to achieve + that.</p> + <p>The embedded environment and all the applications will start automatically + if the script file shown below is added to the <c>/etc/rc3.d</c> directory. + The file must be owned and readable by <c>root</c>, and its name cannot + be arbitrarily assigned. The following name is recommended,</p> + <pre> +S75otp.system </pre> + <p>For further details on initialization (and termination) scripts, and + naming thereof, see the file <c>/etc/init.d/README</c> on a Solaris + 2.5.1 system.</p> + <pre> +#!/bin/sh +# +# File name: S75otp.system +# Purpose: Automatically starts Erlang and applications when the +# system starts +# Author: [email protected] +# Resides in: /etc/rc3.d +# + +if [ ! -d /usr/bin ] +then # /usr not mounted + exit +fi + +killproc() { # kill the named process(es) + pid=`/usr/bin/ps -e | + /usr/bin/grep -w $1 | + /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + [ "$pid" != "" ] && kill $pid +} + +# Start/stop processes required for Erlang + +case "$1" in +'start') + # Start the Erlang emulator + # + su - otpuser -c "/export/home/otpuser/otp/bin/start" & + ;; +'stop') + killproc beam + ;; +*) + echo "Usage: $0 { start | stop }" + ;; +esac </pre> + <p>The file <c>/export/home/otpuser/otp/bin/start</c> referred to in the + above script, is precisely the script <c>start</c> described in the next + chapter of this guide, <em>Starting an Embedded System</em>. The script + variable <c>OTP_ROOT</c> in that <c>start</c> script corresponds to + the example path </p> + <pre> +/export/home/otpuser/otp </pre> + <p>used in this section. The <c>start</c> script should be edited + accordingly.</p> + <p>Use of the <c>killproc</c> procedure in the above script could + be combined with a call to <c>erl_call</c>, e.g.</p> + <pre> + $SOME_PATH/erl_call -n Node init stop </pre> + <p>in order to take Erlang down gracefully (see the <c>erl_call(1)</c> + reference manual page for further details on the use of <c>erl_call</c>). + That however requires that Erlang runs as a distributed node which is + not always the case.</p> + <p>The <c>killproc</c> procedure should not be removed: the purpose is + here to move from run level 3 (multi-user mode with networking resources) + to run level 2 (multi-user mode without such resources), in which Erlang + should not run.</p> + </section> + + <section> + <title>Hardware Watchdog</title> + <p>For Solaris 2.5.1 running on VME boards from Force Computers, there + is a possibility to activate the onboard hardware watchdog, provided a + VME bus driver is added to the operating system. For further details + see the <em>Embedded Systems</em> documentation.</p> + <p>See also the <c>heart(3)</c> reference manual page in <em>Kernel</em>.</p> + </section> + + <section> + <title>Changing permissions for reboot</title> + <p>If the <c>HEART_COMMAND</c> environment variable is to be set in + the <c>start</c> script of the next chapter, <em>Starting an Embedded System</em>, and if the value shall be set to the path of the Solaris + <c>reboot</c> command, i.e.</p> + <pre> +HEART_COMMAND=/usr/sbin/reboot </pre> + <p>the ownership and file permissions for <c>/usr/sbin/reboot</c> must + be changed as follows,</p> + <pre> +chown 0 /usr/sbin/reboot +chmod 4755 /usr/sbin/reboot </pre> + <p>See also the <c>heart(3)</c> reference manual page in <em>Kernel</em>.</p> + </section> + + <section> + <title>The TERM environment variable</title> + <p>When the Erlang runtime system is automatically started from the + <c>S75otp.system</c> script the <c>TERM</c> environment variable + has to be set. The following is a minimal setting,</p> + <pre> +TERM=sun </pre> + <p>which should be added to the <c>start</c> script described in the + next chapter.</p> + </section> + + <section> + <title>Patches for Solaris 2.5.1</title> + <p>For proper functioning of flushing file system data to disk, the + Solaris 2.5.1 specific patch with number 103640-02 must be added + to the operating system.</p> + </section> + + <section> + <title>Installation of module os_sup in application os_mon</title> + <p>The following four installation procedures requires superuser privilege.</p> + + <section> + <title>Installation</title> + <list type="ordered"> + <item> + <p><em>Make a copy the Solaris standard configuration file for syslogd.</em></p> + <list type="bulleted"> + <item> + <p>Make a copy the Solaris standard configuration file for syslogd. + This file is usually named <c>syslog.conf</c> and found in the <c>/etc</c> + directory.</p> + </item> + <item> + <p>The file name of the copy must be <c>syslog.conf.ORIG</c> but the + directory location is optional. Usually it is <c>/etc</c>. + </p> + <p>A simple way to do this is to issue the command</p> + <code type="none"> + cp /etc/syslog.conf /etc/syslog.conf.ORIG</code> + </item> + </list> + </item> + <item> + <p><em>Make an Erlang specific configuration file for syslogd.</em></p> + <list type="bulleted"> + <item> + <p>Make an edited copy of the back-up copy previously made.</p> + </item> + <item> + <p>The file name must be <c>syslog.conf.OTP</c> and the path + must be the same as the back-up copy.</p> + </item> + <item> + <p>The format of the configuration file is found in the man page for + <c>syslog.conf(5)</c>, by issuing the command <c>man syslog.conf</c>.</p> + </item> + <item> + <p>Usually a line is added which should state:</p> + <list type="bulleted"> + <item> + <p>which types of information that will be supervised by Erlang,</p> + </item> + <item> + <p>the name of the file (actually a named pipe) that should receive + the information.</p> + </item> + </list> + </item> + <item> + <p>If e.g. only information originating from the unix-kernel should + be supervised, the line should begin with <c>kern.LEVEL</c> (for the + possible values of <c>LEVEL</c> see <c>syslog.conf(5)</c>).</p> + </item> + <item> + <p>After at least one tab-character, the line added should contain + the full name of the named pipe where syslogd writes its information. The + path must be the same as for the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files. The file name must be <c>syslog.otp</c>.</p> + </item> + <item> + <p>If the directory for the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files is <c>/etc</c> the line in + <c>syslog.conf.OTP</c> will look like:</p> + <code type="none"> + kern.LEVEL /etc/syslog.otp </code> + </item> + </list> + </item> + <item> + <p><em>Check the file privileges of the configuration files.</em></p> + <list type="bulleted"> + <item> + <p>The configuration files should have <c>rw-r--r--</c> file + privileges and be owned by root.</p> + </item> + <item> + <p>A simple way to do this is to issue the commands</p> + <code type="none"> + chmod 644 /etc/syslog.conf + chmod 644 /etc/syslog.conf.ORIG + chmod 644 /etc/syslog.conf.OTP </code> + </item> + <item> + <p><em>Note:</em> If the <c>syslog.conf.ORIG</c> and + <c>syslog.conf.OTP</c> files are not in the <c>/etc</c> directory, + the file path in the second and third command must be modified.</p> + </item> + </list> + </item> + <item> + <p><em>Modify file privileges and ownership of the mod_syslog utility.</em></p> + <list type="bulleted"> + <item> + <p>The file privileges and ownership of the <c>mod_syslog</c> utility + must be modified.</p> + </item> + <item> + <p>The full name of the binary executable file is derived from the + position of the <c>os_mon</c> application if the file system by adding + <c>/priv/bin/mod_syslog</c>. The generic full name of the binary executable + file is thus</p> + <code type="none"><![CDATA[ + <OTP_ROOT>/lib/os_mon-<rev>/priv/bin/mod_syslog ]]></code> + <p><em>Example:</em> If the path to the otp-root is + <c>/usr/otp</c>, thus the path to the <c>os_mon</c> application is + <c>/usr/otp/lib/os_mon-1.0</c> (assuming revision 1.0) and the full name + of the binary executable file is + <c>/usr/otp/lib/os_mon-1.0/priv/bin/mod_syslog</c>.</p> + </item> + <item> + <p>The binary executable file must be owned by root, have + <c>rwsr-xr-x</c> file privileges, in particular the setuid bit of + user must be set.</p> + </item> + <item> + <p>A simple way to do this is to issue the commands</p> + <code type="none"><![CDATA[ + cd <OTP_ROOT>/lib/os_mon-<rev>/priv/bin/mod_syslog + chmod 4755 mod_syslog + chown root mod_syslog ]]></code> + </item> + </list> + </item> + </list> + </section> + + <section> + <title>Testing the application configuration file</title> + <p>The following procedure does not require root privilege.</p> + <list type="bulleted"> + <item> + <p>Ensure that the configuration parameters for the <c>os_sup</c> + module in the <c>os_mon</c> application are correct.</p> + </item> + <item> + <p>Browse the application configuration file (do <em>not</em> edit + it). The full name of the application configuration file is derived + from the position of the os_mon-application if the file system by adding + <c>/ebin/os_mon.app</c>.</p> + <p>The generic full name of the file is thus</p> + <code type="none"><![CDATA[ + <OTP_ROOT>/lib/os_mon-<rev>/ebin/os_mon.app. ]]></code> + <p><em>Example:</em> If the path to the otp-root is <c>/usr/otp</c>, + thus the path to the <c>os_mon</c> application is <c>/usr/otp/lib/os_mon-1.0</c> (assuming revision 1.0) and the full name of the binary executable file + is <c>/usr/otp/lib/os_mon-1.0/ebin/os_mon.app</c>.</p> + </item> + <item> + <p>Ensure that the following configuration parameters are bound to + the correct values.</p> + </item> + </list> + <table> + <row> + <cell align="left" valign="top"><em>Parameter</em></cell> + <cell align="left" valign="top"><em>Function</em></cell> + <cell align="left" valign="top"><em>Standard value</em></cell> + </row> + <row> + <cell align="left" valign="middle">start_os_sup</cell> + <cell align="left" valign="middle">Specifies if os_sup will be started or not.</cell> + <cell align="left" valign="middle"><c>true</c>for the first instance on the hardware; <c>false</c>for the other instances.</cell> + </row> + <row> + <cell align="left" valign="middle">os_sup_own</cell> + <cell align="left" valign="middle">The directory for (1)the back-up copy, (2) the Erlang specific configuration file for syslogd.</cell> + <cell align="left" valign="middle"><c>"/etc"</c></cell> + </row> + <row> + <cell align="left" valign="middle">os_sup_syslogconf</cell> + <cell align="left" valign="middle">The full name for the Solaris standard configuration file for syslogd </cell> + <cell align="left" valign="middle"><c>"/etc/syslog.conf"</c></cell> + </row> + <row> + <cell align="left" valign="middle">error_tag</cell> + <cell align="left" valign="middle">The tag for the messages that are sent to the error logger in the Erlang runtime system.</cell> + <cell align="left" valign="middle"><c>std_error</c></cell> + </row> + <tcaption>Configuration Parameters</tcaption> + </table> + <p>If the values listed in the <c>os_mon.app</c> does not suite your + needs, you should <c>not</c> edit that file. Instead you should + <em>override</em> values in a <em>system configuration file</em>, the + full pathname of which is given on the command line to <c>erl</c>.</p> + <p><em>Example:</em> The following is an example of the contents of an + application configuration file.</p> + <p></p> + <pre> +[{os_mon, [{start_os_sup, true}, {os_sup_own, "/etc"}, + {os_sup_syslogconf, "/etc/syslog.conf"}, {os_sup_errortag, std_error}]}]. </pre> + </section> + + <section> + <title>Related documents</title> + <p>See also the <c>os_mon(3)</c>, <c>application(3)</c> and <c>erl(1)</c> + reference manual pages.</p> + </section> + </section> +</chapter> + diff --git a/system/doc/embedded/vme_problems.xml b/system/doc/embedded/vme_problems.xml new file mode 100644 index 0000000000..7f9b929875 --- /dev/null +++ b/system/doc/embedded/vme_problems.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>VME Bus Driver</title> + <prepared>Fredrik Tillman</prepared> + <responsible></responsible> + <docno>ETX/B/SFP/TILLMAN:96-002</docno> + <approved></approved> + <checked></checked> + <date>1996-10-29</date> + <rev>PA1</rev> + <file>vme_problems.sgml</file> + </header> + <p>This chapter describes the OS specific parts of OTP which relate to + the VME Bus Driver. + </p> + + <section> + <title>Installation Problems</title> + <p>The hardware watchdog timer which is controlled by the + <c>heart</c> port program requires the <c>FORCEvme</c> package, + which contains the VME bus driver, to be installed. This driver, + however, might clash with the Sun <c>mcp</c> driver and cause + the system to completely refuse to boot. To cure this problem, + the following lines should be added to <c>/etc/system</c>: + </p> + <list type="bulleted"> + <item><c>exclude: drv/mcp</c></item> + <item><c>exclude: drv/mcpzsa</c></item> + <item><c>exclude: drv/mcpp</c></item> + </list> + <warning> + <p>It is recommended that these lines be added to avoid the + clash described, which may make it completely impossible to boot + the system.</p> + </warning> + </section> +</chapter> + diff --git a/system/doc/embedded/vxworks.xml b/system/doc/embedded/vxworks.xml new file mode 100644 index 0000000000..52143a42e3 --- /dev/null +++ b/system/doc/embedded/vxworks.xml @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>VxWorks</title> + <prepared>Patrik Winroth</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2000-10-17</date> + <rev></rev> + <file>vxworks.xml</file> + </header> + <p>This chapter describes the OS specific parts of OTP which relate + to VxWorks. + </p> + + <section> + <title>Introduction</title> + <p>The Erlang/OTP distribution for VxWorks is limited to what + Switchboard requires (Switchboard is a general purpose + switching hardware developed by Ericsson). + </p> + <p>Please consult the README file, included at root level in the + installation, for latest information on the distribution. + </p> + </section> + + <section> + <title>Memory Usage</title> + <p>Memory required is 32 Mbyte. + </p> + </section> + + <section> + <title>Disk Usage</title> + <p>The disk space required is 22 Mbyte, the documentation included. + </p> + </section> + + <section> + <title>Installation</title> + <p>OTP/VxWorks is supplied in a distribution file named + <c><![CDATA[<PREFIX>.tar.gz]]></c>; i.e. a tar archive that is + compressed with gzip. <c><![CDATA[<PREFIX>]]></c> represents the + name of the release, + e.g. <c>otp_LXA12345_vxworks_cpu32_R42A</c>. Assuming you are + installing to a Solaris file system, the installation is + performed by following these steps: < + </p> + <p></p> + <list type="bulleted"> + <item>Change to the directory where you want to install + OTP/VxWorks (<c><![CDATA[<ROOTDIR>]]></c>): <c><![CDATA[cd <ROOTDIR>]]></c></item> + <item>Make a directory to put OTP/VxWorks in: <c>mkdir otp_vxworks_cpu32</c> (or whatever you want to call it)</item> + <item>Change directory to the newly created one: <c>cd otp_vxworks_cpu32</c></item> + <item>Copy the distribution file there from where it is located + (<c><![CDATA[<RELDIR>]]></c>): <c><![CDATA[cp <RELDIR>/<PREFIX>.tar.gz .]]></c></item> + <item>Unzip the distribution file: <c><![CDATA[gunzip <PREFIX>.tar.gz]]></c></item> + <item>Untar <c><![CDATA[<PREFIX>.tar]]></c>: <c><![CDATA[tar xvf <PREFIX>.tar]]></c></item> + <item>Create a bin directory: <c>mkdir bin</c></item> + <item>Copy the VxWorks Erlang/OTP start-up script to the bin directory: + <c>cp erts-Vsn/bin/erl bin/.</c></item> + <item>Copy the example start scripts to the bin directory: + <c>cp releases/R42A/*.boot bin/.</c></item> + </list> + <p>If you use VxWorks nfs mounting facility to mount the Solaris + file system, this installation may be directly used. An other + possibility is to copy the installation to a local VxWorks DOS + file system, from where it is used. + </p> + </section> + + <section> + <title>OS Specific Functionality/Information</title> + <p>There are a couple of files that are unique to the VxWorks + distribution of Erlang/OTP, these files are described here. + </p> + <list type="bulleted"> + <item>README - this files has some information on VxWorks + specifics that you are advised to consult. This includes the + latest information on what parts of OTP are included in the + VxWorks distribution of Erlang/OTP. If you want us to + include more parts, please contact us to discuss + this.</item> + <item>erts-Vsn/bin/resolv.conf - A resolver configuration EXAMPLE file. + You have to edit this file.</item> + <item>erts-Vsn/bin/erl - This is an EXAMPLE start script for VxWorks. + You have to edit this file to suit your needs.</item> + <item>erts-Vsn/bin/erl_io - One possible solution to the problem + of competing Erlang and VxWorks shell. Contains the function + 'start_erl' called by the erl script. Also contains the + function 'to_erl' to be used when connecting to the Erlang + shell from VxWorks' shell.</item> + <item>erts-Vsn/bin/erl_exec - Rearranges command line arguments + and starts Erlang.</item> + <item>erts-Vsn/bin/vxcall - Allows spawning of standard VxWorks + shell functions (which is just about any function in the + system...) from open_port/2. E.g. open_port({spawn, 'vxcall + func arg1 arg2'}, []) will cause the output that 'func arg1, + arg2' would have given in the shell to be received from the + port.</item> + <item>erts-Vsn/bin/rdate - Set the time from a networked host, + like the SunOS command. Nothing Erlang-specific, but nice + if you want date/0 and time/0 to give meaningful values (you + also need a TIMEZONE environment setting if GMT isn't + acceptable). For example: <c>putenv "TIMEZONE=CET::-60:033002:102603"</c> sets central european + time.</item> + <item>erts-Vsn/src - Contains source for the above files, and + additionally config.c, driver.h, preload.c and + reclaim.h. Reclaim.h defines the interface to a simple + mechanism for "resource reclamation" that is part of the + Erlang runtime system - may be useful to "port program" writers (and + possibly others). Take careful note of the caveats listed in + the file!</item> + </list> + </section> + + <section> + <title>Starting Erlang</title> + <p>Start (and restart) of the system depends on what file system + is used. To be able to start the system from a nfs mounted + file system you can use VxWorks start script facility to run a + start script similar to the example below. Note that the + Erlang/OTP start-up script is run at the end of this script. + </p> + <code type="none"><![CDATA[ +# start.script v1.0 1997/09/08 patrik +# +# File name: start.script +# Purpose: Starting the VxWorks/cpu32 erlang/OTP +# Author: [email protected] +# Resides in: ~tornado/wind/target/config/ads360/ + +# +# Set shell prompt +# +shellPromptSet("sauron-> ") + +# +# Set default gateway +# +hostAdd "router-20","150.236.20.251" +routeAdd "0","router-20" + +# +# Mount /home from gandalf +# +hostAdd "gandalf","150.236.20.16" +usergroup=10 +nfsAuthUnixSet("gandalf", 452, 10, 1, &usergroup) +nfsMount("gandalf", "/export/home", "/home") + +# +# Load and run rdate.o to set correct date on the target +# +ld < /home/gandalf/tornado/wind/target/config/ads360/rdate.o +rdate("gandalf") + +# +# Setup timezone information (Central European time) +# +putenv "TIMEZONE=CET::-60:033002:102603" + +# +# Run the Erlang/OTP start script +# +cd "/home/gandalf/tornado/wind/target/erlang_cpu32_R42A/bin" +<erl + ]]></code> + </section> +</chapter> + diff --git a/system/doc/embedded/warning.gif b/system/doc/embedded/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/embedded/warning.gif diff --git a/system/doc/embedded/xmlfiles.mk b/system/doc/embedded/xmlfiles.mk new file mode 100644 index 0000000000..2bdc34ae28 --- /dev/null +++ b/system/doc/embedded/xmlfiles.mk @@ -0,0 +1,22 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +EMBEDDED_CHAPTER_FILES = \ + embedded_solaris.xml \ + embedded_nt.xml \ + vxworks.xml diff --git a/system/doc/embedded/xntp.xml b/system/doc/embedded/xntp.xml new file mode 100644 index 0000000000..564b63fc7d --- /dev/null +++ b/system/doc/embedded/xntp.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>XNTP (Network Time Protocol)</title> + <prepared>ETX/B/SFP Kenneth Lundin</prepared> + <responsible></responsible> + <docno>1</docno> + <approved>ETX/B/SFP (Kenneth Lundin)</approved> + <checked></checked> + <date>1996-11-20</date> + <rev>A</rev> + <file>xntp.sgml</file> + </header> + <p>This chapter describes the OS specific part of OTP that relates + to the Network Time Protocol (XNTP). + </p> + + <section> + <title>XNTP for Sunos5</title> + <p>XNTP maintains a Unix system time-of-day which conforms with + the Internet standard time servers. XNTP is a complete + implementation of the Network Time Protocol, version 3 + specification as defined in RFC 1305. + </p> + <p>XNTP for use in an <em>embedded system running Sunos5</em> is + delivered with OTP. The XNTP is delivered as a separate + <c>tar</c> file which also includes extensive documentation and + installation instructions. + </p> + <p>The following section of the introductory documentation is + included in the distribution: + </p> + <quote> + <p>The Network Time Protocol (NTP) is used to synchronize the + time of a computer client or server to another server or + reference time source, such as a radio or satellite receiver + or modem. It provides client accuracies typically within a + millisecond on LANs and up to a few tens of milliseconds on + WANs relative to a primary server synchronized to Coordinated + Universal Time (UTC) via a Global Positioning Service (GPS) + receiver, for example. Typical NTP configurations utilize + multiple redundant servers and diverse network paths, in order + to achieve high accuracy and reliability. ...</p> + </quote> + <p>The XNTP software is supplied without charge under the + conditions set forth in the Copyright Notice provided within the + distribution. + </p> + <p>(© David L. Mills 1992, 1993, 1994, 1995, 1996) + </p> + </section> +</chapter> + diff --git a/system/doc/extensions/Makefile b/system/doc/extensions/Makefile new file mode 100644 index 0000000000..cfc506f7e8 --- /dev/null +++ b/system/doc/extensions/Makefile @@ -0,0 +1,142 @@ +# ``The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved via the world wide web at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# The Initial Developer of the Original Code is Ericsson Utvecklings AB. +# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +# AB. All Rights Reserved.'' +# +# $Id$ +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +include make.dep + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/extensions + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml +XML_CHAPTER_FILES = \ + funs.xml \ + macros.xml \ + misc.xml \ + include.xml \ + records.xml \ + list_comprehensions.xml \ + bit_syntax.xml + +BOOK_FILES = book.xml + +GIF_FILES = note.gif + +PS_FILES = + +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = . +EXTRA_FILES = $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_CHAPTER_FILES:%.xml=%.html) + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = extensions-$(VSN).pdf +TOP_PS_FILE = extensions-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(GIF_FILES) + +debug opt: + +clean_tex: + -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_BOOK) + +clean: + rm -f *.html $(TEX_FILES_USERS_GUIDE) + rm -f $(TOP_PS_FILES) + rm -f errs core *~ $(LATEX_CLEAN) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR) +endif +endif + +release_spec: + + + diff --git a/system/doc/extensions/bit_syntax.xml b/system/doc/extensions/bit_syntax.xml new file mode 100644 index 0000000000..d86f73cd9a --- /dev/null +++ b/system/doc/extensions/bit_syntax.xml @@ -0,0 +1,403 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The Bit Syntax</title> + <prepared>Björn Gustavsson</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne DäKer</approved> + <checked></checked> + <date>00-06-21</date> + <rev>PA1</rev> + <file>bit_syntax.sgml</file> + </header> + <p>This section describes the "bit syntax" which was added to + the Erlang language in release 5.0 (R7). + Compared to the original bit syntax prototype + by Claes Wikström and Tony Rogvall (presented on the + Erlang User's Conference 1999), this implementation differs + primarily in the following respects, + </p> + <list type="ordered"> + <item> + <p>the character pairs '<<' and '>>' are used to delimit + a binary patterns and constructor (not '<' and '>' as in + the prototype), + </p> + </item> + <item> + <p>the tail syntax ('|Variable') has been eliminated, + </p> + </item> + <item> + <p>all size expressions must be bound, + </p> + </item> + <item> + <p>a type <c>unit:U</c> has been added, + </p> + </item> + <item> + <p>lists and tuples cannot be generated + </p> + </item> + <item> + <p>there are no paddings whatsoever. + </p> + </item> + </list> + + <section> + <title>Introduction</title> + <p>In Erlang a Bin is used for constructing binaries and + matching binary patterns. A Bin is written with the + following syntax:</p> + <code type="none"><![CDATA[ + <<E1, E2, ... En>> + ]]></code> + <p>A Bin is a low-level sequence of bytes. The purpose of a + Bin is to be able to, from a high level, + <em>construct</em> a binary, + </p> + <code type="none"><![CDATA[ + Bin = <<E1, E2, ... En>> + ]]></code> + <p>in which case all elements must be bound, or to + <em>match</em> a binary, + </p> + <code type="none"><![CDATA[ + <<E1, E2, ... En>> = Bin + ]]></code> + <p>where <c>Bin</c> is bound, and where the elements are bound or unbound, + as in any match. + </p> + <p>Each element specifies a certain <em>segment</em> of the binary. + A segment is is a set of contiguous bits of the binary (not + necessarily on a byte boundary). The first element specifies + the initial segment, the second element specifies the following + segment etc. + </p> + <p>The following examples illustrate how binaries are constructed + or matched, and how elements and tails are specified. + </p> + + <section> + <title>Examples</title> + <p><em>Example 1: </em>A binary can be constructed from a set of + constants or a string literal:</p> + <code type="none"><![CDATA[ + Bin11 = <<1, 17, 42>>, + Bin12 = <<"abc">> + ]]></code> + <p>yields binaries of size 3; <c>binary_to_list(Bin11)</c> + evaluates to <c>[1, 17, 42]</c>, and + <c>binary_to_list(Bin12)</c> evaluates to <c>[97, 98, 99]</c>. + </p> + <p><em>Example 2: </em>Similarly, a binary can be constructed + from a set of bound variables:</p> + <code type="none"><![CDATA[ + A = 1, B = 17, C = 42, + Bin2 = <<A, B, C:16>> + ]]></code> + <p>yields a binary of size 4, and <c>binary_to_list(Bin2)</c> + evaluates to <c>[1, 17, 00, 42]</c> too. Here we used a + <em>size expression</em> for the variable <c>C</c> in order to + specify a 16-bits segment of <c>Bin2</c>. + </p> + <p><em>Example 3: </em>A Bin can also be used for matching: if + <c>D</c>, <c>E</c>, and <c>F</c> are unbound variables, and + <c>Bin2</c> is bound as in the former example,</p> + <code type="none"><![CDATA[ + <<D:16, E, F/binary>> = Bin2 + ]]></code> + <p>yields <c>D = 273</c>, <c>E = 00</c>, and F binds to a binary + of size 1: <c>binary_to_list(F) = [42]</c>. + </p> + <p><em>Example 4: </em>The following is a more elaborate example + of matching, where <c>Dgram</c> is bound to the consecutive + bytes of an IP datagram of IP protocol version 4, and where we + want to extract the header and the data of the datagram:</p> + <code type="none"><![CDATA[ + -define(IP_VERSION, 4). + -define(IP_MIN_HDR_LEN, 5). + + DgramSize = byte_size(Dgram), + case Dgram of + <<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16, + ID:16, Flgs:3, FragOff:13, + TTL:8, Proto:8, HdrChkSum:16, + SrcIP:32, + DestIP:32, RestDgram/binary>> when HLen >= 5, 4*HLen =< DgramSize -> + OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN), + <<Opts:OptsLen/binary,Data/binary>> = RestDgram, + ... + end. + ]]></code> + <p>Here the segment corresponding to the <c>Opts</c> variable + has a <em>type modifier</em> specifying that <c>Opts</c> should + bind to a binary. All other variables have the default type + equal to unsigned integer. + </p> + <p>An IP datagram header is of variable length, and its length - + measured in the number of 32-bit words - is given in the segment + corresponding to <c>HLen</c>, the minimum value of which is + 5. It is the segment corresponding to <c>Opts</c> that is + variable: if <c>HLen</c> is equal to 5, <c>Opts</c> will be an + empty binary. + </p> + <p>The tail variables <c>RestDgram</c> and <c>Data</c> bind to + binaries, as all tail variables do. Both may bind to empty + binaries. + </p> + <p>If the first 4-bits segment of <c>Dgram</c> is not equal to + 4, or if <c>HLen</c> is less than 5, or if the size of + <c>Dgram</c> is less than <c>4*HLen</c>, the match of + <c>Dgram</c> fails. + </p> + </section> + </section> + + <section> + <title>A Lexical Note</title> + <p>Note that "<c><![CDATA[B=<<1>>]]></c>" will be interpreted as + "<c><![CDATA[B =< ;<1>>]]></c>", which is a syntax error. + The correct way to write the expression is "<c><![CDATA[B = <<1>>]]></c>".</p> + </section> + + <section> + <title>Segments</title> + <p>Each segment has the following general syntax:</p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>Both the <c>Size</c> and the <c>TypeSpecifier</c> or both may be + omitted; thus the following variations are allowed: + </p> + <p><c>Value</c></p> + <p><c>Value:Size</c></p> + <p><c>Value/TypeSpecifierList</c></p> + <p>Default values will be used for missing specifications. The default + values are described in the section "Defaults" below. + </p> + <p>Used in binary construction, the <c>Value</c> part is any expression. + Used in binary matching, the <c>Value</c> part must be a literal or + variable. You can read more about the <c>Value</c> part in the + sections about constructing binaries and matching binaries. + </p> + <p>The <c>Size</c> part of the segment multiplied by the unit in the + <c>TypeSpecifierList</c> (described below) gives the number of bits + for the segment. In construction, <c>Size</c> is any expression that + evaluates to an integer. In matching, <c>Size</c> must be a constant + expression or a variable. + </p> + <p>The <c>TypeSpecifierList</c> is a list of type specifiers separated by + hyphens. + </p> + <taglist> + <tag>Type</tag> + <item>The type can be <c>integer</c>, <c>float</c>, or <c>binary</c>.</item> + <tag>Signedness</tag> + <item>The signedness specification can be either <c>signed</c> + or <c>unsigned</c>. Note that signedness only matters for matching.</item> + <tag>Endianness</tag> + <item>The endianness specification can be either <c>big</c>, + <c>little</c>, or <c>native</c>. Native-endian means that + the endian will be resolved at load time to be either + big-endian or little-endian, depending on what is "native" + for the CPU that the Erlang machine is run on.</item> + <tag>Unit</tag> + <item>The unit size is given as <c>unit:IntegerLiteral</c>. + The allowed range is 1-256. It will be multiplied by the <c>Size</c> + specifier to give the effective size of the segment.</item> + </taglist> + <p>Example: + </p> + <code type="none"> +X:4/little-signed-integer-unit:8 + </code> + <p>This element has a total size of 4*8 = 32 bits, and it contains a + signed integer in little-endian order.</p> + </section> + + <section> + <title>Defaults</title> + <p>The default type for a segment is <c>integer</c>. The default type + does <em>not</em> depend on the value, even if the value is a literal. + For instance, the default type in '<c><![CDATA[<<3.14>>]]></c>' is <c>integer</c>, + not <c>float</c>. + </p> + <p>The default <c>Size</c> depends on the type. + For <c>integer</c> it is 8. For <c>float</c> it is 64. + For <c>binary</c> it is all of the binary. In matching, this default + value is only valid for the very last element. All other binary elements + in matching must have a size specification. + </p> + <p>The default unit depends on the the type. + For <c>integer</c> and <c>float</c> it is 1. + For <c>binary</c> it is 8. + </p> + <p>The default signedness is <c>unsigned</c>. + </p> + <p>The default endianness is <c>big</c>.</p> + </section> + + <section> + <title>Constructing Binaries</title> + <p>This section describes the rules for constructing binaries using + the bit syntax. Unlike when constructing lists or tuples, the construction + of a binary can fail with a <c>badarg</c> exception. + </p> + <p>There can be zero or more segments in a binary to be constructed. + The expression '<c><![CDATA[<<>>]]></c>' constructs a zero length binary. + </p> + <p>Each segment in a binary can consist of zero or more bits. + There are no alignment rules for individual segments, but the total + number of bits in all segments must be evenly divisible by 8, + or in other words, the resulting binary must consist of a whole number + of bytes. An <c>badarg</c> exception will be thrown if the resulting + binary is not byte-aligned. Example: + </p> + <code type="none"><![CDATA[ +<<X:1,Y:6>> + ]]></code> + <p>The total number of bits is 7, which is not evenly divisible by 8; + thus, there will be <c>badarg</c> exception (and a compiler warning + as well). The following example + </p> + <code type="none"><![CDATA[ +<<X:1,Y:6,Z:1>> + ]]></code> + <p>will successfully construct a binary of 8 bits, or one byte. (Provided + that all of X, Y and Z are integers.) + </p> + <p>As noted earlier, segments have the following general syntax: + </p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>When constructing binaries, <c>Value</c> and <c>Size</c> can be + any Erlang expression. However, for syntactical reasons, + both <c>Value</c> and <c>Size</c> must be enclosed in parenthesis + if the expression consists of anything more than a single literal + or variable. The following gives a compiler syntax error: + </p> + <code type="none"><![CDATA[ +<<X+1:8>> + ]]></code> + <p>This expression must be rewritten to + </p> + <code type="none"><![CDATA[ +<<(X+1):8>> + ]]></code> + <p>in order to be accepted by the compiler. + </p> + + <section> + <title>Including Literal Strings</title> + <p>As syntactic sugar, an literal string may be written instead of a + element.</p> + <code type="none"><![CDATA[ +<<"hello">> ]]></code> + <p>which is syntactic sugar for</p> + <code type="none"><![CDATA[ +<<$h,$e,$l,$l,$o>> ]]></code> + </section> + </section> + + <section> + <title>Matching Binaries</title> + <p>This section describes the rules for matching binaries using the + bit syntax. + </p> + <p>There can be zero or more segments in a binary binary pattern. + A binary pattern can occur in every place patterns are allowed, also + inside other patterns. Binary patterns cannot be nested. + </p> + <p>The pattern '<c><![CDATA[<<>>]]></c>' matches a zero length binary. + </p> + <p>Each segment in a binary can consist of zero or more bits. + </p> + <p>A segment of type <c>binary</c> must have a size evenly divisible by 8. + </p> + <p>This means that the following head will never match:</p> + <code type="none"><![CDATA[ +foo(<<X:7/binary,Y:1/binary>>) -> ]]></code> + <p>As noted earlier, segments have the following general syntax: + </p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>When matching <c>Value</c> value must be either a variable or an integer + or floating point literal. Expressions are not allowed. + </p> + <p><c>Size</c> must be an integer literal, or a previously bound variable. + Note that the following is not allowed:</p> + <code type="none"><![CDATA[ +foo(N, <<X:N,T/binary>>) -> + {X,T}. ]]></code> + <p>The two occurrences of <c>N</c> are not related. The compiler + will complain that the <c>N</c> in the size field is unbound. + </p> + <p>The correct way to write this example is like this:</p> + <code type="none"><![CDATA[ +foo(N, Bin) -> + <<X:N,T/binary>> = Bin, + {X,T}. ]]></code> + + <section> + <title>Getting the Rest of the Binary</title> + <p>To match out the rest of binary, specify a binary field without size:</p> + <code type="none"><![CDATA[ +foo(<<A:8,Rest/binary>>) -> ]]></code> + <p>As always, the size of the tail must be evenly divisible by 8. + </p> + </section> + </section> + + <section> + <title>Traps and Pitfalls</title> + <p>Assume that we need a function that creates a binary out of a + list of triples of integers. A first (inefficient) version of such + a function could look like this:</p> + <code type="none"><![CDATA[ +triples_to_bin(T) -> + triples_to_bin(T, <<>>). + +triples_to_bin([{X,Y,Z} | T], Acc) -> + triples_to_bin(T, <<Acc/binary, X:32, Y:32, Z:32>>); % inefficient +triples_to_bin([], Acc) -> + Acc. ]]></code> + <p>The reason for the inefficiency of this function is that for + each triple, the binary constructed so far (<c>Acc</c>) is copied. + (Note: The original bit syntax prototype avoided the copy operation + by using segmented binaries, which are not implemented in R7.) + </p> + <p>The efficient way to write this function in R7 is:</p> + <code type="none"><![CDATA[ +triples_to_bin(T) -> + triples_to_bin(T, []). + +triples_to_bin([{X,Y,Z} | T], Acc) -> + triples_to_bin(T, [<<X:32, Y:32, Z:32>> | Acc]); +triples_to_bin([], Acc) -> + list_to_binary(lists:reverse(Acc)). ]]></code> + <p>Note that <c>list_to_binary/1</c> handles deep lists of binaries + and small integers. (This fact was previously undocumented.) + </p> + </section> +</chapter> + diff --git a/system/doc/extensions/book.xml b/system/doc/extensions/book.xml new file mode 100644 index 0000000000..ffdbe6cb44 --- /dev/null +++ b/system/doc/extensions/book.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book> + <header titlestyle="normal"> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang Extensions Since 4.4</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-05-21</date> + <rev></rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>Erlang Extensions Since 4.4</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <include file="part"></include> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/extensions/fun_test.erl b/system/doc/extensions/fun_test.erl new file mode 100644 index 0000000000..8472fd87f8 --- /dev/null +++ b/system/doc/extensions/fun_test.erl @@ -0,0 +1,17 @@ +%1 +-module(fun_test). +-export([t1/0, t2/0, t3/0, t4/0, double/1]). +-import(lists, [map/2]). + +t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]). + +t2() -> map(fun double/1, [1,2,3,4,5]). + +t3() -> map({?MODULE, double}, [1,2,3,4,5]). + +double(X) -> X * 2. +%1 + + +t4() -> + "hello world". diff --git a/system/doc/extensions/funparse.erl b/system/doc/extensions/funparse.erl new file mode 100644 index 0000000000..5e23c90df9 --- /dev/null +++ b/system/doc/extensions/funparse.erl @@ -0,0 +1,74 @@ +-module(funparse). +-compile(export_all). +-import(lists, [reverse/1]). + +%17 +%% > hof:parse([a,c]). +%% {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} +%% > hof:parse([a,d]). +%% {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} +%% > hof:parse([b,c]). +%% {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} +%% > hof:parse([b,d]). +%% {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} +%% > hof:parse([a,b]). +%% fail +%17 + +%% Grammar = (a | b) & (c | d) + +%12 +parse(List) -> + (grammar())(List). +%12 + +%13 +grammar() -> + pand( + por(pconst(a), pconst(b)), + por(pconst(c), pconst(d))). +%13 + +%14 +pconst(X) -> + fun (T) -> + case T of + [X|T1] -> {ok, {const, X}, T1}; + _ -> fail + end + end. +%14 + +%15 +por(P1, P2) -> + fun (T) -> + case P1(T) of + {ok, R, T1} -> + {ok, {'or',1,R}, T1}; + fail -> + case P2(T) of + {ok, R1, T1} -> + {ok, {'or',2,R1}, T1}; + fail -> + fail + end + end + end. +%15 + +%16 +pand(P1, P2) -> + fun (T) -> + case P1(T) of + {ok, R1, T1} -> + case P2(T1) of + {ok, R2, T2} -> + {ok, {'and', R1, R2}}; + fail -> + fail + end; + fail -> + fail + end + end. +%16 diff --git a/system/doc/extensions/funs.xml b/system/doc/extensions/funs.xml new file mode 100644 index 0000000000..f9c003c8ee --- /dev/null +++ b/system/doc/extensions/funs.xml @@ -0,0 +1,486 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Programming with Funs</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne DäKer</approved> + <checked></checked> + <date>96-01-16</date> + <rev>PA1</rev> + <file>funs.sgml</file> + </header> + <p>This section introduces functional objects (Funs). That is a new data type introduced in Erlang 4.4. Functions which takes Funs as arguments, or which return Funs are called higher order functions.</p> + <list type="bulleted"> + <item>Funs can be passed as arguments to other functions, just like lists or tuples</item> + <item>functions can be written which return Funs, just like any other data object.</item> + </list> + + <section> + <title>Higher Order Functions </title> + <p>Funs encourages us to encapsulate common patterns of design into functional forms called higher order functions. These functions not only shortens programs, but also produce clearer programs because the intended meaning of the program is explicitly rather than implicitly stated.</p> + <p>The concepts of higher order functions and procedural abstraction are introduced with two brief examples.</p> + + <section> + <title>Example 1 - map</title> + <p>If we want to double every element in a list, we could write a function named <c>double</c>:</p> + <code type="none"> + +double([H|T]) -> [2*H|double(T)]; +double([]) -> [] </code> + <p>This function obviously doubles the argument entered as input as follows:</p> + <pre> + +> <input>double([1,2,3,4]).</input> +[2,4,6,8] </pre> + <p>We now add the function <c>add_one</c>, which adds one to every element in a list:</p> + <code type="none"> + +add_one([H|T]) -> [H+1|add_one(T)]; +add_one([]) -> []. </code> + <p>These functions, <c>double</c> and <c>add_one</c>, have a very similar structure. We can exploit this fact and write a function <c>map</c> which expresses this similarity:</p> + <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> + <p>We can now express the functions <c>double</c> and <c>add_one</c> in terms of <c>map</c> as follows:</p> + <code type="none"> + +double(L) -> map(fun(X) -> 2*X end, L). +add_one(L) -> map(fun(X) -> 1 + X end, L). </code> + <p><c>map(F, List)</c> is a function which takes a function <c>F</c> and a list <c>L</c> as arguments and + returns the new list which is obtained by applying <c>F</c> to each of the elements in <c>L</c>.</p> + <p>The process of abstracting out the common features of a number of different programs is called procedural abstraction. Procedural abstraction can be used in order to write several different functions which have a similar structure, but differ only in some minor detail. This is done as follows:</p> + <list type="ordered"> + <item>write one function which represents the common features of these functions</item> + <item>parameterize the difference in terms of functions which are passed as arguments to the common function.</item> + </list> + </section> + + <section> + <title>Example 2 - foreach</title> + <p>This example illustrates procedural abstraction. Initially, we show the following two examples written as conventional functions:</p> + <list type="ordered"> + <item>all elements of a list are printed onto a stream</item> + <item>a message is broadcast to a list of processes.</item> + </list> + <code type="none"> + +print_list(Stream, [H|T]) -> + io:format(Stream, "~p~n", [H]), + print_list(Stream, T); +print_on_list(Stream, []) -> + true. </code> + <code type="none"> + +broadcast(Msg, [Pid|Pids]) -> + Pid ! Msg, + broadcast(Msg, Pids); +broadcast(_, []) -> + true. </code> + <p>Both these functions have a very similar structure. They both iterate over a list doing something to each element in the list. The "something" has to be carried round as an extra argument to the function which does this.</p> + <p>The function <c>foreach</c> expresses this similarity:</p> + <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> + <p>Using <c>foreach</c>, <c>print_on_list</c> becomes:</p> + <code type="none"> + +foreach(fun(H) -> io:format(S, "~p~n~,[H]) end, L) </code> + <p><c>broadcast</c> becomes:</p> + <code type="none"> + +foreach(fun(Pid) -> Pid ! M end, L) </code> + <p><c>foreach</c> is evaluated for its side-effect and not its value. <c>foreach(Fun ,L)</c> calls <c>Fun(X)</c> for each element <c>X</c> in <c>L</c> and the processing occurs in the order in which the elements were defined in <c>L</c>. <c>map</c> does not define the order in which its elements are processed.</p> + </section> + </section> + + <section> + <title>Advantages of Higher Order Functions</title> + <p>Programming with higher order functions, such as <c>map</c> and <c>foreach</c>, has a number of advantages:</p> + <list type="bulleted"> + <item>It is much easier to understand the program and the intention of the programmer is clearly expressed in the code. The statement <c>foreach(fun(X) -></c> clearly indicates that the intention of this program is to do something to each element in the list <c>L</c>. We also know that the function which is passed as the first argument of <c>foreach</c> takes one argument <c>X</c>, which will be successively bound to each of the elements in <c>L</c>.</item> + <item>Functions which take Funs as arguments are much easier to re-use than other functions. </item> + </list> + </section> + + <section> + <title>The Syntax of Funs</title> + <p>Funs are written with the syntax:</p> + <code type="none"> + +F = fun (Arg1, Arg2, ... ArgN) -> + ... + end </code> + <p>This creates an anonymous function of <c>N</c> arguments and binds it to the variable <c>F</c>.</p> + <p>If we have already written a function in the same module and wish to pass this function as an argument, we can use the following syntax:</p> + <code type="none"> + +F = fun FunctionName/Arity </code> + <p>With this form of function reference, the function which is referred to does not need to be exported from the module.</p> + <p>We can also refer to a function defined in a different module with the following syntax:</p> + <code type="none"> + +F = {Module, FunctionName} </code> + <p>In this case, the function must be exported from the module in question.</p> + <p>The follow program illustrates the different ways of creating Funs:</p> + <codeinclude file="fun_test.erl" tag="%1" type="erl"></codeinclude> + <p>We can evaluate the fun <c>F</c> with the syntax:</p> + <code type="none"> + +F(Arg1, Arg2, ..., Argn) </code> + <p>To check whether a term is a Fun, use the test <c>function/1</c> + in a guard. Example:</p> + <code type="none"> +f(F, Args) when function(F) -> + apply(F, Args); +f(N, _) when integer(N) -> + N. </code> + <p>Funs are a distinct type. The BIFs erlang:fun_info/1,2 can + be used to retrieve information about a fun, and the BIF + erlang:fun_to_list/1 returns a textual representation of a fun. + The check_process_code/2 BIF returns true if the + process contains funs that depend on the old version of + a module.</p> + <note> + <p>In OTP R5 and earlier releases, funs were represented + using tuples.</p> + </note> + </section> + + <section> + <title>Variable Bindings within a Fun</title> + <p>The scope rules for variables which occur in Funs are as follows:</p> + <list type="bulleted"> + <item>All variables which occur in the head of a Fun are assumed to be "fresh" variables.</item> + <item>Variables which are defined before the Fun, and which occur in function calls or guard tests within the Fun, have the values they had outside the Fun.</item> + <item>No variables may be exported from a Fun.</item> + </list> + <p>The following examples illustrate these rules:</p> + <code type="none"> + +print_list(File, List) -> + {ok, Stream} = file:open(File, write), + foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List), + file:close(Stream). </code> + <p>In the above example, the variable <c>X</c> which is defined in the head of the Fun is a new variable. The value of the variable <c>Stream</c> which is used within within the Fun gets its value from the + <c>file:open</c> line.</p> + <p>Since any variable which occurs in the head of a Fun is considered a new variable it would be equally valid to write:</p> + <code type="none"> + +print_list(File, List) -> + {ok, Stream} = file:open(File, write), + foreach(fun(File) -> + io:format(Stream,"~p~n",[File]) + end, List), + file:close(Stream). </code> + <p>In this example, <c>File</c> is used as the new variable instead of <c>X</c>. This is rather silly since code in the body of the Fun cannot refer to the variable <c>File</c> which is defined outside the Fun. Compiling this example will yield the diagnostic:</p> + <code type="none"> + +./FileName.erl:Line: Warning: variable 'File' + shadowed in 'lambda head' </code> + <p>This reminds us that the variable <c>File</c> which is defined inside the Fun collides with the variable <c>File</c> which is defined outside the Fun.</p> + <p>The rules for importing variables into a Fun has the consequence that certain pattern matching operations have to be moved into guard expressions and cannot be written in the head of the Fun. For example, we might write the following code if we intend the first clause of <c>F</c> to be evaluated when the value of its argument is <c>Y</c>:</p> + <code type="none"> + +f(...) -> + Y = ... + map(fun(X) when X == Y -> + ; + (_) -> + ... + end, ...) + ... </code> + <p>instead of</p> + <code type="none"> + +f(...) -> + Y = ... + map(fun(Y) -> + ; + (_) -> + ... + end, ...) + ... </code> + </section> + + <section> + <title>Funs and the Module Lists</title> + <p>The following examples show a dialogue with the Erlang shell. All the higher order functions discussed are exported from the module <c>lists</c>.</p> + + <section> + <title>map</title> + <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> + <p><c>map</c> takes a function of one argument and a list of terms. It returns the list obtained by applying the function to every argument in the list.</p> + <pre> + +1> <input>Double = fun(X) -> 2 * X end.</input> +#Fun<erl_eval> +2><input>lists:map(Double, [1,2,3,4,5]).</input> +[2,4,6,8,10] </pre> + <p>When a new Fun is defined in the shell, the value of the Fun is printed as <c><![CDATA[Fun#<erl_eval>]]></c></p> + </section> + + <section> + <title>any</title> + <codeinclude file="funs1.erl" tag="%4" type="erl"></codeinclude> + <p><c>any</c> takes a predicate <c>P</c> of one argument and a list of terms. A predicate is a function which returns <c>true</c> or <c>false</c>. <c>any</c> is true if there is a term <c>X</c> in the list such that <c>P(X)</c> is <c>true</c>.</p> + <p>We define a predicate <c>Big(X)</c> which is <c>true</c> if its argument is greater that 10.</p> + <pre> + +3> <input>Big = fun(X) -> if X > 10 -> true; true -> false end end.</input> +#Fun<erl_eval> +4><input>lists:any(Big, [1,2,3,4]).</input> +false. +5> <input>lists:any(Big, [1,2,3,12,5]).</input> +true. </pre> + </section> + + <section> + <title>all</title> + <codeinclude file="funs1.erl" tag="%3" type="erl"></codeinclude> + <p><c>all</c> has the same arguments as <c>any</c>. It is true if the predicate applied to all elements in the list is true.</p> + <pre> + +6><input>lists:all(Big, [1,2,3,4,12,6]).</input> +false +7><input>lists:all(Big, [12,13,14,15]).</input> +true </pre> + </section> + + <section> + <title>foreach</title> + <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> + <p><c>foreach</c> takes a function of one argument and a list of terms. The function is applied to each argument in the list. <c>foreach</c> returns <c>ok</c>. It is used for its side-effect only.</p> + <pre> + +8> <input>lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]).</input> +1 +2 +3 +4 +true </pre> + </section> + + <section> + <title>foldl</title> + <codeinclude file="funs1.erl" tag="%8" type="erl"></codeinclude> + <p><c>foldl</c> takes a function of two arguments, an accumulator and a list. The function is called with two arguments. The first argument is the successive elements in the list, the second argument is the accumulator. The function must return a new accumulator which is used the next time the function is called.</p> + <p>If we have a list of lists <c>L = ["I","like","Erlang"]</c>, then we can sum the lengths of all the strings in <c>L</c> as follows:</p> + <pre> + +9> <input>L = ["I","like","Erlang"].</input> +["I","like","Erlang"] +10> <input>lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L).</input> +11 </pre> + <p><c>foldl</c> works like a <c>while</c> loop in an imperative language:</p> + <code type="none"> + + L = ["I","like","Erlang"], + Sum = 0, + while( L != []){ + Sum += length(head(L)), + L = tail(L) + end </code> + </section> + + <section> + <title>mapfoldl</title> + <codeinclude file="funs1.erl" tag="%10" type="erl"></codeinclude> + <p><c>mapfoldl</c> simultaneously maps and folds over a list. The following example shows how to change all letters in <c>L</c> to upper case and count them.</p> + <p>First upcase:</p> + <pre> + +11> <input>Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a;</input> +<input>(X) -> X</input> +<input>end.</input> +#Fun<erl_eval> +12> <input>Upcase_word =</input> +<input>fun(X) -></input> +<input>lists:map(Upcase, X)</input> +<input>end.</input> +#Fun<erl_eval> +13><input>Upcase_word("Erlang").</input> +"ERLANG" +14><input>lists:map(Upcase_word, L).</input> +["I","LIKE","ERLANG"] </pre> + <p>Now we can do the fold and the map at the same time:</p> + <pre> + +14> <input>lists:mapfoldl(fun(Word, Sum) -></input> +14> <input>{Upcase_word(Word), Sum + length(Word)}</input> +14> <input>end, 0, L).</input> +{["I","LIKE","ERLANG"],11} </pre> + </section> + + <section> + <title>filter</title> + <codeinclude file="funs1.erl" tag="%9" type="erl"></codeinclude> + <p><c>filter</c> takes a predicate of one argument and a list and returns all element in the list which satisfy the predicate.</p> + <pre> + +15><input>lists:filter(Big, [500,12,2,45,6,7]).</input> +[500,12,45] </pre> + <p>When we combine maps and filters we can write very succinct and obviously correct code. For example, suppose we want to define a set difference function. We want to define <c>diff(L1, L2)</c> to be the difference between the lists <c>L1</c> and <c>L2</c>. + This is the list of all elements in L1 which are not contained in L2. This code can be written as follows:</p> + <code type="none"> + +diff(L1, L2) -> + filter(fun(X) -> not member(X, L2) end, L1). </code> + <p>The AND intersection of the list <c>L1</c> and <c>L2</c> is also easily defined:</p> + <code type="none"> + +intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2). </code> + </section> + + <section> + <title>takewhile</title> + <codeinclude file="funs1.erl" tag="%5" type="erl"></codeinclude> + <p><c>takewhile(P, L)</c> takes elements <c>X</c> from a list <c>L</c> as long as the predicate <c>P(X)</c> is true.</p> + <pre> + +16><input>lists:takewhile(Big, [200,500,45,5,3,45,6]).</input> +[200,500,45] </pre> + </section> + + <section> + <title>dropwhile</title> + <codeinclude file="funs1.erl" tag="%6" type="erl"></codeinclude> + <p><c>dropwhile</c> is the complement of <c>takewhile</c>.</p> + <pre> + +17> <input>lists:dropwhile(Big, [200,500,45,5,3,45,6]).</input> +[5,3,45,6] </pre> + </section> + + <section> + <title>splitlist</title> + <codeinclude file="funs1.erl" tag="%7" type="erl"></codeinclude> + <p><c>splitlist(P, L)</c> splits the list <c>L</c> into the two sub-lists <c>{L1, L2}</c>, where <c>L = takewhile(P, L)</c> and <c>L2 = dropwhile(P, L)</c>.</p> + <pre> + +18><input>lists:splitlist(Big, [200,500,45,5,3,45,6]).</input> +{[200,500,45],[5,3,45,6]} </pre> + </section> + + <section> + <title>first</title> + <codeinclude file="funs1.erl" tag="%11" type="erl"></codeinclude> + <p><c>first</c> returns <c>{true, R}</c>, where <c>R</c> is the first element in a list satisfying a predicate or <c>false</c>:</p> + <pre> + +19><input>lists:first(Big, [1,2,45,6,123]).</input> +{true,45} +20><input>lists:first(Big, [1,2,4,5]). </input> +false </pre> + </section> + </section> + + <section> + <title>Funs which Return Funs</title> + <p>So far, this section has only described functions which take Funs as arguments. It is also possible to write more powerful functions which themselves return Funs. The following examples illustrate these type of functions.</p> + + <section> + <title>Simple Higher Order Functions</title> + <p><c>Adder(X)</c> is a function which, given <c>X</c>, returns a new function <c>G</c> such that <c>G(K)</c> returns <c>K + X</c>.</p> + <pre> + +21> <input>Adder = fun(X) -> fun(Y) -> X + Y end end.</input> +#Fun<erl_eval> +22> <input>Add6 = Adder(6).</input> +#Fun<erl_eval> +23><input>Add6(10).</input> +16 </pre> + </section> + + <section> + <title>Infinite Lists</title> + <p>The idea is to write something like:</p> + <code type="none"> + +-module(lazy). +-export([ints_from/1]). +ints_from(N) -> + fun() -> + [N|ints_from(N+1)] + end. </code> + <p>Then we can proceed as follows:</p> + <code type="none"><![CDATA[ + +24> XX = lazy:ints_from(1). +#Fun<lazy> +25> XX(). +[1|#Fun<lazy>] +26> hd(XX()). +1 +27> Y = tl(XX()). +#Fun<lazy> +28> hd(Y()). +2 ]]></code> + <p>etc. - this is an example of "lazy embedding"</p> + </section> + + <section> + <title>Parsing</title> + <p>The following examples show parsers of the following type:</p> + <pre> +Parser(Toks) -> {ok, Tree, Toks1} | fail </pre> + <p><c>Toks</c> is the list of tokens to be parsed. A successful parse returns <c>{ok, Tree, Toks1}</c>, where <c>Tree</c> is a parse tree and <c>Toks1</c> is a tail of <c>Tree</c> which contains symbols encountered after the structure which was correctly parsed. Otherwise <c>fail</c> is returned.</p> + <p>The example which follows illustrates a simple, functional parser which parses the grammar:</p> + <pre> +(a | b) & (c | d) </pre> + <p>The following code defines a function <c>pconst(X)</c> in the module <c>funparse</c>, which returns a Fun which parses a list of tokens.</p> + <codeinclude file="funparse.erl" tag="%14" type="erl"></codeinclude> + <p>This function can be used as follows:</p> + <pre> +29><input>P1 = funparse:pconst(a).</input> +#Fun<hof> +30> <input>P1([a,b,c]).</input> +{ok,{const,a},[b,c]} +31> <input>P1([x,y,z]).</input> +fail </pre> + <p>Next, we define the two higher order functions <c>pand</c> and <c>por</c> which combine primitive parsers to produce more complex parsers. Firstly <c>pand</c>:</p> + <codeinclude file="funparse.erl" tag="%16" type="erl"></codeinclude> + <p>Given a parser <c>P1</c> for grammar <c>G1</c>, and a parser <c>P2</c> for grammar <c>G2</c>, <c>pand(P1, P2)</c> + returns a parser for the grammar which consists of sequences of tokens which satisfy <c>G1</c> followed by sequences of tokens which satisfy <c>G2</c>.</p> + <p><c>por(P1, P2)</c> returns a parser for the language described by the grammar <c>G1</c> or <c>G2</c>.</p> + <codeinclude file="funparse.erl" tag="%15" type="erl"></codeinclude> + <p>The original problem was to parse the grammar <c><![CDATA[(a | b) & (c | d)]]></c>. The following code addresses this problem: </p> + <codeinclude file="funparse.erl" tag="%13" type="erl"></codeinclude> + <p>The following code adds a parser interface to the grammar:</p> + <codeinclude file="funparse.erl" tag="%12" type="erl"></codeinclude> + <p>We can test this parser as follows:</p> + <pre> + +32> <input>funparse:parse([a,c]).</input> +{ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} +33> <input>funparse:parse([a,d]).</input> +{ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} +34> <input>funparse:parse([b,c]).</input> +{ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} +35> <input>funparse:parse([b,d]).</input> +{ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} +36> <input>funparse:parse([a,b]).</input> +fail </pre> + </section> + </section> +</chapter> + diff --git a/system/doc/extensions/funs1.erl b/system/doc/extensions/funs1.erl new file mode 100644 index 0000000000..b1a3e21525 --- /dev/null +++ b/system/doc/extensions/funs1.erl @@ -0,0 +1,125 @@ +-module(funs1). +-compile(export_all). +-import(lists, [reverse/1]). + +%1 +map(F, [H|T]) -> [F(H)|map(F, T)]; +map(F, []) -> []. +%1 + +%2 +foreach(F, [H|T]) -> + F(H), + foreach(F, T); +foreach(F, []) -> + ok. +%2 +% +%3 +all(Pred, [H|T]) -> + case Pred(H) of + true -> all(Pred, T); + false -> false + end; +all(Pred, []) -> + true. +%3 +%4 +any(Pred, [H|T]) -> + case Pred(H) of + true -> true; + false -> any(Pred, T) + end; +any(Pred, []) -> + false. +%4 +%5 +takewhile(Pred, [H|T]) -> + case Pred(H) of + true -> [H|takewhile(Pred, T)]; + false -> [] + end; +takewhile(Pred, []) -> + []. +%5 +%6 +dropwhile(Pred, [H|T]) -> + case Pred(H) of + true -> dropwhile(Pred, T); + false -> [H|T] + end; +dropwhile(Pred, []) -> + []. +%6 +%7 +splitlist(Pred, L) -> + splitlist(Pred, L, []). + +splitlist(Pred, [H|T], L) -> + case Pred(H) of + true -> splitlist(Pred, T, [H|L]); + false -> {reverse(L), [H|T]} + end; +splitlist(Pred, [], L) -> + {reverse(L), []}. +%7 + +flatmap(F, [Hd|Tail]) -> + F(Hd) ++ flatmap(F, Tail); +flatmap(F, []) -> []. + +%8 +foldl(F, Accu, [Hd|Tail]) -> + foldl(F, F(Hd, Accu), Tail); +foldl(F, Accu, []) -> Accu. +%8 +% +foldr(F, Accu, [Hd|Tail]) -> + F(Hd, foldr(F, Accu, Tail)); +foldr(F, Accu, []) -> Accu. +%9 +filter(F, [H|T]) -> + case F(H) of + true -> [H|filter(F, T)]; + false -> filter(F, T) + end; +filter(F, []) -> []. +%9 +%10 +mapfoldl(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl(F, Accu1, Tail), + {[R|Rs], Accu2}; +mapfoldl(F, Accu, []) -> {[], Accu}. +%10 +mapfoldr(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr(F, Accu, []) -> {[], Accu}. +%11 +first(Pred, [H|T]) -> + case Pred(H) of + true -> + {true, H}; + false -> + first(Pred, T) + end; +first(Pred, []) -> + false. +%11 +% +compose(F, G) -> + fun(X) -> + F(G(X)) + end. + +%20 +iterate(N, F) -> + iterate(N, N+1, F). + +iterate(Stop, Stop, _) -> + []; +iterate(N, Stop, Fun) -> + [Fun(N)|iterate(N+1, Stop, Fun)]. +%20 diff --git a/system/doc/extensions/include.xml b/system/doc/extensions/include.xml new file mode 100644 index 0000000000..cd78644b95 --- /dev/null +++ b/system/doc/extensions/include.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1999</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Includes</title> + <prepared>Arndt Jonasson</prepared> + <docno>1</docno> + <date>99-01-25</date> + <rev>PA1</rev> + <file>include.sgml</file> + </header> + <p>There are two directives which can be used in Erlang source + files to cause the compiler to temporarily read input from another + source. They are typically used to provide macro definitions and + record definitions from header files. It is recommended to use the + file name extension <c>".hrl"</c> for files which are meant to be + included (the 'h' can be read as "header").</p> + <p>When locating header files a list of directory names, the + compiler include path, is used. In short the list contains the current + working directory of the file server, the base name of the compiled + file, and the directories given by the include option, in that order. + See <c>erlc(1)</c> and <c>compile(3)</c> for the details of the + compiler include path.</p> + + <section> + <title>The -include Directive</title> + <p>The first action taken by the <c>-include</c> directive is to + check if the format of the first path component of the specified + filename is <c>$VAR</c>, for some string <c>VAR</c>. If that is the + case, the value of the environment variable <c>VAR</c> as returned by + <c>os:getenv(VAR)</c> is substituted for the first path component. If + <c>os:getenv/1</c> returns <c>false</c>, the first path component is + left as is. If the filename is absolute (possibly after variable + substitution), the header file with that name is included. Otherwise, + the specified header file is searched for in the directories in the + compiler include path, starting with the first directory in the list. + The first file found while traversing the list is included. Examples:</p> + <code type="none"> + -include("my_records.hrl"). + -include("incdir/more_records.hrl"). + -include("/home/users/proj/recs.hrl"). + -include("$PROJ_ROOT/app1/defs.hrl"). </code> + </section> + + <section> + <title>The -include_lib Directive</title> + <p>The <c>-include_lib</c> directive first tries to find the + specified header file using the procedure employed for the + <c>-include</c> directive. If no header file can be found by searching + the compiler include path, the first path component of the specified + filename (possibly after variable substitution) is regarded as the + name of an application, and the directory of the current version of + the application is searched. Example:</p> + <code type="none"> + -include_lib("mnesia/include/mnemosyne.hrl"). </code> + <p>The compiler is instructed to look for the directory where the + current version of the <c>mnesia</c> application is installed, that is + <c>code:lib_dir(mnesia)</c>, and then search the subdirectory + <c>include</c> for the file <c>mnemosyne.hrl</c>.</p> + </section> +</chapter> + diff --git a/system/doc/extensions/list_comprehensions.erl b/system/doc/extensions/list_comprehensions.erl new file mode 100644 index 0000000000..21ac562aa5 --- /dev/null +++ b/system/doc/extensions/list_comprehensions.erl @@ -0,0 +1,118 @@ +-module(t). +-author('[email protected]'). + +%%-export([test/2]). +-compile(export_all). + +%% Odd numbers. + +%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. + +bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. + +bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), + Y <- M, float(Y), gt(X, Y) + ]. + +baz(L) -> [ X || X <- L, atom(X) ]. + +buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. + +gt(X, Y) when X > Y -> true; +gt(X, Y) -> false. + +%% Turn a list into a set. +make_set([]) -> []; +make_set([H|T]) -> + [H|[ + Y || Y <- make_set(T), + Y =/= H + ]]. + +%% Return the Pythagorean triangles with sides +%% of total length less than N +pyth(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N), + C <- lists:seq(1,N), + A+B+C =< N, + A*A+B*B == C*C + ]. + +%% Cut the search space a bit.. +pyth2(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N-A+1), + C <- lists:seq(1,N-A-B+2), + A+B+C =< N, + A*A+B*B == C*C ]. + +%% Return the Cartesian product +cp() -> + [ {X,Y} || + X <- a(), + Y <- b() + ]. + +cp(A,B) when list(A),list(B) -> + [ {X,Y} || + X <- A, + Y <- B + ]. + +%a() -> 1/0. +a() -> [a,b]. +b() -> [1,2,3]. + +%% Return all permutations of a list +perms([]) -> [[]]; +perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. + +%% Quick sort +sort([X|Xs]) -> + sort([ Y || Y <- Xs, Y < X ]) ++ + [X] ++ + sort([ Y || Y <- Xs, Y >= X ]); +sort([]) -> []. + +%% Vector addition +vecAdd(Xs,Ys) -> + [ X+Y || {X,Y} <- zip(Xs,Ys) ]. + +zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)]; +zip([],[]) -> []. + +qsort([X|Xs]) -> + qsort(lt(X,Xs)) + ++ [X] ++ + qsort(ge(X,Xs)); +qsort([]) -> []. + +lt(X,[H|T]) when X>H -> [H|lt(X,T)]; +lt(X,[_|T]) -> lt(X,T); +lt(_,[]) -> []. + +ge(X,[H|T]) when X=<H -> [H|ge(X,T)]; +ge(X,[_|T]) -> ge(X,T); +ge(_,[]) -> []. + +test(1,N) -> statistics(runtime),test1(N),statistics(runtime); +test(2,N) -> statistics(runtime),test2(N),statistics(runtime); +test(3,N) -> statistics(runtime),test3(N),statistics(runtime). + +test1(0) -> true; +test1(N) -> + sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), + test1(N-1). + +test2(0) -> true; +test2(N) -> + qsort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), + test2(N-1). + +test3(0) -> true; +test3(N) -> + lists:sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), + test3(N-1). diff --git a/system/doc/extensions/list_comprehensions.xml b/system/doc/extensions/list_comprehensions.xml new file mode 100644 index 0000000000..30e32da79c --- /dev/null +++ b/system/doc/extensions/list_comprehensions.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>List Comprehensions</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne DäKer</approved> + <checked></checked> + <date>96-09-10</date> + <rev>PA1</rev> + <file>list_comprehensions.sgml</file> + </header> + <p>List comprehensions are a feature of many modern functional programming languages. Subject to certain rules, they provide a succinct notation for generating elements in a list.</p> + <p>List comprehensions are analogous to set comprehensions + in Zermelo-Frankel set theory and are called ZF expressions in + Miranda. They are analogous to the <c>setof</c> and + <c>findall</c> predicates in Prolog.</p> + <p>List comprehensions are written with the following syntax: + </p> + <code type="none"> + +[Expression || Qualifier1, Qualifier2, ...] </code> + <p><c>Expression</c> is an arbitrary expression, and each <c>Qualifier</c> is either a generator or a filter.</p> + <list type="bulleted"> + <item>A <em>generator</em> written as <c><![CDATA[Pattern <- ListExpr]]></c>. <c>ListExpr</c> must be an expression which evaluates to a list of terms.</item> + <item>A <em>filter</em> is either a predicate or a boolean expression. A predicate is a function which returns <c>true</c> or <c>false</c>.</item> + </list> + + <section> + <title>Examples of List Comprehensions</title> + <p>We start with a simple example:</p> + <code type="none"><![CDATA[ + +> [X || X <- [1,2,a,3,4,b,5,6], X > 3]. +[a,4,b,5,6] ]]></code> + <p>This should be read as follows:</p> + <quote> + <p>The list of X such that X is taken from the list <c>[1,2,a,...]</c> and X is greater than 3.</p> + </quote> + <p>The notation <c><![CDATA[X <- [1,2,a,...]]]></c> is a generator and the expression <c>X > 3</c> is a filter.</p> + <p>An additional filter can be added in order to restrict the result to integers:</p> + <code type="none"><![CDATA[ + +> [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3]. +[4,5,6] ]]></code> + <p>Generators can be combined. For example, the Cartesian product of two lists can be written as follows:</p> + <code type="none"><![CDATA[ + +> [{X, Y} || X <- [1,2,3], Y <- [a,b]]. +[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] ]]></code> + + <section> + <title>Quick Sort</title> + <p>The well known quick sort routine can be written as follows:</p> + <code type="none"><![CDATA[ + +sort([Pivot|T]) -> + sort([ X || X <- T, X < Pivot]) ++ + [Pivot] ++ + sort([ X || X <- T, X >= Pivot]); +sort([]) -> []. ]]></code> + <p>The expression <c><![CDATA[[X || X <- T, X < Pivot]]]></c> is the list of all elements in <c>T</c>, which are less than <c>Pivot</c>.</p> + <p><c><![CDATA[[X || X <- T, X >= Pivot]]]></c> is the list of all elements in <c>T</c>, which are greater or equal to <c>Pivot</c>.</p> + <p>To sort a list, we isolate the first element in the list and split the list into two sub-lists. The first sub-list contains all elements which are smaller than the first element in the list, the second contains all elements which are greater than or equal to the first element in the list. We then sort the sub-lists and combine the results.</p> + </section> + + <section> + <title>Permutations</title> + <p>The following example generates all permutations of the elements in a list:</p> + <code type="none"><![CDATA[ + +perms([]) -> [[]]; +perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])]. ]]></code> + <p>We take take <c>H</c> from <c>L</c> in all possible ways. The result is the set of all lists <c>[H|T]</c>, where <c>T</c> is the set of all possible permutations of <c>L</c> with <c>H</c> removed.</p> + <code type="none"> + +> perms([b,u,g]). +[[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]] </code> + </section> + + <section> + <title>Pythagorean Triplets</title> + <p>Pythagorean triplets are sets of integers <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c>.</p> + <p>The function <c>pyth(N)</c> generates a list of all integers <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c> and where the sum of the sides is less than <c>N</c>.</p> + <code type="none"><![CDATA[ + +pyth(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N), + C <- lists:seq(1,N), + A+B+C =< N, + A*A+B*B == C*C + ]. ]]></code> + <pre> + +> <input>pyth(3).</input> +[]. +> <input>pyth(11).</input> +[]. +><input>pyth(12).</input> +[{3,4,5},{4,3,5}] +> <input>pyth(50).</input> +[{3,4,5}, + {4,3,5}, + {5,12,13}, + {6,8,10}, + {8,6,10}, + {8,15,17}, + {9,12,15}, + {12,5,13}, + {12,9,15}, + {12,16,20}, + {15,8,17}, + {16,12,20}]</pre> + <p>The following code reduces the search space and is more efficient:</p> + <code type="none"><![CDATA[ + +pyth1(N) -> + [{A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N-A+1), + C <- lists:seq(1,N-A-B+2), + A+B+C =< N, + A*A+B*B == C*C ]. ]]></code> + </section> + + <section> + <title>Simplifications with List Comprehensions</title> + <p>As an example, list comprehensions can be used to simplify some of the functions in <c>lists.erl</c>:</p> + <code type="none"><![CDATA[ + +append(L) -> [X || L1 <- L, X <- L1]. +map(Fun, L) -> [Fun(X) || X <- L]. +filter(Pred, L) -> [X || X <- L, Pred(X)]. ]]></code> + </section> + </section> + + <section> + <title>Variable Bindings in List Comprehensions</title> + <p>The scope rules for variables which occur in list comprehensions are as follows:</p> + <list type="bulleted"> + <item>all variables which occur in a generator pattern are assumed to be "fresh" variables</item> + <item>any variables which are defined before the list comprehension and which are used in filters have the values they had before the list comprehension</item> + <item>no variables may be exported from a list comprehension.</item> + </list> + <p>As an example of these rules, suppose we want to write the function <c>select</c>, which selects certain elements from a list of tuples. We might write <c><![CDATA[select(X, L) -> [Y || {X, Y} <- L].]]></c> with the intention of extracting all tuples from <c>L</c> where the first item is <c>X</c>.</p> + <p>Compiling this yields the following diagnostic:</p> + <code type="none"> + +./FileName.erl:Line: Warning: variable 'X' shadowed in generate </code> + <p>This diagnostic warns us that the variable <c>X</c> in the pattern is not the same variable as the variable <c>X</c> which occurs in the function head.</p> + <p>Evaluating <c>select</c> yields the following result:</p> + <pre> + +> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> +[1,2,3,7] </pre> + <p>This result is not what we wanted. To achieve the desired effect we must write <c>select</c> as follows:</p> + <code type="none"><![CDATA[ + +select(X, L) -> [Y || {X1, Y} <- L, X == X1]. ]]></code> + <p>The generator now contains unbound variables and the test has been moved into the filter. This now works as expected:</p> + <pre> + +> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> +[2,7] </pre> + <p>One consequence of the rules for importing variables into a list comprehensions is that certain pattern matching operations have to be moved into the filters and cannot be written directly in the generators. To illustrate this, do <em>not</em> write as follows:</p> + <code type="none"><![CDATA[ + +f(...) -> + Y = ... + [ Expression || PatternInvolving Y <- Expr, ...] + ... ]]></code> + <p>Instead, write as follows:</p> + <code type="none"><![CDATA[ + +f(...) -> + Y = ... + [ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...] + ... + ]]></code> + </section> +</chapter> + diff --git a/system/doc/extensions/list_comrehensions.erl b/system/doc/extensions/list_comrehensions.erl new file mode 100644 index 0000000000..f6a23b5dca --- /dev/null +++ b/system/doc/extensions/list_comrehensions.erl @@ -0,0 +1,75 @@ +-module(zf). + +-compile(export_all). + + +%% Odd numbers. + +%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. + +boo() -> [X||X <- [1,2,a,3,4,b,5,6], X > 3]. +boo1() -> [X||X <- [1,2,a,3,4,b,5,6], integer(X),X > 3]. +boo2() -> [{X,Y} || X <- [1,2,3], Y <- [a,b]]. + +bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. + +bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), + Y <- M, float(Y), gt(X, Y) + ]. + +baz(L) -> [ X || X <- L, atom(X) ]. + +buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. + +gt(X, Y) when X > Y -> true; +gt(X, Y) -> false. + + +%% Return the Pythagorean triangles with sides +%% of total length less than N +pyth(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N), + C <- lists:seq(1,N), + A+B+C =< N, + A*A+B*B == C*C + ]. + +%% Cut the search space a bit.. +pyth2(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N-A+1), + C <- lists:seq(1,N-A-B+2), + A+B+C =< N, + A*A+B*B == C*C ]. + +%% Return the Cartesian product + +cp(A,B) -> + [ {X,Y} || + X <- A, + Y <- B + ]. + +%% Return all permutations of a list +perms([]) -> [[]]; +perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. + +%% Quick sort +sort([X|Xs]) -> + sort([ Y || Y <- Xs, Y < X ]) ++ + [X] ++ + sort([ Y || Y <- Xs, Y >= X ]); +sort([]) -> []. + +%% append + +append(L) -> [X||L1<-L,X<-L1]. + +map(Fun, L) -> [Fun(X)||X<-L]. + +filter(Pred, L) -> [X||X<-L,Pred(X)]. + +select(X, L) -> [Y || {X1,Y} <- L, X == X1]. diff --git a/system/doc/extensions/macros.xml b/system/doc/extensions/macros.xml new file mode 100644 index 0000000000..feb3de6102 --- /dev/null +++ b/system/doc/extensions/macros.xml @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Macros</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne DäKer</approved> + <checked></checked> + <date>96-09-10</date> + <rev>PA1</rev> + <file>macros.sgml</file> + </header> + <p>Macros in Erlang are written with the following syntax:</p> + <code type="none"> + +-define(Const, Replacement). +-define(Fun(Var1, Var2,.., Var), Replacement). </code> + <p>Macros are expanded when the syntax <c>?MacroName</c> is encountered.</p> + <p>Consider the macro definition:</p> + <code type="none"> + +-define(timeout, 200). </code> + <p>The expression <c>?timeout</c>, which can occur anywhere in the code which follows the macro definition, will be replaced by <c>200</c>.</p> + <p>Macros with arguments are written as follows:</p> + <code type="none"> + + -define(macro1(X, Y), {a, X, b, Y}). </code> + <p>This type of macro can be used as follows:</p> + <code type="none"> + +bar(X) -> + ?macro1(a, b), + ?macro1(X, 123) </code> + <p>This expands to:</p> + <code type="none"> + +bar(X) -> + {a,a,b,b}, + {a,X,b,123}. </code> + + <section> + <title>Macros and Tokens</title> + <p>Macro expansion works at a token level. We might define a macro as follows:</p> + <code type="none"> + +-define(macro2(X, Y), {a,X,b,Y). </code> + <p>The replacement value of the macro is not a valid Erlang term because the closing right curly bracket is missing. <c>macro2</c> expands into a sequence of tokens <c>{</c>, <c>a</c>, <c>X</c> which are then pasted into the place where the macro is used.</p> + <p>We might use this macro as follows:</p> + <code type="none"> + +bar() -> + ?macro2(x,y)}. </code> + <p>This will expand into the valid sequence of tokens <c>{a,x,y,b}</c> before being parsed and compiled.</p> + <note> + <p>It is good programming practise to ensure that the replacement text of a macro is a valid Erlang syntactic form.</p> + </note> + </section> + + <section> + <title>Pre-Defined Macros</title> + <p>The following macros are pre-defined:</p> + <taglist> + <tag><c>?MODULE</c>. </tag> + <item>This macro returns the name of the current module. + </item> + <tag><c>?MODULE_STRING</c>. </tag> + <item>This macro returns the name of the current module, as a string.</item> + <tag><c>?FILE</c>.</tag> + <item>This macro returns the current file name.</item> + <tag><c>?LINE</c>.</tag> + <item>This macro returns the current line number.</item> + <tag><c>?MACHINE</c>.</tag> + <item>This macro returns the current machine name, + <c>'BEAM'</c>,</item> + </taglist> + </section> + + <section> + <title>Stringifying Macro Arguments</title> + <p>The construction <c>??Arg</c> for an argument to a macro expands to a + string containing the tokens of the argument, similar to the + <c>#arg</c> stringifying construction in C. This was added in Erlang + 5.0 (OTP R7A).</p> + <p>Example:</p> + <code type="none"> +-define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). + +?TESTCALL(myfunction(1,2)), +?TESTCALL(you:function(2,1)).</code> + <p>results in</p> + <code type="none"> +io:format("Call ~s: ~w~n",["myfunction ( 1 , 2 )",m:myfunction(1,2)]), +io:format("Call ~s: ~w~n",["you : function ( 2 , 1 )",you:function(2,1)]).</code> + </section> + + <section> + <title>Flow Control in Macros</title> + <p>The following macro directives are supplied:</p> + <taglist> + <tag>-undef(Macro).</tag> + <item>Causes the macro to behave as if it had never been defined.</item> + <tag>-ifdef(Macro).</tag> + <item>Do the following lines if <c>Macro</c> is defined.</item> + <tag>-ifndef(Macro).</tag> + <item>Do the following lines if <c>Macro</c> is not defined.</item> + <tag>-else.</tag> + <item>"else" macro</item> + <tag>-endif.</tag> + <item>"endif" macro.</item> + </taglist> + <p>The conditional macros must be properly nested. They are usually grouped as follows:</p> + <code type="none"> + +-ifdef(debug) +-define(....) +-else +-define(...) +-endif </code> + <p>The following example illustrates this grouping:</p> + <code type="none"> + +-define(debug, true). +-ifdef(debug). +-define(trace(Str, X), io:format("Mod:~w line:~w ~p ~p~n", + [?MODULE,?LINE, Str, X])). +-else. +-define(trace(X, Y), true). +-endif. </code> + <p>Given these definitions, the expression <c>?trace("X=", X).</c> in line 10 of the module <c>foo</c> expands to:</p> + <code type="none"> + +io:format("Mod:~w line:~w ~p ~p~n",[foo,100,"X=",[X]]), </code> + <p>If we remove the <c>-define(debug, true).</c> line, then the same expression expands to <c>true</c>.</p> + </section> + + <section> + <title>A Macro Expansion Utility</title> + <p>The following code can be used to expand a macro and display the result:</p> + <code type="none"> + +-module(mexpand). +-export([file/1]). +-import(lists, [foreach/2]). +file(File) -> + case epp:parse_file(File ++ ".erl", [],[]) of + {ok, L} -> + {ok, Stream} = file:open(File ++ ".out", write), + foreach(fun(X) -> + io:format(Stream,"~s~n",[erl_pp:form(X)]) + end, L), + file:close(Stream) + end.</code> + <p>Alternatively, we can compile the file with the <c>'P'</c> option. <c>compile:file(File, ['P'])</c> produces a list file <c>File.P</c>, in which the result of any macro expansions can be seen.</p> + </section> +</chapter> + diff --git a/system/doc/extensions/make.dep b/system/doc/extensions/make.dep new file mode 100644 index 0000000000..fdac959667 --- /dev/null +++ b/system/doc/extensions/make.dep @@ -0,0 +1,21 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: bit_syntax.tex book.tex funs.tex include.tex \ + list_comprehensions.tex macros.tex misc.tex \ + part.tex records.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +funs.tex: fun_test.erl funparse.erl funs1.erl + diff --git a/system/doc/extensions/mexpand.erl b/system/doc/extensions/mexpand.erl new file mode 100644 index 0000000000..261f99da46 --- /dev/null +++ b/system/doc/extensions/mexpand.erl @@ -0,0 +1,16 @@ +-module(mexpand). + +-export([file/1]). + +-import(lists, [foreach/2]). + +file(File) -> + case epp:parse_file(File ++ ".erl", [],[]) of + {ok, L} -> + {ok, Stream} = file:open(File ++ ".out", write), + foreach(fun(X) -> + io:format(Stream,"~s~n", + [erl_pp:form(X)]) + end, L), + file:close(Stream) + end. diff --git a/system/doc/extensions/misc.xml b/system/doc/extensions/misc.xml new file mode 100644 index 0000000000..576f705278 --- /dev/null +++ b/system/doc/extensions/misc.xml @@ -0,0 +1,310 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1999</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Miscellaneous</title> + <prepared>Arndt Jonasson</prepared> + <docno>1</docno> + <date>99-01-25</date> + <rev>PA1</rev> + <file>misc.sgml</file> + </header> + <p>In this chapter, a number of miscellaneous features of Erlang + are described.</p> + + <section> + <title>Token Syntax</title> + <p>In Erlang 4.8 (OTP R5A) the syntax of Erlang tokens have been + extended to allow the use of the full ISO-8859-1 (Latin-1) character + set. This is noticeable in the following ways:</p> + <list type="bulleted"> + <item>All the Latin-1 printable characters can be used and are shown without + the escape backslash convention.</item> + <item>Atoms and variables can use all Latin-1 letters.</item> + </list> + <p>The new characters from Latin-1 have the following + classifications in Erlang:</p> + <table> + <row> + <cell align="left" valign="middle"><em>Octal</em></cell> + <cell align="left" valign="middle"><em>Decimal</em></cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle"><em>Class</em></cell> + </row> + <row> + <cell align="left" valign="middle">200 - 237</cell> + <cell align="left" valign="middle">128 - 159</cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle">Control characters</cell> + </row> + <row> + <cell align="left" valign="middle">240 - 277</cell> + <cell align="left" valign="middle">160 - 191</cell> + <cell align="right" valign="middle">- ¿</cell> + <cell align="left" valign="middle">Punctuation characters</cell> + </row> + <row> + <cell align="left" valign="middle">300 - 326</cell> + <cell align="left" valign="middle">192 - 214</cell> + <cell align="center" valign="middle">À - Ö</cell> + <cell align="left" valign="middle">Uppercase letters</cell> + </row> + <row> + <cell align="center" valign="middle">327</cell> + <cell align="center" valign="middle">215</cell> + <cell align="center" valign="middle">×</cell> + <cell align="left" valign="middle">Punctuation character</cell> + </row> + <row> + <cell align="left" valign="middle">330 - 336</cell> + <cell align="left" valign="middle">216 - 222</cell> + <cell align="center" valign="middle">Ø - Þ</cell> + <cell align="left" valign="middle">Uppercase letters</cell> + </row> + <row> + <cell align="left" valign="middle">337 - 366</cell> + <cell align="left" valign="middle">223 - 246</cell> + <cell align="center" valign="middle">ß - ö</cell> + <cell align="left" valign="middle">Lowercase letters</cell> + </row> + <row> + <cell align="center" valign="middle">367</cell> + <cell align="center" valign="middle">247</cell> + <cell align="center" valign="middle">÷</cell> + <cell align="left" valign="middle">Punctuation character</cell> + </row> + <row> + <cell align="left" valign="middle">370 - 377</cell> + <cell align="left" valign="middle">248 - 255</cell> + <cell align="center" valign="middle">ø - ÿ</cell> + <cell align="left" valign="middle">Lowercase letters</cell> + </row> + <tcaption>Character classes</tcaption> + </table> + </section> + + <section> + <title>String Concatenation</title> + <p>Two adjacent string literals are concatenated into one. This is done already + at compile-time, and doesn't incur any runtime overhead. Example:</p> + <code type="none"> + "string" "42" </code> + <p>is equivalent to</p> + <code type="none"> + "string42" </code> + <p>This feature is convenient in at least two situations:</p> + <list type="bulleted"> + <item>when one of the + strings is the result of a macro expansion;</item> + <item>when a string is very + long, and would otherwise either have to wrap, making the source code + harder to read, or force the use of some runtime append operation.</item> + </list> + </section> + + <section> + <title>The ++ list Concatenation Operator</title> + <p>Since list concatenation is a very common operation, it is convenient + to have a terse way of expressing it. The ++ operator appends its second + argument to its first. Example: + </p> + <code type="none"> + X = [1,2,3], + Y = [4,5], + X ++ Y. </code> + <p>results in <c>[1,2,3,4,5]</c>.</p> + <p>The ++ operator has precedence between the binary '+' operator and + the comparison operators. + </p> + </section> + + <section> + <title>The - - list Subtraction Operator</title> + <p>The - - operator produces a list which is a copy of the first + argument, subjected to the following procedure: for each element in + the second argument, its first occurrence in the first argument is + removed.</p> + <code type="none"> + X = [1,2,3,2,1,2], + Y = [2,1,2], + X -- Y. </code> + <p>results in <c>[3,1,2]</c>.</p> + <p>The - - operator has precedence between the binary '+' operator and + the comparison operators. + </p> + </section> + + <section> + <title>Bitwise Operator bnot</title> + <p>Apart from the binary bitwise operators <c>band</c>, <c>bor</c> + and <c>bxor</c>, there is a unary operator <c>bnot</c> with the same + precedence as the other unary operators + and -, i.e., higher than + the binary operators. Example:</p> + <code type="none"> + bnot 7. </code> + <p>returns -8. + </p> + </section> + + <section> + <title>Logical Operators</title> + <p>The atoms <c>true</c> and <c>false</c> are usually used for representing + Boolean values. With the binary operators <c>and</c>, <c>or</c> and + <c>xor</c>, and the unary operator <c>not</c>, Boolean values can be + combined. Example:</p> + <code type="none"> + + M1 = lists:member(A, List1), + M2 = lists:member(A, List2), + M1 and M2.</code> + <p>Note that the operators are strict, i.e., they always evaluate both + their arguments.</p> + <p><c>not</c> has the same priority as the other unary operators. The + binary logical operators have precedence between the <c>=</c> operator + and the comparison operators, the <c>and</c> operator having higher + precedence than <c>or</c> and <c>xor</c>. + </p> + </section> + + <section> + <title>Match Operator = In Patterns</title> + <p>This extension was added in Erlang 4.8 (OTP R5A).</p> + <p>The = operator is also called the `match' operator. The match operator + can now be used in a pattern, so that <c>P1 = P2</c> is a valid pattern, + where both <c>P1</c> and <c>P2</c> are patterns. This compound pattern + when matched against a term causes the term to be matched against both + <c>P1</c> and <c>P2</c>.</p> + <p>One use for this construction is to avoid reconstructing a term which + was part of an argument to a function. Example:</p> + <code type="none"> + f({'+',X,Y}=T) -> {X+Y,T}.</code> + <p>It also makes it possible to rewrite the construction</p> + <code type="none"> + f(X) when X == #rec{x=1, y=a} -> ... </code> + <p>as</p> + <code type="none"> + f(#rec{x=1, y=a} = X) -> ... </code> + <p>In the absence of optimization for the former case, the + latter case is more efficient. + </p> + </section> + + <section> + <title>Literal String Prefix in Patterns</title> + <p>This extension was added in Erlang 4.8 (OTP R5A).</p> + <p>A new construction is allowed in patterns, namely a literal + string as the first operand of the ++ operator. Example:</p> + <code type="none"> + f("prefix" ++ L) -> ... </code> + <p>This is syntactic sugar for the equivalent, but harder to read</p> + <code type="none"> + f([$p,$r,$e,$f,$i,$x | L]) -> ... </code> + </section> + + <section> + <title>Disjunctions in Guards</title> + <p>This extension was added in Erlang 4.9 (OTP R6A).</p> + <p>A new construction is allowed in guards, the disjunction operator + ';'. The construction is syntactic sugar which removes the bother of + writing the same body after several guards.</p> + <code type="none"> + f(X) when xxx ; yyy ; zzz -> + pop(X).</code> + <p>This is syntactic sugar for the equivalent</p> + <code type="none"> + f(X) when xxx -> + pop(X); + f(X) when yyy -> + pop(X); + f(X) when zzz -> + pop(X). </code> + <p>The abstract format has been changed accordingly to contain a list of + (conjunctive) guards where there was previously only one guard. + </p> + </section> + + <section> + <title>Expressions in Patterns</title> + <p>This extension was added in Erlang 5.0 (OTP R7A).</p> + <p>An arithmetic expression can be used within a pattern, if it uses + only numeric or bitwise operators, and if its value can be evaluated + to a constant at compile-time. This is especially useful when the + expression is defined by a macro. + </p> + <p>Example:</p> + <code type="none"> + case X of + {1+2, T} -> T + end.</code> + </section> + + <section> + <title>Boolean expresions in guards</title> + <p>This extension was added in Erlang 5.1 (OTP R8).</p> + <p>In guards, the use of <c>and</c>, <c>or</c> and <c>not</c> is + now allowed. Guard expressions can combine these with + parenthesis. This allows for more elaborate guards than what + may be given with <c>,</c> and <c>;</c>.</p> + <note> + <p>The guard expressions written with these operators are boolean + expressions, and the boolean functions <c>is_list</c>, + <c>is_integer</c> etc. should be used, rather than + <c>list</c>, <c>integer</c> etc.</p> + </note> + <p>Example 1:</p> + <code type="none"> + f(X) when not (is_tuple(X) or is_list(X)) -> + ... </code> + <p>Example 2:</p> + <code type="none"><![CDATA[ + g(A, B) when (A > 0) and (B > 0) and not (A*A < B*B) -> + ... ]]></code> + </section> + + <section> + <title>Short-circuit boolean expressions</title> + <p>This extension was added in Erlang 5.1 (OTP R8).</p> + <p>In a boolean expression it is unnecessary to always evaluate all + terms. If the first term gives a result that determines the + result, the second term is not needed. In Erlang two new + keywords handles boolean expressions without evaluating both + terms, if it's unnecessary. (This is called short-curcuit + boolean evaluation.)</p> + <p>The keyword <c>andalso</c> is a short-curcuit version of + <c>and</c>. The keyword <c>orelse</c> is a short-curcuit version + of <c>or</c>. They can be used in boolean expressions (not + guards) instead of <c>and</c> and <c>or</c>.</p> + <p>Example 1:</p> + <code type="none"> + case A >= -1.0 andalso math:sqrt(A+1) > B of </code> + <p>This will work even if <c>A</c> is less than <c>-1.0</c>, since + in that case, the second term (after <c>andalso</c>) is never + evaluated. (Of course, the same effects could have been done + using guards. In guards, evaluation is always short-circuited, + since guard tests are known to be free of side-effects.)</p> + <p>Example 2:</p> + <code type="none"> + OnlyOne = is_atom(L) orelse + (is_list(L) andalso length(L) == 1), </code> + </section> +</chapter> + diff --git a/system/doc/extensions/part.xml b/system/doc/extensions/part.xml new file mode 100644 index 0000000000..56fd2c09a6 --- /dev/null +++ b/system/doc/extensions/part.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Erlang Extensions Since 4.4</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-02-21</date> + <rev>E</rev> + <file>part.sgml</file> + </header> + <description> + <p>This chapter describes extensions made to the Erlang language + since version 4.4 (where nothing is said to the contrary, an extension + was added in version 4.4). + The chapter contains the following sections: + </p> + <list type="bulleted"> + <item>Records</item> + <item>Functional Objects (Funs)</item> + <item>List Comprehensions</item> + <item>Macros</item> + <item>File inclusion</item> + <item>Bit syntax</item> + <item>Miscellaneous</item> + </list> + </description> + <include file="records"></include> + <include file="funs"></include> + <include file="list_comprehensions"></include> + <include file="macros"></include> + <include file="include"></include> + <include file="bit_syntax"></include> + <include file="misc"></include> +</part> + diff --git a/system/doc/extensions/records.xml b/system/doc/extensions/records.xml new file mode 100644 index 0000000000..21ec73ab77 --- /dev/null +++ b/system/doc/extensions/records.xml @@ -0,0 +1,284 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Records</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne DäKer</approved> + <checked></checked> + <date>96-09-10</date> + <rev>PA1</rev> + <file>records.sgml</file> + </header> + <p>A record is a data structure intended for storing a fixed number of related data items. It is + similar to a <c>struct</c> in C, or a <c>record</c> in Pascal. </p> + <p>The main advantage of using records instead of tuples is that fields in a record are accessed by name, whereas fields in a tuple are accessed by position. To illustrate these differences, suppose that we want to represent a person with the <em>tuple</em><c>{Name, Address, Phone}</c>.</p> + <p>We must remember that the <c>Name</c> field is the first element of the tuple, the <c>Address</c> field is the second element, and so on, in order to write functions which manipulate this data. For example, to extract data from a variable <c>P</c> which contains such a tuple we might write the following code and then use pattern matching to extract the relevant fields.</p> + <code type="none"> + +Name = element(1, P), +Address = element(2, P), +... </code> + <p>Code like this is difficult to read and understand and errors occur if we get the numbering of the elements in the tuple wrong. If we change the data representation by re-ordering the fields, or by adding or removing a field, then all references to the person tuple, wherever they occur, must be checked and possibly modified.</p> + <p><em>Records</em> allow us to refer to the fields by name and not position. We use a record instead of a tuple to store the data . If we write a record definition of the type shown below, we can then refer to the fields of the record by name.</p> + <code type="none"> + +-record(person, {name, phone, address}). </code> + <p>For example, if <c>P</c> is now a variable whose value is a <c>person</c> record, we can code as follows in order to access the name and address fields of the records.</p> + <code type="none"> + +Name = P#person.name, +Address = P#person.address, +... </code> + <p>In the following sections we describe the different operations which can be performed on records:</p> + + <section> + <title>Defining a Record</title> + <p>A record is defined with the following syntax:</p> + <code type="none"> + +-record(RecordName, {Field1 [= DefaultValue1], + Field2 [= DefaultValue2], + ..., + FieldN [= DefaultValueN]}). </code> + <p>The record name and field names must be atoms. The optional default values, which are terms, are used if no value is supplied for a field when a new instance of the record is created. If the default value is not supplied, then the atom <c>undefined</c> is assumed.</p> + <p>For example, in the following record definition, the address field is <c>undefined</c>.</p> + <pre> +-record(person, {name = "", phone = [], address}). </pre> + <p>This definition of a person will be used in many of the examples which follow.</p> + </section> + + <section> + <title>Including a Record Definition</title> + <p>If the record is used in several modules, its definition should be placed in a <c>.hrl</c> header file. Each module which uses the record definition should have a <c>-include(FileName).</c> statement. For example:</p> + <code type="none"> + +-include("my_data_structures.hrl"). </code> + <note> + <p>The definition of the record must come before it is used.</p> + </note> + </section> + + <section> + <title>Creating a Record</title> + <p>A new record is created with the following syntax:</p> + <code type="none"> + +#RecordName{Field1=Expr1, + ..., + FieldM=ExprM}. </code> + <p>If any of the fields is omitted, then the default value supplied in the record definition is used. For example:</p> + <pre> +> #person{phone = [0,8,2,3,4,3,1,2], name = "Robert"}. +{person, "Robert", [0,8,2,3,4,3,1,2], undefined}. </pre> + <p>There is a new feature introduced in Erlang 5.1 (OTP release + R8), with which you can set a value to all fields in a record, + overriding the defaults in the record specification. The special + field <c>_</c>, means "all fields not explicitly specified".</p> + <pre> +> #person{name = "Jakob", _ = '_'} +{person, "Jakob", '_', '_'} </pre> + <p>It is primarily intended to be used in <c>ets:match/2</c> and + <c>mnesia:match_object/3</c>, to set record fields to the atom + <c>'_'</c>. (This is a wildcard in <c>ets:match/2</c>.)</p> + </section> + + <section> + <title>Selectors</title> + <p>The following syntax is used to select an individual field from a record:</p> + <code type="none"> + +Variable#RecordName.Field </code> + <note> + <p>The values contained in record names and fields must be constants, not variables.</p> + </note> + <note> + <p>For the purposes of illustration, we will demonstrate the use of records using an imaginary dialogue with the Erlang shell. Currently the Erlang evaluator does not support records so you may not be able to reproduce this dialogue.</p> + </note> + <pre> + +> <input>P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.</input> +{person, "Joe", [0,8,2,3,4,3,1,2], undefined} +> <input>P#person.name.</input> +"Joe" </pre> + <note> + <p>Selectors for records are allowed in guards.</p> + </note> + </section> + + <section> + <title>Updating a Record</title> + <p>The following syntax is used to create a new copy of the record with some of the fields changed. Only the fields to be changed need to be referred to, all other fields retain their old values.</p> + <code type="none"> + +OldVariable#RecordName{Field1 = NewValue1, + ..., + FieldM = NewValueM} </code> + <p>For example:</p> + <pre> +> P1 = #person{name="Joe", phone=[1,2,3], address="A street"}. +{person, "Joe", [1,2,3], "A street"} +> P2 = P1#person{name="Robert"}. +{person, "Robert", [1,2,3], "A street"} </pre> + </section> + + <section> + <title>Type Testing</title> + <p>The following guard test is used to test the type of a record:</p> + <code type="none"> + +record(Variable, RecordName) </code> + <p>The following example shows that the guard succeeds if <c>P</c> is record of type <c>person</c>.</p> + <pre> +foo(P) when record(P, person) -> a_person; +foo(_) -> not_a_person. </pre> + <note> + <p>This test checks that <c>P</c> is a tuple of arity <c>N + 1</c>, where <c>N</c> is the number + of fields in the record, and the first element in the tuple is the atom <c>person</c>.</p> + </note> + </section> + + <section> + <title>Pattern Matching</title> + <p>Matching can be used in combination with records as shown in the following example:</p> + <pre> +> P = #person{name="Joe", phone=[0,0,7], address="A street"}. +{person, "Joe", [0,0,7], "A street"} +> #person{name = Name} = P, Name. +"Joe" </pre> + <p>The following function takes a list of <c>person</c> records and searches for the phone number of a person with a particular name:</p> + <code type="none"> + +find_phone([#person{name=Name, phone=Phone} | _], Name) -> + {found, Phone}; +find_phone([_| T], Name) -> + find_phone(T, Name); +find_phone([], Name) -> + not_found. </code> + <note> + <p>The fields referred to in the pattern can be given in any order.</p> + </note> + </section> + + <section> + <title>Nested Records</title> + <p>The value of a field in a record might be an instance of a record. Retrieval of nested data can be done stepwise, or in a single step, as shown in the following example:</p> + <pre> +-record(name, {first = "Robert", last = "Ericsson"}). +-record(person, {name = #name{}, phone}). + +demo() -> + P = #person{name= #name{first="Robert",last="Virding"}, phone=123}, + First = (P#person.name)#name.first. </pre> + <note> + <p>In this example, <c>demo()</c> evaluates to <c>"Robert"</c>.</p> + </note> + </section> + + <section> + <title>Internal Representation of Records</title> + <p>It is often desirable to write generic functions which will work on any record, not just a record of a particular type. For this reason, records are represented internally as tuples and the ordering of the fields in the tuple is strictly defined.</p> + <p>For example, the record <c>-record(person, {name, phone, address}).</c> is represented internally by the tuple <c>{person, X, Y, Z}</c>.</p> + <p>The arity of the tuple is one more than the number of fields in the tuple. The first element of the tuple is the name of the record, and the elements of the tuple are the fields in the record. The variables <c>X</c>, <c>Y</c> and <c>Z</c> will store the data contained in the record fields.</p> + <p>The following two functions determine the indices in the tuple which refer to the named fields in the record:</p> + <list type="bulleted"> + <item><c>record_info(fields, Rec) -> [Names]</c>. This function returns the names of the fields in the record <c>Rec</c>. For example, <c>record_info(fields, person)</c> evaluates to <c>[name, address, phone]</c>.</item> + <item><c>record_info(size, Rec) -> Size</c>. This function returns the size of the record <c>Rec</c> when represented as a tuple, which is one more than the number of fields. For example, <c>record_info(size, person)</c> returns <c>4</c>.</item> + </list> + <p>In addition, <c>#Rec.Name</c> returns the index in the tuple representation of <c>Name</c> of the record <c>Rec</c>.</p> + <note> + <p><c>Name</c> must be an atom.</p> + </note> + <p>For example, the following test function <c>test()</c> might return the result shown:</p> + <pre> +test() -> + {record_info(fields, person), + record_info(size, person), + #person.name}. </pre> + <pre> +> <input>Mod:test().</input> +{[name,address,phone],4,2} </pre> + <p>The order in which records map onto tuples is implementation dependent.</p> + <note> + <p><c>record_info</c> is a pseudo-function which cannot be exported from the module where it occurs.</p> + </note> + </section> + + <section> + <title>Example</title> + <pre> +%% File: person.hrl + +%%----------------------------------------------------------- +%% Data Type: person +%% where: +%% name: A string (default is undefined). +%% age: An integer (default is undefined). +%% phone: A list of integers (default is []). +%% dict: A dictionary containing various information +%% about the person. +%% A {Key, Value} list (default is the empty list). +%%------------------------------------------------------------ +-record(person, {name, age, phone = [], dict = []}). + </pre> + <pre> +-module(person). +-include("person.hrl"). +-compile(export_all). % For test purposes only. + +%% This creates an instance of a person. +%% Note: The phone number is not supplied so the +%% default value [] will be used. + +make_hacker_without_phone(Name, Age) -> + #person{name = Name, age = Age, + dict = [{computer_knowledge, excellent}, + {drinks, coke}]}. + +%% This demonstrates matching in arguments + +print(#person{name = Name, age = Age, + phone = Phone, dict = Dict}) -> + io:format("Name: ~s, Age: ~w, Phone: ~w ~n" + "Dictionary: ~w.~n", [Name, Age, Phone, Dict]). + +%% Demonstrates type testing, selector, updating. + +birthday(P) when record(P, person) -> + P#person{age = P#person.age + 1}. + +register_two_hackers() -> + Hacker1 = make_hacker_without_phone("Joe", 29), + OldHacker = birthday(Hacker1), + % The central_register_server should have + % an interface function for this. + central_register_server ! {register_person, Hacker1}, + central_register_server ! {register_person, + OldHacker#person{name = "Robert", + phone = [0,8,3,2,4,5,3,1]}}. </pre> + </section> +</chapter> + diff --git a/system/doc/extensions/warning.gif b/system/doc/extensions/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/extensions/warning.gif diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile new file mode 100644 index 0000000000..5ca885d56e --- /dev/null +++ b/system/doc/getting_started/Makefile @@ -0,0 +1,100 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/getting_started + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES = $(GETTING_STARTED_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +PS_FILES = $(GIF_FILES:%.gif=%.ps) + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/getting_started + + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: diff --git a/system/doc/getting_started/book.xml b/system/doc/getting_started/book.xml new file mode 100644 index 0000000000..c256dc1317 --- /dev/null +++ b/system/doc/getting_started/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Getting Started with Erlang</title> + <prepared>Mike Williams</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>Getting Started with Erlang</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml new file mode 100644 index 0000000000..34ae428b2c --- /dev/null +++ b/system/doc/getting_started/conc_prog.xml @@ -0,0 +1,894 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Concurrent Programming</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>conc_prog.xml</file> + </header> + + <section> + <title>Processes</title> + <p>One of the main reasons for using Erlang instead of other + functional languages is Erlang's ability to handle concurrency + and distributed programming. By concurrency we mean programs + which can handle several threads of execution at the same time. + For example, modern operating systems would allow you to use a + word processor, a spreadsheet, a mail client and a print job all + running at the same time. Of course each processor (CPU) in + the system is probably only handling one thread (or job) at a + time, but it swaps between the jobs a such a rate that it gives + the illusion of running them all at the same time. It is easy to + create parallel threads of execution in an Erlang program and it + is easy to allow these threads to communicate with each other. In + Erlang we call each thread of execution a <em>process</em>.</p> + <p>(Aside: the term "process" is usually used when the threads of + execution share no data with each other and the term "thread" + when they share data in some way. Threads of execution in Erlang + share no data, that's why we call them processes).</p> + <p>The Erlang BIF <c>spawn</c> is used to create a new process: + <c>spawn(Module, Exported_Function, List of Arguments)</c>. + Consider the following module:</p> + <code type="none"> +-module(tut14). + +-export([start/0, say_something/2]). + +say_something(What, 0) -> + done; +say_something(What, Times) -> + io:format("~p~n", [What]), + say_something(What, Times - 1). + +start() -> + spawn(tut14, say_something, [hello, 3]), + spawn(tut14, say_something, [goodbye, 3]).</code> + <pre> +5> <input>c(tut14).</input> +{ok,tut14} +6> <input>tut14:say_something(hello, 3).</input> +hello +hello +hello +done</pre> + <p>We can see that function <c>say_something</c> writes its first + argument the number of times specified by second argument. Now + look at the function <c>start</c>. It starts two Erlang processes, + one which writes "hello" three times and one which writes + "goodbye" three times. Both of these processes use the function + <c>say_something</c>. Note that a function used in this way by + <c>spawn</c> to start a process must be exported from the module + (i.e. in the <c>-export</c> at the start of the module).</p> + <pre> +9> <input>tut14:start().</input> +hello +goodbye +<0.63.0> +hello +goodbye +hello +goodbye</pre> + <p>Notice that it didn't write "hello" three times and then + "goodbye" three times, but the first process wrote a "hello", + the second a "goodbye", the first another "hello" and so forth. + But where did the <0.63.0> come from? The return value of a + function is of course the return value of the last "thing" in + the function. The last thing in the function <c>start</c> is</p> + <code type="none"> +spawn(tut14, say_something, [goodbye, 3]).</code> + <p><c>spawn</c> returns a <em>process identifier</em>, or + <em>pid</em>, which uniquely identifies the process. So <0.63.0> + is the pid of the <c>spawn</c> function call above. We will see + how to use pids in the next example.</p> + <p>Note as well that we have used ~p instead of ~w in + <c>io:format</c>. To quote the manual: "~p Writes the data with + standard syntax in the same way as ~w, but breaks terms whose + printed representation is longer than one line into many lines + and indents each line sensibly. It also tries to detect lists of + printable characters and to output these as strings".</p> + </section> + + <section> + <title>Message Passing</title> + <p>In the following example we create two processes which send + messages to each other a number of times.</p> + <code type="none"> +-module(tut15). + +-export([start/0, ping/2, pong/0]). + +ping(0, Pong_PID) -> + Pong_PID ! finished, + io:format("ping finished~n", []); + +ping(N, Pong_PID) -> + Pong_PID ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping(N - 1, Pong_PID). + +pong() -> + receive + finished -> + io:format("Pong finished~n", []); + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + end. + +start() -> + Pong_PID = spawn(tut15, pong, []), + spawn(tut15, ping, [3, Pong_PID]).</code> + <pre> +1> <input>c(tut15).</input> +{ok,tut15} +2> <input>tut15: start().</input> +<0.36.0> +Pong received ping +Ping received pong +Pong received ping +Ping received pong +Pong received ping +Ping received pong +ping finished +Pong finished</pre> + <p>The function <c>start</c> first creates a process, let's call it + "pong":</p> + <code type="none"> +Pong_PID = spawn(tut15, pong, [])</code> + <p>This process executes <c>tut15:pong()</c>. <c>Pong_PID</c> is + the process identity of the "pong" process. The function + <c>start</c> now creates another process "ping".</p> + <code type="none"> +spawn(tut15, ping, [3, Pong_PID]),</code> + <p>this process executes</p> + <code type="none"> +tut15:ping(3, Pong_PID)</code> + <p><0.36.0> is the return value from the <c>start</c> function.</p> + <p>The process "pong" now does:</p> + <code type="none"> +receive + finished -> + io:format("Pong finished~n", []); + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() +end.</code> + <p>The <c>receive</c> construct is used to allow processes to wait + for messages from other processes. It has the format:</p> + <code type="none"> +receive + pattern1 -> + actions1; + pattern2 -> + actions2; + .... + patternN + actionsN +end.</code> + <p>Note: no ";" before the <c>end</c>.</p> + <p>Messages between Erlang processes are simply valid Erlang terms. + I.e. they can be lists, tuples, integers, atoms, pids etc.</p> + <p>Each process has its own input queue for messages it receives. + New messages received are put at the end of the queue. When a + process executes a <c>receive</c>, the first message in the queue + is matched against the first pattern in the <c>receive</c>, if + this matches, the message is removed from the queue and + the actions corresponding to the the pattern are executed.</p> + <p>However, if the first pattern does not match, the second pattern + is tested, if this matches the message is removed from the queue + and the actions corresponding to the second pattern are executed. + If the second pattern does not match the third is tried and so on + until there are no more pattern to test. If there are no more + patterns to test, the first message is kept in the queue and we + try the second message instead. If this matches any pattern, + the appropriate actions are executed and the second message is + removed from the queue (keeping the first message and any other + messages in the queue). If the second message does not match we + try the third message and so on until we reach the end of + the queue. If we reach the end of the queue, the process blocks + (stops execution) and waits until a new message is received and + this procedure is repeated.</p> + <p>Of course the Erlang implementation is "clever" and minimizes + the number of times each message is tested against the patterns + in each <c>receive</c>.</p> + <p>Now back to the ping pong example.</p> + <p>"Pong" is waiting for messages. If the atom <c>finished</c> is + received, "pong" writes "Pong finished" to the output and as it + has nothing more to do, terminates. If it receives a message with + the format:</p> + <code type="none"> +{ping, Ping_PID}</code> + <p>it writes "Pong received ping" to the output and sends the atom + <c>pong</c> to the process "ping":</p> + <code type="none"> +Ping_PID ! pong</code> + <p>Note how the operator "!" is used to send messages. The syntax + of "!" is:</p> + <code type="none"> +Pid ! Message</code> + <p>I.e. <c>Message</c> (any Erlang term) is sent to the process + with identity <c>Pid</c>.</p> + <p>After sending the message <c>pong</c>, to the process "ping", + "pong" calls the <c>pong</c> function again, which causes it to + get back to the <c>receive</c> again and wait for another message. + Now let's look at the process "ping". Recall that it was started + by executing:</p> + <code type="none"> +tut15:ping(3, Pong_PID)</code> + <p>Looking at the function <c>ping/2</c> we see that the second + clause of <c>ping/2</c> is executed since the value of the first + argument is 3 (not 0) (first clause head is + <c>ping(0,Pong_PID)</c>, second clause head is + <c>ping(N,Pong_PID)</c>, so <c>N</c> becomes 3).</p> + <p>The second clause sends a message to "pong":</p> + <code type="none"> +Pong_PID ! {ping, self()},</code> + <p><c>self()</c> returns the pid of the process which executes + <c>self()</c>, in this case the pid of "ping". (Recall the code + for "pong", this will land up in the variable <c>Ping_PID</c> in + the <c>receive</c> previously explained).</p> + <p>"Ping" now waits for a reply from "pong":</p> + <code type="none"> +receive + pong -> + io:format("Ping received pong~n", []) +end,</code> + <p>and writes "Ping received pong" when this reply arrives, after + which "ping" calls the <c>ping</c> function again.</p> + <code type="none"> +ping(N - 1, Pong_PID)</code> + <p><c>N-1</c> causes the first argument to be decremented until it + becomes 0. When this occurs, the first clause of <c>ping/2</c> + will be executed:</p> + <code type="none"> +ping(0, Pong_PID) -> + Pong_PID ! finished, + io:format("ping finished~n", []);</code> + <p>The atom <c>finished</c> is sent to "pong" (causing it to + terminate as described above) and "ping finished" is written to + the output. "Ping" then itself terminates as it has nothing left + to do.</p> + </section> + + <section> + <title>Registered Process Names</title> + <p>In the above example, we first created "pong" so as to be able + to give the identity of "pong" when we started "ping". I.e. in + some way "ping" must be able to know the identity of "pong" in + order to be able to send a message to it. Sometimes processes + which need to know each others identities are started completely + independently of each other. Erlang thus provides a mechanism for + processes to be given names so that these names can be used as + identities instead of pids. This is done by using + the <c>register</c> BIF:</p> + <code type="none"> +register(some_atom, Pid)</code> + <p>We will now re-write the ping pong example using this and giving + the name <c>pong</c> to the "pong" process:</p> + <code type="none"> +-module(tut16). + +-export([start/0, ping/1, pong/0]). + +ping(0) -> + pong ! finished, + io:format("ping finished~n", []); + +ping(N) -> + pong ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping(N - 1). + +pong() -> + receive + finished -> + io:format("Pong finished~n", []); + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + end. + +start() -> + register(pong, spawn(tut16, pong, [])), + spawn(tut16, ping, [3]).</code> + <pre> +2> <input>c(tut16).</input> +{ok, tut16} +3> <input>tut16:start().</input> +<0.38.0> +Pong received ping +Ping received pong +Pong received ping +Ping received pong +Pong received ping +Ping received pong +ping finished +Pong finished</pre> + <p>In the <c>start/0</c> function,</p> + <code type="none"> +register(pong, spawn(tut16, pong, [])),</code> + <p>both spawns the "pong" process and gives it the name <c>pong</c>. + In the "ping" process we can now send messages to <c>pong</c> by:</p> + <code type="none"> +pong ! {ping, self()},</code> + <p>so that <c>ping/2</c> now becomes <c>ping/1</c> as we don't have + to use the argument <c>Pong_PID</c>.</p> + </section> + + <section> + <title>Distributed Programming</title> + <p>Now let's re-write the ping pong program with "ping" and "pong" + on different computers. Before we do this, there are a few things + we need to set up to get this to work. The distributed Erlang + implementation provides a basic security mechanism to prevent + unauthorized access to an Erlang system on another computer + (*manual*). Erlang systems which talk to each other must have + the same <em>magic cookie</em>. The easiest way to achieve this + is by having a file called <c>.erlang.cookie</c> in your home + directory on all machines which on which you are going to run + Erlang systems communicating with each other (on Windows systems + the home directory is the directory where pointed to by the $HOME + environment variable - you may need to set this. On Linux or Unix + you can safely ignore this and simply create a file called + <c>.erlang.cookie</c> in the directory you get to after executing + the command <c>cd</c> without any argument). + The <c>.erlang.cookie</c> file should contain on line with + the same atom. For example on Linux or Unix in the OS shell:</p> + <pre> +$ <input>cd</input> +$ <input>cat > .erlang.cookie</input> +this_is_very_secret +$ <input>chmod 400 .erlang.cookie</input></pre> + <p>The <c>chmod</c> above make the <c>.erlang.cookie</c> file + accessible only by the owner of the file. This is a requirement.</p> + <p>When you start an Erlang system which is going to talk to other + Erlang systems, you must give it a name, eg: </p> + <pre> +$ <input>erl -sname my_name</input></pre> + <p>We will see more details of this later (*manual*). If you want to + experiment with distributed Erlang, but you only have one + computer to work on, you can start two separate Erlang systems on + the same computer but give them different names. Each Erlang + system running on a computer is called an Erlang node.</p> + <p>(Note: <c>erl -sname</c> assumes that all nodes are in the same + IP domain and we can use only the first component of the IP + address, if we want to use nodes in different domains we use + <c>-name</c> instead, but then all IP address must be given in + full (*manual*).</p> + <p>Here is the ping pong example modified to run on two separate + nodes:</p> + <code type="none"> +-module(tut17). + +-export([start_ping/1, start_pong/0, ping/2, pong/0]). + +ping(0, Pong_Node) -> + {pong, Pong_Node} ! finished, + io:format("ping finished~n", []); + +ping(N, Pong_Node) -> + {pong, Pong_Node} ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping(N - 1, Pong_Node). + +pong() -> + receive + finished -> + io:format("Pong finished~n", []); + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + end. + +start_pong() -> + register(pong, spawn(tut17, pong, [])). + +start_ping(Pong_Node) -> + spawn(tut17, ping, [3, Pong_Node]).</code> + <p>Let us assume we have two computers called gollum and kosken. We + will start a node on kosken called ping and then a node on gollum + called pong.</p> + <p>On kosken (on a Linux/Unix system):</p> + <pre> +kosken> <input>erl -sname ping</input> +Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0] + +Eshell V5.2.3.7 (abort with ^G) +(ping@kosken)1></pre> + <p>On gollum:</p> + <pre> +gollum> <input>erl -sname pong</input> +Erlang (BEAM) emulator version 5.2.3.7 [hipe] [threads:0] + +Eshell V5.2.3.7 (abort with ^G) +(pong@gollum)1></pre> + <p>Now we start the "pong" process on gollum:</p> + <pre> +(pong@gollum)1> <input>tut17:start_pong().</input> +true</pre> + <p>and start the "ping" process on kosken (from the code above you + will see that a parameter of the <c>start_ping</c> function is + the node name of the Erlang system where "pong" is running):</p> + <pre> +(ping@kosken)1> <input>tut17:start_ping(pong@gollum).</input> +<0.37.0> +Ping received pong +Ping received pong +Ping received pong +ping finished</pre> + <p>Here we see that the ping pong program has run, on the "pong" + side we see:</p> + <pre> +(pong@gollum)2> +Pong received ping +Pong received ping +Pong received ping +Pong finished +(pong@gollum)2></pre> + <p>Looking at the <c>tut17</c> code we see that the <c>pong</c> + function itself is unchanged, the lines:</p> + <code type="none"> +{ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong,</code> + <p>work in the same way irrespective of on which node the "ping" + process is executing. Thus Erlang pids contain information about + where the process executes so if you know the pid of a process, + the "!" operator can be used to send it a message if the process + is on the same node or on a different node.</p> + <p>A difference is how we send messages to a registered process on + another node:</p> + <code type="none"> +{pong, Pong_Node} ! {ping, self()},</code> + <p>We use a tuple <c>{registered_name,node_name}</c> instead of + just the <c>registered_name</c>.</p> + <p>In the previous example, we started "ping" and "pong" from + the shells of two separate Erlang nodes. <c>spawn</c> can also be + used to start processes in other nodes. The next example is + the ping pong program, yet again, but this time we will start + "ping" in another node:</p> + <code type="none"> +-module(tut18). + +-export([start/1, ping/2, pong/0]). + +ping(0, Pong_Node) -> + {pong, Pong_Node} ! finished, + io:format("ping finished~n", []); + +ping(N, Pong_Node) -> + {pong, Pong_Node} ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping(N - 1, Pong_Node). + +pong() -> + receive + finished -> + io:format("Pong finished~n", []); + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + end. + +start(Ping_Node) -> + register(pong, spawn(tut18, pong, [])), + spawn(Ping_Node, tut18, ping, [3, node()]).</code> + <p>Assuming an Erlang system called ping (but not the "ping" + process) has already been started on kosken, then on gollum we do:</p> + <pre> +(pong@gollum)1> <input>tut18:start(ping@kosken).</input> +<3934.39.0> +Pong received ping +Ping received pong +Pong received ping +Ping received pong +Pong received ping +Ping received pong +Pong finished +ping finished</pre> + <p>Notice we get all the output on gollum. This is because the io + system finds out where the process is spawned from and sends all + output there.</p> + </section> + + <section> + <title>A Larger Example</title> + <p>Now for a larger example. We will make an extremely simple + "messenger". The messenger is a program which allows users to log + in on different nodes and send simple messages to each other.</p> + <p>Before we start, let's note the following:</p> + <list type="bulleted"> + <item> + <p>This example will just show the message passing logic no + attempt at all has been made to provide a nice graphical user + interface - this can of course also be done in Erlang - but + that's another tutorial.</p> + </item> + <item> + <p>This sort of problem can be solved more easily if you use + the facilities in OTP, which will also provide methods for + updating code on the fly etc. But again, that's another + tutorial.</p> + </item> + <item> + <p>The first program we write will contain some inadequacies as + regards handling of nodes which disappear, we will correct + these in a later version of the program.</p> + </item> + </list> + <p>We will set up the messenger by allowing "clients" to connect to + a central server and say who and where they are. I.e. a user + won't need to know the name of the Erlang node where another user + is located to send a message.</p> + <p>File <c>messenger.erl</c>:</p> + <marker id="ex"></marker> + <code type="none"> +%%% Message passing utility. +%%% User interface: +%%% logon(Name) +%%% One user at a time can log in from each Erlang node in the +%%% system messenger: and choose a suitable Name. If the Name +%%% is already logged in at another node or if someone else is +%%% already logged in at the same node, login will be rejected +%%% with a suitable error message. +%%% logoff() +%%% Logs off anybody at at node +%%% message(ToName, Message) +%%% sends Message to ToName. Error messages if the user of this +%%% function is not logged on or if ToName is not logged on at +%%% any node. +%%% +%%% One node in the network of Erlang nodes runs a server which maintains +%%% data about the logged on users. The server is registered as "messenger" +%%% Each node where there is a user logged on runs a client process registered +%%% as "mess_client" +%%% +%%% Protocol between the client processes and the server +%%% ---------------------------------------------------- +%%% +%%% To server: {ClientPid, logon, UserName} +%%% Reply {messenger, stop, user_exists_at_other_node} stops the client +%%% Reply {messenger, logged_on} logon was successful +%%% +%%% To server: {ClientPid, logoff} +%%% Reply: {messenger, logged_off} +%%% +%%% To server: {ClientPid, logoff} +%%% Reply: no reply +%%% +%%% To server: {ClientPid, message_to, ToName, Message} send a message +%%% Reply: {messenger, stop, you_are_not_logged_on} stops the client +%%% Reply: {messenger, receiver_not_found} no user with this name logged on +%%% Reply: {messenger, sent} Message has been sent (but no guarantee) +%%% +%%% To client: {message_from, Name, Message}, +%%% +%%% Protocol between the "commands" and the client +%%% ---------------------------------------------- +%%% +%%% Started: messenger:client(Server_Node, Name) +%%% To client: logoff +%%% To client: {message_to, ToName, Message} +%%% +%%% Configuration: change the server_node() function to return the +%%% name of the node where the messenger server runs + +-module(messenger). +-export([start_server/0, server/1, logon/1, logoff/0, message/2, client/2]). + +%%% Change the function below to return the name of the node where the +%%% messenger server runs +server_node() -> + messenger@bill. + +%%% This is the server process for the "messenger" +%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] +server(User_List) -> + receive + {From, logon, Name} -> + New_User_List = server_logon(From, Name, User_List), + server(New_User_List); + {From, logoff} -> + New_User_List = server_logoff(From, User_List), + server(New_User_List); + {From, message_to, To, Message} -> + server_transfer(From, To, Message, User_List), + io:format("list is now: ~p~n", [User_List]), + server(User_List) + end. + +%%% Start the server +start_server() -> + register(messenger, spawn(messenger, server, [[]])). + + +%%% Server adds a new user to the user list +server_logon(From, Name, User_List) -> + %% check if logged on anywhere else + case lists:keymember(Name, 2, User_List) of + true -> + From ! {messenger, stop, user_exists_at_other_node}, %reject logon + User_List; + false -> + From ! {messenger, logged_on}, + [{From, Name} | User_List] %add user to the list + end. + +%%% Server deletes a user from the user list +server_logoff(From, User_List) -> + lists:keydelete(From, 1, User_List). + + +%%% Server transfers a message between user +server_transfer(From, To, Message, User_List) -> + %% check that the user is logged on and who he is + case lists:keysearch(From, 1, User_List) of + false -> + From ! {messenger, stop, you_are_not_logged_on}; + {value, {From, Name}} -> + server_transfer(From, Name, To, Message, User_List) + end. +%%% If the user exists, send the message +server_transfer(From, Name, To, Message, User_List) -> + %% Find the receiver and send the message + case lists:keysearch(To, 2, User_List) of + false -> + From ! {messenger, receiver_not_found}; + {value, {ToPid, To}} -> + ToPid ! {message_from, Name, Message}, + From ! {messenger, sent} + end. + + +%%% User Commands +logon(Name) -> + case whereis(mess_client) of + undefined -> + register(mess_client, + spawn(messenger, client, [server_node(), Name])); + _ -> already_logged_on + end. + +logoff() -> + mess_client ! logoff. + +message(ToName, Message) -> + case whereis(mess_client) of % Test if the client is running + undefined -> + not_logged_on; + _ -> mess_client ! {message_to, ToName, Message}, + ok +end. + + +%%% The client process which runs on each server node +client(Server_Node, Name) -> + {messenger, Server_Node} ! {self(), logon, Name}, + await_result(), + client(Server_Node). + +client(Server_Node) -> + receive + logoff -> + {messenger, Server_Node} ! {self(), logoff}, + exit(normal); + {message_to, ToName, Message} -> + {messenger, Server_Node} ! {self(), message_to, ToName, Message}, + await_result(); + {message_from, FromName, Message} -> + io:format("Message from ~p: ~p~n", [FromName, Message]) + end, + client(Server_Node). + +%%% wait for a response from the server +await_result() -> + receive + {messenger, stop, Why} -> % Stop the client + io:format("~p~n", [Why]), + exit(normal); + {messenger, What} -> % Normal response + io:format("~p~n", [What]) + end.</code> + <p>To use this program you need to:</p> + <list type="bulleted"> + <item>configure the <c>server_node()</c> function</item> + <item>copy the compiled code (<c>messenger.beam</c>) to + the directory on each computer where you start Erlang.</item> + </list> + <p>In the following example of use of this program, I have started + nodes on four different computers, but if you don't have that + many machines available on your network, you could start up + several nodes on the same machine.</p> + <p>We start up four Erlang nodes, messenger@super, c1@bilbo, + c2@kosken, c3@gollum.</p> + <p>First we start up a the server at messenger@super:</p> + <pre> +(messenger@super)1> <input>messenger:start_server().</input> +true</pre> + <p>Now Peter logs on at c1@bilbo:</p> + <pre> +(c1@bilbo)1> <input>messenger:logon(peter).</input> +true +logged_on</pre> + <p>James logs on at c2@kosken:</p> + <pre> +(c2@kosken)1> <input>messenger:logon(james).</input> +true +logged_on</pre> + <p>and Fred logs on at c3@gollum:</p> + <pre> +(c3@gollum)1> <input>messenger:logon(fred).</input> +true +logged_on</pre> + <p>Now Peter sends Fred a message:</p> + <pre> +(c1@bilbo)2> <input>messenger:message(fred, "hello").</input> +ok +sent</pre> + <p>And Fred receives the message and sends a message to Peter and + logs off:</p> + <pre> +Message from peter: "hello" +(c3@gollum)2> <input>messenger:message(peter, "go away, I'm busy").</input> +ok +sent +(c3@gollum)3> <input>messenger:logoff().</input> +logoff</pre> + <p>James now tries to send a message to Fred:</p> + <pre> +(c2@kosken)2> <input>messenger:message(fred, "peter doesn't like you").</input> +ok +receiver_not_found</pre> + <p>But this fails as Fred has already logged off.</p> + <p>First let's look at some of the new concepts we have introduced.</p> + <p>There are two versions of the <c>server_transfer</c> function, + one with four arguments (<c>server_transfer/4</c>) and one with + five (<c>server_transfer/5</c>). These are regarded by Erlang as + two separate functions.</p> + <p>Note how we write the <c>server</c> function so that it calls + itself, <c>server(User_List)</c> and thus creates a loop. + The Erlang compiler is "clever" and optimizes the code so that + this really is a sort of loop and not a proper function call. But + this only works if there is no code after the call, otherwise + the compiler will expect the call to return and make a proper + function call. This would result in the process getting bigger + and bigger for every loop.</p> + <p>We use functions in the <c>lists</c> module. This is a very + useful module and a study of the manual page is recommended + (<c>erl -man lists</c>). + <c>lists:keymember(Key,Position,Lists)</c> looks through a list + of tuples and looks at <c>Position</c> in each tuple to see if it + is the same as <c>Key</c>. The first element is position 1. If it + finds a tuple where the element at <c>Position</c> is the same as + Key, it returns <c>true</c>, otherwise <c>false</c>.</p> + <pre> +3> <input>lists:keymember(a, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input> +true +4> <input>lists:keymember(p, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input> +false</pre> + <p><c>lists:keydelete</c> works in the same way but deletes + the first tuple found (if any) and returns the remaining list:</p> + <pre> +5> <input>lists:keydelete(a, 2, [{x,y,z},{b,b,b},{b,a,c},{q,r,s}]).</input> +[{x,y,z},{b,b,b},{q,r,s}]</pre> + <p><c>lists:keysearch</c> is like <c>lists:keymember</c>, but it + returns <c>{value,Tuple_Found}</c> or the atom <c>false</c>.</p> + <p>There are a lot more very useful functions in the <c>lists</c> + module.</p> + <p>An Erlang process will (conceptually) run until it does a + <c>receive</c> and there is no message which it wants to receive + in the message queue. I say "conceptually" because the Erlang + system shares the CPU time between the active processes in + the system.</p> + <p>A process terminates when there is nothing more for it to do, + i.e. the last function it calls simply returns and doesn't call + another function. Another way for a process to terminate is for + it to call <c>exit/1</c>. The argument to <c>exit/1</c> has a + special meaning which we will look at later. In this example we + will do <c>exit(normal)</c> which has the same effect as a + process running out of functions to call.</p> + <p>The BIF <c>whereis(RegisteredName)</c> checks if a registered + process of name <c>RegisteredName</c> exists and return the pid + of the process if it does exist or the atom <c>undefined</c> if + it does not.</p> + <p>You should by now be able to understand most of the code above + so I'll just go through one case: a message is sent from one user + to another.</p> + <p>The first user "sends" the message in the example above by:</p> + <code type="none"> +messenger:message(fred, "hello")</code> + <p>After testing that the client process exists:</p> + <code type="none"> +whereis(mess_client) </code> + <p>and a message is sent to <c>mess_client</c>:</p> + <code type="none"> +mess_client ! {message_to, fred, "hello"}</code> + <p>The client sends the message to the server by:</p> + <code type="none"> +{messenger, messenger@super} ! {self(), message_to, fred, "hello"},</code> + <p>and waits for a reply from the server.</p> + <p>The server receives this message and calls:</p> + <code type="none"> +server_transfer(From, fred, "hello", User_List),</code> + <p>which checks that the pid <c>From</c> is in the <c>User_List</c>:</p> + <code type="none"> +lists:keysearch(From, 1, User_List) </code> + <p>If <c>keysearch</c> returns the atom <c>false</c>, some sort of + error has occurred and the server sends back the message:</p> + <code type="none"> +From ! {messenger, stop, you_are_not_logged_on}</code> + <p>which is received by the client which in turn does + <c>exit(normal)</c> and terminates. If <c>keysearch</c> returns + <c>{value,{From,Name}}</c> we know that the user is logged on and + is his name (peter) is in variable <c>Name</c>. We now call:</p> + <code type="none"> +server_transfer(From, peter, fred, "hello", User_List)</code> + <p>Note that as this is <c>server_transfer/5</c> it is not the same + as the previous function <c>server_transfer/4</c>. We do another + <c>keysearch</c> on <c>User_List</c> to find the pid of the client + corresponding to fred:</p> + <code type="none"> +lists:keysearch(fred, 2, User_List)</code> + <p>This time we use argument 2 which is the second element in + the tuple. If this returns the atom <c>false</c> we know that + fred is not logged on and we send the message:</p> + <code type="none"> +From ! {messenger, receiver_not_found};</code> + <p>which is received by the client, if <c>keysearch</c> returns:</p> + <code type="none"> +{value, {ToPid, fred}}</code> + <p>we send the message:</p> + <code type="none"> +ToPid ! {message_from, peter, "hello"}, </code> + <p>to fred's client and the message:</p> + <code type="none"> +From ! {messenger, sent} </code> + <p>to peter's client.</p> + <p>Fred's client receives the message and prints it:</p> + <code type="none"> +{message_from, peter, "hello"} -> + io:format("Message from ~p: ~p~n", [peter, "hello"])</code> + <p>and peter's client receives the message in + the <c>await_result</c> function.</p> + </section> +</chapter> + diff --git a/system/doc/getting_started/intro.xml b/system/doc/getting_started/intro.xml new file mode 100644 index 0000000000..7b42080723 --- /dev/null +++ b/system/doc/getting_started/intro.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>intro.xml</file> + </header> + + <section> + <title>Introduction</title> + <p>This is a "kick start" tutorial to get you started with Erlang. + Everything here is true, but only part of the truth. For example, + I'll only tell you the simplest form of the syntax, not all + esoteric forms. Where I've greatly oversimplified things I'll + write *manual* which means there is lots more information to be + found in the Erlang book or in the <em>Erlang Reference Manual</em>.</p> + <p>I also assume that this isn't the first time you have touched a + computer and you have a basic idea about how they are programmed. + Don't worry, I won't assume you're a wizard programmer.</p> + </section> + + <section> + <title>Things Left Out</title> + <p>In particular the following has been omitted:</p> + <list type="bulleted"> + <item>References</item> + <item>Local error handling (catch/throw)</item> + <item>Single direction links (monitor)</item> + <item>Handling of binary data (binaries / bit syntax)</item> + <item>List comprehensions</item> + <item>How to communicate with the outside world and/or software + written in other languages (ports). There is however a separate + tutorial for this, <em>Interoperability Tutorial</em></item> + <item>Very few of the Erlang libraries have been touched on (for + example file handling)</item> + <item>OTP has been totally skipped and in consequence the Mnesia + database has been skipped.</item> + <item>Hash tables for Erlang terms (ETS)</item> + <item>Changing code in running systems</item> + </list> + </section> +</chapter> + diff --git a/system/doc/getting_started/make.dep b/system/doc/getting_started/make.dep new file mode 100644 index 0000000000..69b177f77c --- /dev/null +++ b/system/doc/getting_started/make.dep @@ -0,0 +1,14 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex conc_prog.tex intro.tex part.tex \ + records_macros.tex robustness.tex seq_prog.tex + diff --git a/system/doc/getting_started/part.xml b/system/doc/getting_started/part.xml new file mode 100644 index 0000000000..4c277419a4 --- /dev/null +++ b/system/doc/getting_started/part.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Getting Started With Erlang</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <xi:include href="intro.xml"/> + <xi:include href="seq_prog.xml"/> + <xi:include href="conc_prog.xml"/> + <xi:include href="robustness.xml"/> + <xi:include href="records_macros.xml"/> +</part> + diff --git a/system/doc/getting_started/records_macros.xml b/system/doc/getting_started/records_macros.xml new file mode 100644 index 0000000000..45617f0183 --- /dev/null +++ b/system/doc/getting_started/records_macros.xml @@ -0,0 +1,328 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Records and Macros</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>record_macros.xml</file> + </header> + <p>Larger programs are usually written as a collection of files with + a well defined interface between the various parts.</p> + + <section> + <title>The Larger Example Divided into Several Files</title> + <p>To illustrate this, we will divide the messenger example from + the previous chapter into five files.</p> + <taglist> + <tag><c>mess_config.hrl</c></tag> + <item>header file for configuration data</item> + <tag><c>mess_interface.hrl</c></tag> + <item>interface definitions between the client and the messenger</item> + <tag><c>user_interface.erl</c></tag> + <item>functions for the user interface</item> + <tag><c>mess_client.erl</c></tag> + <item>functions for the client side of the messenger</item> + <tag><c>mess_server.erl</c></tag> + <item>functions for the server side of the messenger</item> + </taglist> + <p>While doing this we will also clean up the message passing + interface between the shell, the client and the server and define + it using <em>records</em>, we will also introduce <em>macros</em>.</p> + <code type="none"> +%%%----FILE mess_config.hrl---- + +%%% Configure the location of the server node, +-define(server_node, messenger@super). + +%%%----END FILE----</code> + <code type="none"> +%%%----FILE mess_interface.hrl---- + +%%% Message interface between client and server and client shell for +%%% messenger program + +%%%Messages from Client to server received in server/1 function. +-record(logon,{client_pid, username}). +-record(message,{client_pid, to_name, message}). +%%% {'EXIT', ClientPid, Reason} (client terminated or unreachable. + +%%% Messages from Server to Client, received in await_result/0 function +-record(abort_client,{message}). +%%% Messages are: user_exists_at_other_node, +%%% you_are_not_logged_on +-record(server_reply,{message}). +%%% Messages are: logged_on +%%% receiver_not_found +%%% sent (Message has been sent (no guarantee) +%%% Messages from Server to Client received in client/1 function +-record(message_from,{from_name, message}). + +%%% Messages from shell to Client received in client/1 function +%%% spawn(mess_client, client, [server_node(), Name]) +-record(message_to,{to_name, message}). +%%% logoff + +%%%----END FILE----</code> + <code type="none"> +%%%----FILE user_interface.erl---- + +%%% User interface to the messenger program +%%% login(Name) +%%% One user at a time can log in from each Erlang node in the +%%% system messenger: and choose a suitable Name. If the Name +%%% is already logged in at another node or if someone else is +%%% already logged in at the same node, login will be rejected +%%% with a suitable error message. + +%%% logoff() +%%% Logs off anybody at at node + +%%% message(ToName, Message) +%%% sends Message to ToName. Error messages if the user of this +%%% function is not logged on or if ToName is not logged on at +%%% any node. + +-module(user_interface). +-export([logon/1, logoff/0, message/2]). +-include("mess_interface.hrl"). +-include("mess_config.hrl"). + +logon(Name) -> + case whereis(mess_client) of + undefined -> + register(mess_client, + spawn(mess_client, client, [?server_node, Name])); + _ -> already_logged_on + end. + +logoff() -> + mess_client ! logoff. + +message(ToName, Message) -> + case whereis(mess_client) of % Test if the client is running + undefined -> + not_logged_on; + _ -> mess_client ! #message_to{to_name=ToName, message=Message}, + ok +end. + +%%%----END FILE----</code> + <code type="none"> +%%%----FILE mess_client.erl---- + +%%% The client process which runs on each user node + +-module(mess_client). +-export([client/2]). +-include("mess_interface.hrl"). + +client(Server_Node, Name) -> + {messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, + await_result(), + client(Server_Node). + +client(Server_Node) -> + receive + logoff -> + exit(normal); + #message_to{to_name=ToName, message=Message} -> + {messenger, Server_Node} ! + #message{client_pid=self(), to_name=ToName, message=Message}, + await_result(); + {message_from, FromName, Message} -> + io:format("Message from ~p: ~p~n", [FromName, Message]) + end, + client(Server_Node). + +%%% wait for a response from the server +await_result() -> + receive + #abort_client{message=Why} -> + io:format("~p~n", [Why]), + exit(normal); + #server_reply{message=What} -> + io:format("~p~n", [What]) + after 5000 -> + io:format("No response from server~n", []), + exit(timeout) + end. + +%%%----END FILE---</code> + <code type="none"> +%%%----FILE mess_server.erl---- + +%%% This is the server process of the messenger service + +-module(mess_server). +-export([start_server/0, server/0]). +-include("mess_interface.hrl"). + +server() -> + process_flag(trap_exit, true), + server([]). + +%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] +server(User_List) -> + io:format("User list = ~p~n", [User_List]), + receive + #logon{client_pid=From, username=Name} -> + New_User_List = server_logon(From, Name, User_List), + server(New_User_List); + {'EXIT', From, _} -> + New_User_List = server_logoff(From, User_List), + server(New_User_List); + #message{client_pid=From, to_name=To, message=Message} -> + server_transfer(From, To, Message, User_List), + server(User_List) + end. + +%%% Start the server +start_server() -> + register(messenger, spawn(?MODULE, server, [])). + +%%% Server adds a new user to the user list +server_logon(From, Name, User_List) -> + %% check if logged on anywhere else + case lists:keymember(Name, 2, User_List) of + true -> + From ! #abort_client{message=user_exists_at_other_node}, + User_List; + false -> + From ! #server_reply{message=logged_on}, + link(From), + [{From, Name} | User_List] %add user to the list + end. + +%%% Server deletes a user from the user list +server_logoff(From, User_List) -> + lists:keydelete(From, 1, User_List). + +%%% Server transfers a message between user +server_transfer(From, To, Message, User_List) -> + %% check that the user is logged on and who he is + case lists:keysearch(From, 1, User_List) of + false -> + From ! #abort_client{message=you_are_not_logged_on}; + {value, {_, Name}} -> + server_transfer(From, Name, To, Message, User_List) + end. +%%% If the user exists, send the message +server_transfer(From, Name, To, Message, User_List) -> + %% Find the receiver and send the message + case lists:keysearch(To, 2, User_List) of + false -> + From ! #server_reply{message=receiver_not_found}; + {value, {ToPid, To}} -> + ToPid ! #message_from{from_name=Name, message=Message}, + From ! #server_reply{message=sent} + end. + +%%%----END FILE---</code> + </section> + + <section> + <title>Header Files</title> + <p>You will see some files above with extension <c>.hrl</c>. These + are header files which are included in the <c>.erl</c> files by:</p> + <code type="none"> +-include("File_Name").</code> + <p>for example:</p> + <code type="none"> +-include("mess_interface.hrl").</code> + <p>In our case above the file is fetched from the same directory as + all the other files in the messenger example. (*manual*).</p> + <p>.hrl files can contain any valid Erlang code but are most often + used for record and macro definitions.</p> + </section> + + <section> + <title>Records</title> + <p>A record is defined as:</p> + <code type="none"> +-record(name_of_record,{field_name1, field_name2, field_name3, ......}).</code> + <p>For example:</p> + <code type="none"> +-record(message_to,{to_name, message}).</code> + <p>This is exactly equivalent to:</p> + <code type="none"> +{message_to, To_Name, Message}</code> + <p>Creating record, is best illustrated by an example:</p> + <code type="none"> +#message_to{message="hello", to_name=fred)</code> + <p>This will create:</p> + <code type="none"> +{message_to, fred, "hello"}</code> + <p>Note that you don't have to worry about the order you assign + values to the various parts of the records when you create it. + The advantage of using records is that by placing their + definitions in header files you can conveniently define + interfaces which are easy to change. For example, if you want to + add a new field to the record, you will only have to change + the code where the new field is used and not at every place + the record is referred to. If you leave out a field when creating + a record, it will get the value of the atom undefined. (*manual*)</p> + <p>Pattern matching with records is very similar to creating + records. For example inside a <c>case</c> or <c>receive</c>:</p> + <code type="none"> +#message_to{to_name=ToName, message=Message} -></code> + <p>is the same as:</p> + <code type="none"> +{message_to, ToName, Message}</code> + </section> + + <section> + <title>Macros</title> + <p>The other thing we have added to the messenger is a macro. + The file <c>mess_config.hrl</c> contains the definition:</p> + <code type="none"> +%%% Configure the location of the server node, +-define(server_node, messenger@super).</code> + <p>We include this file in mess_server.erl:</p> + <code type="none"> +-include("mess_config.hrl").</code> + <p>Every occurrence of <c>?server_node</c> in <c>mess_server.erl</c> + will now be replaced by <c>messenger@super</c>.</p> + <p>The other place a macro is used is when we spawn the server + process:</p> + <code type="none"> +spawn(?MODULE, server, [])</code> + <p>This is a standard macro (i.e. defined by the system, not + the user). <c>?MODULE</c> is always replaced by the name of + current module (i.e. the <c>-module</c> definition near the start + of the file). There are more advanced ways of using macros with, + for example parameters (*manual*).</p> + <p>The three Erlang (<c>.erl</c>) files in the messenger example are + individually compiled into object code file (<c>.beam</c>). + The Erlang system loads and links these files into the system + when they are referred to during execution of the code. In our + case we simply have put them in the same directory which is our + current working directory (i.e. the place we have done "cd" to). + There are ways of putting the <c>.beam</c> files in other + directories.</p> + <p>In the messenger example, no assumptions have been made about + what the message being sent is. It could be any valid Erlang term.</p> + </section> +</chapter> + diff --git a/system/doc/getting_started/robustness.xml b/system/doc/getting_started/robustness.xml new file mode 100644 index 0000000000..227da4c027 --- /dev/null +++ b/system/doc/getting_started/robustness.xml @@ -0,0 +1,483 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Robustness</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>robustness.xml</file> + </header> + <p>There are several things which are wrong with + the <seealso marker="conc_prog#ex">messenger example</seealso> from + the previous chapter. For example if a node where a user is logged + on goes down without doing a log off, the user will remain in + the server's <c>User_List</c> but the client will disappear thus + making it impossible for the user to log on again as the server + thinks the user already logged on.</p> + <p>Or what happens if the server goes down in the middle of sending a + message leaving the sending client hanging for ever in + the <c>await_result</c> function?</p> + + <section> + <title>Timeouts</title> + <p>Before improving the messenger program we will look into some + general principles, using the ping pong program as an example. + Recall that when "ping" finishes, it tells "pong" that it has + done so by sending the atom <c>finished</c> as a message to "pong" + so that "pong" could also finish. Another way to let "pong" + finish, is to make "pong" exit if it does not receive a message + from ping within a certain time, this can be done by adding a + <em>timeout</em> to <c>pong</c> as shown in the following example:</p> + <code type="none"> +-module(tut19). + +-export([start_ping/1, start_pong/0, ping/2, pong/0]). + +ping(0, Pong_Node) -> + io:format("ping finished~n", []); + +ping(N, Pong_Node) -> + {pong, Pong_Node} ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping(N - 1, Pong_Node). + +pong() -> + receive + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + after 5000 -> + io:format("Pong timed out~n", []) + end. + +start_pong() -> + register(pong, spawn(tut19, pong, [])). + +start_ping(Pong_Node) -> + spawn(tut19, ping, [3, Pong_Node]).</code> + <p>After we have compiled this and copied the <c>tut19.beam</c> + file to the necessary directories:</p> + <p>On (pong@kosken):</p> + <pre> +(pong@kosken)1> <input>tut19:start_pong().</input> +true +Pong received ping +Pong received ping +Pong received ping +Pong timed out</pre> + <p>On (ping@gollum):</p> + <pre> +(ping@gollum)1> <input>tut19:start_ping(pong@kosken).</input> +<0.36.0> +Ping received pong +Ping received pong +Ping received pong +ping finished </pre> + <p>(The timeout is set in:</p> + <code type="none"> +pong() -> + receive + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + after 5000 -> + io:format("Pong timed out~n", []) + end.</code> + <p>We start the timeout (<c>after 5000</c>) when we enter + <c>receive</c>. The timeout is canceled if <c>{ping,Ping_PID}</c> + is received. If <c>{ping,Ping_PID}</c> is not received, + the actions following the timeout will be done after 5000 + milliseconds. <c>after</c> must be last in the <c>receive</c>, + i.e. preceded by all other message reception specifications in + the <c>receive</c>. Of course we could also call a function which + returned an integer for the timeout:</p> + <code type="none"> +after pong_timeout() -></code> + <p>In general, there are better ways than using timeouts to + supervise parts of a distributed Erlang system. Timeouts are + usually appropriate to supervise external events, for example if + you have expected a message from some external system within a + specified time. For example, we could use a timeout to log a user + out of the messenger system if they have not accessed it, for + example, in ten minutes.</p> + </section> + + <section> + <title>Error Handling</title> + <p>Before we go into details of the supervision and error handling + in an Erlang system, we need see how Erlang processes terminate, + or in Erlang terminology, <em>exit</em>.</p> + <p>A process which executes <c>exit(normal)</c> or simply runs out + of things to do has a <em>normal</em> exit.</p> + <p>A process which encounters a runtime error (e.g. divide by zero, + bad match, trying to call a function which doesn't exist etc) + exits with an error, i.e. has an <em>abnormal</em> exit. A + process which executes + <seealso marker="erts:erlang#exit/1">exit(Reason)</seealso> + where <c>Reason</c> is any Erlang term except the atom + <c>normal</c>, also has an abnormal exit.</p> + <p>An Erlang process can set up links to other Erlang processes. If + a process calls + <seealso marker="erts:erlang#link/1">link(Other_Pid)</seealso> + it sets up a bidirectional link between itself and the process + called <c>Other_Pid</c>. When a process terminates its sends + something called a <em>signal</em> to all the processes it has + links to.</p> + <p>The signal carries information about the pid it was sent from and + the exit reason.</p> + <p>The default behaviour of a process which receives a normal exit + is to ignore the signal.</p> + <p>The default behaviour in the two other cases (i.e. abnormal exit) + above is to bypass all messages to the receiving process and to + kill it and to propagate the same error signal to the killed + process' links. In this way you can connect all processes in a + transaction together using links and if one of the processes + exits abnormally, all the processes in the transaction will be + killed. As we often want to create a process and link to it at + the same time, there is a special BIF, + <seealso marker="erts:erlang#spawn_link/1">spawn_link</seealso> + which does the same as <c>spawn</c>, but also creates a link to + the spawned process.</p> + <p>Now an example of the ping pong example using links to terminate + "pong":</p> + <code type="none"> +-module(tut20). + +-export([start/1, ping/2, pong/0]). + +ping(N, Pong_Pid) -> + link(Pong_Pid), + ping1(N, Pong_Pid). + +ping1(0, _) -> + exit(ping); + +ping1(N, Pong_Pid) -> + Pong_Pid ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping1(N - 1, Pong_Pid). + +pong() -> + receive + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong() + end. + +start(Ping_Node) -> + PongPID = spawn(tut20, pong, []), + spawn(Ping_Node, tut20, ping, [3, PongPID]).</code> + <pre> +(s1@bill)3> <input>tut20:start(s2@kosken).</input> +Pong received ping +<3820.41.0> +Ping received pong +Pong received ping +Ping received pong +Pong received ping +Ping received pong</pre> + <p>This is a slight modification of the ping pong program where both + processes are spawned from the same <c>start/1</c> function, + where the "ping" process can be spawned on a separate node. Note + the use of the <c>link</c> BIF. "Ping" calls + <c>exit(ping)</c> when it finishes and this will cause an exit + signal to be sent to "pong" which will also terminate.</p> + <p>It is possible to modify the default behaviour of a process so + that it does not get killed when it receives abnormal exit + signals, but all signals will be turned into normal messages on + the format <c>{'EXIT',FromPID,Reason}</c> and added to the end of + the receiving processes message queue. This behaviour is set by:</p> + <code type="none"> +process_flag(trap_exit, true)</code> + <p>There are several other process flags, see + <seealso marker="erts:erlang#process_flag/2">erlang(3)</seealso>. + Changing the default behaviour of a process in this way is + usually not done in standard user programs, but is left to + the supervisory programs in OTP (but that's another tutorial). + However we will modify the ping pong program to illustrate exit + trapping.</p> + <code type="none"> +-module(tut21). + +-export([start/1, ping/2, pong/0]). + +ping(N, Pong_Pid) -> + link(Pong_Pid), + ping1(N, Pong_Pid). + +ping1(0, _) -> + exit(ping); + +ping1(N, Pong_Pid) -> + Pong_Pid ! {ping, self()}, + receive + pong -> + io:format("Ping received pong~n", []) + end, + ping1(N - 1, Pong_Pid). + +pong() -> + process_flag(trap_exit, true), + pong1(). + +pong1() -> + receive + {ping, Ping_PID} -> + io:format("Pong received ping~n", []), + Ping_PID ! pong, + pong1(); + {'EXIT', From, Reason} -> + io:format("pong exiting, got ~p~n", [{'EXIT', From, Reason}]) + end. + +start(Ping_Node) -> + PongPID = spawn(tut21, pong, []), + spawn(Ping_Node, tut21, ping, [3, PongPID]).</code> + <pre> +(s1@bill)1> <input>tut21:start(s2@gollum).</input> +<3820.39.0> +Pong received ping +Ping received pong +Pong received ping +Ping received pong +Pong received ping +Ping received pong +pong exiting, got {'EXIT',<3820.39.0>,ping}</pre> + </section> + + <section> + <title>The Larger Example with Robustness Added</title> + <p>Now we return to the messenger program and add changes which + make it more robust:</p> + <code type="none"> +%%% Message passing utility. +%%% User interface: +%%% login(Name) +%%% One user at a time can log in from each Erlang node in the +%%% system messenger: and choose a suitable Name. If the Name +%%% is already logged in at another node or if someone else is +%%% already logged in at the same node, login will be rejected +%%% with a suitable error message. +%%% logoff() +%%% Logs off anybody at at node +%%% message(ToName, Message) +%%% sends Message to ToName. Error messages if the user of this +%%% function is not logged on or if ToName is not logged on at +%%% any node. +%%% +%%% One node in the network of Erlang nodes runs a server which maintains +%%% data about the logged on users. The server is registered as "messenger" +%%% Each node where there is a user logged on runs a client process registered +%%% as "mess_client" +%%% +%%% Protocol between the client processes and the server +%%% ---------------------------------------------------- +%%% +%%% To server: {ClientPid, logon, UserName} +%%% Reply {messenger, stop, user_exists_at_other_node} stops the client +%%% Reply {messenger, logged_on} logon was successful +%%% +%%% When the client terminates for some reason +%%% To server: {'EXIT', ClientPid, Reason} +%%% +%%% To server: {ClientPid, message_to, ToName, Message} send a message +%%% Reply: {messenger, stop, you_are_not_logged_on} stops the client +%%% Reply: {messenger, receiver_not_found} no user with this name logged on +%%% Reply: {messenger, sent} Message has been sent (but no guarantee) +%%% +%%% To client: {message_from, Name, Message}, +%%% +%%% Protocol between the "commands" and the client +%%% ---------------------------------------------- +%%% +%%% Started: messenger:client(Server_Node, Name) +%%% To client: logoff +%%% To client: {message_to, ToName, Message} +%%% +%%% Configuration: change the server_node() function to return the +%%% name of the node where the messenger server runs + +-module(messenger). +-export([start_server/0, server/0, + logon/1, logoff/0, message/2, client/2]). + +%%% Change the function below to return the name of the node where the +%%% messenger server runs +server_node() -> + messenger@super. + +%%% This is the server process for the "messenger" +%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] +server() -> + process_flag(trap_exit, true), + server([]). + +server(User_List) -> + receive + {From, logon, Name} -> + New_User_List = server_logon(From, Name, User_List), + server(New_User_List); + {'EXIT', From, _} -> + New_User_List = server_logoff(From, User_List), + server(New_User_List); + {From, message_to, To, Message} -> + server_transfer(From, To, Message, User_List), + io:format("list is now: ~p~n", [User_List]), + server(User_List) + end. + +%%% Start the server +start_server() -> + register(messenger, spawn(messenger, server, [])). + +%%% Server adds a new user to the user list +server_logon(From, Name, User_List) -> + %% check if logged on anywhere else + case lists:keymember(Name, 2, User_List) of + true -> + From ! {messenger, stop, user_exists_at_other_node}, %reject logon + User_List; + false -> + From ! {messenger, logged_on}, + link(From), + [{From, Name} | User_List] %add user to the list + end. + +%%% Server deletes a user from the user list +server_logoff(From, User_List) -> + lists:keydelete(From, 1, User_List). + + +%%% Server transfers a message between user +server_transfer(From, To, Message, User_List) -> + %% check that the user is logged on and who he is + case lists:keysearch(From, 1, User_List) of + false -> + From ! {messenger, stop, you_are_not_logged_on}; + {value, {_, Name}} -> + server_transfer(From, Name, To, Message, User_List) + end. + +%%% If the user exists, send the message +server_transfer(From, Name, To, Message, User_List) -> + %% Find the receiver and send the message + case lists:keysearch(To, 2, User_List) of + false -> + From ! {messenger, receiver_not_found}; + {value, {ToPid, To}} -> + ToPid ! {message_from, Name, Message}, + From ! {messenger, sent} + end. + +%%% User Commands +logon(Name) -> + case whereis(mess_client) of + undefined -> + register(mess_client, + spawn(messenger, client, [server_node(), Name])); + _ -> already_logged_on + end. + +logoff() -> + mess_client ! logoff. + +message(ToName, Message) -> + case whereis(mess_client) of % Test if the client is running + undefined -> + not_logged_on; + _ -> mess_client ! {message_to, ToName, Message}, + ok +end. + +%%% The client process which runs on each user node +client(Server_Node, Name) -> + {messenger, Server_Node} ! {self(), logon, Name}, + await_result(), + client(Server_Node). + +client(Server_Node) -> + receive + logoff -> + exit(normal); + {message_to, ToName, Message} -> + {messenger, Server_Node} ! {self(), message_to, ToName, Message}, + await_result(); + {message_from, FromName, Message} -> + io:format("Message from ~p: ~p~n", [FromName, Message]) + end, + client(Server_Node). + +%%% wait for a response from the server +await_result() -> + receive + {messenger, stop, Why} -> % Stop the client + io:format("~p~n", [Why]), + exit(normal); + {messenger, What} -> % Normal response + io:format("~p~n", [What]) + after 5000 -> + io:format("No response from server~n", []), + exit(timeout) + end.</code> + <p>We have added the following changes:</p> + <p>The messenger server traps exits. If it receives an exit signal, + <c>{'EXIT',From,Reason}</c> this means that a client process has + terminated or is unreachable because:</p> + <list type="bulleted"> + <item>the user has logged off (we have removed the "logoff" + message),</item> + <item>the network connection to the client is broken,</item> + <item>the node on which the client process resides has gone down, + or</item> + <item>the client processes has done some illegal operation.</item> + </list> + <p>If we receive an exit signal as above, we delete the tuple, + <c>{From,Name}</c> from the servers <c>User_List</c> using + the <c>server_logoff</c> function. If the node on which the server + runs goes down, an exit signal (automatically generated by + the system), will be sent to all of the client processes: + <c>{'EXIT',MessengerPID,noconnection}</c> causing all the client + processes to terminate.</p> + <p>We have also introduced a timeout of five seconds in + the <c>await_result</c> function. I.e. if the server does not + reply within five seconds (5000 ms), the client terminates. This + is really only needed in the logon sequence before the client and + server are linked.</p> + <p>An interesting case is if the client was to terminate before + the server links to it. This is taken care of because linking to a + non-existent process causes an exit signal, + <c>{'EXIT',From,noproc}</c>, to be automatically generated as if + the process terminated immediately after the link operation.</p> + </section> +</chapter> + diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml new file mode 100644 index 0000000000..bc1758d855 --- /dev/null +++ b/system/doc/getting_started/seq_prog.xml @@ -0,0 +1,1231 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Sequential Programming</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>seq_prog.xml</file> + </header> + + <section> + <title>The Erlang Shell</title> + <p>Most operating systems have a command interpreter or shell, Unix + and Linux have many, Windows has the Command Prompt. Erlang has + its own shell where you can directly write bits of Erlang code + and evaluate (run) them to see what happens (see + <seealso marker="stdlib:shell">shell(3)</seealso>). Start + the Erlang shell (in Linux or UNIX) by starting a shell or + command interpreter in your operating system and typing + <c>erl</c>, you will see something like this.</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2 [source] [hipe] + +Eshell V5.2 (abort with ^G) +1></pre> + <p>Now type in "2 + 5." as shown below.</p> + <pre> +1> <input>2 + 5.</input> +7 +2></pre> + <p>In Windows, the shell is started by double-clicking on the Erlang + shell icon.</p> + <p>You'll notice that the Erlang shell has numbered the lines that + can be entered, (as 1> 2>) and that it has correctly told you + that 2 + 5 is 7! Also notice that you have to tell it you are + done entering code by finishing with a full stop "." and a + carriage return. If you make mistakes writing things in the shell, + you can delete things by using the backspace key as in most + shells. There are many more editing commands in the shell + (See the chapter <seealso marker="erts:tty">"tty - A command line interface"</seealso> in ERTS User's Guide).</p> + <p>(Note: you will find a lot of line numbers given by the shell + out of sequence in this tutorial as it was written and the code + tested in several sessions).</p> + <p>Now let's try a more complex calculation.</p> + <pre> +2> <input>(42 + 77) * 66 / 3.</input> +2618.0</pre> + <p>Here you can see the use of brackets and the multiplication + operator "*" and division operator "/", just as in normal + arithmetic (see the chapter + <seealso marker="doc/reference_manual:expressions">"Arithmetic Expressions"</seealso> in the Erlang Reference Manual).</p> + <p>To shutdown the Erlang system and the Erlang shell type + Control-C. You will see the following output:</p> + <pre> +BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded + (v)ersion (k)ill (D)b-tables (d)istribution +<input>a</input> +%</pre> + <p>Type "a" to leave the Erlang system.</p> + <p>Another way to shutdown the Erlang system is by entering + <c>halt()</c>:</p> + <pre> +3> <input>halt().</input> +% </pre> + </section> + + <section> + <title>Modules and Functions</title> + <p>A programming language isn't much use if you can just run code + from the shell. So here is a small Erlang program. Enter it into + a file called <c>tut.erl</c> (the file name <c>tut.erl</c> is + important, also make sure that it is in the same directory as + the one where you started <c>erl</c>) using a suitable + text editor. If you are lucky your editor will have an Erlang + mode which will make it easier for you to enter and format your + code nicely (see the chapter + <seealso marker="tools:erlang_mode_chapter">"The Erlang mode for Emacs"</seealso> in Tools User's Guide), but you can manage + perfectly well without. Here's the code to enter:</p> + <code type="none"> +-module(tut). +-export([double/1]). + +double(X) -> + 2 * X.</code> + <p>It's not hard to guess that this "program" doubles the value of + numbers. I'll get back to the first two lines later. Let's compile + the program. This can be done in your Erlang shell as shown below:</p> + <pre> +3> <input>c(tut).</input> +{ok,tut}</pre> + <p>The <c>{ok,tut}</c> tells you that the compilation was OK. If it + said "error" instead, you have made some mistake in the text you + entered and there will also be error messages to give you some + idea as to what has gone wrong so you can change what you have + written and try again.</p> + <p>Now lets run the program.</p> + <pre> +4> <input>tut:double(10).</input> +20</pre> + <p>As expected double of 10 is 20.</p> + <p>Now let's get back to the first two lines. Erlang programs are + written in files. Each file contains what we call an Erlang + <em>module</em>. The first line of code in the module tells us + the name of the module (see the chapter + <seealso marker="doc/reference_manual:modules">"Modules"</seealso> + in the Erlang Reference Manual).</p> + <code type="none"> +-module(tut).</code> + <p>This tells us that the module is called <em>tut</em>. Note + the "." at the end of the line. The files which are used to store + the module must have the same name as the module but with + the extension ".erl". In our case the file name is <c>tut.erl</c>. + When we use a function in another module, we use the syntax, + <c>module_name:function_name(arguments)</c>. So</p> + <pre> +4> <input>tut:double(10).</input></pre> + <p>means call function <c>double</c> in module <c>tut</c> with + argument "10".</p> + <p>The second line:</p> + <code type="none"> +-export([double/1]).</code> + <p>says that the module <c>tut</c> contains a function called + <c>double</c> which takes one argument (<c>X</c> in our example) + and that this function can be called from outside the module + <c>tut</c>. More about this later. Again note the "." at the end + of the line.</p> + <p>Now for a more complicated example, the factorial of a number + (e.g. factorial of 4 is 4 * 3 * 2 * 1). Enter the following code + in a file called <c>tut1.erl</c>.</p> + <code type="none"> +-module(tut1). +-export([fac/1]). + +fac(1) -> + 1; +fac(N) -> + N * fac(N - 1).</code> + <p>Compile the file</p> + <pre> +5> <input>c(tut1).</input> +{ok,tut1}</pre> + <p>And now calculate the factorial of 4.</p> + <pre> +6> <input>tut1:fac(4).</input> +24</pre> + <p>The first part:</p> + <code type="none"> +fac(1) -> + 1;</code> + <p>says that the factorial of 1 is 1. Note that we end this part + with a ";" which indicates that there is more of this function to + come. The second part:</p> + <code type="none"> +fac(N) -> + N * fac(N - 1).</code> + <p>says that the factorial of N is N multiplied by the factorial of + N - 1. Note that this part ends with a "." saying that there are + no more parts of this function.</p> + <p>A function can have many arguments. Let's expand the module + <c>tut1</c> with the rather stupid function to multiply two + numbers:</p> + <code type="none"> +-module(tut1). +-export([fac/1, mult/2]). + +fac(1) -> + 1; +fac(N) -> + N * fac(N - 1). + +mult(X, Y) -> + X * Y.</code> + <p>Note that we have also had to expand the <c>-export</c> line + with the information that there is another function <c>mult</c> + with two arguments.</p> + <p>Compile:</p> + <pre> +7> <input>c(tut1).</input> +{ok,tut1}</pre> + <p>and try it out:</p> + <pre> +8> <input>tut1:mult(3,4).</input> +12</pre> + <p>In the example above the numbers are integers and the arguments + in the functions in the code, <c>N</c>, <c>X</c>, <c>Y</c> are + called variables. Variables must start with a capital letter + (see the chapter + <seealso marker="doc/reference_manual:expressions">"Variables"</seealso> + in the Erlang Reference Manual). Examples of variable could be + <c>Number</c>, <c>ShoeSize</c>, <c>Age</c> etc.</p> + </section> + + <section> + <title>Atoms</title> + <p>Atoms are another data type in Erlang. Atoms start with a small + letter ((see the chapter + <seealso marker="doc/reference_manual:data_types">"Atom"</seealso> + in the Erlang Reference Manual)), for example: <c>charles</c>, + <c>centimeter</c>, <c>inch</c>. Atoms are simply names, nothing + else. They are not like variables which can have a value.</p> + <p>Enter the next program (file: <c>tut2.erl</c>) which could be + useful for converting from inches to centimeters and vice versa:</p> + <code type="none"> +-module(tut2). +-export([convert/2]). + +convert(M, inch) -> + M / 2.54; + +convert(N, centimeter) -> + N * 2.54.</code> + <p>Compile and test:</p> + <pre> +9> <input>c(tut2).</input> +{ok,tut2} +10> <input>tut2:convert(3, inch).</input> +1.1811023622047243 +11> <input>tut2:convert(7, centimeter).</input> +17.78</pre> + <p>Notice that I have introduced decimals (floating point numbers) + without any explanation, but I guess you can cope with that.</p> + <p>See what happens if I enter something other than centimeter or + inch in the convert function:</p> + <pre> +12> <input>tut2:convert(3, miles).</input> +** exception error: no function clause matching tut2:convert(3,miles)</pre> + <p>The two parts of the <c>convert</c> function are called its + clauses. Here we see that "miles" is not part of either of + the clauses. The Erlang system can't <em>match</em> either of + the clauses so we get an error message <c>function_clause</c>. + The shell formats the error message nicely, but the error tuple + is saved in the shell's history list and can be output by the shell + command <c>v/1</c>:</p> + <pre> +13> <input>v(12).</input> +{'EXIT',{function_clause,[{tut2,convert,[3,miles]}, + {erl_eval,do_apply,5}, + {shell,exprs,6}, + {shell,eval_exprs,6}, + {shell,eval_loop,3}]}}</pre> + + </section> + + <section> + <title>Tuples</title> + <p>Now the <c>tut2</c> program is hardly good programming style. + Consider:</p> + <code type="none"> +tut2:convert(3, inch).</code> + <p>Does this mean that 3 is in inches? or that 3 is in centimeters + and we want to convert it to inches? So Erlang has a way to group + things together to make things more understandable. We call these + <em>tuples</em>. Tuples are surrounded by "{" and "}".</p> + <p>So we can write <c>{inch,3}</c> to denote 3 inches and + <c>{centimeter,5}</c> to denote 5 centimeters. Now let's write a + new program which converts centimeters to inches and vice versa. + (file <c>tut3.erl</c>).</p> + <code type="none"> +-module(tut3). +-export([convert_length/1]). + +convert_length({centimeter, X}) -> + {inch, X / 2.54}; +convert_length({inch, Y}) -> + {centimeter, Y * 2.54}.</code> + <p>Compile and test:</p> + <pre> +14> <input>c(tut3).</input> +{ok,tut3} +15> <input>tut3:convert_length({inch, 5}).</input> +{centimeter,12.7} +16> <input>tut3:convert_length(tut3:convert_length({inch, 5})).</input> +{inch,5.0}</pre> + <p>Note on line 16 we convert 5 inches to centimeters and back + again and reassuringly get back to the original value. I.e + the argument to a function can be the result of another function. + Pause for a moment and consider how line 16 (above) works. + The argument we have given the function <c>{inch,5}</c> is first + matched against the first head clause of <c>convert_length</c> + i.e. <c>convert_length({centimeter,X})</c> where it can be seen + that <c>{centimeter,X}</c> does not match <c>{inch,5}</c> + (the head is the bit before the "->"). This having failed, we try + the head of the next clause i.e. <c>convert_length({inch,Y})</c>, + this matches and <c>Y</c> get the value 5.</p> + <p>We have shown tuples with two parts above, but tuples can have + as many parts as we want and contain any valid Erlang + <em>term</em>. For example, to represent the temperature of + various cities of the world we could write</p> + <code type="none"> +{moscow, {c, -10}} +{cape_town, {f, 70}} +{paris, {f, 28}}</code> + <p>Tuples have a fixed number of things in them. We call each thing + in a tuple an element. So in the tuple <c>{moscow,{c,-10}}</c>, + element 1 is <c>moscow</c> and element 2 is <c>{c,-10}</c>. I + have chosen <c>c</c> meaning Centigrade (or Celsius) and <c>f</c> + meaning Fahrenheit.</p> + </section> + + <section> + <title>Lists</title> + <p>Whereas tuples group things together, we also want to be able to + represent lists of things. Lists in Erlang are surrounded by "[" + and "]". For example a list of the temperatures of various cities + in the world could be:</p> + <code type="none"> +[{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}}, + {paris, {f, 28}}, {london, {f, 36}}]</code> + <p>Note that this list was so long that it didn't fit on one line. + This doesn't matter, Erlang allows line breaks at all "sensible + places" but not, for example, in the middle of atoms, integers + etc.</p> + <p>A very useful way of looking at parts of lists, is by using "|". + This is best explained by an example using the shell.</p> + <pre> +17> <input>[First |TheRest] = [1,2,3,4,5].</input> +[1,2,3,4,5] +18> <input>First.</input> +1 +19> <input>TheRest.</input> +[2,3,4,5]</pre> + <p>We use | to separate the first elements of the list from + the rest of the list. (<c>First</c> has got value 1 and + <c>TheRest</c> value [2,3,4,5]).</p> + <p>Another example:</p> + <pre> +20> <input>[E1, E2 | R] = [1,2,3,4,5,6,7].</input> +[1,2,3,4,5,6,7] +21> <input>E1.</input> +1 +22> <input>E2.</input> +2 +23> <input>R.</input> +[3,4,5,6,7]</pre> + <p>Here we see the use of | to get the first two elements from + the list. Of course if we try to get more elements from the list + than there are elements in the list we will get an error. Note + also the special case of the list with no elements [].</p> + <pre> +24> <input>[A, B | C] = [1, 2].</input> +[1,2] +25> <input>A.</input> +1 +26> <input>B.</input> +2 +27> <input>C.</input> +[]</pre> + <p>In all the examples above, I have been using new variable names, + not reusing the old ones: <c>First</c>, <c>TheRest</c>, <c>E1</c>, + <c>E2</c>, <c>R</c>, <c>A</c>, <c>B</c>, <c>C</c>. The reason + for this is that a variable can only be given a value once in its + context (scope). I'll get back to this later, it isn't so + peculiar as it sounds!</p> + <p>The following example shows how we find the length of a list:</p> + <code type="none"> +-module(tut4). + +-export([list_length/1]). + +list_length([]) -> + 0; +list_length([First | Rest]) -> + 1 + list_length(Rest).</code> + <p>Compile (file <c>tut4.erl</c>) and test:</p> + <pre> +28> <input>c(tut4).</input> +{ok,tut4} +29> <input>tut4:list_length([1,2,3,4,5,6,7]).</input> +7</pre> + <p>Explanation:</p> + <code type="none"> +list_length([]) -> + 0;</code> + <p>The length of an empty list is obviously 0.</p> + <code type="none"> +list_length([First | Rest]) -> + 1 + list_length(Rest).</code> + <p>The length of a list with the first element <c>First</c> and + the remaining elements <c>Rest</c> is 1 + the length of + <c>Rest</c>.</p> + <p>(Advanced readers only: This is not tail recursive, there is a + better way to write this function).</p> + <p>In general we can say we use tuples where we would use "records" + or "structs" in other languages and we use lists when we want to + represent things which have varying sizes, (i.e. where we would + use linked lists in other languages).</p> + <p>Erlang does not have a string date type, instead strings can be + represented by lists of ASCII characters. So the list + <c>[97,98,99]</c> is equivalent to "abc". The Erlang shell is + "clever" and guesses the what sort of list we mean and outputs it + in what it thinks is the most appropriate form, for example:</p> + <pre> +30> <input>[97,98,99].</input> +"abc"</pre> + </section> + + <section> + <title>Standard Modules and Manual Pages</title> + <p>Erlang has a lot of standard modules to help you do things. For + example, the module <c>io</c> contains a lot of functions to help + you do formatted input/output. To look up information about + standard modules, the command <c>erl -man</c> can be used at + the operating shell or command prompt (i.e. at the same place as + that where you started <c>erl</c>). Try the operating system + shell command:</p> + <pre> +% <input>erl -man io</input> +ERLANG MODULE DEFINITION io(3) + +MODULE + io - Standard I/O Server Interface Functions + +DESCRIPTION + This module provides an interface to standard Erlang IO + servers. The output functions all return ok if they are suc- + ...</pre> + <p>If this doesn't work on your system, the documentation is + included as HTML in the Erlang/OTP release, or you can read + the documentation as HTML or download it as PDF from either of + the sites www.erlang.se (commercial Erlang) or www.erlang.org + (open source), for example for release R9B:</p> + <code type="none"> +http://www.erlang.org/doc/r9b/doc/index.html</code> + </section> + + <section> + <title>Writing Output to a Terminal</title> + <p>It's nice to be able to do formatted output in these example, so + the next example shows a simple way to use to use + the <c>io:format</c> function. Of course, just like all other + exported functions, you can test the <c>io:format</c> function in + the shell:</p> + <pre> +31> <input>io:format("hello world~n", []).</input> +hello world +ok +32> <input>io:format("this outputs one Erlang term: ~w~n", [hello]).</input> +this outputs one Erlang term: hello +ok +33> <input>io:format("this outputs two Erlang terms: ~w~w~n", [hello, world]).</input> +this outputs two Erlang terms: helloworld +ok +34> <input>io:format("this outputs two Erlang terms: ~w ~w~n", [hello, world]).</input> +this outputs two Erlang terms: hello world +ok</pre> + <p>The function <c>format/2</c> (i.e. <c>format</c> with two + arguments) takes two lists. The first one is nearly always a list + written between " ". This list is printed out as it stands, + except that each ~w is replaced by a term taken in order from + the second list. Each ~n is replaced by a new line. + The <c>io:format/2</c> function itself returns the atom <c>ok</c> + if everything goes as planned. Like other functions in Erlang, it + crashes if an error occurs. This is not a fault in Erlang, it is + a deliberate policy. Erlang has sophisticated mechanisms to + handle errors which we will show later. As an exercise, try to + make <c>io:format</c> crash, it shouldn't be difficult. But + notice that although <c>io:format</c> crashes, the Erlang shell + itself does not crash.</p> + </section> + + <section> + <title>A Larger Example</title> + <p>Now for a larger example to consolidate what we have learnt so + far. Assume we have a list of temperature readings from a number + of cities in the world. Some of them are in Celsius (Centigrade) + and some in Fahrenheit (as in the previous list). First let's + convert them all to Celsius, then let's print out the data neatly.</p> + <code type="none"> +%% This module is in file tut5.erl + +-module(tut5). +-export([format_temps/1]). + +%% Only this function is exported +format_temps([])-> % No output for an empty list + ok; +format_temps([City | Rest]) -> + print_temp(convert_to_celsius(City)), + format_temps(Rest). + +convert_to_celsius({Name, {c, Temp}}) -> % No conversion needed + {Name, {c, Temp}}; +convert_to_celsius({Name, {f, Temp}}) -> % Do the conversion + {Name, {c, (Temp - 32) * 5 / 9}}. + +print_temp({Name, {c, Temp}}) -> + io:format("~-15w ~w c~n", [Name, Temp]).</code> + <pre> +35> <input>c(tut5).</input> +{ok,tut5} +36> <input>tut5:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +ok</pre> + <p>Before we look at how this program works, notice that we have + added a few comments to the code. A comment starts with a % + character and goes on to the end of the line. Note as well that + the <c>-export([format_temps/1]).</c> line only includes + the function <c>format_temps/1</c>, the other functions are + <em>local</em> functions, i.e. they are not visible from outside + the module <c>tut5</c>.</p> + <p>Note as well that when testing the program from the shell, I had + to spread the input over two lines as the line was too long.</p> + <p>When we call <c>format_temps</c> the first time, <c>City</c> + gets the value <c>{moscow,{c,-10}}</c> and <c>Rest</c> is + the rest of the list. So we call the function + <c>print_temp(convert_to_celsius({moscow,{c,-10}}))</c>.</p> + <p>Here we see a function call as + <c>convert_to_celsius({moscow,{c,-10}})</c> as the argument to + the function <c>print_temp</c>. When we <em>nest</em> function + calls like this we execute (evaluate) them from the inside out. + I.e. we first evaluate <c>convert_to_celsius({moscow,{c,-10}})</c> + which gives the value <c>{moscow,{c,-10}}</c> as the temperature + is already in Celsius and then we evaluate + <c>print_temp({moscow,{c,-10}})</c>. The function + <c>convert_to_celsius</c> works in a similar way to + the <c>convert_length</c> function in the previous example.</p> + <p><c>print_temp</c> simply calls <c>io:format</c> in a similar way + to what has been described above. Note that ~-15w says to print + the "term" with a field length (width) of 15 and left justify it. + (<seealso marker="stdlib:io#fwrite/1">io(3)</seealso>).</p> + <p>Now we call <c>format_temps(Rest)</c> with the rest of the list + as an argument. This way of doing things is similar to the loop + constructs in other languages. (Yes, this is recursion, but don't + let that worry you). So the same <c>format_temps</c> function is + called again, this time <c>City</c> gets the value + <c>{cape_town,{f,70}}</c> and we repeat the same procedure as + before. We go on doing this until the list becomes empty, i.e. [], + which causes the first clause <c>format_temps([])</c> to match. + This simply returns (results in) the atom <c>ok</c>, so + the program ends.</p> + </section> + + <section> + <title>Matching, Guards and Scope of Variables</title> + <p>It could be useful to find the maximum and minimum temperature + in lists like this. Before extending the program to do this, + let's look at functions for finding the maximum value of + the elements in a list:</p> + <code type="none"> +-module(tut6). +-export([list_max/1]). + +list_max([Head|Rest]) -> + list_max(Rest, Head). + +list_max([], Res) -> + Res; +list_max([Head|Rest], Result_so_far) when Head > Result_so_far -> + list_max(Rest, Head); +list_max([Head|Rest], Result_so_far) -> + list_max(Rest, Result_so_far).</code> + <pre> +37> <input>c(tut6).</input> +{ok,tut6} +38> <input>tut6:list_max([1,2,3,4,5,7,4,3,2,1]).</input> +7</pre> + <p>First note that we have two functions here with the same name + <c>list_max</c>. However each of these takes a different number + of arguments (parameters). In Erlang these are regarded as + completely different functions. Where we need to distinguish + between these functions we write <c>name/arity</c>, where + <c>name</c> is the name of the function and <c>arity</c> is + the number of arguments, in this case <c>list_max/1</c> and + <c>list_max/2</c>.</p> + <p>This is an example where we walk through a list "carrying" a + value with us, in this case <c>Result_so_far</c>. + <c>list_max/1</c> simply assumes that the max value of the list + is the head of the list and calls <c>list_max/2</c> with the rest + of the list and the value of the head of the list, in the above + this would be <c>list_max([2,3,4,5,7,4,3,2,1],1)</c>. If we tried + to use <c>list_max/1</c> with an empty list or tried to use it + with something which isn't a list at all, we would cause an error. + Note that the Erlang philosophy is not to handle errors of this + type in the function they occur, but to do so elsewhere. More + about this later.</p> + <p>In <c>list_max/2</c> we walk down the list and use <c>Head</c> + instead of <c>Result_so_far</c> when <c>Head</c> > + <c>Result_so_far</c>. <c>when</c> is a special word we use before + the -> in the function to say that we should only use this part + of the function if the test which follows is true. We call tests + of this type a <em>guard</em>. If the guard isn't true (we say + the guard fails), we try the next part of the function. In this + case if <c>Head</c> isn't greater than <c>Result_so_far</c> then + it must be smaller or equal to is, so we don't need a guard on + the next part of the function.</p> + <p>Some useful operators in guards are, < less than, > + greater than, == equal, >= greater or equal, =< less or + equal, /= not equal. (see the chapter + <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual).</p> + <p>To change the above program to one which works out the minimum + value of the element in a list, all we would need to do is to + write < instead of >. (But it would be wise to change + the name of the function to <c>list_min</c> :-).</p> + <p>Remember that I mentioned earlier that a variable could only be + given a value once in its scope? In the above we see, for example, + that <c>Result_so_far</c> has been given several values. This is + OK since every time we call <c>list_max/2</c> we create a new + scope and one can regard the <c>Result_so_far</c> as a completely + different variable in each scope.</p> + <p>Another way of creating and giving a variable a value is by using + the match operator = . So if I write <c>M = 5</c>, a variable + called <c>M</c> will be created and given the value 5. If, in + the same scope I then write <c>M = 6</c>, I'll get an error. Try + this out in the shell:</p> + <pre> +39> <input>M = 5.</input> +5 +40> <input>M = 6.</input> +** exception error: no match of right hand side value 6 +41> <input>M = M + 1.</input> +** exception error: no match of right hand side value 6 +42> <input>N = M + 1.</input> +6</pre> + <p>The use of the match operator is particularly useful for pulling + apart Erlang terms and creating new ones.</p> + <pre> +43> <input>{X, Y} = {paris, {f, 28}}.</input> +{paris,{f,28}} +44> <input>X.</input> +paris +45> <input>Y.</input> +{f,28}</pre> + <p>Here we see that <c>X</c> gets the value <c>paris</c> and + <c>Y</c><c>{f,28}</c>.</p> + <p>Of course if we try to do the same again with another city, we + get an error:</p> + <pre> +46> <input>{X, Y} = {london, {f, 36}}.</input> +** exception error: no match of right hand side value {london,{f,36}}</pre> + <p>Variables can also be used to improve the readability of + programs, for example, in the <c>list_max/2</c> function above, + we could write:</p> + <code type="none"> +list_max([Head|Rest], Result_so_far) when Head > Result_so_far -> + New_result_far = Head, + list_max(Rest, New_result_far);</code> + <p>which is possibly a little clearer.</p> + </section> + + <section> + <title>More About Lists</title> + <p>Remember that the | operator can be used to get the head of a + list:</p> + <pre> +47> <input>[M1|T1] = [paris, london, rome].</input> +[paris,london,rome] +48> <input>M1.</input> +paris +49> <input>T1.</input> +[london,rome]</pre> + <p>The | operator can also be used to add a head to a list:</p> + <pre> +50> <input>L1 = [madrid | T1].</input> +[madrid,london,rome] +51> <input>L1.</input> +[madrid,london,rome]</pre> + <p>Now an example of this when working with lists - reversing + the order of a list:</p> + <code type="none"> +-module(tut8). + +-export([reverse/1]). + +reverse(List) -> + reverse(List, []). + +reverse([Head | Rest], Reversed_List) -> + reverse(Rest, [Head | Reversed_List]); +reverse([], Reversed_List) -> + Reversed_List.</code> + <pre> +52> <input>c(tut8).</input> +{ok,tut8} +53> <input>tut8:reverse([1,2,3]).</input> +[3,2,1]</pre> + <p>Consider how <c>Reversed_List</c> is built. It starts as [], we + then successively take off the heads of the list to be reversed + and add them to the the <c>Reversed_List</c>, as shown in + the following:</p> + <code type="none"> +reverse([1|2,3], []) => + reverse([2,3], [1|[]]) + +reverse([2|3], [1]) => + reverse([3], [2|[1]) + +reverse([3|[]], [2,1]) => + reverse([], [3|[2,1]]) + +reverse([], [3,2,1]) => + [3,2,1]</code> + <p>The module <c>lists</c> contains a lot of functions for + manipulating lists, for example for reversing them, so before you + write a list manipulating function it is a good idea to check + that one isn't already written for you. (see + <seealso marker="stdlib:lists">lists(3)</seealso>).</p> + <p>Now lets get back to the cities and temperatures, but take a more + structured approach this time. First let's convert the whole list + to Celsius as follows and test the function:</p> + <code type="none"> +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + convert_list_to_c(List_of_cities). + +convert_list_to_c([{Name, {f, F}} | Rest]) -> + Converted_City = {Name, {c, (F -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + [].</code> + <pre> +54> <input>c(tut7).</input> +{ok, tut7}. +55> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {cape_town,{c,21.11111111111111}}, + {stockholm,{c,-4}}, + {paris,{c,-2.2222222222222223}}, + {london,{c,2.2222222222222223}}]</pre> + <p>Looking at this bit by bit:</p> + <code type="none"> +format_temps(List_of_cities) -> + convert_list_to_c(List_of_cities).</code> + <p>Here we see that <c>format_temps/1</c> calls + <c>convert_list_to_c/1</c>. <c>convert_list_to_c/1</c> takes off + the head of the <c>List_of_cities</c>, converts it to Celsius if + needed. The | operator is used to add the (maybe) converted + to the converted rest of the list:</p> + <code type="none"> +[Converted_City | convert_list_to_c(Rest)];</code> + <p>or</p> + <code type="none"> +[City | convert_list_to_c(Rest)];</code> + <p>We go on doing this until we get to the end of the list (i.e. + the list is empty:</p> + <code type="none"> +convert_list_to_c([]) -> + [].</code> + <p>Now we have converted the list, we add a function to print it:</p> + <code type="none"> +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + Converted_List = convert_list_to_c(List_of_cities), + print_temp(Converted_List). + +convert_list_to_c([{Name, {f, F}} | Rest]) -> + Converted_City = {Name, {c, (F -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + []. + +print_temp([{Name, {c, Temp}} | Rest]) -> + io:format("~-15w ~w c~n", [Name, Temp]), + print_temp(Rest); +print_temp([]) -> + ok.</code> + <pre> +56> <input>c(tut7).</input> +{ok,tut7} +57> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +ok</pre> + <p>We now have to add a function to find the cities with + the maximum and minimum temperatures. The program below isn't + the most efficient way of doing this as we walk through the list + of cities four times. But it is better to first strive for + clarity and correctness and to make programs efficient only if + really needed.</p> + <code type="none"><![CDATA[ +-module(tut7). +-export([format_temps/1]). + +format_temps(List_of_cities) -> + Converted_List = convert_list_to_c(List_of_cities), + print_temp(Converted_List), + {Max_city, Min_city} = find_max_and_min(Converted_List), + print_max_and_min(Max_city, Min_city). + +convert_list_to_c([{Name, {f, Temp}} | Rest]) -> + Converted_City = {Name, {c, (Temp -32)* 5 / 9}}, + [Converted_City | convert_list_to_c(Rest)]; + +convert_list_to_c([City | Rest]) -> + [City | convert_list_to_c(Rest)]; + +convert_list_to_c([]) -> + []. + +print_temp([{Name, {c, Temp}} | Rest]) -> + io:format("~-15w ~w c~n", [Name, Temp]), + print_temp(Rest); +print_temp([]) -> + ok. + +find_max_and_min([City | Rest]) -> + find_max_and_min(Rest, City, City). + +find_max_and_min([{Name, {c, Temp}} | Rest], + {Max_Name, {c, Max_Temp}}, + {Min_Name, {c, Min_Temp}}) -> + if + Temp > Max_Temp -> + Max_City = {Name, {c, Temp}}; % Change + true -> + Max_City = {Max_Name, {c, Max_Temp}} % Unchanged + end, + if + Temp < Min_Temp -> + Min_City = {Name, {c, Temp}}; % Change + true -> + Min_City = {Min_Name, {c, Min_Temp}} % Unchanged + end, + find_max_and_min(Rest, Max_City, Min_City); + +find_max_and_min([], Max_City, Min_City) -> + {Max_City, Min_City}. + +print_max_and_min({Max_name, {c, Max_temp}}, {Min_name, {c, Min_temp}}) -> + io:format("Max temperature was ~w c in ~w~n", [Max_temp, Max_name]), + io:format("Min temperature was ~w c in ~w~n", [Min_temp, Min_name]).]]></code><pre> +58> <input>c(tut7).</input> +{ok, tut7} +59> <input>tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow -10 c +cape_town 21.11111111111111 c +stockholm -4 c +paris -2.2222222222222223 c +london 2.2222222222222223 c +Max temperature was 21.11111111111111 c in cape_town +Min temperature was -10 c in moscow +ok</pre> + </section> + + <section> + <title>If and Case</title> + <p>The function <c>find_max_and_min</c> works out the maximum and + minimum temperature. We have introduced a new construct here + <c>if</c>. If works as follows:</p> + <code type="none"> +if + Condition 1 -> + Action 1; + Condition 2 -> + Action 2; + Condition 3 -> + Action 3; + Condition 4 -> + Action 4 +end</code> + <p>Note there is no ";" before <c>end</c>! Conditions are the same + as guards, tests which succeed or fail. Erlang starts at the top + until it finds a condition which succeeds and then it evaluates + (performs) the action following the condition and ignores all + other conditions and action before the <c>end</c>. If no + condition matches, there will be a run-time failure. A condition + which always is succeeds is the atom, <c>true</c> and this is + often used last in an <c>if</c> meaning do the action following + the <c>true</c> if all other conditions have failed.</p> + <p>The following is a short program to show the workings of + <c>if</c>.</p> + <code type="none"> +-module(tut9). +-export([test_if/2]). + +test_if(A, B) -> + if + A == 5 -> + io:format("A == 5~n", []), + a_equals_5; + B == 6 -> + io:format("B == 6~n", []), + b_equals_6; + A == 2, B == 3 -> %i.e. A equals 2 and B equals 3 + io:format("A == 2, B == 3~n", []), + a_equals_2_b_equals_3; + A == 1 ; B == 7 -> %i.e. A equals 1 or B equals 7 + io:format("A == 1 ; B == 7~n", []), + a_equals_1_or_b_equals_7 + end.</code> + <p>Testing this program gives:</p> + <pre> +60> <input>c(tut9).</input> +{ok,tut9} +61> <input>tut9:test_if(5,33).</input> +A == 5 +a_equals_5 +62> <input>tut9:test_if(33,6).</input> +B == 6 +b_equals_6 +63> <input>tut9:test_if(2, 3).</input> +A == 2, B == 3 +a_equals_2_b_equals_3 +64> <input>tut9:test_if(1, 33).</input> +A == 1 ; B == 7 +a_equals_1_or_b_equals_7 +65> <input>tut9:test_if(33, 7).</input> +A == 1 ; B == 7 +a_equals_1_or_b_equals_7 +66> <input>tut9:test_if(33, 33).</input> +** exception error: no true branch found when evaluating an if expression + in function tut9:test_if/2</pre> + <p>Notice that <c>tut9:test_if(33,33)</c> did not cause any + condition to succeed so we got the run time error + <c>if_clause</c>, here nicely formatted by the shell. See the chapter + <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual for details + of the many guard tests available. <c>case</c> is another + construct in Erlang. Recall that we wrote the + <c>convert_length</c> function as:</p> + <code type="none"> +convert_length({centimeter, X}) -> + {inch, X / 2.54}; +convert_length({inch, Y}) -> + {centimeter, Y * 2.54}.</code> + <p>We could also write the same program as:</p> + <code type="none"> +-module(tut10). +-export([convert_length/1]). + +convert_length(Length) -> + case Length of + {centimeter, X} -> + {inch, X / 2.54}; + {inch, Y} -> + {centimeter, Y * 2.54} + end.</code> + <pre> +67> <input>c(tut10).</input> +{ok,tut10} +68> <input>tut10:convert_length({inch, 6}).</input> +{centimeter,15.24} +69> <input>tut10:convert_length({centimeter, 2.5}).</input> +{inch,0.984251968503937}</pre> + <p>Notice that both <c>case</c> and <c>if</c> have <em>return values</em>, i.e. in the above example <c>case</c> returned + either <c>{inch,X/2.54}</c> or <c>{centimeter,Y*2.54}</c>. + The behaviour of <c>case</c> can also be modified by using guards. + An example should hopefully clarify this. The following example + tells us the length of a month, given the year. We need to know + the year of course, since February has 29 days in a leap year.</p> + <code type="none"> +-module(tut11). +-export([month_length/2]). + +month_length(Year, Month) -> + %% All years divisible by 400 are leap + %% Years divisible by 100 are not leap (except the 400 rule above) + %% Years divisible by 4 are leap (except the 100 rule above) + Leap = if + trunc(Year / 400) * 400 == Year -> + leap; + trunc(Year / 100) * 100 == Year -> + not_leap; + trunc(Year / 4) * 4 == Year -> + leap; + true -> + not_leap + end, + case Month of + sep -> 30; + apr -> 30; + jun -> 30; + nov -> 30; + feb when Leap == leap -> 29; + feb -> 28; + jan -> 31; + mar -> 31; + may -> 31; + jul -> 31; + aug -> 31; + oct -> 31; + dec -> 31 + end.</code> + <pre> +70> <input>c(tut11).</input> +{ok,tut11} +71> <input>tut11:month_length(2004, feb).</input> +29 +72> <input>tut11:month_length(2003, feb).</input> +28 +73> <input>tut11:month_length(1947, aug).</input> +31</pre> + </section> + + <section> + <title>Built In Functions (BIFs)</title> + <p>Built in functions BIFs are functions which for some reason is + built in to the Erlang virtual machine. BIFs often implement + functionality that is impossible to implement in Erlang or is to + inefficient to implement in Erlang. Some BIFs can be called + by use of the function name only but they are by default belonging + to the erlang module so for example the call to the BIF <c>trunc</c> + below is equivalent with a call to <c>erlang:trunc</c>.</p> + <p>As you can see, we first find out if a year is leap or not. If a + year is divisible by 400, it is a leap year. To find this out we + first divide the year by 400 and use the built in function + <c>trunc</c> (more later) to cut off any decimals. We then + multiply by 400 again and see if we get back the same value. For + example, year 2004:</p> + <code type="none"> +2004 / 400 = 5.01 +trunc(5.01) = 5 +5 * 400 = 2000</code> + <p>and we can see that we got back 2000 which is not the same as + 2004, so 2004 isn't divisible by 400. Year 2000:</p> + <code type="none"> +2000 / 400 = 5.0 +trunc(5.0) = 5 +5 * 400 = 2000</code> + <p>so we have a leap year. The next two tests if the year is + divisible by 100 or 4 are done in the same way. The first + <c>if</c> returns <c>leap</c> or <c>not_leap</c> which lands up + in the variable <c>Leap</c>. We use this variable in the guard + for <c>feb</c> in the following <c>case</c> which tells us how + long the month is.</p> + <p>This example showed the use of <c>trunc</c>, an easier way would + be to use the Erlang operator <c>rem</c> which gives the remainder + after division. For example:</p> + <pre> +74> <input>2004 rem 400.</input> +4</pre> + <p>so instead of writing</p> + <code type="none"> +trunc(Year / 400) * 400 == Year -> + leap;</code> + <p>we could write</p> + <code type="none"> +Year rem 400 == 0 -> + leap;</code> + <p>There are many other built in functions (BIF) such as + <c>trunc</c>. Only a few built in functions can be used in guards, + and you cannot use functions you have defined yourself in guards. + (see the chapter + <seealso marker="doc/reference_manual:expressions">"Guard Sequences"</seealso> in the Erlang Reference Manual) (Aside for + advanced readers: This is to ensure that guards don't have side + effects). Let's play with a few of these functions in the shell:</p> + <pre> +75> <input>trunc(5.6).</input> +5 +76> <input>round(5.6).</input> +6 +77> <input>length([a,b,c,d]).</input> +4 +78> <input>float(5).</input> +5.0 +79> <input>is_atom(hello).</input> +true +80> <input>is_atom("hello").</input> +false +81> <input>is_tuple({paris, {c, 30}}).</input> +true +82> <input>is_tuple([paris, {c, 30}]).</input> +false</pre> + <p>All the above can be used in guards. Now for some which can't be + used in guards:</p> + <pre> +83> <input>atom_to_list(hello).</input> +"hello" +84> <input>list_to_atom("goodbye").</input> +goodbye +85> <input>integer_to_list(22).</input> +"22"</pre> + <p>The 3 BIFs above do conversions which would be difficult (or + impossible) to do in Erlang.</p> + </section> + + <section> + <title>Higher Order Functions (Funs)</title> + <p>Erlang, like most modern functional programming languages, has + higher order functions. We start with an example using the shell:</p> + <pre> +86> <input>Xf = fun(X) -> X * 2 end.</input> +#Fun<erl_eval.5.123085357> +87> <input>Xf(5).</input> +10</pre> + <p>What we have done here is to define a function which doubles + the value of number and assign this function to a variable. Thus + <c>Xf(5)</c> returned the value 10. Two useful functions when + working with lists are <c>foreach</c> and <c>map</c>, which are + defined as follows:</p> + <code type="none"> +foreach(Fun, [First|Rest]) -> + Fun(First), + foreach(Fun, Rest); +foreach(Fun, []) -> + ok. + +map(Fun, [First|Rest]) -> + [Fun(First)|map(Fun,Rest)]; +map(Fun, []) -> + [].</code> + <p>These two functions are provided in the standard module + <c>lists</c>. <c>foreach</c> takes a list and applies a fun to + every element in the list, <c>map</c> creates a new list by + applying a fun to every element in a list. Going back to + the shell, we start by using <c>map</c> and a fun to add 3 to + every element of a list:</p> + <pre> +88> <input>Add_3 = fun(X) -> X + 3 end.</input> +#Fun<erl_eval.5.123085357> +89> <input>lists:map(Add_3, [1,2,3]).</input> +[4,5,6]</pre> + <p>Now lets print out the temperatures in a list of cities (yet + again):</p> + <pre> +90> <input>Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",</input> +<input>[City, X, Temp]) end.</input> +#Fun<erl_eval.5.123085357> +91> <input>lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +moscow c -10 +cape_town f 70 +stockholm c -4 +paris f 28 +london f 36 +ok</pre> + <p>We will now define a fun which can be used to go through a list + of cities and temperatures and transform them all to Celsius.</p> + <code type="none"> +-module(tut13). + +-export([convert_list_to_c/1]). + +convert_to_c({Name, {f, Temp}}) -> + {Name, {c, trunc((Temp - 32) * 5 / 9)}}; +convert_to_c({Name, {c, Temp}}) -> + {Name, {c, Temp}}. + +convert_list_to_c(List) -> + lists:map(fun convert_to_c/1, List).</code> + <pre> +92> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {cape_town,{c,21}}, + {stockholm,{c,-4}}, + {paris,{c,-2}}, + {london,{c,2}}]</pre> + <p>The <c>convert_to_c</c> function is the same as before, but we + use it as a fun:</p> + <code type="none"> +lists:map(fun convert_to_c/1, List)</code> + <p>When we use a function defined elsewhere as a fun we can refer + to it as <c>Function/Arity</c> (remember that <c>Arity</c> = + number of arguments). So in the <c>map</c> call we write + <c>lists:map(fun convert_to_c/1, List)</c>. As you can see + <c>convert_list_to_c</c> becomes much shorter and easier to + understand.</p> + <p>The standard module <c>lists</c> also contains a function + <c>sort(Fun, List)</c> where <c>Fun</c> is a fun with two + arguments. This fun should return <c>true</c> if the the first + argument is less than the second argument, or else <c>false</c>. + We add sorting to the <c>convert_list_to_c</c>:</p> + <code type="none"><![CDATA[ +-module(tut13). + +-export([convert_list_to_c/1]). + +convert_to_c({Name, {f, Temp}}) -> + {Name, {c, trunc((Temp - 32) * 5 / 9)}}; +convert_to_c({Name, {c, Temp}}) -> + {Name, {c, Temp}}. + +convert_list_to_c(List) -> + New_list = lists:map(fun convert_to_c/1, List), + lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> + Temp1 < Temp2 end, New_list).]]></code> + <pre> +93> <input>c(tut13).</input> +{ok,tut13} +94> <input>tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},</input> +<input>{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).</input> +[{moscow,{c,-10}}, + {stockholm,{c,-4}}, + {paris,{c,-2}}, + {london,{c,2}}, + {cape_town,{c,21}}]</pre> + <p>In <c>sort</c> we use the fun:</p> + <code type="none"><![CDATA[ +fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,]]></code> + <p>Here we introduce the concept of an <em>anonymous variable</em> + "_". This is simply shorthand for a variable which is going to + get a value, but we will ignore the value. This can be used + anywhere suitable, not just in fun's. <c><![CDATA[Temp1 < Temp2]]></c> + returns <c>true</c> if <c>Temp1</c> is less than <c>Temp2</c>.</p> + </section> +</chapter> + diff --git a/system/doc/getting_started/xmlfiles.mk b/system/doc/getting_started/xmlfiles.mk new file mode 100644 index 0000000000..c784d79dc3 --- /dev/null +++ b/system/doc/getting_started/xmlfiles.mk @@ -0,0 +1,24 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +GETTING_STARTED_CHAPTER_FILES = \ + conc_prog.xml \ + intro.xml \ + records_macros.xml \ + robustness.xml \ + seq_prog.xml diff --git a/system/doc/html/.gitignore b/system/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/system/doc/html/.gitignore diff --git a/system/doc/images/.gitignore b/system/doc/images/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/system/doc/images/.gitignore diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile new file mode 100644 index 0000000000..c51f0ee5f3 --- /dev/null +++ b/system/doc/installation_guide/Makefile @@ -0,0 +1,100 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/installation_guide + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(INST_GUIDE_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +PS_FILES = + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/installation_guide + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + diff --git a/system/doc/installation_guide/book.xml b/system/doc/installation_guide/book.xml new file mode 100644 index 0000000000..7d8001f2b3 --- /dev/null +++ b/system/doc/installation_guide/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installation Guide</title> + <prepared>Peter Högfeldt</prepared> + <docno></docno> + <date>1997-11-06</date> + <rev>D</rev> + <file>book.xml</file> + </header> + <insidecover> + </insidecover> + <pagetext>Installation Guide</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/installation_guide/install.xml b/system/doc/installation_guide/install.xml new file mode 100644 index 0000000000..2e37ff35e9 --- /dev/null +++ b/system/doc/installation_guide/install.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installation</title> + <prepared>Peter Högfeldt</prepared> + <responsible>Peter Högfeldt</responsible> + <docno></docno> + <approved>(Peter Högfeldt</approved> + <checked></checked> + <date>1997-05-26</date> + <rev>C</rev> + <file>install.xml</file> + </header> + + <section> + <title>UNIX</title> + + <section> + <title>Introduction</title> + <p>The system is delivered as a single compressed tar file.</p> + <p>To browse the on-line HTML documentation, Netscape or an equivalent + browser supporting frames is needed.</p> + </section> + + <section> + <title>Installation Procedure</title> + <p>When installed, the entire system, except for a small start-up + script, resides in a single directory tree. The location of this + directory tree can be chosen arbitrarily by the installer, and it + does not need to be in the user's <c>$PATH</c>. The only requirements + are that the file system where it is placed has enough free space, + and that the users who run Erlang/OTP have read access to it. In the + example below, the directory tree is assumed to be located at + <c>/usr/local/erlang</c>, which is here called the <em>top-level directory</em>.</p> + <p>It is assumed that you have the compressed tar file, the name of + which is <c><![CDATA[<PREFIX>.tar.gz]]></c>, where <c><![CDATA[<PREFIX>]]></c> is a string + denoting the particular Erlang/OTP release, e.g. + <c>otp_LXA_11930_sunos5_R9B</c>.</p> + <p>Wherever the string <c><![CDATA[<PREFIX>]]></c> is used below, it should + be replaced by the actual name prefix of the compressed tar file.</p> + <p>The tape archive file does not have one single directory in which + all other files are rooted. Therefore the tape archive file must be + extracted into an empty (newly created) directory.</p> + <list type="ordered"> + <item> + <p>If the <em>top-level directory</em> does not already exist, + create it:</p> + <pre> +mkdir /usr/local/erlang</pre> + </item> + <item> + <p>Change the current directory to the <em>top level directory</em>:</p> + <pre> +cd /usr/local/erlang</pre> + </item> + <item> + <p>Create the <em>installation directory</em> with an appropriate + name. For example:</p> + <pre> +mkdir otp_r7b</pre> + </item> + <item> + <p>Change to the <em>installation directory</em>, e.g.</p> + <pre> +cd otp_r7b</pre> + </item> + <item> + <p>Assuming the compressed tar file resides in the directory + <c><![CDATA[<SOME-DIR>]]></c>,. extract the compressed tar file into the + current directory:</p> + <pre> +gunzip -c <SOME-DIR>/<PREFIX>.tar.gz | tar xfp -</pre> + </item> + <item> + <p>Read the <c>README</c> file in the installation directory for + last minute updates, before proceeding.</p> + </item> + <item> + <p>Run the <c>Install</c> script in the installation directory, + with the absolute path of the installation directory as argument,</p> + <pre> +./Install /usr/local/erlang/otp_r7b</pre> + <p>and supply answers to the prompts.</p> + <p>In most cases, there is a default answer in square brackets + (<c>[]</c>). If the default is satisfactory, just press + <c><![CDATA[<Return>]]></c>. In general you are only prompted for one thing:</p> + <list type="bulleted"> + <item> + <p>"Do you want to use a minimal system startup instead of the + SASL startup?" <br></br> + + In a minimal system, only the Kernel and STDLIB applications + are loaded and started. If the SASL startup is used, the SASL + application is included as well. Normally, the minimal system + is enough.</p> + </item> + </list> + </item> + <item> + <p>Make Erlang/OTP available for users, either by putting the path + <c>/usr/local/erlang/otp_r7b/bin</c> in users <c>$PATH</c> + variable, or link the executable + <c>/usr/local/erlang/otp_r7b/bin/erl</c> accordingly, e.g.:</p> + <pre> +ln -s /usr/local/erlang/otp_r7b/bin/erl /usr/local/bin/erl </pre> + </item> + </list> + </section> + </section> + + <section> + <title>Windows</title> + + <section> + <title>Introduction</title> + <p>The system is delivered as a single <c>.exe</c> file.</p> + <p>To browse the on-line HTML documentation, Netscape or an equivalent + browser supporting frames is needed.</p> + </section> + + <section> + <title>Installation Procedure</title> + <p>The installation procedure is is automated. Double-click the + <c>.exe</c> file icon and follow the instructions.</p> + </section> + </section> +</chapter> + diff --git a/system/doc/installation_guide/make.dep b/system/doc/installation_guide/make.dep new file mode 100644 index 0000000000..3d1477935d --- /dev/null +++ b/system/doc/installation_guide/make.dep @@ -0,0 +1,13 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex install.tex part.tex verification.tex + diff --git a/system/doc/installation_guide/note.gif b/system/doc/installation_guide/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/installation_guide/note.gif diff --git a/system/doc/installation_guide/part.xml b/system/doc/installation_guide/part.xml new file mode 100644 index 0000000000..3019d2e118 --- /dev/null +++ b/system/doc/installation_guide/part.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installation Guide</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>part.xml</file> + </header> + <description> + <p>How to install Erlang/OTP on UNIX or Windows.</p> + </description> + <xi:include href="install.xml"/> + <xi:include href="verification.xml"/> +</part> + diff --git a/system/doc/installation_guide/verification.xml b/system/doc/installation_guide/verification.xml new file mode 100644 index 0000000000..814c252dca --- /dev/null +++ b/system/doc/installation_guide/verification.xml @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Installation Verification</title> + <prepared>Peter Högfeldt</prepared> + <responsible>Peter Högfeldt</responsible> + <docno></docno> + <approved>(Peter Högfeldt</approved> + <checked></checked> + <date>1997-05-26</date> + <rev>C</rev> + <file>verification.xml</file> + </header> + <p>This chapter is about verifying your installation by performing + a few simple tests to see that your system is properly installed.</p> + + <section> + <title>UNIX</title> + <list type="bulleted"> + <item> + <p>Start Erlang/OTP from the command line,</p> + <pre> + unix> erl</pre> + <p>Expect the following output:</p> + <pre> + Erlang (BEAM) emulator version 5.0.1 [threads] + + Eshell V5.0.1 (abort with ^G) + 1></pre> + </item> + <item> + <p>Start the GS-based toolbar from the Erlang shell, </p> + <pre> + 1> <input>toolbar:start().</input></pre> + <p>and check that the toolbar window pops up. + </p> + <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker + for all commands in the Erlang shell, and must be entered for a + command to begin execution.</p> + </item> + <item> + <p>Exit by entering the command <c>halt()</c>,</p> + <pre> + 2> <input>halt().</input></pre> + <p>which should end both the toolbar window and the command line window. </p> + </item> + </list> + </section> + + <section> + <title>Windows</title> + <list type="bulleted"> + <item> + <p>Start Erlang/OTP by double-clicking on the Erlang shortcut icon on the + desktop.</p> + <p>Expect a command line window to pop up with the following output,</p> + <pre> + Erlang (BEAM) emulator version 5.0.1 [threads] + + Eshell V5.0.1 (abort with ^G) + 1></pre> + </item> + <item> + <p>Start the GS-based toolbar from the Erlang shell, </p> + <pre> + 1> <input>toolbar:start().</input></pre> + <p>and check that the toolbar window pops up. + </p> + <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker + for all commands in the Erlang shell, and must be entered for a + command to begin execution.</p> + </item> + <item> + <p>Exit by entering the command <c>halt()</c>,</p> + <pre> + 2> <input>halt().</input></pre> + <p>which should end both the toolbar window and the command line window. </p> + </item> + </list> + </section> +</chapter> + diff --git a/system/doc/installation_guide/warning.gif b/system/doc/installation_guide/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/installation_guide/warning.gif diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk new file mode 100644 index 0000000000..7e1235b64d --- /dev/null +++ b/system/doc/installation_guide/xmlfiles.mk @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +INST_GUIDE_CHAPTER_FILES = \ + install.xml \ + verification.xml diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile new file mode 100644 index 0000000000..e3288c9182 --- /dev/null +++ b/system/doc/oam/Makefile @@ -0,0 +1,102 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/oam + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(OAM_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = \ + snmp_model_1.gif \ + snmp_model_2.gif \ + snmp_model_3.gif \ + terminology.gif + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) +# ---------------------------------------------------- + +HTMLDIR = ../html/oam + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(HTML_UG_FILE) gifs + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + diff --git a/system/doc/oam/book.xml b/system/doc/oam/book.xml new file mode 100644 index 0000000000..a2596b7fbe --- /dev/null +++ b/system/doc/oam/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OAM Principles</title> + <prepared>Martin Björklund</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file></file> + </header> + <insidecover> + </insidecover> + <pagetext>OAM Principles</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/oam/make.dep b/system/doc/oam/make.dep new file mode 100644 index 0000000000..3694df9f1b --- /dev/null +++ b/system/doc/oam/make.dep @@ -0,0 +1,26 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex oam_intro.tex part.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +oam_intro.tex: ../../../system/doc/definitions/term.defs + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: snmp_model_1.ps snmp_model_2.ps snmp_model_3.ps \ + terminology.ps + diff --git a/system/doc/oam/note.gif b/system/doc/oam/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/oam/note.gif diff --git a/system/doc/oam/oam_intro.xml b/system/doc/oam/oam_intro.xml new file mode 100644 index 0000000000..bd7369b84c --- /dev/null +++ b/system/doc/oam/oam_intro.xml @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared>Martin Björklund</prepared> + <docno></docno> + <date>1997-11-01</date> + <rev>A</rev> + <file>oam_intro.xml</file> + </header> + <p>The operation and maintenance support in OTP consists of a + generic model for management subsystems in OTP, and some + components to be used in these subsystems. This document + describes the model. + </p> + <p>The main idea in the model is that it is management protocol + independent. Thus, it is not tied to any specific management + protocol. An API is defined which can be used to write + adaptations for specific management protocols. + </p> + <p>Each OAM component in OTP is implemented as one sub application, + which can be included in a management application for the system. + Note that such a complete management application is not in the + scope of this generic functionality. Examples illustrating how such an + application can be built are included however. + </p> + + <section> + <title>Terminology</title> + <p>The protocol independent architectural model on the network + level is the well-known <term id="Manager-Agent model"><termdef>Client-Server model for management operations</termdef></term>. This model is based on the client-server + principle, where the manager (client) sends <term id="requests"><termdef>A request is sent from a manager to an agent when it accesses management information.</termdef></term>to the + agent (server), the agent sends <term id="replies"><termdef>A reply is sent from the agent as a response to a request from a manager.</termdef></term>back to the manager. There are two main + differences to the normal client-server model. First, there are + usually a few managers that communicate with many agents; and + second, the agent may spontaneously send <term id="notifications"><termdef>A notification is sent spontaneously from an agent to a manager, e.g. an alarm.</termdef></term>to the + manager. The picture below illustrates the idea.</p> + <image file="../oam/terminology.gif"> + <icaption>Terminology</icaption> + </image> + <p>The manager is often referred to as the <term id="NMS"></term>, to + emphasize that it usually is realized as a program that presents + data to an operator. + </p> + <p>The agent is an entity that executes within a <term id="NE"></term>. + In OTP, the network element may be a distributed system, meaning + that the distributed system is managed as one entity. Of + course, the agent may be configured to be able to run on one of + several nodes, making it a distributed OTP application. + </p> + <p>The management information is defined in an <term id="MIB"></term>. + It is a formal definition of which information the agent makes + available to the manager. The manager accesses the MIB through + a management protocol, such as SNMP, CMIP, HTTP or CORBA. Each + of these protocols have their own MIB definition language. In + SNMP, it is a subset of ASN.1, in CMIP it is GDMO, in HTTP it is + implicit, and using CORBA, it is IDL. Usually, the entities + defined in the MIB are called <term id="MO"></term>, although these + objects do not have to be objects in the OO way,for example, a simple + scalar variable defined in an MIB is called a Managed Object. + The Managed Objects are logical objects, not necessarily with a + one-to-one mapping to the resources. + </p> + </section> + + <section> + <title>Model</title> + <p>In this section, the generic protocol independent model for use + within an OTP based network element is presented. This model is + used by all operation and maintenance components, and may be + used by the applications. The advantage of the model is that it + clearly separates the resources from the management protocol. + The resources do not need to be aware of which management + protocol is used to manage the system. This makes it possible + to manage the same resources with different protocols. + </p> + <p>The different entities involved in this model are the <term id="agent"></term>which terminates the management protocol, and the + <term id="resources"></term>which is to be managed, i.e. the actual + application entities. The resources should in general have no + knowledge of the management protocol used, and the agent should + have no knowledge of the managed resources. This implies that + some sort of translation mechanism must be used, to translate + the management operations to operations on the resources. This + translation mechanism is usually called + <em>instrumentation</em>, and the function that implements it is + called <term id="instrumentation function"></term>. The + instrumentation functions are written for each combination of + management protocol and resource to be managed. For example, if + an application is to be managed by SNMP and HTTP, two sets of + instrumentation functions are defined; one that maps SNMP + requests to the resources, and one that e.g. generates an HTML + page for some resources. + </p> + <p>When a manager makes a request to the agent, we have the + following picture:</p> + <image file="../oam/snmp_model_1.gif"> + <icaption>Request to an agent by a manager</icaption> + </image> + <p>Note that the mapping between instrumentation function and + resource is not necessarily 1-1. It is also possible to write + one instrumentation function for each resource, and use that + function from different protocols. + </p> + <p>The agent receives a request and maps this request to calls to + one or several instrumentation functions. The instrumentation + functions perform operations on the resources to implement the + semantics associated with the managed object. + </p> + <p>For example, a system that is managed with SNMP and HTTP may be + structured in the following way:</p> + <image file="../oam/snmp_model_2.gif"> + <icaption>Structure of a system managed with SNMP and HTTP</icaption> + </image> + <p>The resources may send notifications to the manager as well. + Examples of notifications are events and alarms. There is a + need for the resource to generate protocol independent + notifications. The following picture illustrates how this is + achieved:</p> + <image file="../oam/snmp_model_3.gif"> + <icaption>Notification handling</icaption> + </image> + <p>The main idea is that the resource sends the notfications as + Erlang terms to a dedicated <c>gen_event</c> process. Into this + process, handlers for the different management protocols are + installed. When an event is received by this process, it is + forwarded to each installed handler. The handlers are + responsible for translating the event into a notification to be + sent over the management protocol. For example, a handler for + SNMP would translate each event into an SNMP trap. + </p> + </section> + + <section> + <title>SNMP based OAM</title> + <p>For all OAM components, SNMP adaptations are provided. Other + adaptations may be defined in the future. + </p> + <p>The OAM components, and some other OTP applications, define + SNMP MIBs. All these MIBs are written in SNMPv2 SMI syntax, as + defined in RFC1902. For convenience we also deliver the SNMPv1 + SMI equivalent. All MIBs are designed to be v1/v2 compatible, + i.e. the v2 MIBs do not use any construct not available in v1. + </p> + + <section> + <title>MIB structure</title> + <p>The top-level OTP MIB is called <c>OTP-REG</c>, and it is + included in the <c>sasl</c> application. All other OTP mibs + import some objects from this MIB. + </p> + <p>Each MIB is contained in one application. The MIB text files + are stored under <c><![CDATA[mibs/<MIB>.mib]]></c> in the application + directory. The generated <c>.hrl</c> files with constant + declarations are stored under <c><![CDATA[include/<MIB>.hrl]]></c>, and + the compiled MIBs are stored under + <c><![CDATA[priv/mibs/<MIB>.bin]]></c>. For example, the <c>OTP-MIB</c> + is included in the <c>sasl</c> application: + </p> + <code type="none"> +sasl-1.3/mibs/OTP-MIB.mib + include/OTP-MIB.hrl + priv/mibs/OTP-MIB.bin</code> + <p>An application that needs to IMPORT this mib into another + MIB, should use the <c>il</c> option to the snmp mib compiler: + </p> + <code type="none"> +snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).</code> + <p>If the application needs to include the generated + <c>.hrl</c> file, it should use the <c>-include_lib</c> + directive to the Erlang compiler. + </p> + <code type="none"> +-module(my_mib). + +-include_lib("sasl/include/OTP-MIB.hrl").</code> + <p>The following MIBs are defined in the OTP system: + </p> + <taglist> + <tag>OTP-REG (sasl)</tag> + <item> + <p>This MIB contains the top-level OTP registration + objects, used by all other MIBs. + </p> + </item> + <tag>OTP-TC (sasl)</tag> + <item> + <p>This MIB contains the general Textual Conventions, + which can be used by any other MIB. + </p> + </item> + <tag>OTP-MIB (sasl)</tag> + <item> + <p>This MIB contains objects for instrumentation of the + Erlang nodes, the Erlang machines and the applications in + the system. + </p> + </item> + <tag>OTP-OS-MON-MIB (os_mon)</tag> + <item> + <p>This MIB contains objects for instrumentation of disk, + memory and cpu usage of the nodes in the system. + </p> + </item> + <tag>OTP-SNMPEA-MIB (snmp)</tag> + <item> + <p>This MIB contains objects for instrumentation and + control of the extensible snmp agent itself. Note that + the agent also implements the standard SNMPv2-MIB (or v1 + part of MIB-II, if SNMPv1 is used). + </p> + </item> + <tag>OTP-EVA-MIB (eva)</tag> + <item> + <p>This MIB contains objects for instrumentation and + control of the events and alarms in the system. + </p> + </item> + <tag>OTP-LOG-MIB (eva)</tag> + <item> + <p>This MIB contains objects for instrumentation and + control of the logs and FTP transfer of logs. + </p> + </item> + <tag>OTP-EVA-LOG-MIB (eva)</tag> + <item> + <p>This MIB contains objects for instrumentation and + control of the events and alarm logs in the system. + </p> + </item> + <tag>OTP-SNMPEA-LOG-MIB (eva)</tag> + <item> + <p>This MIB contains objects for instrumentation and + control of the snmp audit trail log in the system. + </p> + </item> + </taglist> + <p>The different applications use different strategies for + loading the MIBs into the agent. Some MIB implementations are + code-only, while others need a server. One way, used by the + code-only mib implementations, is for the user to call a + function such as <c>otp_mib:init(Agent)</c> to load the MIB, + and <c>otp_mib:stop(Agent)</c> to unload the MIB. See the + application manual page for each application for a description + of how to load each MIB. + </p> + </section> + </section> +</chapter> + diff --git a/system/doc/oam/part.xml b/system/doc/oam/part.xml new file mode 100644 index 0000000000..8e3acb6e0d --- /dev/null +++ b/system/doc/oam/part.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OAM Principles</title> + <prepared>Martin Björklund</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>1997-11-01</date> + <rev>A</rev> + <file></file> + </header> + <xi:include href="oam_intro.xml"/> +</part> + diff --git a/system/doc/oam/snmp_model_1.fig b/system/doc/oam/snmp_model_1.fig new file mode 100644 index 0000000000..ab5ec76eaf --- /dev/null +++ b/system/doc/oam/snmp_model_1.fig @@ -0,0 +1,42 @@ +#FIG 3.1 +Portrait +Center +Inches +1200 2 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3900 2850 5625 2850 5625 3600 3900 3600 3900 2850 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1500 2850 3225 2850 3225 3600 1500 3600 1500 2850 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2775 1500 4575 1500 4575 2325 2775 2325 2775 1500 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 5025 4200 6225 4200 6225 4800 5025 4800 5025 4200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1650 4200 2850 4200 2850 4800 1650 4800 1650 4200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 3600 825 3600 1500 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3150 2325 2325 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4200 2325 4800 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2250 3600 2250 4200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4500 3600 4050 4200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 5175 3600 5700 4200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 6975 1050 6975 4350 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3450 4200 4650 4200 4650 4800 3450 4800 3450 4200 +4 0 -1 0 0 0 12 0.0000 4 135 1110 1875 3300 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 135 1110 4200 3300 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 2025 4575 Res1\001 +4 0 -1 0 0 0 12 0.0000 4 135 345 3450 525 NET\001 +4 0 -1 0 0 0 12 0.0000 4 180 435 3375 1950 Agent\001 +4 0 -1 0 0 0 12 0.0000 4 135 330 6825 600 flow\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 3825 4575 Res2\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 5475 4575 Res3\001 +4 0 -1 0 0 0 12 0.0000 4 135 240 1500 2175 NE\001 diff --git a/system/doc/oam/snmp_model_1.gif b/system/doc/oam/snmp_model_1.gif Binary files differnew file mode 100644 index 0000000000..cf44d0fcc4 --- /dev/null +++ b/system/doc/oam/snmp_model_1.gif diff --git a/system/doc/oam/snmp_model_1.ps b/system/doc/oam/snmp_model_1.ps new file mode 100644 index 0000000000..1e4307cd09 --- /dev/null +++ b/system/doc/oam/snmp_model_1.ps @@ -0,0 +1,160 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: snmp_model_1.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Wed Jan 12 11:13:58 2000 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 341 264 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-89.0 289.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 3900 2850 m 5625 2850 l 5625 3600 l 3900 3600 l cp gs col-1 s gr +% Polyline +n 1500 2850 m 3225 2850 l 3225 3600 l 1500 3600 l cp gs col-1 s gr +% Polyline +n 2775 1500 m 4575 1500 l 4575 2325 l 2775 2325 l cp gs col-1 s gr +% Polyline +n 5025 4200 m 6225 4200 l 6225 4800 l 5025 4800 l cp gs col-1 s gr +% Polyline +n 1650 4200 m 2850 4200 l 2850 4800 l 1650 4800 l cp gs col-1 s gr +% Polyline +gs clippath +3630 1353 m 3600 1473 l 3570 1353 l 3570 1515 l 3630 1515 l cp clip +n 3600 825 m 3600 1500 l gs col-1 s gr gr + +% arrowhead +n 3630 1353 m 3600 1473 l 3570 1353 l col-1 s +% Polyline +n 3150 2325 m 2325 2850 l gs col-1 s gr +% Polyline +n 4200 2325 m 4800 2850 l gs col-1 s gr +% Polyline +n 2250 3600 m 2250 4200 l gs col-1 s gr +% Polyline +n 4500 3600 m 4050 4200 l gs col-1 s gr +% Polyline +n 5175 3600 m 5700 4200 l gs col-1 s gr +% Polyline +gs clippath +7005 4203 m 6975 4323 l 6945 4203 l 6945 4365 l 7005 4365 l cp clip +n 6975 1050 m 6975 4350 l gs col-1 s gr gr + +% arrowhead +n 7005 4203 m 6975 4323 l 6945 4203 l col-1 s +% Polyline +n 3450 4200 m 4650 4200 l 4650 4800 l 3450 4800 l cp gs col-1 s gr +/Times-Roman ff 180.00 scf sf +1875 3300 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +4200 3300 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +2025 4575 m +gs 1 -1 sc (Res1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3450 525 m +gs 1 -1 sc (NET) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3375 1950 m +gs 1 -1 sc (Agent) col-1 sh gr +/Times-Roman ff 180.00 scf sf +6825 600 m +gs 1 -1 sc (flow) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3825 4575 m +gs 1 -1 sc (Res2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +5475 4575 m +gs 1 -1 sc (Res3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1500 2175 m +gs 1 -1 sc (NE) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/oam/snmp_model_2.fig b/system/doc/oam/snmp_model_2.fig new file mode 100644 index 0000000000..7719ea58bf --- /dev/null +++ b/system/doc/oam/snmp_model_2.fig @@ -0,0 +1,52 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 1200 2475 1200 2475 1800 1200 1800 1200 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2475 1800 2475 1800 2475 1800 2475 1800 2475 1800 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3600 1200 4875 1200 4875 1800 3600 1800 3600 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3600 1200 4875 1200 4875 1800 3600 1800 3600 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1050 2400 2550 2400 2550 3000 1050 3000 1050 2400 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3450 2400 4950 2400 4950 3000 3450 3000 3450 2400 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 3600 2400 3600 2400 4125 1200 4125 1200 3600 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2400 4125 2400 4125 2400 4125 2400 4125 2400 4125 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2775 3600 3900 3600 3900 4125 2775 4125 2775 3600 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 4275 3600 5400 3600 5400 4125 4275 4125 4275 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1800 1800 1800 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4200 1800 4200 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1800 3000 1800 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 3 + 4125 3000 3300 3600 3375 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4350 3000 4875 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2250 3000 3150 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3600 3000 2100 3600 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 6225 1200 6225 3600 +4 0 -1 0 0 0 12 0.0000 4 135 510 1500 1425 SNMP\001 +4 0 -1 0 0 0 12 0.0000 4 135 450 3825 1425 HTTP\001 +4 0 -1 0 0 0 12 0.0000 4 135 465 3825 1665 Server\001 +4 0 -1 0 0 0 12 0.0000 4 135 465 1500 1665 Server\001 +4 0 -1 0 0 0 12 0.0000 4 135 1110 1275 2775 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 135 1110 3675 2775 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 1575 3900 Res1\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 3150 3900 Res2\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 4500 3900 Res3\001 +4 0 -1 0 0 0 12 0.0000 4 135 330 6075 1050 flow\001 diff --git a/system/doc/oam/snmp_model_2.gif b/system/doc/oam/snmp_model_2.gif Binary files differnew file mode 100644 index 0000000000..79c6ef1af5 --- /dev/null +++ b/system/doc/oam/snmp_model_2.gif diff --git a/system/doc/oam/snmp_model_2.ps b/system/doc/oam/snmp_model_2.ps new file mode 100644 index 0000000000..a58b061690 --- /dev/null +++ b/system/doc/oam/snmp_model_2.ps @@ -0,0 +1,168 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: snmp_model_2.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Wed Jan 12 12:16:38 2000 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 323 193 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-62.0 249.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 1200 1200 m 2475 1200 l 2475 1800 l 1200 1800 l cp gs col-1 s gr +% Polyline +n 2475 1800 m 2475 1800 l 2475 1800 l 2475 1800 l cp gs col-1 s gr +% Polyline +n 3600 1200 m 4875 1200 l 4875 1800 l 3600 1800 l cp gs col-1 s gr +% Polyline +n 3600 1200 m 4875 1200 l 4875 1800 l 3600 1800 l cp gs col-1 s gr +% Polyline +n 1050 2400 m 2550 2400 l 2550 3000 l 1050 3000 l cp gs col-1 s gr +% Polyline +n 3450 2400 m 4950 2400 l 4950 3000 l 3450 3000 l cp gs col-1 s gr +% Polyline +n 1200 3600 m 2400 3600 l 2400 4125 l 1200 4125 l cp gs col-1 s gr +% Polyline +n 2400 4125 m 2400 4125 l 2400 4125 l 2400 4125 l cp gs col-1 s gr +% Polyline +n 2775 3600 m 3900 3600 l 3900 4125 l 2775 4125 l cp gs col-1 s gr +% Polyline +n 4275 3600 m 5400 3600 l 5400 4125 l 4275 4125 l cp gs col-1 s gr +% Polyline +n 1800 1800 m 1800 2400 l gs col-1 s gr +% Polyline +n 4200 1800 m 4200 2400 l gs col-1 s gr +% Polyline +n 1800 3000 m 1800 3600 l gs col-1 s gr +% Polyline +n 4125 3000 m 3300 3600 l 3375 3600 l gs col-1 s gr +% Polyline +n 4350 3000 m 4875 3600 l gs col-1 s gr +% Polyline +n 2250 3000 m 3150 3600 l gs col-1 s gr +% Polyline +n 3600 3000 m 2100 3600 l gs col-1 s gr +% Polyline +gs clippath +6255 3453 m 6225 3573 l 6195 3453 l 6195 3615 l 6255 3615 l cp clip +n 6225 1200 m 6225 3600 l gs col-1 s gr gr + +% arrowhead +n 6255 3453 m 6225 3573 l 6195 3453 l col-1 s +/Times-Roman ff 180.00 scf sf +1500 1425 m +gs 1 -1 sc (SNMP) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3825 1425 m +gs 1 -1 sc (HTTP) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3825 1665 m +gs 1 -1 sc (Server) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1500 1665 m +gs 1 -1 sc (Server) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1275 2775 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3675 2775 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1575 3900 m +gs 1 -1 sc (Res1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3150 3900 m +gs 1 -1 sc (Res2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +4500 3900 m +gs 1 -1 sc (Res3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +6075 1050 m +gs 1 -1 sc (flow) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/oam/snmp_model_3.fig b/system/doc/oam/snmp_model_3.fig new file mode 100644 index 0000000000..b2356c7cfe --- /dev/null +++ b/system/doc/oam/snmp_model_3.fig @@ -0,0 +1,56 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 1800 1500 2325 1950 +4 0 -1 0 0 0 12 0.0000 4 135 465 1800 1890 Server\001 +4 0 -1 0 0 0 12 0.0000 4 135 510 1800 1650 SNMP\001 +-6 +6 4200 1425 4725 1875 +4 0 -1 0 0 0 12 0.0000 4 135 450 4200 1575 HTTP\001 +4 0 -1 0 0 0 12 0.0000 4 135 465 4200 1815 Server\001 +-6 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 1200 3000 1200 3000 2250 1200 2250 1200 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3600 1200 5400 1200 5400 2250 3600 2250 3600 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 3000 3000 3000 3000 3825 1200 3825 1200 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3600 3000 5400 3000 5400 3825 3600 3825 3600 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2475 4500 4200 4500 4200 5400 2475 5400 2475 4500 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 4200 6000 5400 6000 5400 6600 4200 6600 4200 6000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 6000 2400 6000 2400 6600 1200 6600 1200 6000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2700 6000 3900 6000 3900 6600 2700 6600 2700 6000 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2100 2250 2100 3000 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4500 2250 4500 3000 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2100 3825 3000 4500 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4500 3825 3600 4500 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 1800 6000 3000 5400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 3300 6000 3300 5400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 4800 6000 3600 5400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 1 2 + 2 1 1.00 60.00 120.00 + 6600 1575 6600 5850 +4 0 -1 0 0 0 12 0.0000 4 135 1110 3900 3450 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 135 1110 1500 3450 Instrumentation\001 +4 0 -1 0 0 0 12 0.0000 4 165 720 3000 4950 gen_event\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 3150 6375 Res2\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 4650 6375 Res3\001 +4 0 -1 0 0 0 12 0.0000 4 135 360 1650 6375 Res1\001 +4 0 -1 0 0 0 12 0.0000 4 135 330 6450 1275 flow\001 diff --git a/system/doc/oam/snmp_model_3.gif b/system/doc/oam/snmp_model_3.gif Binary files differnew file mode 100644 index 0000000000..dbc8157ed1 --- /dev/null +++ b/system/doc/oam/snmp_model_3.gif diff --git a/system/doc/oam/snmp_model_3.ps b/system/doc/oam/snmp_model_3.ps new file mode 100644 index 0000000000..c615918cca --- /dev/null +++ b/system/doc/oam/snmp_model_3.ps @@ -0,0 +1,182 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: snmp_model_3.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Wed Jan 12 12:37:37 2000 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 337 327 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-71.0 397.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +/Times-Roman ff 180.00 scf sf +1800 1890 m +gs 1 -1 sc (Server) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1800 1650 m +gs 1 -1 sc (SNMP) col-1 sh gr +/Times-Roman ff 180.00 scf sf +4200 1575 m +gs 1 -1 sc (HTTP) col-1 sh gr +/Times-Roman ff 180.00 scf sf +4200 1815 m +gs 1 -1 sc (Server) col-1 sh gr +7.500 slw +% Polyline +n 1200 1200 m 3000 1200 l 3000 2250 l 1200 2250 l cp gs col-1 s gr +% Polyline +n 3600 1200 m 5400 1200 l 5400 2250 l 3600 2250 l cp gs col-1 s gr +% Polyline +n 1200 3000 m 3000 3000 l 3000 3825 l 1200 3825 l cp gs col-1 s gr +% Polyline +n 3600 3000 m 5400 3000 l 5400 3825 l 3600 3825 l cp gs col-1 s gr +% Polyline +n 2475 4500 m 4200 4500 l 4200 5400 l 2475 5400 l cp gs col-1 s gr +% Polyline +n 4200 6000 m 5400 6000 l 5400 6600 l 4200 6600 l cp gs col-1 s gr +% Polyline +n 1200 6000 m 2400 6000 l 2400 6600 l 1200 6600 l cp gs col-1 s gr +% Polyline +n 2700 6000 m 3900 6000 l 3900 6600 l 2700 6600 l cp gs col-1 s gr +% Polyline +n 2100 2250 m 2100 3000 l gs col-1 s gr +% Polyline +n 4500 2250 m 4500 3000 l gs col-1 s gr +% Polyline +n 2100 3825 m 3000 4500 l gs col-1 s gr +% Polyline +n 4500 3825 m 3600 4500 l gs col-1 s gr +% Polyline +gs clippath +2855 5439 m 2975 5412 l 2882 5493 l 3027 5420 l 3000 5366 l cp clip +n 1800 6000 m 3000 5400 l gs col-1 s gr gr + +% arrowhead +n 2855 5439 m 2975 5412 l 2882 5493 l col-1 s +% Polyline +gs clippath +3270 5547 m 3300 5427 l 3330 5547 l 3330 5385 l 3270 5385 l cp clip +n 3300 6000 m 3300 5400 l gs col-1 s gr gr + +% arrowhead +n 3270 5547 m 3300 5427 l 3330 5547 l col-1 s +% Polyline +gs clippath +3718 5493 m 3624 5412 l 3745 5439 l 3600 5366 l 3573 5420 l cp clip +n 4800 6000 m 3600 5400 l gs col-1 s gr gr + +% arrowhead +n 3718 5493 m 3624 5412 l 3745 5439 l col-1 s +% Polyline +gs clippath +6570 1746 m 6600 1602 l 6630 1746 l 6630 1560 l 6570 1560 l cp clip +n 6600 1575 m 6600 5850 l gs col-1 s gr gr + +% arrowhead +n 6570 1746 m 6600 1602 l 6630 1746 l 6600 1722 l 6570 1746 l cp gs 0.00 setgray ef gr col-1 s +/Times-Roman ff 180.00 scf sf +3900 3450 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1500 3450 m +gs 1 -1 sc (Instrumentation) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3000 4950 m +gs 1 -1 sc (gen_event) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3150 6375 m +gs 1 -1 sc (Res2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +4650 6375 m +gs 1 -1 sc (Res3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1650 6375 m +gs 1 -1 sc (Res1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +6450 1275 m +gs 1 -1 sc (flow) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/oam/terminology.fig b/system/doc/oam/terminology.fig new file mode 100644 index 0000000000..5a3638764a --- /dev/null +++ b/system/doc/oam/terminology.fig @@ -0,0 +1,37 @@ +#FIG 3.1 +Portrait +Center +Inches +1200 2 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2400 525 3600 525 3600 1050 2400 1050 2400 525 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2400 1950 3600 1950 3600 2475 2400 2475 2400 1950 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1575 3075 2775 3075 2775 3600 1575 3600 1575 3075 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 1 + 3000 2475 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3600 750 3600 825 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 7 0 0 5 + 3075 3075 4275 3075 4275 3600 3075 3600 3075 3075 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 7 0 0 2 + 3000 2475 3675 3075 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 7 0 0 2 + 3000 2475 2175 3075 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 7 0 0 2 + 3000 1050 3000 1950 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 7 0 0 2 + 3600 750 4275 1350 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 7 0 0 2 + 3600 2175 4275 1650 +4 0 -1 0 0 0 14 0.0000 4 105 330 3975 2100 sees\001 +4 0 -1 0 0 0 14 0.0000 4 150 450 1275 750 NMS\001 +4 0 -1 0 0 0 14 0.0000 4 150 420 1275 1575 NET\001 +4 0 -1 0 0 0 14 0.0000 4 150 285 1350 2700 NE\001 +4 0 -1 0 0 0 14 0.0000 4 105 330 3975 975 sees\001 +4 0 -1 0 0 0 14 0.0000 4 150 390 4125 1575 MIB\001 +4 0 -1 0 0 0 14 0.0000 4 150 405 1950 3375 Res1\001 +4 0 -1 0 0 0 14 0.0000 4 150 405 3450 3375 Res2\001 +4 0 -1 0 0 0 14 0.0000 4 195 510 2775 2325 Agent\001 +4 0 -1 0 0 0 14 0.0000 4 195 735 2625 825 Manager\001 diff --git a/system/doc/oam/terminology.gif b/system/doc/oam/terminology.gif Binary files differnew file mode 100644 index 0000000000..89f071abf6 --- /dev/null +++ b/system/doc/oam/terminology.gif diff --git a/system/doc/oam/terminology.ps b/system/doc/oam/terminology.ps new file mode 100644 index 0000000000..525fa24f88 --- /dev/null +++ b/system/doc/oam/terminology.ps @@ -0,0 +1,154 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: terminology.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Fri Dec 17 10:43:21 1999 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 196 187 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-76.0 217.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 2400 525 m 3600 525 l 3600 1050 l 2400 1050 l cp gs col-1 s gr +% Polyline +n 2400 1950 m 3600 1950 l 3600 2475 l 2400 2475 l cp gs col-1 s gr +% Polyline +n 1575 3075 m 2775 3075 l 2775 3600 l 1575 3600 l cp gs col-1 s gr +% Polyline +n 3000 2475 m 3000 2475 l gs col-1 s gr +% Polyline +n 3600 750 m 3600 825 l gs col-1 s gr +% Polyline +n 3075 3075 m 4275 3075 l 4275 3600 l 3075 3600 l cp gs col-1 s gr +% Polyline + [66.7] 0 sd +n 3000 2475 m 3675 3075 l gs col-1 s gr [] 0 sd +% Polyline + [66.7] 0 sd +n 3000 2475 m 2175 3075 l gs col-1 s gr [] 0 sd +% Polyline + [66.7] 0 sd +n 3000 1050 m 3000 1950 l gs col-1 s gr [] 0 sd +% Polyline + [66.7] 0 sd +n 3600 750 m 4275 1350 l gs col-1 s gr [] 0 sd +% Polyline + [66.7] 0 sd +n 3600 2175 m 4275 1650 l gs col-1 s gr [] 0 sd +/Times-Roman ff 210.00 scf sf +3975 2100 m +gs 1 -1 sc (sees) col-1 sh gr +/Times-Roman ff 210.00 scf sf +1275 750 m +gs 1 -1 sc (NMS) col-1 sh gr +/Times-Roman ff 210.00 scf sf +1275 1575 m +gs 1 -1 sc (NET) col-1 sh gr +/Times-Roman ff 210.00 scf sf +1350 2700 m +gs 1 -1 sc (NE) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3975 975 m +gs 1 -1 sc (sees) col-1 sh gr +/Times-Roman ff 210.00 scf sf +4125 1575 m +gs 1 -1 sc (MIB) col-1 sh gr +/Times-Roman ff 210.00 scf sf +1950 3375 m +gs 1 -1 sc (Res1) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3450 3375 m +gs 1 -1 sc (Res2) col-1 sh gr +/Times-Roman ff 210.00 scf sf +2775 2325 m +gs 1 -1 sc (Agent) col-1 sh gr +/Times-Roman ff 210.00 scf sf +2625 825 m +gs 1 -1 sc (Manager) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/oam/warning.gif b/system/doc/oam/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/oam/warning.gif diff --git a/system/doc/oam/xmlfiles.mk b/system/doc/oam/xmlfiles.mk new file mode 100644 index 0000000000..0610bdb989 --- /dev/null +++ b/system/doc/oam/xmlfiles.mk @@ -0,0 +1,19 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +OAM_CHAPTER_FILES = oam_intro.xml diff --git a/system/doc/pdf/.gitignore b/system/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/system/doc/pdf/.gitignore diff --git a/system/doc/pics/Makefile b/system/doc/pics/Makefile new file mode 100644 index 0000000000..fc5996259d --- /dev/null +++ b/system/doc/pics/Makefile @@ -0,0 +1,58 @@ +# +# Copyright (C) 1996,1997 Ericsson Telecommunications +# Author: Lars Thorsen +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +# +# Common macros +# + +GIF_FILES= \ + min_head.gif \ + ps.gif + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +docs: + +pdf: + +ps: + +debug opt: + + + +clean: + @echo "No action" >/dev/null + +# +# Release Targets +# +include $(ERL_TOP)/make/otp_release_targets.mk + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/pics + $(INSTALL_DATA) $(GIF_FILES) $(RELSYSDIR)/pics +endif +endif + +release_spec: diff --git a/system/doc/pics/app.gif b/system/doc/pics/app.gif Binary files differnew file mode 100644 index 0000000000..345d5795b1 --- /dev/null +++ b/system/doc/pics/app.gif diff --git a/system/doc/pics/ede.gif b/system/doc/pics/ede.gif Binary files differnew file mode 100644 index 0000000000..7a51766898 --- /dev/null +++ b/system/doc/pics/ede.gif diff --git a/system/doc/pics/ede_logo.gif b/system/doc/pics/ede_logo.gif Binary files differnew file mode 100644 index 0000000000..f7c902791b --- /dev/null +++ b/system/doc/pics/ede_logo.gif diff --git a/system/doc/pics/min_head.gif b/system/doc/pics/min_head.gif Binary files differnew file mode 100644 index 0000000000..67948a6378 --- /dev/null +++ b/system/doc/pics/min_head.gif diff --git a/system/doc/pics/notes.gif b/system/doc/pics/notes.gif Binary files differnew file mode 100644 index 0000000000..e000cca26a --- /dev/null +++ b/system/doc/pics/notes.gif diff --git a/system/doc/pics/otp.gif b/system/doc/pics/otp.gif Binary files differnew file mode 100644 index 0000000000..48c4ca9c02 --- /dev/null +++ b/system/doc/pics/otp.gif diff --git a/system/doc/pics/otp_logo.gif b/system/doc/pics/otp_logo.gif Binary files differnew file mode 100644 index 0000000000..d1a1f7f72d --- /dev/null +++ b/system/doc/pics/otp_logo.gif diff --git a/system/doc/pics/ps.gif b/system/doc/pics/ps.gif Binary files differnew file mode 100644 index 0000000000..186dfc7e24 --- /dev/null +++ b/system/doc/pics/ps.gif diff --git a/system/doc/pics/ref_man.gif b/system/doc/pics/ref_man.gif Binary files differnew file mode 100644 index 0000000000..b13c4efd53 --- /dev/null +++ b/system/doc/pics/ref_man.gif diff --git a/system/doc/pics/user_guide.gif b/system/doc/pics/user_guide.gif Binary files differnew file mode 100644 index 0000000000..e6275a803d --- /dev/null +++ b/system/doc/pics/user_guide.gif diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile new file mode 100644 index 0000000000..73512c9654 --- /dev/null +++ b/system/doc/programming_examples/Makefile @@ -0,0 +1,98 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/programming_examples + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(PROG_EX_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +PS_FILES = + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/programming_examples + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + + diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml new file mode 100644 index 0000000000..3306365c0e --- /dev/null +++ b/system/doc/programming_examples/bit_syntax.xml @@ -0,0 +1,327 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Bit Syntax</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>bit_syntax.xml</file> + </header> + + <section> + <title>Introduction</title> + <p>In Erlang a Bin is used for constructing binaries and matching + binary patterns. A Bin is written with the following syntax:</p> + <code type="none"><![CDATA[ + <<E1, E2, ... En>>]]></code> + <p>A Bin is a low-level sequence of bits or bytes. The purpose of a Bin is + to be able to, from a high level, construct a binary,</p> + <code type="none"><![CDATA[ +Bin = <<E1, E2, ... En>>]]></code> + <p>in which case all elements must be bound, or to match a binary,</p> + <code type="none"><![CDATA[ +<<E1, E2, ... En>> = Bin ]]></code> + <p>where <c>Bin</c> is bound, and where the elements are bound or + unbound, as in any match.</p> + <p>In R12B, a Bin need not consist of a whole number of bytes.</p> + + <p>A <em>bitstring</em> is a sequence of zero or more bits, where + the number of bits doesn't need to be divisible by 8. If the number + of bits is divisible by 8, the bitstring is also a binary.</p> + <p>Each element specifies a certain <em>segment</em> of the bitstring. + A segment is a set of contiguous bits of the binary (not + necessarily on a byte boundary). The first element specifies + the initial segment, the second element specifies the following + segment etc.</p> + <p>The following examples illustrate how binaries are constructed + or matched, and how elements and tails are specified.</p> + + <section> + <title>Examples</title> + <p><em>Example 1: </em>A binary can be constructed from a set of + constants or a string literal:</p> + <code type="none"><![CDATA[ +Bin11 = <<1, 17, 42>>, +Bin12 = <<"abc">>]]></code> + <p>yields binaries of size 3; <c>binary_to_list(Bin11)</c> + evaluates to <c>[1, 17, 42]</c>, and + <c>binary_to_list(Bin12)</c> evaluates to <c>[97, 98, 99]</c>.</p> + <p><em>Example 2: </em>Similarly, a binary can be constructed + from a set of bound variables:</p> + <code type="none"><![CDATA[ +A = 1, B = 17, C = 42, +Bin2 = <<A, B, C:16>>]]></code> + <p>yields a binary of size 4, and <c>binary_to_list(Bin2)</c> + evaluates to <c>[1, 17, 00, 42]</c> too. Here we used a + <em>size expression</em> for the variable <c>C</c> in order to + specify a 16-bits segment of <c>Bin2</c>.</p> + <p><em>Example 3: </em>A Bin can also be used for matching: if + <c>D</c>, <c>E</c>, and <c>F</c> are unbound variables, and + <c>Bin2</c> is bound as in the former example,</p> + <code type="none"><![CDATA[ +<<D:16, E, F/binary>> = Bin2]]></code> + <p>yields <c>D = 273</c>, <c>E = 00</c>, and F binds to a binary + of size 1: <c>binary_to_list(F) = [42]</c>.</p> + <p><em>Example 4:</em> The following is a more elaborate example + of matching, where <c>Dgram</c> is bound to the consecutive + bytes of an IP datagram of IP protocol version 4, and where we + want to extract the header and the data of the datagram:</p> + <code type="none"><![CDATA[ +-define(IP_VERSION, 4). +-define(IP_MIN_HDR_LEN, 5). + +DgramSize = byte_size(Dgram), +case Dgram of + <<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16, + ID:16, Flgs:3, FragOff:13, + TTL:8, Proto:8, HdrChkSum:16, + SrcIP:32, + DestIP:32, RestDgram/binary>> when HLen>=5, 4*HLen=<DgramSize -> + OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN), + <<Opts:OptsLen/binary,Data/binary>> = RestDgram, + ... +end.]]></code> + <p>Here the segment corresponding to the <c>Opts</c> variable + has a <em>type modifier</em> specifying that <c>Opts</c> should + bind to a binary. All other variables have the default type + equal to unsigned integer.</p> + <p>An IP datagram header is of variable length, and its length - + measured in the number of 32-bit words - is given in + the segment corresponding to <c>HLen</c>, the minimum value of + which is 5. It is the segment corresponding to <c>Opts</c> + that is variable: if <c>HLen</c> is equal to 5, <c>Opts</c> + will be an empty binary.</p> + <p>The tail variables <c>RestDgram</c> and <c>Data</c> bind to + binaries, as all tail variables do. Both may bind to empty + binaries.</p> + <p>If the first 4-bits segment of <c>Dgram</c> is not equal to + 4, or if <c>HLen</c> is less than 5, or if the size of + <c>Dgram</c> is less than <c>4*HLen</c>, the match of + <c>Dgram</c> fails.</p> + </section> + </section> + + <section> + <title>A Lexical Note</title> + <p>Note that "<c><![CDATA[B=<<1>>]]></c>" will be interpreted as + "<c><![CDATA[B =< <1>>]]></c>", which is a syntax error. + The correct way to write the expression is + "<c><![CDATA[B = <<1>>]]></c>".</p> + </section> + + <section> + <title>Segments</title> + <p>Each segment has the following general syntax:</p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>Both the <c>Size</c> and the <c>TypeSpecifier</c> or both may be + omitted; thus the following variations are allowed:</p> + <p><c>Value</c></p> + <p><c>Value:Size</c></p> + <p><c>Value/TypeSpecifierList</c></p> + <p>Default values will be used for missing specifications. + The default values are described in the section + <seealso marker="#Defaults">Defaults</seealso>.</p> + <p>Used in binary construction, the <c>Value</c> part is any + expression. Used in binary matching, the <c>Value</c> part must + be a literal or variable. You can read more about + the <c>Value</c> part in the section about constructing + binaries and matching binaries.</p> + <p>The <c>Size</c> part of the segment multiplied by the unit in + the <c>TypeSpecifierList</c> (described below) gives the number + of bits for the segment. In construction, <c>Size</c> is any + expression that evaluates to an integer. In matching, + <c>Size</c> must be a constant expression or a variable.</p> + <p>The <c>TypeSpecifierList</c> is a list of type specifiers + separated by hyphens.</p> + <taglist> + <tag>Type</tag> + <item>The type can be <c>integer</c>, <c>float</c>, or + <c>binary</c>.</item> + <tag>Signedness</tag> + <item>The signedness specification can be either <c>signed</c> + or <c>unsigned</c>. Note that signedness only matters for + matching.</item> + <tag>Endianness</tag> + <item>The endianness specification can be either <c>big</c>, + <c>little</c>, or <c>native</c>. Native-endian means that + the endian will be resolved at load time to be either + big-endian or little-endian, depending on what is "native" + for the CPU that the Erlang machine is run on.</item> + <tag>Unit</tag> + <item>The unit size is given as <c>unit:IntegerLiteral</c>. + The allowed range is 1-256. It will be multiplied by + the <c>Size</c> specifier to give the effective size of + the segment. In R12B, the unit size specifies the alignment + for binary segments without size (examples will follow).</item> + </taglist> + <p>Example:</p> + <code type="none"> +X:4/little-signed-integer-unit:8</code> + <p>This element has a total size of 4*8 = 32 bits, and it contains + a signed integer in little-endian order.</p> + </section> + + <section> + <title>Defaults</title> + <p><marker id="Defaults"></marker>The default type for a segment is integer. The default + type does not depend on the value, even if the value is a + literal. For instance, the default type in '<c><![CDATA[<<3.14>>]]></c>' is + integer, not float.</p> + <p>The default <c>Size</c> depends on the type. For integer it is + 8. For float it is 64. For binary it is all of the binary. In + matching, this default value is only valid for the very last + element. All other binary elements in matching must have a size + specification.</p> + <p>The default unit depends on the the type. For <c>integer</c>, + <c>float</c>, and <c>bitstring</c> it is 1. For binary it is 8.</p> + <p>The default signedness is <c>unsigned</c>.</p> + <p>The default endianness is <c>big</c>.</p> + </section> + + <section> + <title>Constructing Binaries and Bitstrings</title> + <p>This section describes the rules for constructing binaries using + the bit syntax. Unlike when constructing lists or tuples, + the construction of a binary can fail with a <c>badarg</c> + exception.</p> + <p>There can be zero or more segments in a binary to be + constructed. The expression '<c><![CDATA[<<>>]]></c>' constructs a zero + length binary.</p> + <p>Each segment in a binary can consist of zero or more bits. + There are no alignment rules for individual segments of type + <c>integer</c> and <c>float</c>. For binaries and bitstrings + without size, the unit specifies the alignment. Since the default + alignment for the <c>binary</c> type is 8, the size of a binary + segment must be a multiple of 8 bits (i.e. only whole bytes). + Example:</p> + <code type="none"><![CDATA[ +<<Bin/binary,Bitstring/bitstring>>]]></code> + <p>The variable <c>Bin</c> must contain a whole number of bytes, + because the <c>binary</c> type defaults to <c>unit:8</c>. + A <c>badarg</c> exception will be generated if <c>Bin</c> would + consist of (for instance) 17 bits.</p> + + <p>On the other hand, the variable <c>Bitstring</c> may consist of + any number of bits, for instance 0, 1, 8, 11, 17, 42, and so on, + because the default <c>unit</c> for bitstrings is 1.</p> + + <warning><p>For clarity, it is recommended not to change the unit + size for binaries, but to use <c>binary</c> when you need byte + alignment, and <c>bitstring</c> when you need bit alignment.</p></warning> + + <p>The following example</p> + <code type="none"><![CDATA[ +<<X:1,Y:6>>]]></code> + <p>will successfully construct a bitstring of 7 bits. + (Provided that all of X and Y are integers.)</p> + <p>As noted earlier, segments have the following general syntax:</p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>When constructing binaries, <c>Value</c> and <c>Size</c> can be + any Erlang expression. However, for syntactical reasons, both + <c>Value</c> and <c>Size</c> must be enclosed in parenthesis if + the expression consists of anything more than a single literal + or variable. The following gives a compiler syntax error:</p> + <code type="none"><![CDATA[ +<<X+1:8>>]]></code> + <p>This expression must be rewritten to</p> + <code type="none"><![CDATA[ +<<(X+1):8>>]]></code> + <p>in order to be accepted by the compiler.</p> + + <section> + <title>Including Literal Strings</title> + <p>As syntactic sugar, an literal string may be written instead + of a element.</p> + <code type="none"><![CDATA[ +<<"hello">>]]></code> + <p>which is syntactic sugar for</p> + <code type="none"><![CDATA[ +<<$h,$e,$l,$l,$o>>]]></code> + </section> + </section> + + <section> + <title>Matching Binaries</title> + <p>This section describes the rules for matching binaries using + the bit syntax.</p> + <p>There can be zero or more segments in a binary pattern. + A binary pattern can occur in every place patterns are allowed, + also inside other patterns. Binary patterns cannot be nested.</p> + <p>The pattern '<c><![CDATA[<<>>]]></c>' matches a zero length binary.</p> + <p>Each segment in a binary can consist of zero or more bits.</p> + <p>A segment of type <c>binary</c> must have a size evenly + divisible by 8 (or divisible by the unit size, if the unit size has been changed).</p> + <p>A segment of type <c>bitstring</c> has no restrictions on the size.</p> + <p>As noted earlier, segments have the following general syntax:</p> + <p><c>Value:Size/TypeSpecifierList</c></p> + <p>When matching <c>Value</c> value must be either a variable or + an integer or floating point literal. Expressions are not + allowed.</p> + <p><c>Size</c> must be an integer literal, or a previously bound + variable. Note that the following is not allowed:</p> + <code type="none"><![CDATA[ +foo(N, <<X:N,T/binary>>) -> + {X,T}.]]></code> + <p>The two occurrences of <c>N</c> are not related. The compiler + will complain that the <c>N</c> in the size field is unbound.</p> + <p>The correct way to write this example is like this:</p> + <code type="none"><![CDATA[ +foo(N, Bin) -> + <<X:N,T/binary>> = Bin, + {X,T}.]]></code> + + <section> + <title>Getting the Rest of the Binary or Bitstring</title> + <p>To match out the rest of a binary, specify a binary field + without size:</p> + <code type="none"><![CDATA[ +foo(<<A:8,Rest/binary>>) ->]]></code> + <p>The size of the tail must be evenly divisible by 8.</p> + + <p>To match out the rest of a bitstring, specify a field + without size:</p> + <code type="none"><![CDATA[ +foo(<<A:8,Rest/bitstring>>) ->]]></code> + <p>There is no restriction on the number of bits in the tail.</p> + </section> + </section> + + <section> + <title>Appending to a Binary</title> + <p>In R12B, the following function for creating a binary out of + a list of triples of integers is now efficient:</p> + <code type="none"><![CDATA[ +triples_to_bin(T) -> + triples_to_bin(T, <<>>). + +triples_to_bin([{X,Y,Z} | T], Acc) -> + triples_to_bin(T, <<Acc/binary,X:32,Y:32,Z:32>>); % inefficient before R12B +triples_to_bin([], Acc) -> + Acc.]]></code> + <p>In previous releases, this function was highly inefficient, because + the binary constructed so far (<c>Acc</c>) was copied in each recursion step. + That is no longer the case. See the Efficiency Guide for more information.</p> + </section> +</chapter> + diff --git a/system/doc/programming_examples/book.xml b/system/doc/programming_examples/book.xml new file mode 100644 index 0000000000..91346ceea4 --- /dev/null +++ b/system/doc/programming_examples/book.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Programming Examples</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <pagetext>Programming Examples</pagetext> + <preamble> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> +</book> + diff --git a/system/doc/programming_examples/fun_test.erl b/system/doc/programming_examples/fun_test.erl new file mode 100644 index 0000000000..8472fd87f8 --- /dev/null +++ b/system/doc/programming_examples/fun_test.erl @@ -0,0 +1,17 @@ +%1 +-module(fun_test). +-export([t1/0, t2/0, t3/0, t4/0, double/1]). +-import(lists, [map/2]). + +t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]). + +t2() -> map(fun double/1, [1,2,3,4,5]). + +t3() -> map({?MODULE, double}, [1,2,3,4,5]). + +double(X) -> X * 2. +%1 + + +t4() -> + "hello world". diff --git a/system/doc/programming_examples/funparse.erl b/system/doc/programming_examples/funparse.erl new file mode 100644 index 0000000000..5e23c90df9 --- /dev/null +++ b/system/doc/programming_examples/funparse.erl @@ -0,0 +1,74 @@ +-module(funparse). +-compile(export_all). +-import(lists, [reverse/1]). + +%17 +%% > hof:parse([a,c]). +%% {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} +%% > hof:parse([a,d]). +%% {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} +%% > hof:parse([b,c]). +%% {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} +%% > hof:parse([b,d]). +%% {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} +%% > hof:parse([a,b]). +%% fail +%17 + +%% Grammar = (a | b) & (c | d) + +%12 +parse(List) -> + (grammar())(List). +%12 + +%13 +grammar() -> + pand( + por(pconst(a), pconst(b)), + por(pconst(c), pconst(d))). +%13 + +%14 +pconst(X) -> + fun (T) -> + case T of + [X|T1] -> {ok, {const, X}, T1}; + _ -> fail + end + end. +%14 + +%15 +por(P1, P2) -> + fun (T) -> + case P1(T) of + {ok, R, T1} -> + {ok, {'or',1,R}, T1}; + fail -> + case P2(T) of + {ok, R1, T1} -> + {ok, {'or',2,R1}, T1}; + fail -> + fail + end + end + end. +%15 + +%16 +pand(P1, P2) -> + fun (T) -> + case P1(T) of + {ok, R1, T1} -> + case P2(T1) of + {ok, R2, T2} -> + {ok, {'and', R1, R2}}; + fail -> + fail + end; + fail -> + fail + end + end. +%16 diff --git a/system/doc/programming_examples/funs.xmlsrc b/system/doc/programming_examples/funs.xmlsrc new file mode 100644 index 0000000000..92f99cf6d3 --- /dev/null +++ b/system/doc/programming_examples/funs.xmlsrc @@ -0,0 +1,515 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Funs</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>funs.xml</file> + </header> + + <section> + <title>Example 1 - map</title> + <p>If we want to double every element in a list, we could write a + function named <c>double</c>:</p> + <code type="none"> +double([H|T]) -> [2*H|double(T)]; +double([]) -> [].</code> + <p>This function obviously doubles the argument entered as input + as follows:</p> + <pre> +> <input>double([1,2,3,4]).</input> +[2,4,6,8]</pre> + <p>We now add the function <c>add_one</c>, which adds one to every + element in a list:</p> + <code type="none"> +add_one([H|T]) -> [H+1|add_one(T)]; +add_one([]) -> [].</code> + <p>These functions, <c>double</c> and <c>add_one</c>, have a very + similar structure. We can exploit this fact and write a function + <c>map</c> which expresses this similarity:</p> + <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> + <p>We can now express the functions <c>double</c> and + <c>add_one</c> in terms of <c>map</c> as follows:</p> + <code type="none"> +double(L) -> map(fun(X) -> 2*X end, L). +add_one(L) -> map(fun(X) -> 1 + X end, L).</code> + <p><c>map(F, List)</c> is a function which takes a function + <c>F</c> and a list <c>L</c> as arguments and returns the new + list which is obtained by applying <c>F</c> to each of + the elements in <c>L</c>.</p> + <p>The process of abstracting out the common features of a number + of different programs is called procedural abstraction. + Procedural abstraction can be used in order to write several + different functions which have a similar structure, but differ + only in some minor detail. This is done as follows:</p> + <list type="ordered"> + <item>write one function which represents the common features of + these functions</item> + <item>parameterize the difference in terms of functions which + are passed as arguments to the common function.</item> + </list> + </section> + + <section> + <title>Example 2 - foreach</title> + <p>This example illustrates procedural abstraction. Initially, we + show the following two examples written as conventional + functions:</p> + <list type="ordered"> + <item>all elements of a list are printed onto a stream</item> + <item>a message is broadcast to a list of processes.</item> + </list> + <code type="none"> +print_list(Stream, [H|T]) -> + io:format(Stream, "~p~n", [H]), + print_list(Stream, T); +print_list(Stream, []) -> + true.</code> + <code type="none"> +broadcast(Msg, [Pid|Pids]) -> + Pid ! Msg, + broadcast(Msg, Pids); +broadcast(_, []) -> + true.</code> + <p>Both these functions have a very similar structure. They both + iterate over a list doing something to each element in the list. + The "something" has to be carried round as an extra argument to + the function which does this.</p> + <p>The function <c>foreach</c> expresses this similarity:</p> + <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> + <p>Using <c>foreach</c>, <c>print_list</c> becomes:</p> + <code type="none"> +foreach(fun(H) -> io:format(S, "~p~n",[H]) end, L)</code> + <p><c>broadcast</c> becomes:</p> + <code type="none"> +foreach(fun(Pid) -> Pid ! M end, L)</code> + <p><c>foreach</c> is evaluated for its side-effect and not its + value. <c>foreach(Fun ,L)</c> calls <c>Fun(X)</c> for each + element <c>X</c> in <c>L</c> and the processing occurs in + the order in which the elements were defined in <c>L</c>. + <c>map</c> does not define the order in which its elements are + processed.</p> + </section> + + <section> + <title>The Syntax of Funs</title> + <p>Funs are written with the syntax:</p> + <code type="none"> +F = fun (Arg1, Arg2, ... ArgN) -> + ... + end</code> + <p>This creates an anonymous function of <c>N</c> arguments and + binds it to the variable <c>F</c>.</p> + <p>If we have already written a function in the same module and + wish to pass this function as an argument, we can use + the following syntax:</p> + <code type="none"> +F = fun FunctionName/Arity</code> + <p>With this form of function reference, the function which is + referred to does not need to be exported from the module.</p> + <p>We can also refer to a function defined in a different module + with the following syntax:</p> + <code type="none"> +F = {Module, FunctionName}</code> + <p>In this case, the function must be exported from the module in + question.</p> + <p>The follow program illustrates the different ways of creating + funs:</p> + <codeinclude file="fun_test.erl" tag="%1" type="erl"></codeinclude> + <p>We can evaluate the fun <c>F</c> with the syntax:</p> + <code type="none"> +F(Arg1, Arg2, ..., Argn)</code> + <p>To check whether a term is a fun, use the test + <c>is_function/1</c> in a guard. Example:</p> + <code type="none"> +f(F, Args) when is_function(F) -> + apply(F, Args); +f(N, _) when is_integer(N) -> + N.</code> + <p>Funs are a distinct type. The BIFs erlang:fun_info/1,2 can + be used to retrieve information about a fun, and the BIF + erlang:fun_to_list/1 returns a textual representation of a fun. + The check_process_code/2 BIF returns true if the process + contains funs that depend on the old version of a module.</p> + <note> + <p>In OTP R5 and earlier releases, funs were represented using + tuples.</p> + </note> + </section> + + <section> + <title>Variable Bindings Within a Fun</title> + <p>The scope rules for variables which occur in funs are as + follows:</p> + <list type="bulleted"> + <item>All variables which occur in the head of a fun are assumed + to be "fresh" variables.</item> + <item>Variables which are defined before the fun, and which + occur in function calls or guard tests within the fun, have + the values they had outside the fun.</item> + <item>No variables may be exported from a fun.</item> + </list> + <p>The following examples illustrate these rules:</p> + <code type="none"> +print_list(File, List) -> + {ok, Stream} = file:open(File, write), + foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List), + file:close(Stream).</code> + <p>In the above example, the variable <c>X</c> which is defined in + the head of the fun is a new variable. The value of the variable + <c>Stream</c> which is used within within the fun gets its value + from the <c>file:open</c> line.</p> + <p>Since any variable which occurs in the head of a fun is + considered a new variable it would be equally valid to write:</p> + <code type="none"> +print_list(File, List) -> + {ok, Stream} = file:open(File, write), + foreach(fun(File) -> + io:format(Stream,"~p~n",[File]) + end, List), + file:close(Stream).</code> + <p>In this example, <c>File</c> is used as the new variable + instead of <c>X</c>. This is rather silly since code in the body + of the fun cannot refer to the variable <c>File</c> which is + defined outside the fun. Compiling this example will yield + the diagnostic:</p> + <code type="none"> +./FileName.erl:Line: Warning: variable 'File' + shadowed in 'lambda head'</code> + <p>This reminds us that the variable <c>File</c> which is defined + inside the fun collides with the variable <c>File</c> which is + defined outside the fun.</p> + <p>The rules for importing variables into a fun has the consequence + that certain pattern matching operations have to be moved into + guard expressions and cannot be written in the head of the fun. + For example, we might write the following code if we intend + the first clause of <c>F</c> to be evaluated when the value of + its argument is <c>Y</c>:</p> + <code type="none"> +f(...) -> + Y = ... + map(fun(X) when X == Y -> + ; + (_) -> + ... + end, ...) + ...</code> + <p>instead of</p> + <code type="none"> +f(...) -> + Y = ... + map(fun(Y) -> + ; + (_) -> + ... + end, ...) + ...</code> + </section> + + <section> + <title>Funs and the Module Lists</title> + <p>The following examples show a dialogue with the Erlang shell. + All the higher order functions discussed are exported from + the module <c>lists</c>.</p> + + <section> + <title>map</title> + <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> + <p><c>map</c> takes a function of one argument and a list of + terms. It returns the list obtained by applying the function + to every argument in the list.</p> + <pre> +> <input>Double = fun(X) -> 2 * X end.</input> +#Fun<erl_eval.6.72228031> +> <input>lists:map(Double, [1,2,3,4,5]).</input> +[2,4,6,8,10]</pre> + <p>When a new fun is defined in the shell, the value of the Fun + is printed as <c><![CDATA[Fun#<erl_eval>]]></c>.</p> + </section> + + <section> + <title>any</title> + <codeinclude file="funs1.erl" tag="%4" type="erl"></codeinclude> + <p><c>any</c> takes a predicate <c>P</c> of one argument and a + list of terms. A predicate is a function which returns + <c>true</c> or <c>false</c>. <c>any</c> is true if there is a + term <c>X</c> in the list such that <c>P(X)</c> is <c>true</c>.</p> + <p>We define a predicate <c>Big(X)</c> which is <c>true</c> if + its argument is greater that 10.</p> + <pre> +> <input>Big = fun(X) -> if X > 10 -> true; true -> false end end.</input> +#Fun<erl_eval.6.72228031> +> <input>lists:any(Big, [1,2,3,4]).</input> +false +> <input>lists:any(Big, [1,2,3,12,5]).</input> +true</pre> + </section> + + <section> + <title>all</title> + <codeinclude file="funs1.erl" tag="%3" type="erl"></codeinclude> + <p><c>all</c> has the same arguments as <c>any</c>. It is true + if the predicate applied to all elements in the list is true.</p> + <pre> +> <input>lists:all(Big, [1,2,3,4,12,6]).</input> +false +> <input>lists:all(Big, [12,13,14,15]).</input> +true</pre> + </section> + + <section> + <title>foreach</title> + <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> + <p><c>foreach</c> takes a function of one argument and a list of + terms. The function is applied to each argument in the list. + <c>foreach</c> returns <c>ok</c>. It is used for its + side-effect only.</p> + <pre> +> <input>lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]).</input> +1 +2 +3 +4 +ok</pre> + </section> + + <section> + <title>foldl</title> + <codeinclude file="funs1.erl" tag="%8" type="erl"></codeinclude> + <p><c>foldl</c> takes a function of two arguments, an + accumulator and a list. The function is called with two + arguments. The first argument is the successive elements in + the list, the second argument is the accumulator. The function + must return a new accumulator which is used the next time + the function is called.</p> + <p>If we have a list of lists <c>L = ["I","like","Erlang"]</c>, + then we can sum the lengths of all the strings in <c>L</c> as + follows:</p> + <pre> +> <input>L = ["I","like","Erlang"].</input> +["I","like","Erlang"] +10> <input>lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L).</input> +11</pre> + <p><c>foldl</c> works like a <c>while</c> loop in an imperative + language:</p> + <code type="none"> +L = ["I","like","Erlang"], +Sum = 0, +while( L != []){ + Sum += length(head(L)), + L = tail(L) +end</code> + </section> + + <section> + <title>mapfoldl</title> + <codeinclude file="funs1.erl" tag="%10" type="erl"></codeinclude> + <p><c>mapfoldl</c> simultaneously maps and folds over a list. + The following example shows how to change all letters in + <c>L</c> to upper case and count them.</p> + <p>First upcase:</p> + <pre> +> <input>Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a;</input> +<input>(X) -> X</input> +<input>end.</input> +#Fun<erl_eval.6.72228031> +> <input>Upcase_word =</input> +<input>fun(X) -></input> +<input>lists:map(Upcase, X)</input> +<input>end.</input> +#Fun<erl_eval.6.72228031> +> <input>Upcase_word("Erlang").</input> +"ERLANG" +> <input>lists:map(Upcase_word, L).</input> +["I","LIKE","ERLANG"]</pre> + <p>Now we can do the fold and the map at the same time:</p> + <pre> +> <input>lists:mapfoldl(fun(Word, Sum) -></input> +<input>{Upcase_word(Word), Sum + length(Word)}</input> +<input>end, 0, L).</input> +{["I","LIKE","ERLANG"],11}</pre> + </section> + + <section> + <title>filter</title> + <codeinclude file="funs1.erl" tag="%9" type="erl"></codeinclude> + <p><c>filter</c> takes a predicate of one argument and a list + and returns all element in the list which satisfy + the predicate.</p> + <pre> +> <input>lists:filter(Big, [500,12,2,45,6,7]).</input> +[500,12,45]</pre> + <p>When we combine maps and filters we can write very succinct + code. For example, suppose we want to define a set difference + function. We want to define <c>diff(L1, L2)</c> to be + the difference between the lists <c>L1</c> and <c>L2</c>. + This is the list of all elements in L1 which are not contained + in L2. This code can be written as follows:</p> + <code type="none"> +diff(L1, L2) -> + filter(fun(X) -> not member(X, L2) end, L1).</code> + <p>The AND intersection of the list <c>L1</c> and <c>L2</c> is + also easily defined:</p> + <code type="none"> +intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2).</code> + </section> + + <section> + <title>takewhile</title> + <codeinclude file="funs1.erl" tag="%5" type="erl"></codeinclude> + <p><c>takewhile(P, L)</c> takes elements <c>X</c> from a list + <c>L</c> as long as the predicate <c>P(X)</c> is true.</p> + <pre> +> <input>lists:takewhile(Big, [200,500,45,5,3,45,6]).</input> +[200,500,45]</pre> + </section> + + <section> + <title>dropwhile</title> + <codeinclude file="funs1.erl" tag="%6" type="erl"></codeinclude> + <p><c>dropwhile</c> is the complement of <c>takewhile</c>.</p> + <pre> +> <input>lists:dropwhile(Big, [200,500,45,5,3,45,6]).</input> +[5,3,45,6]</pre> + </section> + + <section> + <title>splitwith</title> + <codeinclude file="funs1.erl" tag="%7" type="erl"></codeinclude> + <p><c>splitwith(P, L)</c> splits the list <c>L</c> into the two + sub-lists <c>{L1, L2}</c>, where <c>L = takewhile(P, L)</c> + and <c>L2 = dropwhile(P, L)</c>.</p> + <pre> +> <input>lists:splitwith(Big, [200,500,45,5,3,45,6]).</input> +{[200,500,45],[5,3,45,6]}</pre> + </section> + </section> + + <section> + <title>Funs Which Return Funs</title> + <p>So far, this section has only described functions which take + funs as arguments. It is also possible to write more powerful + functions which themselves return funs. The following examples + illustrate these type of functions.</p> + + <section> + <title>Simple Higher Order Functions</title> + <p><c>Adder(X)</c> is a function which, given <c>X</c>, returns + a new function <c>G</c> such that <c>G(K)</c> returns + <c>K + X</c>.</p> + <pre> +> <input>Adder = fun(X) -> fun(Y) -> X + Y end end.</input> +#Fun<erl_eval.6.72228031> +> <input>Add6 = Adder(6).</input> +#Fun<erl_eval.6.72228031> +> <input>Add6(10).</input> +16</pre> + </section> + + <section> + <title>Infinite Lists</title> + <p>The idea is to write something like:</p> + <code type="none"> +-module(lazy). +-export([ints_from/1]). +ints_from(N) -> + fun() -> + [N|ints_from(N+1)] + end.</code> + <p>Then we can proceed as follows:</p> + <pre> +> <input>XX = lazy:ints_from(1).</input> +#Fun<lazy.0.29874839> +> <input>XX().</input> +[1|#Fun<lazy.0.29874839>] +> <input>hd(XX()).</input> +1 +> <input>Y = tl(XX()).</input> +#Fun<lazy.0.29874839> +> <input>hd(Y()).</input> +2</pre> + <p>etc. - this is an example of "lazy embedding".</p> + </section> + + <section> + <title>Parsing</title> + <p>The following examples show parsers of the following type:</p> + <pre> +Parser(Toks) -> {ok, Tree, Toks1} | fail</pre> + <p><c>Toks</c> is the list of tokens to be parsed. A successful + parse returns <c>{ok, Tree, Toks1}</c>, where <c>Tree</c> is a + parse tree and <c>Toks1</c> is a tail of <c>Tree</c> which + contains symbols encountered after the structure which was + correctly parsed. Otherwise <c>fail</c> is returned.</p> + <p>The example which follows illustrates a simple, functional + parser which parses the grammar:</p> + <pre> +(a | b) & (c | d)</pre> + <p>The following code defines a function <c>pconst(X)</c> in + the module <c>funparse</c>, which returns a fun which parses a + list of tokens.</p> + <codeinclude file="funparse.erl" tag="%14" type="erl"></codeinclude> + <p>This function can be used as follows:</p> + <pre> +> <input>P1 = funparse:pconst(a).</input> +#Fun<funparse.0.22674075> +> <input>P1([a,b,c]).</input> +{ok,{const,a},[b,c]} +> <input>P1([x,y,z]).</input> +fail</pre> + <p>Next, we define the two higher order functions <c>pand</c> + and <c>por</c> which combine primitive parsers to produce more + complex parsers. Firstly <c>pand</c>:</p> + <codeinclude file="funparse.erl" tag="%16" type="erl"></codeinclude> + <p>Given a parser <c>P1</c> for grammar <c>G1</c>, and a parser + <c>P2</c> for grammar <c>G2</c>, <c>pand(P1, P2)</c> returns a + parser for the grammar which consists of sequences of tokens + which satisfy <c>G1</c> followed by sequences of tokens which + satisfy <c>G2</c>.</p> + <p><c>por(P1, P2)</c> returns a parser for the language + described by the grammar <c>G1</c> or <c>G2</c>.</p> + <codeinclude file="funparse.erl" tag="%15" type="erl"></codeinclude> + <p>The original problem was to parse the grammar + <c><![CDATA[(a | b) & (c | d)]]></c>. The following code addresses this + problem:</p> + <codeinclude file="funparse.erl" tag="%13" type="erl"></codeinclude> + <p>The following code adds a parser interface to the grammar:</p> + <codeinclude file="funparse.erl" tag="%12" type="erl"></codeinclude> + <p>We can test this parser as follows:</p> + <pre> +> <input>funparse:parse([a,c]).</input> +{ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} +> <input>funparse:parse([a,d]).</input> +{ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} +> <input>funparse:parse([b,c]).</input> +{ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} +> <input>funparse:parse([b,d]).</input> +{ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} +> <input>funparse:parse([a,b]).</input> +fail</pre> + </section> + </section> +</chapter> + diff --git a/system/doc/programming_examples/funs1.erl b/system/doc/programming_examples/funs1.erl new file mode 100644 index 0000000000..8cf20378ea --- /dev/null +++ b/system/doc/programming_examples/funs1.erl @@ -0,0 +1,125 @@ +-module(funs1). +-compile(export_all). +-import(lists, [reverse/1]). + +%1 +map(F, [H|T]) -> [F(H)|map(F, T)]; +map(F, []) -> []. +%1 + +%2 +foreach(F, [H|T]) -> + F(H), + foreach(F, T); +foreach(F, []) -> + ok. +%2 +% +%3 +all(Pred, [H|T]) -> + case Pred(H) of + true -> all(Pred, T); + false -> false + end; +all(Pred, []) -> + true. +%3 +%4 +any(Pred, [H|T]) -> + case Pred(H) of + true -> true; + false -> any(Pred, T) + end; +any(Pred, []) -> + false. +%4 +%5 +takewhile(Pred, [H|T]) -> + case Pred(H) of + true -> [H|takewhile(Pred, T)]; + false -> [] + end; +takewhile(Pred, []) -> + []. +%5 +%6 +dropwhile(Pred, [H|T]) -> + case Pred(H) of + true -> dropwhile(Pred, T); + false -> [H|T] + end; +dropwhile(Pred, []) -> + []. +%6 +%7 +splitwith(Pred, L) -> + splitwith(Pred, L, []). + +splitwith(Pred, [H|T], L) -> + case Pred(H) of + true -> splitwith(Pred, T, [H|L]); + false -> {reverse(L), [H|T]} + end; +splitwith(Pred, [], L) -> + {reverse(L), []}. +%7 + +flatmap(F, [Hd|Tail]) -> + F(Hd) ++ flatmap(F, Tail); +flatmap(F, []) -> []. + +%8 +foldl(F, Accu, [Hd|Tail]) -> + foldl(F, F(Hd, Accu), Tail); +foldl(F, Accu, []) -> Accu. +%8 +% +foldr(F, Accu, [Hd|Tail]) -> + F(Hd, foldr(F, Accu, Tail)); +foldr(F, Accu, []) -> Accu. +%9 +filter(F, [H|T]) -> + case F(H) of + true -> [H|filter(F, T)]; + false -> filter(F, T) + end; +filter(F, []) -> []. +%9 +%10 +mapfoldl(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl(F, Accu1, Tail), + {[R|Rs], Accu2}; +mapfoldl(F, Accu, []) -> {[], Accu}. +%10 +mapfoldr(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr(F, Accu, []) -> {[], Accu}. +%11 +first(Pred, [H|T]) -> + case Pred(H) of + true -> + {true, H}; + false -> + first(Pred, T) + end; +first(Pred, []) -> + false. +%11 +% +compose(F, G) -> + fun(X) -> + F(G(X)) + end. + +%20 +iterate(N, F) -> + iterate(N, N+1, F). + +iterate(Stop, Stop, _) -> + []; +iterate(N, Stop, Fun) -> + [Fun(N)|iterate(N+1, Stop, Fun)]. +%20 diff --git a/system/doc/programming_examples/list_comprehensions.xml b/system/doc/programming_examples/list_comprehensions.xml new file mode 100644 index 0000000000..825459238b --- /dev/null +++ b/system/doc/programming_examples/list_comprehensions.xml @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>List Comprehensions</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>list_comprehensions.xml</file> + </header> + + <section> + <title>Simple Examples</title> + <p>We start with a simple example:</p> + <pre> +> <input>[X || X <- [1,2,a,3,4,b,5,6], X > 3].</input> +[a,4,b,5,6]</pre> + <p>This should be read as follows:</p> + <quote> + <p>The list of X such that X is taken from the list + <c>[1,2,a,...]</c> and X is greater than 3.</p> + </quote> + <p>The notation <c><![CDATA[X <- [1,2,a,...]]]></c> is a generator and + the expression <c>X > 3</c> is a filter.</p> + <p>An additional filter can be added in order to restrict + the result to integers:</p> + <pre> +> <input>[X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3].</input> +[4,5,6]</pre> + <p>Generators can be combined. For example, the Cartesian product + of two lists can be written as follows:</p> + <pre> +> <input>[{X, Y} || X <- [1,2,3], Y <- [a,b]].</input> +[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}]</pre> + </section> + + <section> + <title>Quick Sort</title> + <p>The well known quick sort routine can be written as follows:</p> + <code type="none"><![CDATA[ +sort([Pivot|T]) -> + sort([ X || X <- T, X < Pivot]) ++ + [Pivot] ++ + sort([ X || X <- T, X >= Pivot]); +sort([]) -> [].]]></code> + <p>The expression <c><![CDATA[[X || X <- T, X < Pivot]]]></c> is the list of + all elements in <c>T</c>, which are less than <c>Pivot</c>.</p> + <p><c><![CDATA[[X || X <- T, X >= Pivot]]]></c> is the list of all elements in + <c>T</c>, which are greater or equal to <c>Pivot</c>.</p> + <p>To sort a list, we isolate the first element in the list and + split the list into two sub-lists. The first sub-list contains + all elements which are smaller than the first element in + the list, the second contains all elements which are greater + than or equal to the first element in the list. We then sort + the sub-lists and combine the results.</p> + </section> + + <section> + <title>Permutations</title> + <p>The following example generates all permutations of + the elements in a list:</p> + <code type="none"><![CDATA[ +perms([]) -> [[]]; +perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].]]></code> + <p>We take take <c>H</c> from <c>L</c> in all possible ways. + The result is the set of all lists <c>[H|T]</c>, where <c>T</c> + is the set of all possible permutations of <c>L</c> with + <c>H</c> removed.</p> + <pre> +> <input>perms([b,u,g]).</input> +[[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]]</pre> + </section> + + <section> + <title>Pythagorean Triplets</title> + <p>Pythagorean triplets are sets of integers <c>{A,B,C}</c> such + that <c>A**2 + B**2 = C**2</c>.</p> + <p>The function <c>pyth(N)</c> generates a list of all integers + <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c> and where + the sum of the sides is equal to or less than <c>N</c>.</p> + <code type="none"><![CDATA[ +pyth(N) -> + [ {A,B,C} || + A <- lists:seq(1,N), + B <- lists:seq(1,N), + C <- lists:seq(1,N), + A+B+C =< N, + A*A+B*B == C*C + ].]]></code> + <pre> +> <input>pyth(3).</input> +[]. +> <input>pyth(11).</input> +[]. +> <input>pyth(12).</input> +[{3,4,5},{4,3,5}] +> <input>pyth(50).</input> +[{3,4,5}, + {4,3,5}, + {5,12,13}, + {6,8,10}, + {8,6,10}, + {8,15,17}, + {9,12,15}, + {12,5,13}, + {12,9,15}, + {12,16,20}, + {15,8,17}, + {16,12,20}]</pre> + <p>The following code reduces the search space and is more + efficient:</p> + <code type="none"><![CDATA[ +pyth1(N) -> + [{A,B,C} || + A <- lists:seq(1,N-2), + B <- lists:seq(A+1,N-1), + C <- lists:seq(B+1,N), + A+B+C =< N, + A*A+B*B == C*C ].]]></code> + </section> + + <section> + <title>Simplifications with List Comprehensions</title> + <p>As an example, list comprehensions can be used to simplify some + of the functions in <c>lists.erl</c>:</p> + <code type="none"><![CDATA[ +append(L) -> [X || L1 <- L, X <- L1]. +map(Fun, L) -> [Fun(X) || X <- L]. +filter(Pred, L) -> [X || X <- L, Pred(X)].]]></code> + </section> + + <section> + <title>Variable Bindings in List Comprehensions</title> + <p>The scope rules for variables which occur in list + comprehensions are as follows:</p> + <list type="bulleted"> + <item>all variables which occur in a generator pattern are + assumed to be "fresh" variables</item> + <item>any variables which are defined before the list + comprehension and which are used in filters have the values + they had before the list comprehension</item> + <item>no variables may be exported from a list comprehension.</item> + </list> + <p>As an example of these rules, suppose we want to write + the function <c>select</c>, which selects certain elements from + a list of tuples. We might write + <c><![CDATA[select(X, L) -> [Y || {X, Y} <- L].]]></c> with the intention + of extracting all tuples from <c>L</c> where the first item is + <c>X</c>.</p> + <p>Compiling this yields the following diagnostic:</p> + <code type="none"> +./FileName.erl:Line: Warning: variable 'X' shadowed in generate</code> + <p>This diagnostic warns us that the variable <c>X</c> in + the pattern is not the same variable as the variable <c>X</c> + which occurs in the function head.</p> + <p>Evaluating <c>select</c> yields the following result:</p> + <pre> +> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> +[1,2,3,7]</pre> + <p>This result is not what we wanted. To achieve the desired + effect we must write <c>select</c> as follows:</p> + <code type="none"><![CDATA[ +select(X, L) -> [Y || {X1, Y} <- L, X == X1].]]></code> + <p>The generator now contains unbound variables and the test has + been moved into the filter. This now works as expected:</p> + <pre> +> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> +[2,7]</pre> + <p>One consequence of the rules for importing variables into a + list comprehensions is that certain pattern matching operations + have to be moved into the filters and cannot be written directly + in the generators. To illustrate this, do not write as follows:</p> + <code type="none"><![CDATA[ +f(...) -> + Y = ... + [ Expression || PatternInvolving Y <- Expr, ...] + ...]]></code> + <p>Instead, write as follows:</p> + <code type="none"><![CDATA[ +f(...) -> + Y = ... + [ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...] + ...]]></code> + </section> +</chapter> + diff --git a/system/doc/programming_examples/make.dep b/system/doc/programming_examples/make.dep new file mode 100644 index 0000000000..b0655f56b3 --- /dev/null +++ b/system/doc/programming_examples/make.dep @@ -0,0 +1,20 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: bit_syntax.tex book.tex funs.tex list_comprehensions.tex \ + part.tex records.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +funs.tex: fun_test.erl funparse.erl funs1.erl + diff --git a/system/doc/programming_examples/part.xml b/system/doc/programming_examples/part.xml new file mode 100644 index 0000000000..5b22ddf82f --- /dev/null +++ b/system/doc/programming_examples/part.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Programming Examples</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>This chapter contains examples on using records, funs, list + comprehensions and the bit syntax.</p> + </description> + <xi:include href="records.xml"/> + <xi:include href="funs.xml"/> + <xi:include href="list_comprehensions.xml"/> + <xi:include href="bit_syntax.xml"/> +</part> + diff --git a/system/doc/programming_examples/records.xml b/system/doc/programming_examples/records.xml new file mode 100644 index 0000000000..2f2434f11c --- /dev/null +++ b/system/doc/programming_examples/records.xml @@ -0,0 +1,232 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Records</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>records.xml</file> + </header> + + <section> + <title>Records vs Tuples</title> + <p>The main advantage of using records instead of tuples is that + fields in a record are accessed by name, whereas fields in a + tuple are accessed by position. To illustrate these differences, + suppose that we want to represent a person with the tuple + <c>{Name, Address, Phone}</c>.</p> + <p>We must remember that the <c>Name</c> field is the first + element of the tuple, the <c>Address</c> field is the second + element, and so on, in order to write functions which manipulate + this data. For example, to extract data from a variable <c>P</c> + which contains such a tuple we might write the following code + and then use pattern matching to extract the relevant fields.</p> + <code type="none"> +Name = element(1, P), +Address = element(2, P), +...</code> + <p>Code like this is difficult to read and understand and errors + occur if we get the numbering of the elements in the tuple wrong. + If we change the data representation by re-ordering the fields, + or by adding or removing a field, then all references to + the person tuple, wherever they occur, must be checked and + possibly modified.</p> + <p>Records allow us to refer to the fields by name and not + position. We use a record instead of a tuple to store the data. + If we write a record definition of the type shown below, we can + then refer to the fields of the record by name.</p> + <code type="none"> +-record(person, {name, phone, address}).</code> + <p>For example, if <c>P</c> is now a variable whose value is a + <c>person</c> record, we can code as follows in order to access + the name and address fields of the records.</p> + <code type="none"> +Name = P#person.name, +Address = P#person.address, +...</code> + <p>Internally, records are represented using tagged tuples:</p> + <code type="none"> +{person, Name, Phone, Address}</code> + </section> + + <section> + <title>Defining a Record</title> + <p>This definition of a person will be used in many of + the examples which follow. It contains three fields, <c>name</c>, + <c>phone</c> and <c>address</c>. The default values for + <c>name</c> and <c>phone</c> is "" and [], respectively. + The default value for <c>address</c> is the atom + <c>undefined</c>, since no default value is supplied for this + field:</p> + <pre> +-record(person, {name = "", phone = [], address}).</pre> + <p>We have to define the record in the shell in order to be able + use the record syntax in the examples:</p> + <pre> +> <input>rd(person, {name = "", phone = [], address}).</input> +person</pre> + <p>This is due to the fact that record definitions are available + at compile time only, not at runtime. See <c>shell(3)</c> for + details on records in the shell. + </p> + </section> + + <section> + <title>Creating a Record</title> + <p>A new <c>person</c> record is created as follows:</p> + <pre> +> <input>#person{phone=[0,8,2,3,4,3,1,2], name="Robert"}.</input> +#person{name = "Robert",phone = [0,8,2,3,4,3,1,2],address = undefined}</pre> + <p>Since the <c>address</c> field was omitted, its default value + is used.</p> + <p>There is a new feature introduced in Erlang 5.1/OTP R8B, + with which you can set a value to all fields in a record, + overriding the defaults in the record specification. The special + field <c>_</c>, means "all fields not explicitly specified".</p> + <pre> +> <input>#person{name = "Jakob", _ = '_'}.</input> +#person{name = "Jakob",phone = '_',address = '_'}</pre> + <p>It is primarily intended to be used in <c>ets:match/2</c> and + <c>mnesia:match_object/3</c>, to set record fields to the atom + <c>'_'</c>. (This is a wildcard in <c>ets:match/2</c>.)</p> + </section> + + <section> + <title>Accessing a Record Field</title> + <pre> +> <input>P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.</input> +#person{name = "Joe",phone = [0,8,2,3,4,3,1,2],address = undefined} +> <input>P#person.name.</input> +"Joe"</pre> + </section> + + <section> + <title>Updating a Record</title> + <pre> +> <input>P1 = #person{name="Joe", phone=[1,2,3], address="A street"}.</input> +#person{name = "Joe",phone = [1,2,3],address = "A street"} +> <input>P2 = P1#person{name="Robert"}.</input> +#person{name = "Robert",phone = [1,2,3],address = "A street"}</pre> + </section> + + <section> + <title>Type Testing</title> + <p>The following example shows that the guard succeeds if + <c>P</c> is record of type <c>person</c>.</p> + <pre> +foo(P) when is_record(P, person) -> a_person; +foo(_) -> not_a_person.</pre> + </section> + + <section> + <title>Pattern Matching</title> + <p>Matching can be used in combination with records as shown in + the following example:</p> + <pre> +> <input>P3 = #person{name="Joe", phone=[0,0,7], address="A street"}.</input> +#person{name = "Joe",phone = [0,0,7],address = "A street"} +> <input>#person{name = Name} = P3, Name.</input> +"Joe"</pre> + <p>The following function takes a list of <c>person</c> records + and searches for the phone number of a person with a particular + name:</p> + <code type="none"> +find_phone([#person{name=Name, phone=Phone} | _], Name) -> + {found, Phone}; +find_phone([_| T], Name) -> + find_phone(T, Name); +find_phone([], Name) -> + not_found.</code> + <p>The fields referred to in the pattern can be given in any order.</p> + </section> + + <section> + <title>Nested Records</title> + <p>The value of a field in a record might be an instance of a + record. Retrieval of nested data can be done stepwise, or in a + single step, as shown in the following example:</p> + <pre> +-record(name, {first = "Robert", last = "Ericsson"}). +-record(person, {name = #name{}, phone}). + +demo() -> + P = #person{name= #name{first="Robert",last="Virding"}, phone=123}, + First = (P#person.name)#name.first.</pre> + <p>In this example, <c>demo()</c> evaluates to <c>"Robert"</c>.</p> + </section> + + <section> + <title>Example</title> + <pre> +%% File: person.hrl + +%%----------------------------------------------------------- +%% Data Type: person +%% where: +%% name: A string (default is undefined). +%% age: An integer (default is undefined). +%% phone: A list of integers (default is []). +%% dict: A dictionary containing various information +%% about the person. +%% A {Key, Value} list (default is the empty list). +%%------------------------------------------------------------ +-record(person, {name, age, phone = [], dict = []}).</pre> + <pre> +-module(person). +-include("person.hrl"). +-compile(export_all). % For test purposes only. + +%% This creates an instance of a person. +%% Note: The phone number is not supplied so the +%% default value [] will be used. + +make_hacker_without_phone(Name, Age) -> + #person{name = Name, age = Age, + dict = [{computer_knowledge, excellent}, + {drinks, coke}]}. + +%% This demonstrates matching in arguments + +print(#person{name = Name, age = Age, + phone = Phone, dict = Dict}) -> + io:format("Name: ~s, Age: ~w, Phone: ~w ~n" + "Dictionary: ~w.~n", [Name, Age, Phone, Dict]). + +%% Demonstrates type testing, selector, updating. + +birthday(P) when record(P, person) -> + P#person{age = P#person.age + 1}. + +register_two_hackers() -> + Hacker1 = make_hacker_without_phone("Joe", 29), + OldHacker = birthday(Hacker1), + % The central_register_server should have + % an interface function for this. + central_register_server ! {register_person, Hacker1}, + central_register_server ! {register_person, + OldHacker#person{name = "Robert", + phone = [0,8,3,2,4,5,3,1]}}.</pre> + </section> +</chapter> + diff --git a/system/doc/programming_examples/xmlfiles.mk b/system/doc/programming_examples/xmlfiles.mk new file mode 100644 index 0000000000..5eb42a2881 --- /dev/null +++ b/system/doc/programming_examples/xmlfiles.mk @@ -0,0 +1,23 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +PROG_EX_CHAPTER_FILES = \ + bit_syntax.xml \ + funs.xml \ + list_comprehensions.xml \ + records.xml diff --git a/system/doc/reference_manual/Makefile b/system/doc/reference_manual/Makefile new file mode 100644 index 0000000000..34e5b7f555 --- /dev/null +++ b/system/doc/reference_manual/Makefile @@ -0,0 +1,113 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/reference_manual + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk +XML_CHAPTER_FILES=$(REF_MAN_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES= + + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) +# ---------------------------------------------------- + +C_FILES = + +ERL_FILES = + +HRL_FILES = + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/reference_manual + +EXTRA_FILES = $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(C_FILES) \ + $(ERL_FILES) \ + $(HRL_FILES) \ + $(MISC_FILES) \ + $(XML_CHAPTER_FILES:%.xml=%.html) + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + + diff --git a/system/doc/reference_manual/book.xml b/system/doc/reference_manual/book.xml new file mode 100644 index 0000000000..eb2e860f80 --- /dev/null +++ b/system/doc/reference_manual/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erlang Reference Manual</title> + <prepared>Gunilla Arendt</prepared> + <docno></docno> + <date>2003-01-11</date> + <rev></rev> + <file></file> + </header> + <insidecover> + </insidecover> + <pagetext>Erlang Reference Manual</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/reference_manual/code_loading.xml b/system/doc/reference_manual/code_loading.xml new file mode 100644 index 0000000000..8861b3bea5 --- /dev/null +++ b/system/doc/reference_manual/code_loading.xml @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Compilation and Code Loading</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>code_loading.xml</file> + </header> + <p>How code is compiled and loaded is not a language issue, but + is system dependent. This chapter describes compilation and + code loading in Erlang/OTP with pointers to relevant parts of + the documentation.</p> + + <section> + <title>Compilation</title> + <p>Erlang programs must be <em>compiled</em> to object code. + The compiler can generate a new file which contains the object + code. The current abstract machine which runs the object code is + called BEAM, therefore the object files get the suffix + <c>.beam</c>. The compiler can also generate a binary which can + be loaded directly.</p> + <p>The compiler is located in the Kernel module <c>compile</c>, see + <c>compile(3)</c>.</p> + <pre> +compile:file(Module) +compile:file(Module, Options)</pre> + <p>The Erlang shell understands the command <c>c(Module)</c> which + both compiles and loads <c>Module</c>.</p> + <p>There is also a module <c>make</c> which provides a set of + functions similar to the UNIX type Make functions, see + <c>make(3)</c>.</p> + <p>The compiler can also be accessed from the OS prompt, see + <c>erl(1)</c>.</p> + <pre> +% erl -compile <input>Module1</input>...<input>ModuleN</input> +% erl -make</pre> + <p>The <c>erlc</c> program provides an even better way to compile + modules from the shell, see <c>erlc(1)</c>. It understands a + number of flags that can be used to define macros, add search + paths for include files, and more.</p> + <pre> +% erlc <input><flags></input> <input>File1.erl</input>...<input>FileN.erl</input></pre> + </section> + + <section> + <marker id="loading"></marker> + <title>Code Loading</title> + <p>The object code must be <em>loaded</em> into the Erlang runtime + system. This is handled by the <em>code server</em>, see + <c>code(3)</c>.</p> + <p>The code server loads code according to a code loading strategy + which is either <em>interactive</em> (default) or + <em>embedded</em>. In interactive mode, code are searched for in + a <em>code path</em> and loaded when first referenced. In + embedded mode, code is loaded at start-up according to a <em>boot script</em>. This is described in <em>System Principles</em>.</p> + </section> + + <section> + <title>Code Replacement</title> + <p>Erlang supports change of code in a running system. Code + replacement is done on module level.</p> + <p>The code of a module can exist in two variants in a system: + <em>current</em> and <em>old</em>. When a module is loaded into + the system for the first time, the code becomes 'current'. If then + a new instance of the module is loaded, the code of the previous + instance becomes 'old' and the new instance becomes 'current'.</p> + <p>Both old and current code is valid, and may be evaluated + concurrently. Fully qualified function calls always refer to + current code. Old code may still be evaluated because of processes + lingering in the old code.</p> + <p>If a third instance of the module is loaded, the code server will + remove (purge) the old code and any processes lingering in it will + be terminated. Then the third instance becomes 'current' and + the previously current code becomes 'old'.</p> + <p>To change from old code to current code, a process must make a + fully qualified function call. Example:</p> + <pre> +-module(m). +-export([loop/0]). + +loop() -> + receive + code_switch -> + m:loop(); + Msg -> + ... + loop() + end.</pre> + <p>To make the process change code, send the message + <c>code_switch</c> to it. The process then will make a fully + qualified call to <c>m:loop()</c> and change to current code. + Note that <c>m:loop/0</c> must be exported.</p> + <p>For code replacement of funs to work, the tuple syntax + <c>{Module,FunctionName}</c> must be used to represent the fun.</p> + </section> + + <section> + <title>Running a function when a module is loaded</title> + + <warning> + <p>This section describes an experimental feature introduced in R13B03. + There may be backward-incompatible changes in the feature in future releases.</p> + </warning> + + <p>The <c>-on_load()</c> directive names a function that should + be run automatically when a module a loaded. Its syntax is:</p> + +<pre> +-on_load(Name/0).</pre> + + <p>It is not necessary to export the function. It will be called in a + freshly spawned process (which will be terminated as soon as the function + returns). The function must return <c>true</c> if the module is to + be remained loaded and be callable, or <c>false</c> if the module + is to be unloaded. Returning any other value or generating an exception + will also cause the module to be unloaded.</p> + + <p>A process that calls any function in a module whose <c>on_load</c> + function has not yet returned will be suspended until the <c>on_load</c> + function has returned.</p> + + <p>Example:</p> + + <pre> +-module(m). +-on_load(run_me/0). + +run_me() -> + %% Do something with side effects here, for instance load a library + %% containing native-implemented functions. + true.</pre> + + </section> + +</chapter> + diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml new file mode 100644 index 0000000000..c85ac44165 --- /dev/null +++ b/system/doc/reference_manual/data_types.xml @@ -0,0 +1,399 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Data Types</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>data_types.xml</file> + </header> + + <section> + <title>Terms</title> + <p>Erlang provides a number of data types which are listed in this + chapter. A piece of data of any data type is called a + <em>term</em>.</p> + </section> + + <section> + <title>Number</title> + <p>There are two types of numeric literals, <em>integers</em> and + <em>floats</em>. Besides the conventional notation, there are two + Erlang-specific notations:</p> + <list type="bulleted"> + <item><c>$</c><em><c>char</c></em> <br></br> + + ASCII value of the character <em><c>char</c></em>.</item> + <item><em><c>base</c></em><c>#</c><em><c>value</c></em> <br></br> + + Integer with the base <em><c>base</c></em>, which must be an + integer in the range 2..36. <br></br> + + In Erlang 5.2/OTP R9B and earlier versions, the allowed range + is 2..16.</item> + </list> + <p>Examples:</p> + <pre> +1> <input>42.</input> +42 +2> <input>$A.</input> +65 +3> <input>$\ .</input> +10 +4> <input>2#101.</input> +5 +5> <input>16#1f.</input> +31 +6> <input>2.3.</input> +2.3 +7> <input>2.3e3.</input> +2.3e3 +8> <input>2.3e-3.</input> +0.0023</pre> + </section> + + <section> + <title>Atom</title> + <p>An atom is a literal, a constant with name. An atom should be + enclosed in single quotes (') if it does not begin with a + lower-case letter or if it contains other characters than + alphanumeric characters, underscore (_), or @.</p> + <p>Examples:</p> + <pre> +hello +phone_number +'Monday' +'phone number'</pre> + </section> + + <section> + <title>Bit Strings and Binaries</title> + <p>A bit string is used to store an area of untyped memory.</p> + <p>Bit Strings are expressed using the + <seealso marker="expressions#bit_syntax">bit syntax</seealso>.</p> + <p>Bit Strings which consists of a number of bits which is evenly + divisible by eight are called Binaries</p> + <p>Examples:</p> + <pre> +1> <input><<10,20>>.</input> +<<10,20>> +2> <input><<"ABC">>.</input> +<<"ABC">> +1> <input><<1:1,0:1>>.</input> +<<2:2>></pre> + <p>More examples can be found in Programming Examples.</p> + </section> + + <section> + <title>Reference</title> + <p>A reference is a term which is unique in an Erlang runtime + system, created by calling <c>make_ref/0</c>.</p> + </section> + + <section> + <title>Fun</title> + <p>A fun is a functional object. Funs make it possible to create + an anonymous function and pass the function itself -- not its + name -- as argument to other functions.</p> + <p>Example:</p> + <pre> +1> <input>Fun1 = fun (X) -> X+1 end.</input> +#Fun<erl_eval.6.39074546> +2> <input>Fun1(2).</input> +3</pre> + <p>Read more about funs in <seealso marker="expressions#funs">Fun Expressions</seealso>. More examples can be found in Programming + Examples.</p> + </section> + + <section> + <title>Port Identifier</title> + <p>A port identifier identifies an Erlang port. <c>open_port/2</c>, + which is used to create ports, will return a value of this type.</p> + <p>Read more about ports in <seealso marker="ports">Ports and Port Drivers</seealso>.</p> + </section> + + <section> + <title>Pid</title> + <p>A process identifier, pid, identifies a process. + <c>spawn/1,2,3,4</c>, <c>spawn_link/1,2,3,4</c> and + <c>spawn_opt/4</c>, which are used to create processes, return + values of this type. Example:</p> + <pre> +1> <input>spawn(m, f, []).</input> +<0.51.0></pre> + <p>The BIF <c>self()</c> returns the pid of the calling process. + Example:</p> + <pre> +-module(m). +-export([loop/0]). + +loop() -> + receive + who_are_you -> + io:format("I am ~p~n", [self()]), + loop() + end. + +1> <input>P = spawn(m, loop, []).</input> +<0.58.0> +2> <input>P ! who_are_you.</input> +I am <0.58.0> +who_are_you</pre> + <p>Read more about processes in + <seealso marker="processes">Processes</seealso>.</p> + </section> + + <section> + <title>Tuple</title> + <p>Compound data type with a fixed number of terms:</p> + <pre> +{Term1,...,TermN}</pre> + <p>Each term <c>Term</c> in the tuple is called an + <em>element</em>. The number of elements is said to be + the <em>size</em> of the tuple.</p> + <p>There exists a number of BIFs to manipulate tuples.</p> + <p>Examples:</p> + <pre> +1> <input>P = {adam,24,{july,29}}.</input> +{adam,24,{july,29}} +2> <input>element(1,P).</input> +adam +3> <input>element(3,P).</input> +{july,29} +4> <input>P2 = setelement(2,P,25).</input> +{adam,25,{july,29}} +5> <input>tuple_size(P).</input> +3 +6> <input>tuple_size({}).</input> +0</pre> + </section> + + <section> + <title>List</title> + <p>Compound data type with a variable number of terms.</p> + <pre> +[Term1,...,TermN]</pre> + <p>Each term <c>Term</c> in the list is called an + <em>element</em>. The number of elements is said to be + the <em>length</em> of the list.</p> + <p>Formally, a list is either the empty list <c>[]</c> or + consists of a <em>head</em> (first element) and a <em>tail</em> + (remainder of the list) which is also a list. The latter can + be expressed as <c>[H|T]</c>. The notation + <c>[Term1,...,TermN]</c> above is actually shorthand for + the list <c>[Term1|[...|[TermN|[]]]]</c>.</p> + <p>Example: <br></br> +<c>[]</c> is a list, thus <br></br> +<c>[c|[]]</c> is a list, thus <br></br> +<c>[b|[c|[]]]</c> is a list, thus <br></br> +<c>[a|[b|[c|[]]]]</c> is a list, or in short <c>[a,b,c]</c>.</p> + <p></p> + <p>A list where the tail is a list is sometimes called a <em>proper list</em>. It is allowed to have a list where the tail is not a + list, for example <c>[a|b]</c>. However, this type of list is of + little practical use.</p> + <p>Examples:</p> + <pre> +1> <input>L1 = [a,2,{c,4}].</input> +[a,2,{c,4}] +2> <input>[H|T] = L1.</input> +[a,2,{c,4}] +3> <input>H.</input> +a +4> <input>T.</input> +[2,{c,4}] +5> <input>L2 = [d|T].</input> +[d,2,{c,4}] +6> <input>length(L1).</input> +3 +7> <input>length([]).</input> +0</pre> + <p>A collection of list processing functions can be found in + the STDLIB module <c>lists</c>.</p> + </section> + + <section> + <title>String</title> + <p>Strings are enclosed in double quotes ("), but is not a + data type in Erlang. Instead a string <c>"hello"</c> is + shorthand for the list <c>[$h,$e,$l,$l,$o]</c>, that is + <c>[104,101,108,108,111]</c>.</p> + <p>Two adjacent string literals are concatenated into one. This is + done at compile-time and does not incur any runtime overhead. + Example:</p> + <pre> +"string" "42"</pre> + <p>is equivalent to</p> + <pre> +"string42"</pre> + </section> + + <section> + <title>Record</title> + <p>A record is a data structure for storing a fixed number of + elements. It has named fields and is similar to a struct in C. + However, record is not a true data type. Instead record + expressions are translated to tuple expressions during + compilation. Therefore, record expressions are not understood by + the shell unless special actions are taken. See <c>shell(3)</c> + for details.</p> + <p>Examples:</p> + <pre> +-module(person). +-export([new/2]). + +-record(person, {name, age}). + +new(Name, Age) -> + #person{name=Name, age=Age}. + +1> <input>person:new(ernie, 44).</input> +{person,ernie,44}</pre> + <p>Read more about records in + <seealso marker="records">Records</seealso>. More examples can be + found in Programming Examples.</p> + </section> + + <section> + <title>Boolean</title> + <p>There is no Boolean data type in Erlang. Instead the atoms + <c>true</c> and <c>false</c> are used to denote Boolean values.</p> + <p>Examples:</p> + <pre> +1> <input>2 =< 3</input>. +true +2> <input>true or false</input>. +true</pre> + </section> + + <section> + <title>Escape Sequences</title> + <p>Within strings and quoted atoms, the following escape sequences + are recognized:</p> + <table> + <row> + <cell align="left" valign="middle"><em>Sequence</em></cell> + <cell align="left" valign="middle"><em>Description</em></cell> + </row> + <row> + <cell align="left" valign="middle">\\b</cell> + <cell align="left" valign="middle">backspace</cell> + </row> + <row> + <cell align="left" valign="middle">\\d</cell> + <cell align="left" valign="middle">delete</cell> + </row> + <row> + <cell align="left" valign="middle">\\e</cell> + <cell align="left" valign="middle">escape</cell> + </row> + <row> + <cell align="left" valign="middle">\\f</cell> + <cell align="left" valign="middle">form feed</cell> + </row> + <row> + <cell align="left" valign="middle">\</cell> + <cell align="left" valign="middle">newline</cell> + </row> + <row> + <cell align="left" valign="middle">\\r</cell> + <cell align="left" valign="middle">carriage return</cell> + </row> + <row> + <cell align="left" valign="middle">\\s</cell> + <cell align="left" valign="middle">space</cell> + </row> + <row> + <cell align="left" valign="middle">\\t</cell> + <cell align="left" valign="middle">tab</cell> + </row> + <row> + <cell align="left" valign="middle">\\v</cell> + <cell align="left" valign="middle">vertical tab</cell> + </row> + <row> + <cell align="left" valign="middle">\\XYZ, \\YZ, \\Z</cell> + <cell align="left" valign="middle">character with octal representation XYZ, YZ or Z</cell> + </row> + <row> + <cell align="left" valign="middle">\\xXY</cell> + <cell align="left" valign="middle">character with hexadecimal representation XY</cell> + </row> + <row> + <cell align="left" valign="middle">\\x{X...}</cell> + <cell align="left" valign="middle">character with hexadecimal representation; X... is one or more hexadecimal characters</cell> + </row> + <row> + <cell align="left" valign="middle">\\^a...\\^z <br></br> +\\^A...\\^Z</cell> + <cell align="left" valign="middle">control A to control Z</cell> + </row> + <row> + <cell align="left" valign="middle">\\'</cell> + <cell align="left" valign="middle">single quote</cell> + </row> + <row> + <cell align="left" valign="middle">\\"</cell> + <cell align="left" valign="middle">double quote</cell> + </row> + <row> + <cell align="left" valign="middle">\\\\</cell> + <cell align="left" valign="middle">backslash</cell> + </row> + <tcaption>Recognized Escape Sequences.</tcaption> + </table> + </section> + + <section> + <title>Type Conversions</title> + <p>There are a number of BIFs for type conversions. Examples:</p> + <pre> +1> <input>atom_to_list(hello).</input> +"hello" +2> <input>list_to_atom("hello").</input> +hello +3> <input>binary_to_list(<<"hello">>).</input> +"hello" +4> <input>binary_to_list(<<104,101,108,108,111>>).</input> +"hello" +5> <input>list_to_binary("hello").</input> +<<104,101,108,108,111>> +6> <input>float_to_list(7.0).</input> +"7.00000000000000000000e+00" +7> <input>list_to_float("7.000e+00").</input> +7.0 +8> <input>integer_to_list(77).</input> +"77" +9> <input>list_to_integer("77").</input> +77 +10> <input>tuple_to_list({a,b,c}).</input> +[a,b,c] +11> <input>list_to_tuple([a,b,c]).</input> +{a,b,c} +12> <input>term_to_binary({a,b,c}).</input> +<<131,104,3,100,0,1,97,100,0,1,98,100,0,1,99>> +13> <input>binary_to_term(<<131,104,3,100,0,1,97,100,0,1,98,100,0,1,99>>).</input> +{a,b,c}</pre> + </section> +</chapter> + diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml new file mode 100644 index 0000000000..52222c6d9d --- /dev/null +++ b/system/doc/reference_manual/distributed.xml @@ -0,0 +1,279 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Distributed Erlang</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>distributed.xml</file> + </header> + + <section> + <title>Distributed Erlang System</title> + <p>A <em>distributed Erlang system</em> consists of a number of + Erlang runtime systems communicating with each other. Each such + runtime system is called a <em>node</em>. Message passing between + processes at different nodes, as well as links and monitors, are + transparent when pids are used. Registered names, however, are + local to each node. This means the node must be specified as well + when sending messages etc. using registered names.</p> + <p>The distribution mechanism is implemented using TCP/IP sockets. + How to implement an alternative carrier is described in <em>ERTS User's Guide</em>.</p> + </section> + + <section> + <title>Nodes</title> + <p>A <em>node</em> is an executing Erlang runtime system which has + been given a name, using the command line flag <c>-name</c> + (long names) or <c>-sname</c> (short names).</p> + <p>The format of the node name is an atom <c>name@host</c> where + <c>name</c> is the name given by the user and <c>host</c> is + the full host name if long names are used, or the first part of + the host name if short names are used. <c>node()</c> returns + the name of the node. Example:</p> + <pre> +% <input>erl -name dilbert</input> +([email protected])1> <input>node().</input> + +% <input>erl -sname dilbert</input> +(dilbert@uab)1> <input>node().</input> +dilbert@uab</pre> + <note> + <p>A node with a long node name cannot communicate with a node + with a short node name.</p> + </note> + </section> + + <section> + <title>Node Connections</title> + <p>The nodes in a distributed Erlang system are loosely connected. + The first time the name of another node is used, for example if + <c>spawn(Node,M,F,A)</c> or <c>net_adm:ping(Node)</c> is called, + a connection attempt to that node will be made.</p> + <p>Connections are by default transitive. If a node A connects to + node B, and node B has a connection to node C, then node A will + also try to connect to node C. This feature can be turned off by + using the command line flag <c>-connect_all false</c>, see + <c>erl(1)</c>.</p> + <p>If a node goes down, all connections to that node are removed. + Calling <c>erlang:disconnect(Node)</c> will force disconnection + of a node.</p> + <p>The list of (visible) nodes currently connected to is returned by + <c>nodes()</c>.</p> + </section> + + <section> + <title>epmd</title> + <p>The Erlang Port Mapper Daemon <em>epmd</em> is automatically + started at every host where an Erlang node is started. It is + responsible for mapping the symbolic node names to machine + addresses. See <c>epmd(1)</c>.</p> + </section> + + <section> + <title>Hidden Nodes</title> + <p>In a distributed Erlang system, it is sometimes useful to + connect to a node without also connecting to all other nodes. + An example could be some kind of O&M functionality used to + inspect the status of a system without disturbing it. For this + purpose, a <em>hidden node</em> may be used.</p> + <p>A hidden node is a node started with the command line flag + <c>-hidden</c>. Connections between hidden nodes and other nodes + are not transitive, they must be set up explicitly. Also, hidden + nodes does not show up in the list of nodes returned by + <c>nodes()</c>. Instead, <c>nodes(hidden)</c> or + <c>nodes(connected)</c> must be used. This means, for example, + that the hidden node will not be added to the set of nodes that + <c>global</c> is keeping track of.</p> + <p>This feature was added in Erlang 5.0/OTP R7.</p> + </section> + + <section> + <title>C Nodes</title> + <p>A <em>C node</em> is a C program written to act as a hidden node + in a distributed Erlang system. The library <em>Erl_Interface</em> + contains functions for this purpose. Refer to the documentation + for Erl_Interface and <em>Interoperability Tutorial</em> for more + information about C nodes.</p> + </section> + + <section> + <title>Security</title> + <p>Authentication determines which nodes are allowed to communicate + with each other. In a network of different Erlang nodes, it is + built into the system at the lowest possible level. Each node has + its own <em>magic cookie</em>, which is an Erlang atom.</p> + <p>When a nodes tries to connect to another node, the magic cookies + are compared. If they do not match, the connected node rejects + the connection.</p> + <p>At start-up, a node has a random atom assigned as its magic + cookie and the cookie of other nodes is assumed to be + <c>nocookie</c>. The first action of the Erlang network + authentication server (<c>auth</c>) is then to read a file named + <c>$HOME/.erlang.cookie</c>. If the file does not exist, it is + created. The UNIX permissions mode of the file is set to octal + 400 (read-only by user) and its contents are a random string. An + atom <c>Cookie</c> is created from the contents of the file and + the cookie of the local node is set to this using + <c>erlang:set_cookie(node(), Cookie)</c>. This also makes + the local node assume that all other nodes have the same cookie + <c>Cookie</c>.</p> + <p>Thus, groups of users with identical cookie files get Erlang + nodes which can communicate freely and without interference from + the magic cookie system. Users who want run nodes on separate + file systems must make certain that their cookie files are + identical on the different file systems.</p> + <p>For a node <c>Node1</c> with magic cookie <c>Cookie</c> to be + able to connect to, or accept a connection from, another node + <c>Node2</c> with a different cookie <c>DiffCookie</c>, + the function <c>erlang:set_cookie(Node2, DiffCookie)</c> must + first be called at <c>Node1</c>. Distributed systems with + multiple user IDs can be handled in this way.</p> + <p>The default when a connection is established between two nodes, + is to immediately connect all other visible nodes as well. This + way, there is always a fully connected network. If there are + nodes with different cookies, this method might be inappropriate + and the command line flag <c>-connect_all false</c> must be set, + see <seealso marker="erts:erl">erl(1)</seealso>.</p> + <p>The magic cookie of the local node is retrieved by calling + <c>erlang:get_cookie()</c>.</p> + </section> + + <section> + <title>Distribution BIFs</title> + <p>Some useful BIFs for distributed programming, see + <c>erlang(3)</c> for more information:</p> + <table> + <row> + <cell align="left" valign="middle"><c>erlang:disconnect_node(Node)</c></cell> + <cell align="left" valign="middle">Forces the disconnection of a node.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>erlang:get_cookie()</c></cell> + <cell align="left" valign="middle">Returns the magic cookie of the current node.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_alive()</c></cell> + <cell align="left" valign="middle">Returns <c>true</c>if the runtime system is a node and can connect to other nodes, <c>false</c>otherwise.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>monitor_node(Node, true|false)</c></cell> + <cell align="left" valign="middle">Monitor the status of <c>Node</c>. A message<c>{nodedown, Node}</c>is received if the connection to it is lost.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>node()</c></cell> + <cell align="left" valign="middle">Returns the name of the current node. Allowed in guards.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>node(Arg)</c></cell> + <cell align="left" valign="middle">Returns the node where <c>Arg</c>, a pid, reference, or port, is located.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>nodes()</c></cell> + <cell align="left" valign="middle">Returns a list of all visible nodes this node is connected to.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>nodes(Arg)</c></cell> + <cell align="left" valign="middle">Depending on <c>Arg</c>, this function can return a list not only of visible nodes, but also hidden nodes and previously known nodes, etc.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>set_cookie(Node, Cookie)</c></cell> + <cell align="left" valign="middle">Sets the magic cookie used when connecting to <c>Node</c>. If <c>Node</c>is the current node, <c>Cookie</c>will be used when connecting to all new nodes.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>spawn[_link|_opt](Node, Fun)</c></cell> + <cell align="left" valign="middle">Creates a process at a remote node.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>spawn[_link|opt](Node, Module, FunctionName, Args)</c></cell> + <cell align="left" valign="middle">Creates a process at a remote node.</cell> + </row> + <tcaption>Distribution BIFs.</tcaption> + </table> + </section> + + <section> + <title>Distribution Command Line Flags</title> + <p>Examples of command line flags used for distributed programming, + see <c>erl(1)</c> for more information:</p> + <table> + <row> + <cell align="left" valign="middle"><c>-connect_all false</c></cell> + <cell align="left" valign="middle">Only explicit connection set-ups will be used.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>-hidden</c></cell> + <cell align="left" valign="middle">Makes a node into a hidden node.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>-name Name</c></cell> + <cell align="left" valign="middle">Makes a runtime system into a node, using long node names.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>-setcookie Cookie</c></cell> + <cell align="left" valign="middle">Same as calling <c>erlang:set_cookie(node(), Cookie)</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>-sname Name</c></cell> + <cell align="left" valign="middle">Makes a runtime system into a node, using short node names.</cell> + </row> + <tcaption>Distribution Command Line Flags.</tcaption> + </table> + </section> + + <section> + <title>Distribution Modules</title> + <p>Examples of modules useful for distributed programming:</p> + <p>In Kernel:</p> + <table> + <row> + <cell align="left" valign="middle"><c>global</c></cell> + <cell align="left" valign="middle">A global name registration facility.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>global_group</c></cell> + <cell align="left" valign="middle">Grouping nodes to global name registration groups.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>net_adm</c></cell> + <cell align="left" valign="middle">Various Erlang net administration routines.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>net_kernel</c></cell> + <cell align="left" valign="middle">Erlang networking kernel.</cell> + </row> + <tcaption>Kernel Modules Useful For Distribution.</tcaption> + </table> + <p>In STDLIB:</p> + <table> + <row> + <cell align="left" valign="middle"><c>slave</c></cell> + <cell align="left" valign="middle">Start and control of slave nodes.</cell> + </row> + <tcaption>STDLIB Modules Useful For Distribution.</tcaption> + </table> + </section> +</chapter> + diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml new file mode 100644 index 0000000000..02885a3813 --- /dev/null +++ b/system/doc/reference_manual/errors.xml @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Errors and Error Handling</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>errors.xml</file> + </header> + + <section> + <title>Terminology</title> + <p>Errors can roughly be divided into four different types:</p> + <list type="bulleted"> + <item>Compile-time errors</item> + <item>Logical errors</item> + <item>Run-time errors</item> + <item>Generated errors</item> + </list> + <p>A compile-time error, for example a syntax error, should not + cause much trouble as it is caught by the compiler.</p> + <p>A logical error is when a program does not behave as intended, + but does not crash. An example could be that nothing happens when + a button in a graphical user interface is clicked.</p> + <p>A run-time error is when a crash occurs. An example could be + when an operator is applied to arguments of the wrong type. + The Erlang programming language has built-in features for + handling of run-time errors.</p> + <p>A run-time error can also be emulated by calling + <c>erlang:error(Reason)</c>, <c>erlang:error(Reason, Args)</c> + (those appeared in Erlang 5.4/OTP-R10), + <c>erlang:fault(Reason)</c> or <c>erlang:fault(Reason, Args)</c> + (old equivalents).</p> + <p>A run-time error is another name for an exception + of class <c>error</c>. + </p> + <p>A generated error is when the code itself calls + <c>exit/1</c> or <c>throw/1</c>. Note that emulated run-time + errors are not denoted as generated errors here. + </p> + <p>Generated errors are exceptions of classes <c>exit</c> and + <c>throw</c>. + </p> + <p>When a run-time error or generated error occurs in Erlang, + execution for the process which evaluated + the erroneous expression is stopped. + This is referred to as a <em>failure</em>, that execution or + evaluation <em>fails</em>, or that the process <em>fails</em>, + <em>terminates</em> or <em>exits</em>. Note that a process may + terminate/exit for other reasons than a failure.</p> + <p>A process that terminates will emit an <em>exit signal</em> with + an <em>exit reason</em> that says something about which error + has occurred. Normally, some information about the error will + be printed to the terminal.</p> + </section> + + <section> + <title>Exceptions</title> + <p>Exceptions are run-time errors or generated errors and + are of three different classes, with different origins. The + <seealso marker="expressions#try">try</seealso> expression + (appeared in Erlang 5.4/OTP-R10B) + can distinguish between the different classes, whereas the + <seealso marker="expressions#catch">catch</seealso> + expression can not. They are described in the Expressions chapter.</p> + <table> + <row> + <cell align="left" valign="middle"><em>Class</em></cell> + <cell align="left" valign="middle"><em>Origin</em></cell> + </row> + <row> + <cell align="left" valign="middle"><c>error</c></cell> + <cell align="left" valign="middle">Run-time error for example <c>1+a</c>, or the process called <c>erlang:error/1,2</c> (appeared in Erlang 5.4/OTP-R10B) or <c>erlang:fault/1,2</c> (old equivalent)</cell> + </row> + <row> + <cell align="left" valign="middle"><c>exit</c></cell> + <cell align="left" valign="middle">The process called <c>exit/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>throw</c></cell> + <cell align="left" valign="middle">The process called <c>throw/1</c></cell> + </row> + <tcaption>Exception Classes.</tcaption> + </table> + <p>An exception consists of its class, an exit reason + (the <seealso marker="#exit_reasons">Exit Reason</seealso>), + and a stack trace (that aids in finding the code location of + the exception).</p> + <p>The stack trace can be retrieved using + <c>erlang:get_stacktrace/0</c> (new in Erlang 5.4/OTP-R10B + from within a <c>try</c> expression, and is returned for + exceptions of class <c>error</c> from a <c>catch</c> expression.</p> + <p>An exception of class <c>error</c> is also known as a run-time + error.</p> + </section> + + <section> + <title>Handling of Run-Time Errors in Erlang</title> + + <section> + <title>Error Handling Within Processes</title> + <p>It is possible to prevent run-time errors and other + exceptions from causing + the process to terminate by using <c>catch</c> or + <c>try</c>, see the Expressions chapter about + <seealso marker="expressions#catch">Catch</seealso> + and <seealso marker="expressions#try">Try</seealso>.</p> + </section> + + <section> + <title>Error Handling Between Processes</title> + <p>Processes can monitor other processes and detect process + terminations, see + the <seealso marker="processes#errors">Processes</seealso> + chapter.</p> + </section> + </section> + + <section> + <marker id="exit_reasons"></marker> + <title>Exit Reasons</title> + <p>When a run-time error occurs, + that is an exception of class <c>error</c>, + the exit reason is a tuple <c>{Reason,Stack}</c>. + <c>Reason</c> is a term indicating the type of error:</p> + <table> + <row> + <cell align="left" valign="middle"><em>Reason</em></cell> + <cell align="left" valign="middle"><em>Type of error</em></cell> + </row> + <row> + <cell align="left" valign="middle"><c>badarg</c></cell> + <cell align="left" valign="middle">Bad argument. The argument is of wrong data type, or is otherwise badly formed.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>badarith</c></cell> + <cell align="left" valign="middle">Bad argument in an arithmetic expression.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{badmatch,V}</c></cell> + <cell align="left" valign="middle">Evaluation of a match expression failed. The value <c>V</c> did not match.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>function_clause</c></cell> + <cell align="left" valign="middle">No matching function clause is found when evaluating a function call.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{case_clause,V}</c></cell> + <cell align="left" valign="middle">No matching branch is found when evaluating a <c>case</c> expression. The value <c>V</c> did not match.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>if_clause</c></cell> + <cell align="left" valign="middle">No true branch is found when evaluating an <c>if</c> expression.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{try_clause,V}</c></cell> + <cell align="left" valign="middle">No matching branch is found when evaluating the of-section of a <c>try</c> expression. The value <c>V</c> did not match.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>undef</c></cell> + <cell align="left" valign="middle">The function cannot be found when evaluating a function call.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{badfun,F}</c></cell> + <cell align="left" valign="middle">There is something wrong with a fun <c>F</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{badarity,F}</c></cell> + <cell align="left" valign="middle">A fun is applied to the wrong number of arguments. <c>F</c> describes the fun and the arguments.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>timeout_value</c></cell> + <cell align="left" valign="middle">The timeout value in a <c>receive..after</c> expression is evaluated to something else than an integer or <c>infinity</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>noproc</c></cell> + <cell align="left" valign="middle">Trying to link to a non-existing process.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{nocatch,V}</c></cell> + <cell align="left" valign="middle">Trying to evaluate a <c>throw </c>outside a <c>catch</c>. <c>V</c> is the thrown term.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>system_limit</c></cell> + <cell align="left" valign="middle">A system limit has been reached. See Efficiency Guide for information about system limits.</cell> + </row> + <tcaption>Exit Reasons.</tcaption> + </table> + <p><c>Stack</c> is the stack of function calls being evaluated + when the error occurred, given as a list of tuples + <c>{Module,Name,Arity}</c> with the most recent function call + first. The most recent function call tuple may in some + cases be <c>{Module,Name,[Arg]}</c>.</p> + </section> +</chapter> + diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml new file mode 100644 index 0000000000..fa7870d96c --- /dev/null +++ b/system/doc/reference_manual/expressions.xml @@ -0,0 +1,1422 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Expressions</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>expressions.xml</file> + </header> + <p>In this chapter, all valid Erlang expressions are listed. + When writing Erlang programs, it is also allowed to use macro- + and record expressions. However, these expressions are expanded + during compilation and are in that sense not true Erlang + expressions. Macro- and record expressions are covered in + separate chapters: <seealso marker="macros">Macros</seealso> and + <seealso marker="records">Records</seealso>.</p> + + <section> + <title>Expression Evaluation</title> + <p>All subexpressions are evaluated before an expression itself is + evaluated, unless explicitly stated otherwise. For example, + consider the expression:</p> + <code type="none"> +Expr1 + Expr2</code> + <p><c>Expr1</c> and <c>Expr2</c>, which are also expressions, are + evaluated first - in any order - before the addition is + performed.</p> + <p>Many of the operators can only be applied to arguments of a + certain type. For example, arithmetic operators can only be + applied to numbers. An argument of the wrong type will cause + a <c>badarg</c> run-time error.</p> + </section> + + <section> + <marker id="term"></marker> + <title>Terms</title> + <p>The simplest form of expression is a term, that is an integer, + float, atom, string, list or tuple. + The return value is the term itself.</p> + </section> + + <section> + <title>Variables</title> + <p>A variable is an expression. If a variable is bound to a value, + the return value is this value. Unbound variables are only + allowed in patterns.</p> + <p>Variables start with an uppercase letter or underscore (_) + and may contain alphanumeric characters, underscore and @. + Examples:</p> + <pre> +X +Name1 +PhoneNumber +Phone_number +_ +_Height</pre> + <p>Variables are bound to values using + <seealso marker="patterns">pattern matching</seealso>. Erlang + uses <em>single assignment</em>, a variable can only be bound + once.</p> + <p>The <em>anonymous variable</em> is denoted by underscore (_) and + can be used when a variable is required but its value can be + ignored. Example:</p> + <pre> +[H|_] = [1,2,3]</pre> + <p>Variables starting with underscore (_), for example + <c>_Height</c>, are normal variables, not anonymous. They are + however ignored by the compiler in the sense that they will not + generate any warnings for unused variables. Example: The following + code</p> + <pre> +member(_, []) -> + [].</pre> + <p>can be rewritten to be more readable:</p> + <pre> +member(Elem, []) -> + [].</pre> + <p>This will however cause a warning for an unused variable + <c>Elem</c>, if the code is compiled with the flag + <c>warn_unused_vars</c> set. Instead, the code can be rewritten + to:</p> + <pre> +member(_Elem, []) -> + [].</pre> + <p>Note that since variables starting with an underscore are + not anonymous, this will match:</p> + <pre> +{_,_} = {1,2}</pre> + <p>But this will fail:</p> + <pre> +{_N,_N} = {1,2}</pre> + <p>The scope for a variable is its function clause. + Variables bound in a branch of an <c>if</c>, <c>case</c>, + or <c>receive</c> expression must be bound in all branches + to have a value outside the expression, otherwise they + will be regarded as 'unsafe' outside the expression.</p> + <p>For the <c>try</c> expression introduced in + Erlang 5.4/OTP-R10B, variable scoping is limited so that + variables bound in the expression are always 'unsafe' outside + the expression. This will be improved.</p> + </section> + + <section> + <marker id="pattern"></marker> + <title>Patterns</title> + <p>A pattern has the same structure as a term but may contain + unbound variables. Example:</p> + <pre> +Name1 +[H|T] +{error,Reason}</pre> + <p>Patterns are allowed in clause heads, <c>case</c> and + <c>receive</c> expressions, and match expressions.</p> + + <section> + <title>Match Operator = in Patterns</title> + <p>If <c>Pattern1</c> and <c>Pattern2</c> are valid patterns, + then the following is also a valid pattern:</p> + <pre> +Pattern1 = Pattern2</pre> + <p>When matched against a term, both <c>Pattern1</c> and + <c>Pattern2</c> will be matched against the term. The idea + behind this feature is to avoid reconstruction of terms. + Example:</p> + <pre> +f({connect,From,To,Number,Options}, To) -> + Signal = {connect,From,To,Number,Options}, + ...; +f(Signal, To) -> + ignore.</pre> + <p>can instead be written as</p> + <pre> +f({connect,_,To,_,_} = Signal, To) -> + ...; +f(Signal, To) -> + ignore.</pre> + </section> + + <section> + <title>String Prefix in Patterns</title> + <p>When matching strings, the following is a valid pattern:</p> + <pre> +f("prefix" ++ Str) -> ...</pre> + <p>This is syntactic sugar for the equivalent, but harder to + read</p> + <pre> +f([$p,$r,$e,$f,$i,$x | Str]) -> ...</pre> + </section> + + <section> + <title>Expressions in Patterns</title> + <p>An arithmetic expression can be used within a pattern, if + it uses only numeric or bitwise operators, and if its value + can be evaluated to a constant at compile-time. Example:</p> + <pre> +case {Value, Result} of + {?THRESHOLD+1, ok} -> ...</pre> + <p>This feature was added in Erlang 5.0/OTP R7.</p> + </section> + </section> + + <section> + <title>Match</title> + <pre> +Expr1 = Expr2</pre> + <p>Matches <c>Expr1</c>, a pattern, against <c>Expr2</c>. + If the matching succeeds, any unbound variable in the pattern + becomes bound and the value of <c>Expr2</c> is returned.</p> + <p>If the matching fails, a <c>badmatch</c> run-time error will + occur.</p> + <p>Examples:</p> + <pre> +1> <input>{A, B} = {answer, 42}.</input> +{answer,42} +2> <input>A.</input> +answer +3> <input>{C, D} = [1, 2].</input> +** exception error: no match of right hand side value [1,2]</pre> + </section> + + <section> + <marker id="calls"></marker> + <title>Function Calls</title> + <pre> +ExprF(Expr1,...,ExprN) +ExprM:ExprF(Expr1,...,ExprN)</pre> + <p>In the first form of function calls, + <c>ExprM:ExprF(Expr1,...,ExprN)</c>, each of <c>ExprM</c> and + <c>ExprF</c> must be an atom or an expression that evaluates to + an atom. The function is said to be called by using the + <em>fully qualified function name</em>. This is often referred + to as a <em>remote</em> or <em>external function call</em>. + Example:</p> + <code type="none"> +lists:keysearch(Name, 1, List)</code> + <p>In the second form of function calls, + <c>ExprF(Expr1,...,ExprN)</c>, <c>ExprF</c> must be an atom or + evaluate to a fun.</p> + <p>If <c>ExprF</c> is an atom the function is said to be called by + using the <em>implicitly qualified function name</em>. If + <c>ExprF/N</c> is the name of a function explicitly or + automatically imported from module <c>M</c>, then the call is + short for <c>M:ExprF(Expr1,...,ExprN)</c>. Otherwise, + <c>ExprF/N</c> must be a locally defined function. Examples:</p> + <code type="none"> +handle(Msg, State) +spawn(m, init, [])</code> + <p>Examples where ExprF is a fun:</p> + <code type="none"> +Fun1 = fun(X) -> X+1 end +Fun1(3) +=> 4 + +Fun2 = {lists,append} +Fun2([1,2], [3,4]) +=> [1,2,3,4] + +fun lists:append/2([1,2], [3,4]) +=> [1,2,3,4]</code> + <p>To avoid possible ambiguities, the fully qualified function + name must be used when calling a function with the same name as + a BIF, and the compiler does not allow defining a function with + the same name as an explicitly imported function.</p> + <p>Note that when calling a local function, there is a difference + between using the implicitly or fully qualified function name, as + the latter always refers to the latest version of the module. See + <seealso marker="code_loading">Compilation and Code Loading</seealso>.</p> + <p>See also the chapter about + <seealso marker="functions#eval">Function Evaluation</seealso>.</p> + </section> + + <section> + <title>If</title> + <pre> +if + GuardSeq1 -> + Body1; + ...; + GuardSeqN -> + BodyN +end</pre> + <p>The branches of an <c>if</c>-expression are scanned sequentially + until a guard sequence <c>GuardSeq</c> which evaluates to true is + found. Then the corresponding <c>Body</c> (sequence of expressions + separated by ',') is evaluated.</p> + <p>The return value of <c>Body</c> is the return value of + the <c>if</c> expression.</p> + <p>If no guard sequence is true, an <c>if_clause</c> run-time error + will occur. If necessary, the guard expression <c>true</c> can be + used in the last branch, as that guard sequence is always true.</p> + <p>Example:</p> + <pre> +is_greater_than(X, Y) -> + if + X>Y -> + true; + true -> % works as an 'else' branch + false + end</pre> + </section> + + <section> + <marker id="case"></marker> + <title>Case</title> + <pre> +case Expr of + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +end</pre> + <p>The expression <c>Expr</c> is evaluated and the patterns + <c>Pattern</c> are sequentially matched against the result. If a + match succeeds and the optional guard sequence <c>GuardSeq</c> is + true, the corresponding <c>Body</c> is evaluated.</p> + <p>The return value of <c>Body</c> is the return value of + the <c>case</c> expression.</p> + <p>If there is no matching pattern with a true guard sequence, + a <c>case_clause</c> run-time error will occur.</p> + <p>Example:</p> + <pre> +is_valid_signal(Signal) -> + case Signal of + {signal, _What, _From, _To} -> + true; + {signal, _What, _To} -> + true; + _Else -> + false + end.</pre> + </section> + + <section> + <marker id="send"></marker> + <title>Send</title> + <pre> +Expr1 ! Expr2</pre> + <p>Sends the value of <c>Expr2</c> as a message to the process + specified by <c>Expr1</c>. The value of <c>Expr2</c> is also + the return value of the expression.</p> + <p><c>Expr1</c> must evaluate to a pid, a registered name (atom) or + a tuple <c>{Name,Node}</c>, where <c>Name</c> is an atom and + <c>Node</c> a node name, also an atom.</p> + <list type="bulleted"> + <item>If <c>Expr1</c> evaluates to a name, but this name is not + registered, a <c>badarg</c> run-time error will occur.</item> + <item>Sending a message to a pid never fails, even if the pid + identifies a non-existing process.</item> + <item>Distributed message sending, that is if <c>Expr1</c> + evaluates to a tuple <c>{Name,Node}</c> (or a pid located at + another node), also never fails.</item> + </list> + </section> + + <section> + <marker id="receive"></marker> + <title>Receive</title> + <pre> +receive + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +end</pre> + <p>Receives messages sent to the process using the send operator + (!). The patterns <c>Pattern</c> are sequentially matched + against the first message in time order in the mailbox, then + the second, and so on. If a match succeeds and the optional + guard sequence <c>GuardSeq</c> is true, the corresponding + <c>Body</c> is evaluated. The matching message is consumed, that + is removed from the mailbox, while any other messages in + the mailbox remain unchanged.</p> + <p>The return value of <c>Body</c> is the return value of + the <c>receive</c> expression.</p> + <p><c>receive</c> never fails. Execution is suspended, possibly + indefinitely, until a message arrives that does match one of + the patterns and with a true guard sequence. </p> + <p>Example:</p> + <pre> +wait_for_onhook() -> + receive + onhook -> + disconnect(), + idle(); + {connect, B} -> + B ! {busy, self()}, + wait_for_onhook() + end.</pre> + <p>It is possible to augment the <c>receive</c> expression with a + timeout:</p> + <pre> +receive + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +after + ExprT -> + BodyT +end</pre> + <p><c>ExprT</c> should evaluate to an integer. The highest allowed + value is 16#ffffffff, that is, the value must fit in 32 bits. + <c>receive..after</c> works exactly as <c>receive</c>, except + that if no matching message has arrived within <c>ExprT</c> + milliseconds, then <c>BodyT</c> is evaluated instead and its + return value becomes the return value of the <c>receive..after</c> + expression.</p> + <p>Example:</p> + <pre> +wait_for_onhook() -> + receive + onhook -> + disconnect(), + idle(); + {connect, B} -> + B ! {busy, self()}, + wait_for_onhook() + after + 60000 -> + disconnect(), + error() + end.</pre> + <p>It is legal to use a <c>receive..after</c> expression with no + branches:</p> + <pre> +receive +after + ExprT -> + BodyT +end</pre> + <p>This construction will not consume any messages, only suspend + execution in the process for <c>ExprT</c> milliseconds and can be + used to implement simple timers.</p> + <p>Example:</p> + <pre> +timer() -> + spawn(m, timer, [self()]). + +timer(Pid) -> + receive + after + 5000 -> + Pid ! timeout + end.</pre> + <p>There are two special cases for the timeout value <c>ExprT</c>:</p> + <taglist> + <tag><c>infinity</c></tag> + <item>The process should wait indefinitely for a matching message + -- this is the same as not using a timeout. Can be + useful for timeout values that are calculated at run-time.</item> + <tag>0</tag> + <item>If there is no matching message in the mailbox, the timeout + will occur immediately.</item> + </taglist> + </section> + + <section> + <title>Term Comparisons</title> + <pre> +Expr1 <input>op</input> Expr2</pre> + <table> + <row> + <cell align="left" valign="middle"><em>op</em></cell> + <cell align="left" valign="middle"><em>Description</em></cell> + </row> + <row> + <cell align="left" valign="middle">==</cell> + <cell align="left" valign="middle">equal to</cell> + </row> + <row> + <cell align="left" valign="middle">/=</cell> + <cell align="left" valign="middle">not equal to</cell> + </row> + <row> + <cell align="left" valign="middle">=<</cell> + <cell align="left" valign="middle">less than or equal to</cell> + </row> + <row> + <cell align="left" valign="middle"><</cell> + <cell align="left" valign="middle">less than</cell> + </row> + <row> + <cell align="left" valign="middle">>=</cell> + <cell align="left" valign="middle">greater than or equal to</cell> + </row> + <row> + <cell align="left" valign="middle">></cell> + <cell align="left" valign="middle">greater than</cell> + </row> + <row> + <cell align="left" valign="middle">=:=</cell> + <cell align="left" valign="middle">exactly equal to</cell> + </row> + <row> + <cell align="left" valign="middle">=/=</cell> + <cell align="left" valign="middle">exactly not equal to</cell> + </row> + <tcaption>Term Comparison Operators.</tcaption> + </table> + <p>The arguments may be of different data types. The following + order is defined:</p> + <pre> +number < atom < reference < fun < port < pid < tuple < list < bit string</pre> + <p>Lists are compared element by element. Tuples are ordered by + size, two tuples with the same size are compared element by + element.</p> + <p>If one of the compared terms is an integer and the other a + float, the integer is first converted into a float, unless the + operator is one of =:= and =/=. If the integer is too big to fit + in a float no conversion is done, but the order is determined by + inspecting the sign of the numbers.</p> + <p>Returns the Boolean value of the expression, <c>true</c> or + <c>false</c>.</p> + <p>Examples:</p> + <pre> +1> <input>1==1.0.</input> +true +2> <input>1=:=1.0.</input> +false +3> <input>1 > a.</input> +false</pre> + </section> + + <section> + <title>Arithmetic Expressions</title> + <pre> +<input>op</input> Expr +Expr1 <input>op</input> Expr2</pre> + <table> + <row> + <cell align="left" valign="middle"><em>op</em></cell> + <cell align="left" valign="middle"><em>Description</em></cell> + <cell align="left" valign="middle"><em>Argument type</em></cell> + </row> + <row> + <cell align="left" valign="middle">+</cell> + <cell align="left" valign="middle">unary +</cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">-</cell> + <cell align="left" valign="middle">unary -</cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">+</cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">-</cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">*</cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">/</cell> + <cell align="left" valign="middle">floating point division</cell> + <cell align="left" valign="middle">number</cell> + </row> + <row> + <cell align="left" valign="middle">bnot</cell> + <cell align="left" valign="middle">unary bitwise not</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">div</cell> + <cell align="left" valign="middle">integer division</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">rem</cell> + <cell align="left" valign="middle">integer remainder of X/Y</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">band</cell> + <cell align="left" valign="middle">bitwise and</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">bor</cell> + <cell align="left" valign="middle">bitwise or</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">bxor</cell> + <cell align="left" valign="middle">arithmetic bitwise xor</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">bsl</cell> + <cell align="left" valign="middle">arithmetic bitshift left</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <row> + <cell align="left" valign="middle">bsr</cell> + <cell align="left" valign="middle">bitshift right</cell> + <cell align="left" valign="middle">integer</cell> + </row> + <tcaption>Arithmetic Operators.</tcaption> + </table> + + <p>Examples:</p> + <pre> +1> <input>+1.</input> +1 +2> <input>-1.</input> +-1 +3> <input>1+1.</input> +2 +4> <input>4/2.</input> +2.0 +5> <input>5 div 2.</input> +2 +6> <input>5 rem 2.</input> +1 +7> <input>2#10 band 2#01.</input> +0 +8> <input>2#10 bor 2#01.</input> +3 +9> <input>a + 10.</input> +** exception error: bad argument in an arithmetic expression + in operator +/2 + called as a + 10 +10> <input>1 bsl (1 bsl 64).</input> +** exception error: a system limit has been reached + in operator bsl/2 + called as 1 bsl 18446744073709551616</pre> + </section> + + <section> + <title>Boolean Expressions</title> + <pre> +<input>op</input> Expr +Expr1 <input>op</input> Expr2</pre> + <table> + <row> + <cell align="left" valign="middle"><em>op</em></cell> + <cell align="left" valign="middle"><em>Description</em></cell> + </row> + <row> + <cell align="left" valign="middle">not</cell> + <cell align="left" valign="middle">unary logical not</cell> + </row> + <row> + <cell align="left" valign="middle">and</cell> + <cell align="left" valign="middle">logical and</cell> + </row> + <row> + <cell align="left" valign="middle">or</cell> + <cell align="left" valign="middle">logical or</cell> + </row> + <row> + <cell align="left" valign="middle">xor</cell> + <cell align="left" valign="middle">logical xor</cell> + </row> + <tcaption>Logical Operators.</tcaption> + </table> + <p>Examples:</p> + <pre> +1> <input>not true.</input> +false +2> <input>true and false.</input> +false +3> <input>true xor false.</input> +true +4> <input>true or garbage.</input> +** exception error: bad argument + in operator or/2 + called as true or garbage</pre> + </section> + + <section> + <title>Short-Circuit Expressions</title> + <pre> +Expr1 orelse Expr2 +Expr1 andalso Expr2</pre> + <p>Expressions where <c>Expr2</c> is evaluated only if + necessary. That is, <c>Expr2</c> is evaluated only if <c>Expr1</c> + evaluates to <c>false</c> in an <c>orelse</c> expression, or only + if <c>Expr1</c> evaluates to <c>true</c> in an <c>andalso</c> + expression. Returns either the value of <c>Expr1</c> (that is, + <c>true</c> or <c>false</c>) or the value of <c>Expr2</c> + (if <c>Expr2</c> was evaluated).</p> + + <p>Example 1:</p> + <pre> +case A >= -1.0 andalso math:sqrt(A+1) > B of</pre> + <p>This will work even if <c>A</c> is less than <c>-1.0</c>, + since in that case, <c>math:sqrt/1</c> is never evaluated.</p> + <p>Example 2:</p> + <pre> +OnlyOne = is_atom(L) orelse + (is_list(L) andalso length(L) == 1),</pre> + + <p>From R13A, <c>Expr2</c> is no longer required to evaluate to a + boolean value. As a consequence, <c>andalso</c> and <c>orelse</c> + are now tail-recursive. For instance, the following function is + tail-recursive in R13A and later:</p> + + <pre> +all(Pred, [Hd|Tail]) -> + Pred(Hd) andalso all(Pred, Tail); +all(_, []) -> + true.</pre> + </section> + + <section> + <title>List Operations</title> + <pre> +Expr1 ++ Expr2 +Expr1 -- Expr2</pre> + <p>The list concatenation operator <c>++</c> appends its second + argument to its first and returns the resulting list.</p> + <p>The list subtraction operator <c>--</c> produces a list which + is a copy of the first argument, subjected to the following + procedure: for each element in the second argument, the first + occurrence of this element (if any) is removed.</p> + <p>Example:</p> + <pre> +1> <input>[1,2,3]++[4,5].</input> +[1,2,3,4,5] +2> <input>[1,2,3,2,1,2]--[2,1,2].</input> +[3,1,2]</pre> + + <warning><p>The complexity of <c>A -- B</c> is + proportional to <c>length(A)*length(B)</c>, meaning that it + will be very slow if both <c>A</c> and <c>B</c> are + long lists.</p></warning> + </section> + + <section> + <marker id="bit_syntax"></marker> + <title>Bit Syntax Expressions</title> + <code type="none"><![CDATA[<<>> +<<E1,...,En>>]]></code> + <p>Each element <c>Ei</c> specifies a <em>segment</em> of + the bit string. Each element <c>Ei</c> is a value, followed by an + optional <em>size expression</em> and an optional <em>type specifier list</em>.</p> + <pre> +Ei = Value | + Value:Size | + Value/TypeSpecifierList | + Value:Size/TypeSpecifierList</pre> + <p>Used in a bit string construction, <c>Value</c> is an expression + which should evaluate to an integer, float or bit string. If the + expression is something else than a single literal or variable, it + should be enclosed in parenthesis.</p> + + <p>Used in a bit string matching, <c>Value</c> must be a variable, + or an integer, float or string.</p> + + <p>Note that, for example, using a string literal as in + <c><![CDATA[<<"abc">>]]></c> is syntactic sugar for + <c><![CDATA[<<$a,$b,$c>>]]></c>.</p> + + <p>Used in a bit string construction, <c>Size</c> is an expression + which should evaluate to an integer.</p> + + <p>Used in a bit string matching, <c>Size</c> must be an integer or a + variable bound to an integer.</p> + + <p>The value of <c>Size</c> specifies the size of the segment in + units (see below). The default value depends on the type (see + below). For <c>integer</c> it is 8, for + <c>float</c> it is 64, for <c>binary</c> and <c>bitstring</c> it is + the whole binary or bit string. In matching, this default value is only + valid for the very last element. All other bit string or binary + elements in the matching must have a size specification.</p> + + <p>For the <c>utf8</c>, <c>utf16</c>, and <c>utf32</c> types, + <c>Size</c> must not be given. The size of the segment is implicitly + determined by the type and value itself.</p> + + <p><c>TypeSpecifierList</c> is a list of type specifiers, in any + order, separated by hyphens (-). Default values are used for any + omitted type specifiers.</p> + <taglist> + <tag><c>Type</c>= <c>integer</c> | <c>float</c> | <c>binary</c> | + <c>bytes</c> | <c>bitstring</c> | <c>bits</c> | + <c>utf8</c> | <c>utf16</c> | <c>utf32</c> </tag> + <item>The default is <c>integer</c>. <c>bytes</c> is a shorthand for + <c>binary</c> and <c>bits</c> is a shorthand for <c>bitstring</c>. + See below for more information about the <c>utf</c> types. + </item> + + <tag><c>Signedness</c>= <c>signed</c> | <c>unsigned</c></tag> + <item>Only matters for matching and when the type is <c>integer</c>. + The default is <c>unsigned</c>.</item> + + <tag><c>Endianness</c>= <c>big</c> | <c>little</c> | <c>native</c></tag> + <item>Native-endian means that the endianness will be resolved at load + time to be either big-endian or little-endian, depending on + what is native for the CPU that the Erlang machine is run on. + Endianness only matters when the Type is either <c>integer</c>, + <c>utf16</c>, <c>utf32</c>, or <c>float</c>. The default is <c>big</c>. + </item> + + <tag><c>Unit</c>= <c>unit:IntegerLiteral</c></tag> + <item>The allowed range is 1..256. Defaults to 1 for <c>integer</c>, + <c>float</c> and <c>bitstring</c>, and to 8 for <c>binary</c>. + No unit specifier must be given for the types + <c>utf8</c>, <c>utf16</c>, and <c>utf32</c>. + </item> + </taglist> + <p>The value of <c>Size</c> multiplied with the unit gives + the number of bits. A segment of type <c>binary</c> must have + a size that is evenly divisible by 8.</p> + + <note><p>When constructing binaries, if the size <c>N</c> of an integer + segment is too small to contain the given integer, the most significant + bits of the integer will be silently discarded and only the <c>N</c> least + significant bits will be put into the binary.</p></note> + + <p>The types <c>utf8</c>, <c>utf16</c>, and <c>utf32</c> specifies + encoding/decoding of the <em>Unicode Transformation Format</em>s UTF-8, UTF-16, + and UTF-32, respectively.</p> + + <p>When constructing a segment of a <c>utf</c> type, <c>Value</c> + must be an integer in one of the ranges 0..16#D7FF, + 16#E000..16#FFFD, or 16#10000..16#10FFFF + (i.e. a valid Unicode code point). Construction + will fail with a <c>badarg</c> exception if <c>Value</c> is + outside the allowed ranges. The size of the resulting binary + segment depends on the type and/or <c>Value</c>. For <c>utf8</c>, + <c>Value</c> will be encoded in 1 through 4 bytes. For + <c>utf16</c>, <c>Value</c> will be encoded in 2 or 4 + bytes. Finally, for <c>utf32</c>, <c>Value</c> will always be + encoded in 4 bytes.</p> + + <p>When constructing, a literal string may be given followed + by one of the UTF types, for example: <c><![CDATA[<<"abc"/utf8>>]]></c> + which is syntatic sugar for + <c><![CDATA[<<$a/utf8,$b/utf8,$c/utf8>>]]></c>.</p> + + <p>A successful match of a segment of a <c>utf</c> type results + in an integer in one of the ranges 0..16#D7FF, 16#E000..16#FFFD, + or 16#10000..16#10FFFF + (i.e. a valid Unicode code point). The match will fail if returned value + would fall outside those ranges.</p> + + <p>A segment of type <c>utf8</c> will match 1 to 4 bytes in the binary, + if the binary at the match position contains a valid UTF-8 sequence. + (See RFC-2279 or the Unicode standard.)</p> + + <p>A segment of type <c>utf16</c> may match 2 or 4 bytes in the binary. + The match will fail if the binary at the match position does not contain + a legal UTF-16 encoding of a Unicode code point. (See RFC-2781 or + the Unicode standard.)</p> + + <p>A segment of type <c>utf32</c> may match 4 bytes in the binary in the + same way as an <c>integer</c> segment matching 32 bits. + The match will fail if the resulting integer is outside the legal ranges + mentioned above.</p> + + <p>Examples:</p> + <pre> +1> <input>Bin1 = <<1,17,42>>.</input> +<<1,17,42>> +2> <input>Bin2 = <<"abc">>.</input> +<<97,98,99>> +3> <input>Bin3 = <<1,17,42:16>>.</input> +<<1,17,0,42>> +4> <input><<A,B,C:16>> = <<1,17,42:16>>.</input> +<<1,17,0,42>> +5> <input>C.</input> +42 +6> <input><<D:16,E,F>> = <<1,17,42:16>>.</input> +<<1,17,0,42>> +7> <input>D.</input> +273 +8> <input>F.</input> +42 +9> <input><<G,H/binary>> = <<1,17,42:16>>.</input> +<<1,17,0,42>> +10> <input>H.</input> +<<17,0,42>> +11> <input><<G,H/bitstring>> = <<1,17,42:12>>.</input> +<<1,17,1,10:4>> +12> <input>H.</input> +<<17,1,10:4>> +13> <input><<1024/utf8>>.</input> +<<208,128>> +</pre> + <p>Note that bit string patterns cannot be nested.</p> + <p>Note also that "<c><![CDATA[B=<<1>>]]></c>" is interpreted as + "<c><![CDATA[B =<<1>>]]></c>" which is a syntax error. The correct way is + to write a space after '=': "<c><![CDATA[B= <<1>>]]></c>.</p> + <p>More examples can be found in <em>Programming Examples</em>.</p> + </section> + + <section> + <marker id="funs"></marker> + <title>Fun Expressions</title> + <pre> +fun + (Pattern11,...,Pattern1N) [when GuardSeq1] -> + Body1; + ...; + (PatternK1,...,PatternKN) [when GuardSeqK] -> + BodyK +end</pre> + <p>A fun expression begins with the keyword <c>fun</c> and ends + with the keyword <c>end</c>. Between them should be a function + declaration, similar to a + <seealso marker="functions#syntax">regular function declaration</seealso>, except that no function name is + specified.</p> + <p>Variables in a fun head shadow variables in the + function clause surrounding the fun expression, and + variables bound in a fun body are local to the fun body.</p> + <p>The return value of the expression is the resulting fun.</p> + <p>Examples:</p> + <pre> +1> <input>Fun1 = fun (X) -> X+1 end.</input> +#Fun<erl_eval.6.39074546> +2> <input>Fun1(2).</input> +3 +3> <input>Fun2 = fun (X) when X>=5 -> gt; (X) -> lt end.</input> +#Fun<erl_eval.6.39074546> +4> <input>Fun2(7).</input> +gt</pre> + <p>The following fun expressions are also allowed:</p> + <pre> +fun Name/Arity +fun Module:Name/Arity</pre> + <p>In <c>Name/Arity</c>, <c>Name</c> is an atom and <c>Arity</c> is an integer. + <c>Name/Arity</c> must specify an existing local function. The expression is + syntactic sugar for:</p> + <pre> +fun (Arg1,...,ArgN) -> Name(Arg1,...,ArgN) end</pre> + <p>In <c>Module:Name/Arity</c>, <c>Module</c> and <c>Name</c> are atoms + and <c>Arity</c> is an integer. + A fun defined in this way will refer to the function <c>Name</c> + with arity <c>Arity</c> in the <em>latest</em> version of module <c>Module</c>. + </p> + <p>When applied to a number N of arguments, a tuple + <c>{Module,FunctionName}</c> is interpreted as a fun, referring + to the function <c>FunctionName</c> with arity N in the module + <c>Module</c>. The function must be exported. + <em>This usage is deprecated.</em> + See <seealso marker="#calls">Function Calls</seealso> for an example.</p> + <p>More examples can be found in <em>Programming Examples</em>.</p> + </section> + + <section> + <marker id="catch"></marker> + <title>Catch and Throw</title> + <code type="none"> +catch Expr</code> + <p>Returns the value of <c>Expr</c> unless an exception + occurs during the evaluation. In that case, the exception is + caught. For exceptions of class <c>error</c>, + that is run-time errors: <c>{'EXIT',{Reason,Stack}}</c> + is returned. For exceptions of class <c>exit</c>, that is + the code called <c>exit(Term)</c>: <c>{'EXIT',Term}</c> is returned. + For exceptions of class <c>throw</c>, that is + the code called <c>throw(Term)</c>: <c>Term</c> is returned.</p> + <p><c>Reason</c> depends on the type of error that occurred, and + <c>Stack</c> is the stack of recent function calls, see + <seealso marker="errors#exit_reasons">Errors and Error Handling</seealso>.</p> + <p>Examples:</p> + <p></p> + <pre> +1> <input>catch 1+2.</input> +3 +2> <input>catch 1+a.</input> +{'EXIT',{badarith,[...]}}</pre> + <p>Note that <c>catch</c> has low precedence and catch + subexpressions often needs to be enclosed in a block + expression or in parenthesis:</p> + <pre> +3> <input>A = catch 1+2.</input> +** 1: syntax error before: 'catch' ** +4> <input>A = (catch 1+2).</input> +3</pre> + <p>The BIF <c>throw(Any)</c> can be used for non-local return from + a function. It must be evaluated within a <c>catch</c>, which will + return the value <c>Any</c>. Example:</p> + <pre> +5> <input>catch throw(hello).</input> +hello</pre> + <p>If <c>throw/1</c> is not evaluated within a catch, a + <c>nocatch</c> run-time error will occur.</p> + </section> + + <section> + <marker id="try"></marker> + <title>Try</title> + <code type="none"> +try Exprs +catch + [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] -> + ExceptionBody1; + [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] -> + ExceptionBodyN +end</code> + <p>This is an enhancement of + <seealso marker="#catch">catch</seealso> that appeared in + Erlang 5.4/OTP-R10B. It gives the possibility do distinguish + between different exception classes, and to choose to handle only + the desired ones, passing the others on to an enclosing + <c>try</c> or <c>catch</c> or to default error handling.</p> + <p>Note that although the keyword <c>catch</c> is used in + the <c>try</c> expression, there is not a <c>catch</c> expression + within the <c>try</c> expression.</p> + <p>Returns the value of <c>Exprs</c> (a sequence of expressions + <c>Expr1, ..., ExprN</c>) unless an exception occurs during + the evaluation. In that case the exception is caught and + the patterns <c>ExceptionPattern</c> with the right exception + class <c>Class</c> are sequentially matched against the caught + exception. An omitted <c>Class</c> is shorthand for <c>throw</c>. + If a match succeeds and the optional guard sequence + <c>ExceptionGuardSeq</c> is true, the corresponding + <c>ExceptionBody</c> is evaluated to become the return value.</p> + <p>If an exception occurs during evaluation of <c>Exprs</c> but + there is no matching <c>ExceptionPattern</c> of the right + <c>Class</c> with a true guard sequence, the exception is passed + on as if <c>Exprs</c> had not been enclosed in a <c>try</c> + expression.</p> + <p>If an exception occurs during evaluation of <c>ExceptionBody</c> + it is not caught.</p> + <p>The <c>try</c> expression can have an <c>of</c> + section: + </p> + <code type="none"> +try Exprs of + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +catch + [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] -> + ExceptionBody1; + ...; + [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] -> + ExceptionBodyN +end</code> + <p>If the evaluation of <c>Exprs</c> succeeds without an exception, + the patterns <c>Pattern</c> are sequentially matched against + the result in the same way as for a + <seealso marker="#case">case</seealso> expression, except that if + the matching fails, a <c>try_clause</c> run-time error will occur.</p> + <p>An exception occurring during the evaluation of <c>Body</c> is + not caught.</p> + <p>The <c>try</c> expression can also be augmented with an + <c>after</c> section, intended to be used for cleanup with side + effects:</p> + <code type="none"> +try Exprs of + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +catch + [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] -> + ExceptionBody1; + ...; + [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] -> + ExceptionBodyN +after + AfterBody +end</code> + <p><c>AfterBody</c> is evaluated after either <c>Body</c> or + <c>ExceptionBody</c> no matter which one. The evaluated value of + <c>AfterBody</c> is lost; the return value of the <c>try</c> + expression is the same with an <c>after</c> section as without.</p> + <p>Even if an exception occurs during evaluation of <c>Body</c> or + <c>ExceptionBody</c>, <c>AfterBody</c> is evaluated. In this case + the exception is passed on after <c>AfterBody</c> has been + evaluated, so the exception from the <c>try</c> expression is + the same with an <c>after</c> section as without.</p> + <p>If an exception occurs during evaluation of <c>AfterBody</c> + itself it is not caught, so if <c>AfterBody</c> is evaluated after + an exception in <c>Exprs</c>, <c>Body</c> or <c>ExceptionBody</c>, + that exception is lost and masked by the exception in + <c>AfterBody</c>.</p> + <p>The <c>of</c>, <c>catch</c> and <c>after</c> sections are all + optional, as long as there is at least a <c>catch</c> or an + <c>after</c> section, so the following are valid <c>try</c> + expressions:</p> + <code type="none"> +try Exprs of + Pattern when GuardSeq -> + Body +after + AfterBody +end + +try Exprs +catch + ExpressionPattern -> + ExpressionBody +after + AfterBody +end + +try Exprs after AfterBody end</code> + <p>Example of using <c>after</c>, this code will close the file + even in the event of exceptions in <c>file:read/2</c> or in + <c>binary_to_term/1</c>, and exceptions will be the same as + without the <c>try</c>...<c>after</c>...<c>end</c> expression:</p> + <code type="none"> +termize_file(Name) -> + {ok,F} = file:open(Name, [read,binary]), + try + {ok,Bin} = file:read(F, 1024*1024), + binary_to_term(Bin) + after + file:close(F) + end.</code> + <p>Example: Using <c>try</c> to emulate <c>catch Expr</c>.</p> + <code type="none"> +try Expr +catch + throw:Term -> Term; + exit:Reason -> {'EXIT',Reason} + error:Reason -> {'EXIT',{Reason,erlang:get_stacktrace()}} +end</code> + </section> + + <section> + <title>Parenthesized Expressions</title> + <pre> +(Expr)</pre> + <p>Parenthesized expressions are useful to override + <seealso marker="#prec">operator precedences</seealso>, + for example in arithmetic expressions:</p> + <pre> +1> <input>1 + 2 * 3.</input> +7 +2> <input>(1 + 2) * 3.</input> +9</pre> + </section> + + <section> + <title>Block Expressions</title> + <pre> +begin + Expr1, + ..., + ExprN +end</pre> + <p>Block expressions provide a way to group a sequence of + expressions, similar to a clause body. The return value is + the value of the last expression <c>ExprN</c>.</p> + </section> + + <section> + <marker id="lcs"></marker> + <title>List Comprehensions</title> + <p>List comprehensions are a feature of many modern functional + programming languages. Subject to certain rules, they provide a + succinct notation for generating elements in a list.</p> + <p>List comprehensions are analogous to set comprehensions in + Zermelo-Frankel set theory and are called ZF expressions in + Miranda. They are analogous to the <c>setof</c> and + <c>findall</c> predicates in Prolog.</p> + <p>List comprehensions are written with the following syntax:</p> + <pre> +[Expr || Qualifier1,...,QualifierN]</pre> + <p><c>Expr</c> is an arbitrary expression, and each + <c>Qualifier</c> is either a generator or a filter.</p> + <list type="bulleted"> + <item>A <em>generator</em> is written as: <br></br> + + <c><![CDATA[Pattern <- ListExpr]]></c>. <br></br> +<c>ListExpr</c> must be an expression which evaluates to a + list of terms.</item> +<item>A <em>bit string generator</em> is written as: <br></br> + + <c><![CDATA[BitstringPattern <= BitStringExpr]]></c>. <br></br> +<c>BitStringExpr</c> must be an expression which evaluates to a + bitstring.</item> + <item>A <em>filter</em> is an expression which evaluates to + <c>true</c> or <c>false</c>.</item> + </list> + <p>The variables in the generator patterns shadow variables in the function + clause surrounding the list comprehensions.</p> <p>A list comprehension + returns a list, where the elements are the result of evaluating <c>Expr</c> + for each combination of generator list elements and bit string generator + elements for which all filters are true.</p> <p></p> <p>Example:</p> + <pre> +1> <input>[X*2 || X <- [1,2,3]].</input> +[2,4,6]</pre> + <p>More examples can be found in <em>Programming Examples</em>.</p> + + + </section> + +<section> + <title>Bit String Comprehensions</title> + + <p>Bit string comprehensions are + analogous to List Comprehensions. They are used to generate bit strings + efficiently and succinctly.</p> + <p>Bit string comprehensions are written with + the following syntax:</p> + <pre> +<< BitString || Qualifier1,...,QualifierN >></pre> + <p><c>BitString</c> is a bit string expression, and each + <c>Qualifier</c> is either a generator, a bit string generator or a filter.</p> + <list type="bulleted"> + <item>A <em>generator</em> is written as: <br></br> + <c><![CDATA[Pattern <- ListExpr]]></c>. <br></br> + <c>ListExpr</c> must be an expression which evaluates to a + list of terms.</item> + <item>A <em>bit string generator</em> is written as: <br></br> + + <c><![CDATA[BitstringPattern <= BitStringExpr]]></c>. <br></br> +<c>BitStringExpr</c> must be an expression which evaluates to a + bitstring.</item> + <item>A <em>filter</em> is an expression which evaluates to + <c>true</c> or <c>false</c>.</item> + </list> + <p>The variables in the generator patterns shadow variables in + the function clause surrounding the bit string comprehensions.</p> + <p>A bit string comprehension returns a bit string, which is + created by concatenating the results of evaluating <c>BitString</c> + for each combination of bit string generator elements for which all + filters are true.</p> + <p></p> + <p>Example:</p> + <pre> +1> <input><< << (X*2) >> || +<<X>> <= << 1,2,3 >> >>.</input> +<<2,4,6>></pre> + <p>More examples can be found in <em>Programming Examples</em>.</p> + </section> + + <section> + <marker id="guards"></marker> + <title>Guard Sequences</title> + + <p>A <em>guard sequence</em> is a sequence of guards, separated + by semicolon (;). The guard sequence is true if at least one of + the guards is true. (The remaining guards, if any, will not be + evaluated.)<br></br> +<c>Guard1;...;GuardK</c></p> + <p>A <em>guard</em> is a sequence of guard expressions, separated + by comma (,). The guard is true if all guard expressions + evaluate to <c>true</c>.<br></br> +<c>GuardExpr1,...,GuardExprN</c></p> + <p>The set of valid <em>guard expressions</em> (sometimes called + guard tests) is a subset of the set of valid Erlang expressions. + The reason for restricting the set of valid expressions is that + evaluation of a guard expression must be guaranteed to be free + of side effects. Valid guard expressions are:</p> + <list type="bulleted"> + <item>the atom <c>true</c>,</item> + <item>other constants (terms and bound variables), all regarded + as false,</item> + <item>calls to the BIFs specified below,</item> + <item>term comparisons,</item> + <item>arithmetic expressions,</item> + <item>boolean expressions, and</item> + <item>short-circuit expressions (<c>andalso</c>/<c>orelse</c>).</item> + </list> + <table> + <row> + <cell align="left" valign="middle"><c>is_atom/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_binary/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_bitstring/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_float/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_function/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_function/2</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_integer/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_list/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_number/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_pid/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_port/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_record/2</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_record/3</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_reference/1</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>is_tuple/1</c></cell> + </row> + <tcaption>Type Test BIFs.</tcaption> + </table> + <p>Note that most type test BIFs have older equivalents, without + the <c>is_</c> prefix. These old BIFs are retained for backwards + compatibility only and should not be used in new code. They are + also only allowed at top level. For example, they are not allowed + in boolean expressions in guards.</p> + <table> + <row> + <cell align="left" valign="middle"><c>abs(Number)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>bit_size(Bitstring)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>byte_size(Bitstring)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>element(N, Tuple)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>float(Term)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>hd(List)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>length(List)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>node()</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>node(Pid|Ref|Port)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>round(Number)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>self()</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>size(Tuple|Bitstring)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>tl(List)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>trunc(Number)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>tuple_size(Tuple)</c></cell> + </row> + <tcaption>Other BIFs Allowed in Guard Expressions.</tcaption> + </table> + + <p>If an arithmetic expression, a boolean expression, a + short-circuit expression, or a call to a guard BIF fails (because + of invalid arguments), the entire guard fails. If the guard was + part of a guard sequence, the next guard in the sequence (that is, + the guard following the next semicolon) will be evaluated.</p> + + </section> + + <section> + <marker id="prec"></marker> + <title>Operator Precedence</title> + <p>Operator precedence in falling priority:</p> + <table> + <row> + <cell align="left" valign="middle">:</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">#</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">Unary + - bnot not</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">/ * div rem band and</cell> + <cell align="left" valign="middle">Left associative</cell> + </row> + <row> + <cell align="left" valign="middle">+ - bor bxor bsl bsr or xor</cell> + <cell align="left" valign="middle">Left associative</cell> + </row> + <row> + <cell align="left" valign="middle">++ --</cell> + <cell align="left" valign="middle">Right associative</cell> + </row> + <row> + <cell align="left" valign="middle">== /= =< < >= > =:= =/=</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">andalso</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">orelse</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> + <cell align="left" valign="middle">= !</cell> + <cell align="left" valign="middle">Right associative</cell> + </row> + <row> + <cell align="left" valign="middle">catch</cell> + <cell align="left" valign="middle"> </cell> + </row> + <tcaption>Operator Precedence.</tcaption> + </table> + <p>When evaluating an expression, the operator with the highest + priority is evaluated first. Operators with the same priority + are evaluated according to their associativity. Example: + The left associative arithmetic operators are evaluated left to + right:</p> + <pre> +<input>6 + 5 * 4 - 3 / 2</input> evaluates to +<input>6 + 20 - 1.5</input> evaluates to +<input>26 - 1.5</input> evaluates to +<input>24.5</input></pre> + </section> +</chapter> + diff --git a/system/doc/reference_manual/functions.xml b/system/doc/reference_manual/functions.xml new file mode 100644 index 0000000000..3746ee6fad --- /dev/null +++ b/system/doc/reference_manual/functions.xml @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Functions</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>functions.xml</file> + </header> + + <section> + <marker id="syntax"></marker> + <title>Function Declaration Syntax</title> + <p>A <em>function declaration</em> is a sequence of function + clauses separated by semicolons, and terminated by period (.).</p> + <p>A <em>function clause</em> consists of a clause head and a + clause body, separated by <c>-></c>.</p> + <p>A clause <em>head</em> consists of the function name, an + argument list, and an optional guard sequence + beginning with the keyword <c>when</c>.</p> + <pre> +Name(Pattern11,...,Pattern1N) [when GuardSeq1] -> + Body1; +...; +Name(PatternK1,...,PatternKN) [when GuardSeqK] -> + BodyK.</pre> + <p>The function name is an atom. Each argument is a pattern.</p> + <p>The number of arguments <c>N</c> is the <em>arity</em> of + the function. A function is uniquely defined by the module name, + function name and arity. That is, two functions with the same + name and in the same module, but with different arities are two + completely different functions.</p> + <p>A function named <c>f</c> in the module <c>m</c> and with arity + <c>N</c> is often denoted as <c>m:f/N</c>.</p> + <p>A clause <em>body</em> consists of a sequence of expressions + separated by comma (,):</p> + <pre> +Expr1, +..., +ExprN</pre> + <p>Valid Erlang expressions and guard sequences are described in + <seealso marker="expressions">Erlang Expressions</seealso>.</p> + <p>Example:</p> + <pre> +fact(N) when N>0 -> % first clause head + N * fact(N-1); % first clause body + +fact(0) -> % second clause head + 1. % second clause body</pre> + </section> + + <section> + <marker id="eval"></marker> + <title>Function Evaluation</title> + <p>When a function <c>m:f/N</c> is called, first the code for + the function is located. If the function cannot be found, an + <c>undef</c> run-time error will occur. Note that the function + must be exported to be visible outside the module it is defined + in.</p> + <p>If the function is found, the function clauses are scanned + sequentially until a clause is found that fulfills the following + two conditions:</p> + <list type="ordered"> + <item>the patterns in the clause head can be successfully + matched against the given arguments, and</item> + <item>the guard sequence, if any, is true.</item> + </list> + <p>If such a clause cannot be found, a <c>function_clause</c> + run-time error will occur.</p> + <p>If such a clause is found, the corresponding clause body is + evaluated. That is, the expressions in the body are evaluated + sequentially and the value of the last expression is returned.</p> + <p>Example: Consider the function <c>fact</c>:</p> + <pre> +-module(m). +-export([fact/1]). + +fact(N) when N>0 -> + N * fact(N-1); +fact(0) -> + 1.</pre> + <p>Assume we want to calculate factorial for 1:</p> + <pre> +1> <input>m:fact(1).</input></pre> + <p>Evaluation starts at the first clause. The pattern <c>N</c> is + matched against the argument 1. The matching succeeds and + the guard (<c>N>0</c>) is true, thus <c>N</c> is bound to 1 and + the corresponding body is evaluated:</p> + <pre> +<input>N * fact(N-1)</input> => (N is bound to 1) +<input>1 * fact(0)</input></pre> + <p>Now <c>fact(0)</c> is called and the function clauses are + scanned sequentially again. First, the pattern <c>N</c> is + matched against 0. The matching succeeds, but the guard + (<c>N>0</c>) is false. Second, the pattern 0 is matched against + 0. The matching succeeds and the body is evaluated:</p> + <pre> +<input>1 * fact(0)</input> => +<input>1 * 1</input> => +<input>1</input></pre> + <p>Evaluation has succeed and <c>m:fact(1)</c> returns 1.</p> + <p>If <c>m:fact/1</c> is called with a negative number as + argument, no clause head will match. A <c>function_clause</c> + run-time error will occur.</p> + </section> + + <section> + <title>Tail recursion</title> + <p>If the last expression of a function body is a function call, + a <em>tail recursive</em> call is done so that no system + resources for example call stack are consumed. This means + that an infinite loop can be done if it uses tail recursive + calls.</p> + <p>Example:</p> + <pre> +loop(N) -> + io:format("~w~n", [N]), + loop(N+1).</pre> + <p>As a counter-example see the factorial example above + that is not tail recursive since a multiplication is done + on the result of the recursive call to <c>fact(N-1)</c>.</p> + </section> + + <section> + <title>Built-In Functions, BIFs</title> + <p><em>Built-in functions</em>, BIFs, are implemented in C code in + the runtime system and do things that are difficult or impossible + to implement in Erlang. Most of the built-in functions belong + to the module <c>erlang</c> but there are also built-in functions + belonging to a few other modules, for example <c>lists</c> and + <c>ets</c>.</p> + <p>The most commonly used BIFs belonging to <c>erlang</c> are + <em>auto-imported</em>, they do not need to be prefixed with + the module name. Which BIFs are auto-imported is specified in + <c>erlang(3)</c>. For example, standard type conversion BIFs like + <c>atom_to_list</c> and BIFs allowed in guards can be called + without specifying the module name. Examples:</p> + <pre> +1> <input>tuple_size({a,b,c}).</input> +3 +2> <input>atom_to_list('Erlang').</input> +"Erlang"</pre> + <p>Note that normally it is the set of auto-imported built-in + functions that is referred to when talking about 'BIFs'.</p> + </section> +</chapter> + diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml new file mode 100644 index 0000000000..3dac5cfe13 --- /dev/null +++ b/system/doc/reference_manual/introduction.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>introduction.xml</file> + </header> + + <section> + <title>Purpose</title> + <p>This reference manual describes the Erlang programming + language. The focus is on the language itself, not + the implementation. The language constructs are described in + text and with examples rather than formally specified, with + the intention to make the manual more readable. + The manual is not intended as a tutorial.</p> + <p>Information about this implementation of Erlang can be found, for + example, in <em>System Principles</em> (starting and stopping, + boot scripts, code loading, error logging, creating target + systems), <em>Efficiency Guide</em> (memory consumption, system + limits) and <em>ERTS User's Guide</em> (crash dumps, drivers).</p> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader has done some programming and + is familiar with concepts such as data types and programming + language syntax.</p> + </section> + + <section> + <title>Document Conventions</title> + <p>In the document, the following terminology is used:</p> + <list type="bulleted"> + <item>A <em>sequence</em> is one or more items. For example, a + clause body consists of a sequence of expressions. This + means that there must be at least one expression.</item> + <item>A <em>list</em> is any number of items. For example, + an argument list can consist of zero, one or more arguments.</item> + </list> + <p>If a feature has been added recently, in Erlang 5.0/OTP R7 or + later, this is mentioned in the text.</p> + </section> + + <section> + <title>Complete List of BIFs</title> + <p>For a complete list of BIFs, their arguments and return values, + refer to <c>erlang(3)</c>.</p> + </section> + + <section> + <title>Reserved Words</title> + <p>The following are reserved words in Erlang:</p> + <p>after and andalso band begin bnot bor bsl bsr bxor case catch + cond div end fun if let not of or orelse query receive rem try + when xor</p> + </section> + + <section> + <title>Character Set</title> + <p>In Erlang 4.8/OTP R5A the syntax of Erlang tokens was extended to + allow the use of the full ISO-8859-1 (Latin-1) character set. This + is noticeable in the following ways:</p> + <list type="bulleted"> + <item> + <p>All the Latin-1 printable characters can be used and are + shown without the escape backslash convention.</p> + </item> + <item> + <p>Atoms and variables can use all Latin-1 letters.</p> + </item> + </list> + <table> + <row> + <cell align="left" valign="middle"><em>Octal</em></cell> + <cell align="left" valign="middle"><em>Decimal</em></cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle"><em>Class</em></cell> + </row> + <row> + <cell align="left" valign="middle">200 - 237</cell> + <cell align="left" valign="middle">128 - 159</cell> + <cell align="left" valign="middle"> </cell> + <cell align="left" valign="middle">Control characters</cell> + </row> + <row> + <cell align="left" valign="middle">240 - 277</cell> + <cell align="left" valign="middle">160 - 191</cell> + <cell align="right" valign="middle">- ¿</cell> + <cell align="left" valign="middle">Punctuation characters</cell> + </row> + <row> + <cell align="left" valign="middle">300 - 326</cell> + <cell align="left" valign="middle">192 - 214</cell> + <cell align="center" valign="middle">À - Ö</cell> + <cell align="left" valign="middle">Uppercase letters</cell> + </row> + <row> + <cell align="center" valign="middle">327</cell> + <cell align="center" valign="middle">215</cell> + <cell align="center" valign="middle">×</cell> + <cell align="left" valign="middle">Punctuation character</cell> + </row> + <row> + <cell align="left" valign="middle">330 - 336</cell> + <cell align="left" valign="middle">216 - 222</cell> + <cell align="center" valign="middle">Ø - Þ</cell> + <cell align="left" valign="middle">Uppercase letters</cell> + </row> + <row> + <cell align="left" valign="middle">337 - 366</cell> + <cell align="left" valign="middle">223 - 246</cell> + <cell align="center" valign="middle">ß - ö</cell> + <cell align="left" valign="middle">Lowercase letters</cell> + </row> + <row> + <cell align="center" valign="middle">367</cell> + <cell align="center" valign="middle">247</cell> + <cell align="center" valign="middle">÷</cell> + <cell align="left" valign="middle">Punctuation character</cell> + </row> + <row> + <cell align="left" valign="middle">370 - 377</cell> + <cell align="left" valign="middle">248 - 255</cell> + <cell align="center" valign="middle">ø - ÿ</cell> + <cell align="left" valign="middle">Lowercase letters</cell> + </row> + <tcaption>Character Classes.</tcaption> + </table> + </section> +</chapter> + diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml new file mode 100644 index 0000000000..a1ba182eff --- /dev/null +++ b/system/doc/reference_manual/macros.xml @@ -0,0 +1,211 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The Preprocessor</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>macros.xml</file> + </header> + + <section> + <title>File Inclusion</title> + <p>A file can be included in the following way:</p> + <pre> +-include(File). +-include_lib(File).</pre> + <p><c>File</c>, a string, should point out a file. The contents of + this file are included as-is, at the position of the directive.</p> + <p>Include files are typically used for record and macro + definitions that are shared by several modules. It is + recommended that the file name extension <c>.hrl</c> be used + for include files.</p> + <p><c>File</c> may start with a path component <c>$VAR</c>, for + some string <c>VAR</c>. If that is the case, the value of + the environment variable <c>VAR</c> as returned by + <c>os:getenv(VAR)</c> is substituted for <c>$VAR</c>. If + <c>os:getenv(VAR)</c> returns <c>false</c>, <c>$VAR</c> is left + as is.</p> + <p>If the filename <c>File</c> is absolute (possibly after + variable substitution), the include file with that name is + included. Otherwise, the specified file is searched for in + the current working directory, in the same directory as + the module being compiled, and in the directories given by + the <c>include</c> option, in that order. + See <c>erlc(1)</c> and <c>compile(3)</c> for details.</p> + <p>Examples:</p> + <pre> +-include("my_records.hrl"). +-include("incdir/my_records.hrl"). +-include("/home/user/proj/my_records.hrl"). +-include("$PROJ_ROOT/my_records.hrl").</pre> + <p><c>include_lib</c> is similar to <c>include</c>, but should not + point out an absolute file. Instead, the first path component + (possibly after variable substitution) is assumed to be + the name of an application. Example:</p> + <pre> +-include_lib("kernel/include/file.hrl").</pre> + <p>The code server uses <c>code:lib_dir(kernel)</c> to find + the directory of the current (latest) version of Kernel, and + then the subdirectory <c>include</c> is searched for the file + <c>file.hrl</c>.</p> + </section> + + <section> + <title>Defining and Using Macros</title> + <p>A macro is defined the following way:</p> + <code type="none"> +-define(Const, Replacement). +-define(Func(Var1,...,VarN), Replacement).</code> + <p>A macro definition can be placed anywhere among the attributes + and function declarations of a module, but the definition must + come before any usage of the macro.</p> + <p>If a macro is used in several modules, it is recommended that + the macro definition is placed in an include file.</p> + <p>A macro is used the following way:</p> + <code type="none"> +?Const +?Func(Arg1,...,ArgN)</code> + <p>Macros are expanded during compilation. A simple macro + <c>?Const</c> will be replaced with <c>Replacement</c>. + Example:</p> + <code type="none"> +-define(TIMEOUT, 200). +... +call(Request) -> + server:call(refserver, Request, ?TIMEOUT).</code> + <p>This will be expanded to:</p> + <code type="none"> +call(Request) -> + server:call(refserver, Request, 200).</code> + <p>A macro <c>?Func(Arg1,...,ArgN)</c> will be replaced with + <c>Replacement</c>, where all occurrences of a variable <c>Var</c> + from the macro definition are replaced with the corresponding + argument <c>Arg</c>. Example:</p> + <code type="none"> +-define(MACRO1(X, Y), {a, X, b, Y}). +... +bar(X) -> + ?MACRO1(a, b), + ?MACRO1(X, 123)</code> + <p>This will be expanded to:</p> + <code type="none"> +bar(X) -> + {a,a,b,b}, + {a,X,b,123}.</code> + <p>It is good programming practice, but not mandatory, to ensure + that a macro definition is a valid Erlang syntactic form.</p> + <p>To view the result of macro expansion, a module can be compiled + with the <c>'P'</c> option. <c>compile:file(File, ['P'])</c>. + This produces a listing of the parsed code after preprocessing + and parse transforms, in the file <c>File.P</c>.</p> + </section> + + <section> + <title>Predefined Macros</title> + <p>The following macros are predefined:</p> + <taglist> + <tag><c>?MODULE</c></tag> + <item>The name of the current module.</item> + <tag><c>?MODULE_STRING</c>.</tag> + <item>The name of the current module, as a string.</item> + <tag><c>?FILE</c>.</tag> + <item>The file name of the current module.</item> + <tag><c>?LINE</c>.</tag> + <item>The current line number.</item> + <tag><c>?MACHINE</c>.</tag> + <item>The machine name, <c>'BEAM'</c>.</item> + </taglist> + </section> + + <section> + <title>Flow Control in Macros</title> + <p>The following macro directives are supplied:</p> + <taglist> + <tag><c>-undef(Macro).</c></tag> + <item>Causes the macro to behave as if it had never been defined.</item> + <tag><c>-ifdef(Macro).</c></tag> + <item>Evaluate the following lines only if <c>Macro</c> is + defined.</item> + <tag><c>-ifndef(Macro).</c></tag> + <item>Evaluate the following lines only if <c>Macro</c> is not + defined.</item> + <tag><c>-else.</c></tag> + <item>Only allowed after an <c>ifdef</c> or <c>ifndef</c> + directive. If that condition was false, the lines following + <c>else</c> are evaluated instead.</item> + <tag><c>-endif.</c></tag> + <item>Specifies the end of an <c>ifdef</c> or <c>ifndef</c> + directive.</item> + </taglist> + <note> + <p>The macro directives cannot be used inside functions.</p> + </note> + <p>Example:</p> + <code type="none"> +-module(m). +... + +-ifdef(debug). +-define(LOG(X), io:format("{~p,~p}: ~p~n", [?MODULE,?LINE,X])). +-else. +-define(LOG(X), true). +-endif. + +...</code> + <p>When trace output is desired, <c>debug</c> should be defined + when the module <c>m</c> is compiled:</p> + <pre> +% <input>erlc -Ddebug m.erl</input> + +or + +1> <input>c(m, {d, debug}).</input> +{ok,m}</pre> + <p><c>?LOG(Arg)</c> will then expand to a call to <c>io:format/2</c> + and provide the user with some simple trace output.</p> + </section> + + <section> + <title>Stringifying Macro Arguments</title> + <p>The construction <c>??Arg</c>, where <c>Arg</c> is a macro + argument, will be expanded to a string containing the tokens of + the argument. This is similar to the <c>#arg</c> stringifying + construction in C.</p> + <p>The feature was added in Erlang 5.0/OTP R7.</p> + <p>Example:</p> + <code type="none"> +-define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). + +?TESTCALL(myfunction(1,2)), +?TESTCALL(you:function(2,1)).</code> + <p>results in</p> + <code type="none"> +io:format("Call ~s: ~w~n",["myfunction ( 1 , 2 )",m:myfunction(1,2)]), +io:format("Call ~s: ~w~n",["you : function ( 2 , 1 )",you:function(2,1)]).</code> + <p>That is, a trace output with both the function called and + the resulting value.</p> + </section> +</chapter> + diff --git a/system/doc/reference_manual/make.dep b/system/doc/reference_manual/make.dep new file mode 100644 index 0000000000..0e7687448c --- /dev/null +++ b/system/doc/reference_manual/make.dep @@ -0,0 +1,16 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex code_loading.tex data_types.tex distributed.tex \ + errors.tex expressions.tex functions.tex introduction.tex \ + macros.tex modules.tex part.tex patterns.tex \ + ports.tex processes.tex records.tex + diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml new file mode 100644 index 0000000000..8b14ca3459 --- /dev/null +++ b/system/doc/reference_manual/modules.xml @@ -0,0 +1,254 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Modules</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>modules.xml</file> + </header> + + <section> + <title>Module Syntax</title> + <p>Erlang code is divided into <em>modules</em>. A module consists + of a sequence of attributes and function declarations, each + terminated by period (.). Example:</p> + <pre> +-module(m). % module attribute +-export([fact/1]). % module attribute + +fact(N) when N>0 -> % beginning of function declaration + N * fact(N-1); % | +fact(0) -> % | + 1. % end of function declaration</pre> + <p>See the <seealso marker="functions">Functions</seealso> chapter + for a description of function declarations.</p> + </section> + + <section> + <title>Module Attributes</title> + <p>A <em>module attribute</em> defines a certain property of a + module. A module attribute consists of a tag and a value.</p> + <pre> +-Tag(Value).</pre> + <p><c>Tag</c> must be an atom, while <c>Value</c> must be a literal + term. As a convenience in user-defined attributes, the literal term + <c>Value</c> the syntax <c>Name/Arity</c> + (where <c>Name</c> is an atom and <c>Arity</c> a positive integer) + will be translated to <c>{Name,Arity}</c>.</p> + + <p>Any module attribute can be specified. The attributes are stored + in the compiled code and can be retrieved by calling + <c>Module:module_info(attributes)</c> or by using + <seealso marker="stdlib:beam_lib#chunks/2">beam_lib(3)</seealso>.</p> + + <p>There are several module attributes with predefined meanings, + some of which have arity two, but user-defined module + attributes must have arity one.</p> + + <section> + <title>Pre-Defined Module Attributes</title> + <p>Pre-defined module attributes should be placed before any + function declaration.</p> + <taglist> + <tag><c>-module(Module).</c></tag> + <item> + <p>Module declaration, defining the name of the module. + The name <c>Module</c>, an atom, should be the same as + the file name minus the extension <c>erl</c>. Otherwise + <seealso marker="code_loading#loading">code loading</seealso> will + not work as intended.</p> + <p>This attribute should be specified first and is the only + attribute which is mandatory.</p> + </item> + <tag><c>-export(Functions).</c></tag> + <item> + <p>Exported functions. Specifies which of the functions + defined within the module that are visible outside + the module.</p> + <p><c>Functions</c> is a list + <c>[Name1/Arity1, ..., NameN/ArityN]</c>, where each + <c>NameI</c> is an atom and <c>ArityI</c> an integer.</p> + </item> + <tag><c>-import(Module,Functions).</c></tag> + <item> + <p>Imported functions. Imported functions can be called + the same way as local functions, that is without any module + prefix.</p> + <p><c>Module</c>, an atom, specifies which module to import + functions from. <c>Functions</c> is a list similar as for + <c>export</c> above.</p> + </item> + <tag><c>-compile(Options).</c></tag> + <item> + <p>Compiler options. <c>Options</c>, which is a single option + or a list of options, will be added to the option list when + compiling the module. See <c>compile(3)</c>.</p> + </item> + <tag><c>-vsn(Vsn).</c></tag> + <item> + <p>Module version. <c>Vsn</c> is any literal term and can be + retrieved using <c>beam_lib:version/1</c>, see + <seealso marker="stdlib:beam_lib#version/1">beam_lib(3)</seealso>.</p> + <p>If this attribute is not specified, the version defaults + to the MD5 checksum of the module.</p> + </item> + </taglist> + </section> + + <section> + <title>Behaviour Module Attribute</title> + <p>It is possible to specify that the module is the callback + module for a <em>behaviour</em>:</p> + <pre> +-behaviour(Behaviour).</pre> + <p>The atom <c>Behaviour</c> gives the name of the behaviour, + which can be a user defined behaviour or one of the OTP + standard behaviours <c>gen_server</c>, <c>gen_fsm</c>, + <c>gen_event</c> or <c>supervisor</c>.</p> + <p>The spelling <c>behavior</c> is also accepted.</p> + <p>Read more about behaviours and callback modules in OTP Design + Principles.</p> + </section> + + <section> + <title>Record Definitions</title> + <p>The same syntax as for module attributes is used by + for record definitions:</p> + <pre> +-record(Record,Fields).</pre> + <p>Record definitions are allowed anywhere in a module, + also among the function declarations. + Read more in <seealso marker="records">Records</seealso>.</p> + </section> + + <section> + <title>The Preprocessor</title> + <p>The same syntax as for module attributes is used by + the preprocessor, which supports file inclusion, macros, + and conditional compilation:</p> + <pre> +-include("SomeFile.hrl"). +-define(Macro,Replacement).</pre> + + <p>Read more in <seealso marker="macros">The Preprocessor</seealso>.</p> + </section> + + <section> + <title>Setting File and Line</title> + <p>The same syntax as for module attributes is used for + changing the pre-defined macros <c>?FILE</c> and <c>?LINE</c>:</p> + <pre> +-file(File, Line).</pre> + <p>This attribute is used by tools such as Yecc to inform the + compiler that the source program was generated by another tool + and indicates the correspondence of source files to lines of + the original user-written file from which the source program + was produced.</p> + </section> + </section> + + <section> + <title>Comments</title> + <p>Comments may be placed anywhere in a module except within strings + and quoted atoms. The comment begins with the character "%", + continues up to, but does not include the next end-of-line, and + has no effect. Note that the terminating end-of-line has + the effect of white space.</p> + </section> + + <section> + <title>The module_info/0 and module_info/1 functions</title> + + <p>The compiler automatically inserts the two special, exported + functions into each module: <c>Module:module_info/0</c> and + <c>Module:module_info/1</c>. These functions can be called to + retrieve information about the module.</p> + + <section> + <title>module_info/0</title> + <p>The <c>module_info/0</c> function in each module returns + a list of <c>{Key,Value}</c> tuples with information about + the module. Currently, the list contain tuples with the following + <c>Key</c>s: <c>attributes</c>, <c>compile</c>, + <c>exports</c>, and <c>imports</c>. The order and number of tuples + may change without prior notice.</p> + + <warning><p>The <c>{imports,Value}</c> tuple may be removed in a future + release because <c>Value</c> is always an empty list. + Do not write code that depends on it being present.</p></warning> + </section> + + <section> + <title>module_info/1</title> + <p>The call <c>module_info(Key)</c>, where key is an atom, + returns a single piece of information about the module.</p> + + <p>The following values are allowed for <c>Key</c>:</p> + + <taglist> + <tag><c>attributes</c></tag> + <item> + <p>Return a list of <c>{AttributeName,ValueList}</c> tuples, + where <c>AttributeName</c> is the name of an attribute, + and <c>ValueList</c> is a list of values. Note: a given + attribute may occur more than once in the list with different + values if the attribute occurs more than once in the module.</p> + + <p>The list of attributes will be empty if + the module has been stripped with + <seealso marker="stdlib:beam_lib#strip/1">beam_lib(3)</seealso>.</p> + </item> + + <tag><c>compile</c></tag> + <item> + <p>Return a list of tuples containing information about + how the module was compiled. This list will be empty if + the module has been stripped with + <seealso marker="stdlib:beam_lib#strip/1">beam_lib(3)</seealso>.</p> + </item> + + <tag><c>imports</c></tag> + <item> + <p>Always return an empty list. The <c>imports</c> key may not + be supported in future release.</p> + </item> + + <tag><c>exports</c></tag> + <item> + <p>Return a list of <c>{Name,Arity}</c> tuples with + all exported functions in the module.</p> + </item> + + <tag><c>functions</c></tag> + <item> + <p>Return a list of <c>{Name,Arity}</c> tuples with + all functions in the module.</p> + </item> + </taglist> + </section> + </section> + +</chapter> + diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml new file mode 100644 index 0000000000..aebeaf335a --- /dev/null +++ b/system/doc/reference_manual/part.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erlang Reference Manual</title> + <prepared>Gunilla Arendt</prepared> + <docno></docno> + <date>2003-01-11</date> + <rev></rev> + </header> + <xi:include href="introduction.xml"/> + <xi:include href="data_types.xml"/> + <xi:include href="patterns.xml"/> + <xi:include href="modules.xml"/> + <xi:include href="functions.xml"/> + <xi:include href="expressions.xml"/> + <xi:include href="macros.xml"/> + <xi:include href="records.xml"/> + <xi:include href="errors.xml"/> + <xi:include href="processes.xml"/> + <xi:include href="distributed.xml"/> + <xi:include href="code_loading.xml"/> + <xi:include href="ports.xml"/> +</part> + diff --git a/system/doc/reference_manual/patterns.xml b/system/doc/reference_manual/patterns.xml new file mode 100644 index 0000000000..7289f14d73 --- /dev/null +++ b/system/doc/reference_manual/patterns.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Pattern Matching</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>patterns.xml</file> + </header> + + <section> + <title>Pattern Matching</title> + <p>Variables are bound to values through the <em>pattern matching</em> mechanism. Pattern matching occurs when + evaluating a function call, <c>case</c>- <c>receive</c>- + <c>try</c>- expressions and match operator (=) expressions.</p> + <p>In a pattern matching, a left-hand side + <seealso marker="expressions#pattern">pattern</seealso> is matched + against a right-hand side + <seealso marker="expressions#term">term</seealso>. If + the matching succeeds, any unbound variables in the pattern + become bound. If the matching fails, a run-time error occurs.</p> + <p>Examples:</p> + <pre> +1> <input>X.</input> +** 1: variable 'X' is unbound ** +2> <input>X = 2.</input> +2 +3> <input>X + 1.</input> +3 +4> <input>{X, Y} = {1, 2}.</input> +** exception error: no match of right hand side value {1,2} +5> <input>{X, Y} = {2, 3}.</input> +{2,3} +6> <input>Y.</input> +3</pre> + </section> +</chapter> + diff --git a/system/doc/reference_manual/ports.xml b/system/doc/reference_manual/ports.xml new file mode 100644 index 0000000000..4847dd67cd --- /dev/null +++ b/system/doc/reference_manual/ports.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Ports and Port Drivers</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>ports.xml</file> + </header> + <p>Examples of how to use ports and port drivers can be found in + <em>Interoperability Tutorial</em>. The BIFs mentioned are as usual + documented in <c>erlang(3)</c>.</p> + + <section> + <title>Ports</title> + <p><em>Ports</em> provide the basic mechanism for communication + with the external world, from Erlang's point of view. They + provide a byte-oriented interface to an external program. When a + port has been created, Erlang can communicate with it by sending + and receiving lists of bytes, including binaries.</p> + <p>The Erlang process which creates a port is said to be + the <em>port owner</em>, or the <em>connected process</em> of + the port. All communication to and from the port should go via + the port owner. If the port owner terminates, so will the port + (and the external program, if it is written correctly).</p> + <p>The external program resides in another OS process. By default, + it should read from standard input (file descriptor 0) and write + to standard output (file descriptor 1). The external program + should terminate when the port is closed.</p> + </section> + + <section> + <title>Port Drivers</title> + <p>It is also possible to write a driver in C according to certain + principles and dynamically link it to the Erlang runtime system. + The linked-in driver looks like a port from the Erlang + programmer's point of view and is called a <em>port driver</em>.</p> + <warning> + <p>An erroneous port driver will cause the entire Erlang runtime + system to leak memory, hang or crash.</p> + </warning> + <p>Port drivers are documented in <c>erl_driver(4)</c>, + <c>driver_entry(1)</c> and <c>erl_ddll(3)</c>.</p> + </section> + + <section> + <title>Port BIFs</title> + <p>To create a port:</p> + <table> + <row> + <cell align="left" valign="middle"><c>open_port(PortName, PortSettings</c></cell> + <cell align="left" valign="middle">Returns a port identifier <c>Port</c>as the result of opening a new Erlang port. Messages can be sent to and received from a port identifier, just like a pid. Port identifiers can also be linked to or registered under a name using <c>link/1</c>and <c>register/2</c>.</cell> + </row> + <tcaption>Port Creation BIF.</tcaption> + </table> + <p><c>PortName</c> is usually a tuple <c>{spawn,Command}</c>, where + the string <c>Command</c> is the name of the external program. + The external program runs outside the Erlang workspace unless a + port driver with the name <c>Command</c> is found. If found, that + driver is started.</p> + <p><c>PortSettings</c> is a list of settings (options) for the port. + The list typically contains at least a tuple <c>{packet,N}</c> + which specifies that data sent between the port and the external + program are preceded by an N-byte length indicator. Valid values + for N are 1, 2 or 4. If binaries should be used instead of lists + of bytes, the option <c>binary</c> must be included.</p> + <p>The port owner <c>Pid</c> can communicate with the port + <c>Port</c> by sending and receiving messages. (In fact, any + process can send the messages to the port, but the messages from + the port always go to the port owner).</p> + <p>Below, <c>Data</c> must be an I/O list. An I/O list is a binary + or a (possibly deep) list of binaries or integers in the range + 0..255.</p> + <table> + <row> + <cell align="left" valign="middle"><c>{Pid,{command,Data}}</c></cell> + <cell align="left" valign="middle">Sends <c>Data</c>to the port.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{Pid,close}</c></cell> + <cell align="left" valign="middle">Closes the port. Unless the port is already closed, the port replies with <c>{Port,closed}</c>when all buffers have been flushed and the port really closes.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{Pid,{connect,NewPid}}</c></cell> + <cell align="left" valign="middle">Sets the port owner of <c>Port</c>to <c>NewPid</c>. Unless the port is already closed, the port replies with<c>{Port,connected}</c>to the old port owner. Note that the old port owner is still linked to the port, but the new port owner is not.</cell> + </row> + <tcaption>Messages Sent To a Port.</tcaption> + </table> + <table> + <row> + <cell align="left" valign="middle"><c>{Port,{data,Data}}</c></cell> + <cell align="left" valign="middle"><c>Data</c>is received from the external program.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{Port,closed}</c></cell> + <cell align="left" valign="middle">Reply to <c>Port ! {Pid,close}</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>{Port,connected}</c></cell> + <cell align="left" valign="middle">Reply to <c>Port ! {Pid,{connect,NewPid}}</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>{'EXIT',Port,Reason}</c></cell> + <cell align="left" valign="middle">If the port has terminated for some reason.</cell> + </row> + <tcaption>Messages Received From a Port.</tcaption> + </table> + <p>Instead of sending and receiving messages, there are also a + number of BIFs that can be used. These can be called by any + process, not only the port owner.</p> + <table> + <row> + <cell align="left" valign="middle"><c>port_command(Port,Data)</c></cell> + <cell align="left" valign="middle">Sends <c>Data</c>to the port.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>port_close(Port)</c></cell> + <cell align="left" valign="middle">Closes the port.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>port_connect(Port,NewPid)</c></cell> + <cell align="left" valign="middle">Sets the port owner of <c>Port</c>to <c>NewPid</c>. The old port owner <c>Pid</c>stays linked to the port and have to call <c>unlink(Port)</c>if this is not desired.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>erlang:port_info(Port,Item)</c></cell> + <cell align="left" valign="middle">Returns information as specified by <c>Item</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>erlang:ports()</c></cell> + <cell align="left" valign="middle">Returns a list of all ports on the current node.</cell> + </row> + <tcaption>Port BIFs.</tcaption> + </table> + <p>There are some additional BIFs that only apply to port drivers: + <c>port_control/3</c> and <c>erlang:port_call/3</c>.</p> + </section> +</chapter> + diff --git a/system/doc/reference_manual/processes.xml b/system/doc/reference_manual/processes.xml new file mode 100644 index 0000000000..305d7d9c66 --- /dev/null +++ b/system/doc/reference_manual/processes.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Processes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>processes.xml</file> + </header> + + <section> + <title>Processes</title> + <p>Erlang is designed for massive concurrency. Erlang processes are + light-weight (grow and shrink dynamically) with small memory + footprint, fast to create and terminate and the scheduling + overhead is low.</p> + </section> + + <section> + <title>Process Creation</title> + <p>A process is created by calling <c>spawn</c>:</p> + <pre> +spawn(Module, Name, Args) -> pid() + Module = Name = atom() + Args = [Arg1,...,ArgN] + ArgI = term()</pre> + <p><c>spawn</c> creates a new process and returns the pid.</p> + <p>The new process will start executing in + <c>Module:Name(Arg1,...,ArgN)</c> where the arguments is + the elements of the (possible empty) <c>Args</c> argument list.</p> + <p>There exist a number of other <c>spawn</c> BIFs, for example + <c>spawn/4</c> for spawning a process at another node.</p> + </section> + + <section> + <title>Registered Processes</title> + <p>Besides addressing a process by using its pid, there are also + BIFs for registering a process under a name. The name must be an + atom and is automatically unregistered if the process terminates:</p> + <table> + <row> + <cell align="left" valign="middle"><c>register(Name, Pid)</c></cell> + <cell align="left" valign="middle">Associates the name <c>Name</c>, an atom, with the process <c>Pid</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>registered()</c></cell> + <cell align="left" valign="middle">Returns a list of names which have been registered using<c>register/2</c>.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>whereis(Name)</c></cell> + <cell align="left" valign="middle">Returns the pid registered under <c>Name</c>, or<c>undefined</c>if the name is not registered.</cell> + </row> + <tcaption>Name Registration BIFs.</tcaption> + </table> + </section> + + <section> + <marker id="term"></marker> + <title>Process Termination</title> + <p>When a process terminates, it always terminates with an + <em>exit reason</em>. The reason may be any term.</p> + <p>A process is said to terminate <em>normally</em>, if the exit + reason is the atom <c>normal</c>. A process with no more code to + execute terminates normally.</p> + <p>A process terminates with exit reason <c>{Reason,Stack}</c> + when a run-time error occurs. See + <seealso marker="errors#exit_reasons">Error and Error Handling</seealso>.</p> + <p>A process can terminate itself by calling one of the BIFs + <c>exit(Reason)</c>, + <c>erlang:error(Reason)</c>, <c>erlang:error(Reason, Args)</c>, + <c>erlang:fault(Reason)</c> or <c>erlang:fault(Reason, Args)</c>. + The process then terminates with reason <c>Reason</c> for + <c>exit/1</c> or <c>{Reason,Stack} for the others</c>.</p> + <p>A process may also be terminated if it receives an exit signal + with another exit reason than <c>normal</c>, see + <seealso marker="#errors">Error Handling</seealso> below.</p> + </section> + + <section> + <title>Message Sending</title> + <p>Processes communicate by sending and receiving messages. + Messages are sent by using + the <seealso marker="expressions#send">send operator !</seealso> + and received by calling + <seealso marker="expressions#receive">receive</seealso>.</p> + <p>Message sending is asynchronous and safe, the message is + guaranteed to eventually reach the recipient, provided that + the recipient exists.</p> + </section> + + <section> + <title>Links</title> + <p>Two processes can be <em>linked</em> to each other. A link + between two processes <c>Pid1</c> and <c>Pid2</c> is created + by <c>Pid1</c> calling the BIF <c>link(Pid2)</c> (or vice versa). + There also exists a number a <c>spawn_link</c> BIFs, which spawns + and links to a process in one operation.</p> + <p>Links are bidirectional and there can only be one link between + two processes. Repeated calls to <c>link(Pid)</c> have no effect.</p> + <p>A link can be removed by calling the BIF <c>unlink(Pid)</c>.</p> + <p>Links are used to monitor the behaviour of other processes, see + <seealso marker="#errors">Error Handling</seealso> below.</p> + </section> + + <section> + <marker id="errors"></marker> + <title>Error Handling</title> + <p>Erlang has a built-in feature for error handling between + processes. Terminating processes will emit exit signals to all + linked processes, which may terminate as well or handle the exit + in some way. This feature can be used to build hierarchical + program structures where some processes are supervising other + processes, for example restarting them if they terminate + abnormally.</p> + <p>Refer to OTP Design Principles for more information about + OTP supervision trees, which uses this feature.</p> + + <section> + <title>Emitting Exit Signals</title> + <p>When a process terminates, it will terminate with an <em>exit reason</em> as explained in <seealso marker="#term">Process Termination</seealso> above. This exit reason is emitted in + an <em>exit signal</em> to all linked processes.</p> + <p>A process can also call the function <c>exit(Pid,Reason)</c>. + This will result in an exit signal with exit reason + <c>Reason</c> being emitted to <c>Pid</c>, but does not affect + the calling process.</p> + </section> + + <section> + <title>Receiving Exit Signals</title> + <p>The default behaviour when a process receives an exit signal + with an exit reason other than <c>normal</c>, is to terminate + and in turn emit exit signals with the same exit reason to its + linked processes. An exit signal with reason <c>normal</c> is + ignored.</p> + <p>A process can be set to trap exit signals by calling:</p> + <pre> +process_flag(trap_exit, true)</pre> + <p>When a process is trapping exits, it will not terminate when + an exit signal is received. Instead, the signal is transformed + into a message <c>{'EXIT',FromPid,Reason}</c> which is put into + the mailbox of the process just like a regular message.</p> + <p>An exception to the above is if the exit reason is <c>kill</c>, + that is if <c>exit(Pid,kill)</c> has been called. This will + unconditionally terminate the process, regardless of if it is + trapping exit signals or not.</p> + </section> + </section> + + <section> + <title>Monitors</title> + <p>An alternative to links are <em>monitors</em>. A process + <c>Pid1</c> can create a monitor for <c>Pid2</c> by calling + the BIF <c>erlang:monitor(process, Pid2)</c>. The function returns + a reference <c>Ref</c>.</p> + <p>If <c>Pid2</c> terminates with exit reason <c>Reason</c>, a + 'DOWN' message is sent to <c>Pid1</c>:</p> + <code type="none"> +{'DOWN', Ref, process, Pid2, Reason}</code> + <p>If <c>Pid2</c> does not exist, the 'DOWN' message is sent + immediately with <c>Reason</c> set to <c>noproc</c>.</p> + <p>Monitors are unidirectional. Repeated calls to + <c>erlang:monitor(process, Pid)</c> will create several, + independent monitors and each one will send a 'DOWN' message when + <c>Pid</c> terminates.</p> + <p>A monitor can be removed by calling + <c>erlang:demonitor(Ref)</c>.</p> + <p>It is possible to create monitors for processes with registered + names, also at other nodes.</p> + </section> + + <section> + <title>Process Dictionary</title> + <p>Each process has its own process dictionary, accessed by calling + the following BIFs:</p> + <pre> +put(Key, Value) +get(Key) +get() +get_keys(Value) +erase(Key) +erase()</pre> + </section> +</chapter> + diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml new file mode 100644 index 0000000000..e2fe5fe8de --- /dev/null +++ b/system/doc/reference_manual/records.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Records</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>records.xml</file> + </header> + <p>A record is a data structure for storing a fixed number of + elements. It has named fields and is similar to a struct in C. + Record expressions are translated to tuple expressions during + compilation. Therefore, record expressions are not understood by + the shell unless special actions are taken. See <c>shell(3)</c> + for details.</p> + <p>More record examples can be found in <em>Programming Examples</em>.</p> + + <section> + <title>Defining Records</title> + <p>A record definition consists of the name of the record, + followed by the field names of the record. Record and field names + must be atoms. Each field can be given an optional default value. + If no default value is supplied, <c>undefined</c> will be used.</p> + <pre> +-record(Name, {Field1 [= Value1], + ... + FieldN [= ValueN]}).</pre> + <p>A record definition can be placed anywhere among the attributes + and function declarations of a module, but the definition must + come before any usage of the record.</p> + <p>If a record is used in several modules, it is recommended that + the record definition is placed in an include file.</p> + </section> + + <section> + <title>Creating Records</title> + <p>The following expression creates a new <c>Name</c> record where + the value of each field <c>FieldI</c> is the value of evaluating + the corresponding expression <c>ExprI</c>:</p> + <pre> +#Name{Field1=Expr1,...,FieldK=ExprK}</pre> + <p>The fields may be in any order, not necessarily the same order as + in the record definition, and fields can be omitted. Omitted + fields will get their respective default value instead.</p> + <p>If several fields should be assigned the same value, + the following construction can be used:</p> + <pre> +#Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}</pre> + <p>Omitted fields will then get the value of evaluating <c>ExprL</c> + instead of their default values. This feature was added in + Erlang 5.1/OTP R8 and is primarily intended to be used to create + patterns for ETS and Mnesia match functions. Example:</p> + <pre> +-record(person, {name, phone, address}). + +... + +lookup(Name, Tab) -> + ets:match_object(Tab, #person{name=Name, _='_'}).</pre> + </section> + + <section> + <title>Accessing Record Fields</title> + <pre> +Expr#Name.Field</pre> + <p>Returns the value of the specified field. <c>Expr</c> should + evaluate to a <c>Name</c> record.</p> + <p>The following expression returns the position of the specified + field in the tuple representation of the record:</p> + <pre> +#Name.Field</pre> + <p>Example:</p> + <pre> +-record(person, {name, phone, address}). + +... + +lookup(Name, List) -> + lists:keysearch(Name, #person.name, List).</pre> + </section> + + <section> + <title>Updating Records</title> + <pre> +Expr#Name{Field1=Expr1,...,FieldK=ExprK}</pre> + <p><c>Expr</c> should evaluate to a <c>Name</c> record. Returns a + copy of this record, with the value of each specified field + <c>FieldI</c> changed to the value of evaluating the corresponding + expression <c>ExprI</c>. All other fields retain their old + values.</p> + <p></p> + </section> + + <section> + <title>Records in Guards</title> + <p>Since record expressions are expanded to tuple expressions, + creating records and accessing record fields are allowed in + guards. However all subexpressions, for example for field + initiations, must of course be valid guard expressions as well. + Examples:</p> + <code type="none"> +handle(Msg, State) when Msg==#msg{to=void, no=3} -> + ... + +handle(Msg, State) when State#state.running==true -> + ...</code> + <p>There is also a type test BIF <c>is_record(Term, RecordTag)</c>. + Example:</p> + <pre> +is_person(P) when is_record(P, person) -> + true; +is_person(_P) -> + false.</pre> + </section> + + <section> + <title>Records in Patterns</title> + <p>A pattern that will match a certain record is created the same + way as a record is created:</p> + <pre> +#Name{Field1=Expr1,...,FieldK=ExprK}</pre> + <p>In this case, one or more of <c>Expr1</c>...<c>ExprK</c> may be + unbound variables.</p> + </section> + + <section> + <title>Internal Representation of Records</title> + <p>Record expressions are translated to tuple expressions during + compilation. A record defined as</p> + <pre> +-record(Name, {Field1,...,FieldN}).</pre> + <p>is internally represented by the tuple</p> + <pre> +{Name,Value1,...,ValueN}</pre> + <p>where each <c>ValueI</c> is the default value for <c>FieldI</c>.</p> + <p>To each module using records, a pseudo function is added + during compilation to obtain information about records:</p> + <pre> +record_info(fields, Record) -> [Field] +record_info(size, Record) -> Size</pre> + <p><c>Size</c> is the size of the tuple representation, that is + one more than the number of fields.</p> + <p>In addition, <c>#Record.Name</c> returns the index in the tuple + representation of <c>Name</c> of the record <c>Record</c>. + <c>Name</c> must be an atom.</p> + </section> +</chapter> + diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk new file mode 100644 index 0000000000..6886c8c7cf --- /dev/null +++ b/system/doc/reference_manual/xmlfiles.mk @@ -0,0 +1,33 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +REF_MAN_CHAPTER_FILES = \ + introduction.xml \ + data_types.xml \ + patterns.xml \ + modules.xml \ + functions.xml \ + expressions.xml \ + macros.xml \ + records.xml \ + errors.xml \ + processes.xml \ + distributed.xml \ + code_loading.xml \ + ports.xml + diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile new file mode 100644 index 0000000000..0fff9bc4d5 --- /dev/null +++ b/system/doc/system_architecture_intro/Makefile @@ -0,0 +1,97 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/system_architecture_intro + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +PS_FILES = + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTMLDIR = ../html/system_architecture_intro + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + + diff --git a/system/doc/system_architecture_intro/book.xml b/system/doc/system_architecture_intro/book.xml new file mode 100644 index 0000000000..e83c1a482a --- /dev/null +++ b/system/doc/system_architecture_intro/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>System Architecture</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2000-03-21</date> + <rev>B</rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>System Architecture Introduction</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/system_architecture_intro/make.dep b/system/doc/system_architecture_intro/make.dep new file mode 100644 index 0000000000..6b7bd860a0 --- /dev/null +++ b/system/doc/system_architecture_intro/make.dep @@ -0,0 +1,13 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex part.tex sys_arch_intro.tex + diff --git a/system/doc/system_architecture_intro/note.gif b/system/doc/system_architecture_intro/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/system_architecture_intro/note.gif diff --git a/system/doc/system_architecture_intro/part.xml b/system/doc/system_architecture_intro/part.xml new file mode 100644 index 0000000000..7f3ea62190 --- /dev/null +++ b/system/doc/system_architecture_intro/part.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction to the System Architecture</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2000-03-21</date> + <rev>U</rev> + <file>part.sgml</file> + </header> + <xi:include href="sys_arch_intro.xml"/> +</part> + diff --git a/system/doc/system_architecture_intro/sys_arch_intro.xml b/system/doc/system_architecture_intro/sys_arch_intro.xml new file mode 100644 index 0000000000..1cd8cf99e2 --- /dev/null +++ b/system/doc/system_architecture_intro/sys_arch_intro.xml @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>sys_arch_intro.xml</file> + </header> + + <section> + <title>Erlang and OTP</title> + <p>Erlang is a general-purpose programming language with built-in + support for concurrency, distribution and fault tolerance.</p> + <p>OTP (Open Telecom Platform) is aimed at providing time-saving and + flexible development for robust, adaptable telecom systems. It + consists of an Erlang runtime system, a number of ready-to-use + components mainly written in Erlang, and a set of design principles + for Erlang programs. Since Erlang and OTP are closely interconnected + the term Erlang/OTP is normally used instead of OTP.</p> + </section> + + <section> + <title>Erlang/OTP</title> + + <section> + <title>Erlang Runtime System</title> + <p>The Erlang runtime system (ERTS) is made up of an emulator running on top of the host operating system, a kernel providing low-level services such as distribution and I/O handling, and a standard library containing a large number of re-usable modules.</p> + <p>The OTP design principles provides the user with a way to structure the system based on a concept called application. An OTP application is a way to package a system component and is either a set of library modules or a supervision tree. A supervision tree is a hierarchical tree of processes used to program fault-tolerant systems. The processes are easiest implemented using behavior modules which are formalizations of design patterns. The standard library includes behavior modules for supervisors, servers, state machines and generic event handlers. In chapter 4 "OTP Design Principles" the design principles are explained in detail.</p> + </section> + + <section> + <title>OTP Components</title> + <p>The OTP components can be divided into six categories:</p> + <list type="bulleted"> + <item> + <p>Basic Applications - Basic Erlang/OTP functionality.</p> + <list type="bulleted"> + <item><em>Compiler</em> A compiler for Erlang modules.</item> + <item><em>Kernel</em> Functionality necessary to run Erlang/OTP itself.</item> + <item><em>SASL</em> (System Architecture Support Libraries) A set of tools for code replacement and alarm handling etc.</item> + <item><em>Stdlib</em> The standard library.</item> + </list> + </item> + <item> + <p>Operations and Maintenance - OAM both of the system developed by the user and of Erlang/OTP itself.</p> + <list type="bulleted"> + <item><em>EVA</em> A multi-featured event and alarm handler.</item> + <item><em>OS_Mon</em> A monitor which allows inspection of the underlying operating system.</item> + <item><em>SNMP</em> SNMP support including a MIB compiler and tools for creating SNMP agents.</item> + </list> + </item> + <item> + <p>Interface and Communication - Interoperability and protocols support.</p> + <list type="bulleted"> + <item><em>Asn1</em> Support for ASN.1.</item> + <item><em>Comet</em> A library that enables Erlang/OTP to call COM + objects on windows </item> + <item><em>Crypto</em> Cryptographical support</item> + <item><em>Erl_Interface</em> Low level interface to C.</item> + <item><em>GS</em> A graphics system used to write platform + independent user interfaces.</item> + <item><em>Inets</em> A set of services such as a web server + and a FTP client.</item> + <item><em>Jinterface</em> Low level interface to Java.</item> + <item><em>SSL</em> Secure Socket Layer (SSL),interface to UNIX BSD + sockets </item> + </list> + </item> + <item> + <p>Database Management.</p> + <list type="bulleted"> + <item><em>QLC</em> Query language support for Mnesia DBMS.</item> + <item><em>Mnesia</em> A heavy duty real-time distributed database.</item> + <item><em>ODBC</em> ODBC database interface.</item> + </list> + </item> + <item> + <p>CORBA services and IDL compiler.</p> + <list type="bulleted"> + <item><em>cosEvent</em> Orber OMG Event Service.</item> + <item><em>cosNotification</em> Orber OMG Notification + Service.</item> + <item><em>cosTime</em> Orber OMG Timer and TimerEvent + Services.</item> + <item><em>cosTransactions</em> Orber OMG Transaction + Service.</item> + <item><em>IC</em> IDL compiler</item> + <item><em>Orber</em> A CORBA object request broker.</item> + </list> + </item> + <item> + <p>Tools.</p> + <list type="bulleted"> + <item><em>Appmon</em> A utility used to view OTP applications.</item> + <item><em>Debugger</em> For debugging and testing of Erlang programs.</item> + <item><em>Parsetools</em> A set of parsing and lexical analysis tools.</item> + <item><em>Pman</em> A process manager used to inspect the state of an Erlang/OTP system.</item> + <item><em>Runtime_Tools</em> Tools to include in a production system.</item> + <item><em>Toolbar</em> A tool bar simplifying access to the Erlang/OTP tools.</item> + <item><em>Tools</em> A set of programming tools including a coverage analyzer etc.</item> + <item><em>TV</em> An ETS and Mnesia graphical table visualizer.</item> + </list> + </item> + </list> + </section> + </section> + + <section> + <title>Scope and Purpose</title> + <p>This documentation describes the Erlang runtime system, the OTP applications and the OTP design principles. It assumes that the reader is familiar with the Erlang programming language and does not explain how to program in Erlang. The language is described in <em>Concurrent Programming in Erlang, 2nd Edition</em>, ISBN 0-13-508301-X.</p> + </section> + + <section> + <title>About the Erlang/OTP Documentation</title> + + <section> + <title>Structure of this Book</title> + <p>The documentation is divided into eight parts. This book, <em>Erlang 5.1/OTP R8 System Documentation, EN/LZT 108 4095 R2</em>, is the starting point of the documentation and contains information about the Erlang programming language and runtime system, the OTP design principles, and how to install and configure Erlang/OTP.</p> + <list type="bulleted"> + <item>Chapter 2: "Getting Started with Erlang" describes the Erlang runtime system and introduces the reader to tools such as the compiler and debugger.</item> + <item>Chapter 3: "Erlang Extensions Since 4.4" lists all extensions added to the Erlang programming languages since the latest version of the book <em>Concurrent Programming in ERLANG</em>.</item> + <item>Chapter 4: "OTP Design Principles" describes a way to structure Erlang code in terms of applications and supervision trees. The standard behaviors are described and examples illustrate how to apply these behaviors to typical applications.</item> + <item>Chapter 5: "Installation Guide"gives guidelines on how to install Erlang/OTP on UNIX or Windows.</item> + <item>Chapter 6: "System Principles" describes the strategies + and options, which are available to start an Erlang/OTP system. This chapter also provides a brief description of the applications included in an Erla + ng/OTP system. </item> + <item>Chapter 7: "Embedded Systems" is a supplement to "Installation Guide". t describes issues that are specific for running Erlang/OTP on an embedded system.</item> + <item>Chapter 8: "Operation and Management Principles" describes the model for operation and maintenance of sub-systems.</item> + <item>Chapter 9: "Tutorial" gives an orientation of the different + interoperability mechanism, which can be used when integrating an + Erlang program with a program written in an other programming language.</item> + </list> + </section> + + <section> + <title>Typographical Conventions</title> + <p>The following typographical conventions are used in the documentation.</p> + <table> + <row> + <cell align="left" valign="middle"><em>Convention</em></cell> + <cell align="left" valign="middle"><em>Where used</em></cell> + </row> + <row> + <cell align="left" valign="middle"><em>command</em></cell> + <cell align="left" valign="middle">To show menu selections and equivalent command line entries. <br></br> +To show keyboard entries at system prompts.</cell> + </row> + <row> + <cell align="left" valign="middle"><c>code</c></cell> + <cell align="left" valign="middle">To highlight Erlang code, module and function names, arguments, variables, and file names. </cell> + </row> + <tcaption>Examples of typographical conventions.</tcaption> + </table> + </section> + </section> +</chapter> + diff --git a/system/doc/system_architecture_intro/warning.gif b/system/doc/system_architecture_intro/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/system_architecture_intro/warning.gif diff --git a/system/doc/system_architecture_intro/xmlfiles.mk b/system/doc/system_architecture_intro/xmlfiles.mk new file mode 100644 index 0000000000..0b91c3bc0f --- /dev/null +++ b/system/doc/system_architecture_intro/xmlfiles.mk @@ -0,0 +1,19 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +XML_CHAPTER_FILES = sys_arch_intro.xml diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile new file mode 100644 index 0000000000..b0698fec9d --- /dev/null +++ b/system/doc/system_principles/Makefile @@ -0,0 +1,95 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/system_principles + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(SYSTEM_PRINCIPLES_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTMLDIR = ../html/system_principles + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(GIF_FILES) $(HTML_UG_FILE) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: + diff --git a/system/doc/system_principles/book.xml b/system/doc/system_principles/book.xml new file mode 100644 index 0000000000..868bbeecdd --- /dev/null +++ b/system/doc/system_principles/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>System Principles</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-05-21</date> + <rev></rev> + <file>book.xml</file> + </header> + <insidecover> + </insidecover> + <pagetext>System Principles</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/system_principles/create_target.xml b/system/doc/system_principles/create_target.xml new file mode 100644 index 0000000000..9899b6e266 --- /dev/null +++ b/system/doc/system_principles/create_target.xml @@ -0,0 +1,502 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Creating a First Target System</title> + <prepared>Peter Högfeldt</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2002-09-17</date> + <rev>A</rev> + <file>create_target.xml</file> + </header> + + <section> + <title>Introduction</title> + <p>When creating a system using Erlang/OTP, the most simple way is + to install Erlang/OTP somewhere, install the application specific + code somewhere else, and then start the Erlang runtime system, + making sure the code path includes the application specific code.</p> + <p>Often it is not desirable to use an Erlang/OTP system as is. A + developer may create new Erlang/OTP compliant applications for a + particular purpose, and several original Erlang/OTP applications + may be irrelevant for the purpose in question. Thus, there is a + need to be able to create a new system based on a given + Erlang/OTP system, where dispensable applications are removed, + and a set of new applications that are included in the new + system. Documentation and source code is irrelevant and is + therefore not included in the new system.</p> + <p>This chapter is about creating such a system, which we call a + <em>target system</em>.</p> + <p>In the following sections we consider creating target systems with + different requirements of functionality:</p> + <list type="bulleted"> + <item>a <em>basic target system</em> that can be started by + calling the ordinary <c>erl</c> script, </item> + <item>a <em>simple target system</em> where also code + replacement in run-time can be performed, and</item> + <item>an <em>embedded target system</em> where there is also + support for logging output from the system to file for later + inspection, and where the system can be started automatically + at boot time. </item> + </list> + <p>We only consider the case when Erlang/OTP is running on a UNIX + system.</p> + <p>There is an example Erlang module <c>target_system.erl</c> that + contains functions for creating and installing a target system. + That module is used in the examples below. The source code of + the module is listed at the end of this chapter.</p> + </section> + + <section> + <title>Creating a Target System</title> + <p>It is assumed that you have a working Erlang/OTP system structured + according to the OTP Design Principles.</p> + <p><em>Step 1.</em> First create a <c>.rel</c> file (see + <c>rel(4)</c>) that specifies the <c>erts</c> version + and lists all applications that should be included in the new + basic target system. An example is the following + <c>mysystem.rel</c> file:</p> + <code type="none"> +%% mysystem.rel +{release, + {"MYSYSTEM", "FIRST"}, + {erts, "5.1"}, + [{kernel, "2.7"}, + {stdlib, "1.10"}, + {sasl, "1.9.3"}, + {pea, "1.0"}]}. </code> + <p>The listed applications are not only original Erlang/OTP + applications but possibly also new applications that you have + written yourself (here examplified by the application + <c>pea</c>). </p> + <p><em>Step 2.</em> From the directory where the <c>mysystem.rel</c> + file reside, start the Erlang/OTP system:</p> + <pre> +os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre> + <p>where also the path to the <c>pea-1.0</c> ebin directory is + provided. </p> + <p><em>Step 3.</em> Now create the target system: </p> + <pre> +1> <input>target_system:create("mysystem").</input></pre> + <p>The <c>target_system:create/1</c> function does the following:</p> + <list type="ordered"> + <item>Reads the <c>mysystem.rel</c> file, and creates a new file + <c>plain.rel</c> which is identical to former, except that it + only lists the <c>kernel</c> and <c>stdlib</c> applications. </item> + <item>From the <c>mysystem.rel</c> and <c>plain.rel</c> files + creates the files <c>mysystem.script</c>, + <c>mysystem.boot</c>, <c>plain.script</c>, and + <c>plain.boot</c> through a call to + <c>systools:make_script/2</c>.</item> + <item> + <p>Creates the file <c>mysystem.tar.gz</c> by a call to + <c>systools:make_tar/2</c>. That file has the following + contents:</p> + <code type="none"> +erts-5.1/bin/ +releases/FIRST/start.boot +releases/mysystem.rel +lib/kernel-2.7/ +lib/stdlib-1.10/ +lib/sasl-1.9.3/ +lib/pea-1.0/ </code> + <p>The file <c>releases/FIRST/start.boot</c> is a copy of our + <c>mysystem.boot</c>, and a copy of the original + <c>mysystem.rel</c> has been put in the <c>releases</c> + directory.</p> + </item> + <item>Creates the temporary directory <c>tmp</c> and extracts the tar file + <c>mysystem.tar.gz</c> into that directory. </item> + <item>Deletes the <c>erl</c> and <c>start</c> files from + <c>tmp/erts-5.1/bin</c>. XXX Why.</item> + <item>Creates the directory <c>tmp/bin</c>.</item> + <item>Copies the previously creates file <c>plain.boot</c> to + <c>tmp/bin/start.boot</c>.</item> + <item>Copies the files <c>epmd</c>, <c>run_erl</c>, and + <c>to_erl</c> from the directory <c>tmp/erts-5.1/bin</c> to + the directory <c>tmp/bin</c>.</item> + <item>Creates the file <c>tmp/releases/start_erl.data</c> with the + contents "5.1 FIRST". + </item> + <item>Recreates the file <c>mysystem.tar.gz</c> from the directories + in the directory <c>tmp</c>, and removes <c>tmp</c>.</item> + </list> + </section> + + <section> + <title>Installing a Target System</title> + <p><em>Step 4.</em> Install the created target system in a + suitable directory. </p> + <pre> +2> <input>target_system:install("mysystem", "/usr/local/erl-target").</input></pre> + <p>The function <c>target_system:install/2</c> does the following: + </p> + <list type="ordered"> + <item>Extracts the tar file <c>mysystem.tar.gz</c> into the target + directory <c>/usr/local/erl-target</c>.</item> + <item>In the target directory reads the file <c>releases/start_erl.data</c> + in order to find the Erlang runtime system version ("5.1").</item> + <item>Substitutes <c>%FINAL_ROOTDIR%</c> and <c>%EMU%</c> for + <c>/usr/local/erl-target</c> and <c>beam</c>, respectively, in + the files <c>erl.src</c>, <c>start.src</c>, and + <c>start_erl.src</c> of the target <c>erts-5.1/bin</c> + directory, and puts the resulting files <c>erl</c>, + <c>start</c>, and <c>run_erl</c> in the target <c>bin</c> + directory.</item> + <item>Finally the target <c>releases/RELEASES</c> file is created + from data in the <c>releases/mysystem.rel</c> file.</item> + </list> + </section> + + <section> + <title>Starting a Target System</title> + <p>Now we have a target system that can be started in various ways.</p> + <p>We start it as a <em>basic target system</em> by invoking</p> + <pre> +os> <input>/usr/local/erl-target/bin/erl</input></pre> + <p>where only the <c>kernel</c> and <c>stdlib</c> applications are + started, i.e. the system is started as an ordinary development + system. There are only two files needed for all this to work: + <c>bin/erl</c> file (obtained from <c>erts-5.1/bin/erl.src</c>) + and the <c>bin/start.boot</c> file (a copy of <c>plain.boot</c>).</p> + <p>We can also start a distributed system (requires <c>bin/epmd</c>).</p> + <p>To start all applications specified in the original + <c>mysystem.rel</c> file, use the <c>-boot</c> flag as follows:</p> + <pre> +os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FIRST/start</input></pre> + <p>We start a <em>simple target system</em> as above. The only difference + is that also the file <c>releases/RELEASES</c> is present for + code replacement in run-time to work.</p> + <p>To start an <em>embedded target system</em> the shell script + <c>bin/start</c> is used. That shell script calls + <c>bin/run_erl</c>, which in turn calls <c>bin/start_erl</c> + (roughly, <c>start_erl</c> is an embedded variant of + <c>erl</c>). </p> + <p>The shell script <c>start</c> is only an example. You should + edit it to suite your needs. Typically it is executed when the + UNIX system boots.</p> + <p><c>run_erl</c> is a wrapper that provides logging of output from + the run-time system to file. It also provides a simple mechanism + for attaching to the Erlang shell (<c>to_erl</c>).</p> + <p><c>start_erl</c> requires the root directory + (<c>"/usr/local/erl-target"</c>), the releases directory + (<c>"/usr/local/erl-target/releases"</c>), and the location of + the <c>start_erl.data</c> file. It reads the run-time system + version (<c>"5.1"</c>) and release version (<c>"FIRST"</c>) from + the <c>start_erl.data</c> file, starts the run-time system of the + version found, and provides <c>-boot</c> flag specifying the boot + file of the release version found + (<c>"releases/FIRST/start.boot"</c>).</p> + <p><c>start_erl</c> also assumes that there is <c>sys.config</c> in + release version directory (<c>"releases/FIRST/sys.config</c>). That + is the topic of the next section (see below).</p> + <p>The <c>start_erl</c> shell script should normally not be + altered by the user.</p> + </section> + + <section> + <title>System Configuration Parameters</title> + <p>As was pointed out above <c>start_erl</c> requires a + <c>sys.config</c> in the release version directory + (<c>"releases/FIRST/sys.config"</c>). If there is no such a + file, the system start will fail. Hence such a file has to + added as well.</p> + <p></p> + <p>If you have system configuration data that are neither file + location dependent nor site dependent, it may be convenient to + create the <c>sys.config</c> early, so that it becomes a part of + the target system tar file created by + <c>target_system:create/1</c>. In fact, if you create, in the + current directory, not only the <c>mysystem.rel</c> file, but + also a <c>sys.config</c> file, that latter file will be tacitly + put in the apropriate directory.</p> + </section> + + <section> + <title>Differences from the Install Script</title> + <p>The above <c>install/2</c> procedure differs somewhat from that + of the ordinary <c>Install</c> shell script. In fact, <c>create/1</c> + makes the release package as complete as possible, and leave to the + <c>install/2</c> procedure to finish by only considering location + dependent files.</p> + </section> + + <section> + <title>Listing of target_system.erl</title> + <code type="none"><![CDATA[ +-module(target_system). +-include_lib("kernel/include/file.hrl"). +-export([create/1, install/2]). +-define(BUFSIZE, 8192). + +%% Note: RelFileName below is the *stem* without trailing .rel, +%% .script etc. +%% + +%% create(RelFileName) +%% +create(RelFileName) -> + RelFile = RelFileName ++ ".rel", + io:fwrite("Reading file: \\"~s\\" ...~n", [RelFile]), + {ok, [RelSpec]} = file:consult(RelFile), + io:fwrite("Creating file: \\"~s\\" from \\"~s\\" ...~n", + ["plain.rel", RelFile]), + {release, + {RelName, RelVsn}, + {erts, ErtsVsn}, + AppVsns} = RelSpec, + PlainRelSpec = {release, + {RelName, RelVsn}, + {erts, ErtsVsn}, + lists:filter(fun({kernel, _}) -> + true; + ({stdlib, _}) -> + true; + (_) -> + false + end, AppVsns) + }, + {ok, Fd} = file:open("plain.rel", [write]), + io:fwrite(Fd, "~p.~n", [PlainRelSpec]), + file:close(Fd), + + io:fwrite("Making \\"plain.script\\" and \\"plain.boot\\" files ...~n"), + make_script("plain"), + + io:fwrite("Making \\"~s.script\\" and \\"~s.boot\\" files ...~n", + [RelFileName, RelFileName]), + make_script(RelFileName), + + TarFileName = io_lib:fwrite("~s.tar.gz", [RelFileName]), + io:fwrite("Creating tar file \\"~s\\" ...~n", [TarFileName]), + make_tar(RelFileName), + + io:fwrite("Creating directory \\"tmp\\" ...~n"), + file:make_dir("tmp"), + + io:fwrite("Extracting \\"~s\\" into directory \\"tmp\\" ...~n", [TarFileName]), + extract_tar(TarFileName, "tmp"), + + TmpBinDir = filename:join(["tmp", "bin"]), + ErtsBinDir = filename:join(["tmp", "erts-" ++ ErtsVsn, "bin"]), + io:fwrite("Deleting \\"erl\\" and \\"start\\" in directory \\"~s\\" ...~n", + [ErtsBinDir]), + file:delete(filename:join([ErtsBinDir, "erl"])), + file:delete(filename:join([ErtsBinDir, "start"])), + + io:fwrite("Creating temporary directory \\"~s\\" ...~n", [TmpBinDir]), + file:make_dir(TmpBinDir), + + io:fwrite("Copying file \\"plain.boot\\" to \\"~s\\" ...~n", + [filename:join([TmpBinDir, "start.boot"])]), + copy_file("plain.boot", filename:join([TmpBinDir, "start.boot"])), + + io:fwrite("Copying files \\"epmd\\", \\"run_erl\\" and \\"to_erl\\" from \ +" + "\\"~s\\" to \\"~s\\" ...~n", + [ErtsBinDir, TmpBinDir]), + copy_file(filename:join([ErtsBinDir, "epmd"]), + filename:join([TmpBinDir, "epmd"]), [preserve]), + copy_file(filename:join([ErtsBinDir, "run_erl"]), + filename:join([TmpBinDir, "run_erl"]), [preserve]), + copy_file(filename:join([ErtsBinDir, "to_erl"]), + filename:join([TmpBinDir, "to_erl"]), [preserve]), + + StartErlDataFile = filename:join(["tmp", "releases", "start_erl.data"]), + io:fwrite("Creating \\"~s\\" ...~n", [StartErlDataFile]), + StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), + write_file(StartErlDataFile, StartErlData), + + io:fwrite("Recreating tar file \\"~s\\" from contents in directory " + "\\"tmp\\" ...~n", [TarFileName]), + {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), + {ok, Cwd} = file:get_cwd(), + file:set_cwd("tmp"), + erl_tar:add(Tar, "bin", []), + erl_tar:add(Tar, "erts-" ++ ErtsVsn, []), + erl_tar:add(Tar, "releases", []), + erl_tar:add(Tar, "lib", []), + erl_tar:close(Tar), + file:set_cwd(Cwd), + io:fwrite("Removing directory \\"tmp\\" ...~n"), + remove_dir_tree("tmp"), + ok. + + +install(RelFileName, RootDir) -> + TarFile = RelFileName ++ ".tar.gz", + io:fwrite("Extracting ~s ...~n", [TarFile]), + extract_tar(TarFile, RootDir), + StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), + {ok, StartErlData} = read_txt_file(StartErlDataFile), + [ErlVsn, RelVsn| _] = string:tokens(StartErlData, " \ +"), + ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), + BinDir = filename:join([RootDir, "bin"]), + io:fwrite("Substituting in erl.src, start.src and start_erl.src to\ +" + "form erl, start and start_erl ...\ +"), + subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, + [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], + [preserve]), + io:fwrite("Creating the RELEASES file ...\ +"), + create_RELEASES(RootDir, + filename:join([RootDir, "releases", RelFileName])). + +%% LOCALS + +%% make_script(RelFileName) +%% +make_script(RelFileName) -> + Opts = [no_module_tests], + systools:make_script(RelFileName, Opts). + +%% make_tar(RelFileName) +%% +make_tar(RelFileName) -> + RootDir = code:root_dir(), + systools:make_tar(RelFileName, [{erts, RootDir}]). + +%% extract_tar(TarFile, DestDir) +%% +extract_tar(TarFile, DestDir) -> + erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). + +create_RELEASES(DestDir, RelFileName) -> + release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). + +subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> + lists:foreach(fun(Script) -> + subst_src_script(Script, SrcDir, DestDir, + Vars, Opts) + end, Scripts). + +subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> + subst_file(filename:join([SrcDir, Script ++ ".src"]), + filename:join([DestDir, Script]), + Vars, Opts). + +subst_file(Src, Dest, Vars, Opts) -> + {ok, Conts} = read_txt_file(Src), + NConts = subst(Conts, Vars), + write_file(Dest, NConts), + case lists:member(preserve, Opts) of + true -> + {ok, FileInfo} = file:read_file_info(Src), + file:write_file_info(Dest, FileInfo); + false -> + ok + end. + +%% subst(Str, Vars) +%% Vars = [{Var, Val}] +%% Var = Val = string() +%% Substitute all occurrences of %Var% for Val in Str, using the list +%% of variables in Vars. +%% +subst(Str, Vars) -> + subst(Str, Vars, []). + +subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> + subst_var([C| Rest], Vars, Result, []); +subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> + subst_var([C| Rest], Vars, Result, []); +subst([$%, C| Rest], Vars, Result) when C == $_ -> + subst_var([C| Rest], Vars, Result, []); +subst([C| Rest], Vars, Result) -> + subst(Rest, Vars, [C| Result]); +subst([], _Vars, Result) -> + lists:reverse(Result). + +subst_var([$%| Rest], Vars, Result, VarAcc) -> + Key = lists:reverse(VarAcc), + case lists:keysearch(Key, 1, Vars) of + {value, {Key, Value}} -> + subst(Rest, Vars, lists:reverse(Value, Result)); + false -> + subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) + end; +subst_var([C| Rest], Vars, Result, VarAcc) -> + subst_var(Rest, Vars, Result, [C| VarAcc]); +subst_var([], Vars, Result, VarAcc) -> + subst([], Vars, [VarAcc ++ [$%| Result]]). + +copy_file(Src, Dest) -> + copy_file(Src, Dest, []). + +copy_file(Src, Dest, Opts) -> + {ok, InFd} = file:open(Src, [raw, binary, read]), + {ok, OutFd} = file:open(Dest, [raw, binary, write]), + do_copy_file(InFd, OutFd), + file:close(InFd), + file:close(OutFd), + case lists:member(preserve, Opts) of + true -> + {ok, FileInfo} = file:read_file_info(Src), + file:write_file_info(Dest, FileInfo); + false -> + ok + end. + +do_copy_file(InFd, OutFd) -> + case file:read(InFd, ?BUFSIZE) of + {ok, Bin} -> + file:write(OutFd, Bin), + do_copy_file(InFd, OutFd); + eof -> + ok + end. + +write_file(FName, Conts) -> + {ok, Fd} = file:open(FName, [write]), + file:write(Fd, Conts), + file:close(Fd). + +read_txt_file(File) -> + {ok, Bin} = file:read_file(File), + {ok, binary_to_list(Bin)}. + +remove_dir_tree(Dir) -> + remove_all_files(".", [Dir]). + +remove_all_files(Dir, Files) -> + lists:foreach(fun(File) -> + FilePath = filename:join([Dir, File]), + {ok, FileInfo} = file:read_file_info(FilePath), + case FileInfo#file_info.type of + directory -> + {ok, DirFiles} = file:list_dir(FilePath), + remove_all_files(FilePath, DirFiles), + file:del_dir(FilePath); + _ -> + file:delete(FilePath) + end + end, Files). + ]]></code> + </section> +</chapter> + diff --git a/system/doc/system_principles/error_logging.xml b/system/doc/system_principles/error_logging.xml new file mode 100644 index 0000000000..3cb290227e --- /dev/null +++ b/system/doc/system_principles/error_logging.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Error Logging</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>error_logging.xml</file> + </header> + + <section> + <title>Error Information From the Runtime System</title> + <p>Error information from the runtime system, that is, information + about a process terminating due to an uncaught error exception, + is by default written to terminal (tty):</p> + <code type="none"><![CDATA[ +=ERROR REPORT==== 9-Dec-2003::13:25:02 === +Error in process <0.27.0> with exit value: {{badmatch,[1,2,3]},[{m,f,1},{shell,eval_loop,2}]}]]></code> + <p>The error information is handled by the <em>error logger</em>, a + system process registered as <c>error_logger</c>. This process + receives all error messages from the Erlang runtime system and + also from the standard behaviours and different Erlang/OTP + applications.</p> + <p>The exit reasons (such as <c>badarg</c> above) used by + the runtime system are described in + <seealso marker="doc/reference_manual:errors#exit_reasons">Errors and Error Handling</seealso> + in the Erlang Reference Manual.</p> + <p>The process <c>error_logger</c> and its user interface (with + the same name) are described in + <seealso marker="kernel:error_logger">error_logger(3)</seealso>. + It is possible to configure the system so that error information + is written to file instead/as well as tty. Also, it is possible + for user defined applications to send and format error + information using <c>error_logger</c>.</p> + </section> + + <section> + <title>SASL Error Logging</title> + <p>The standard behaviors (<c>supervisor</c>, <c>gen_server</c>, + etc.) sends progress and error information to <c>error_logger</c>. + If the SASL application is started, this information is written + to tty as well. See + <seealso marker="sasl:error_logging">SASL Error Logging</seealso> + in the SASL User's Guide for further information.</p> + <pre> +% <input>erl -boot start_sasl</input> +Erlang (BEAM) emulator version 5.4.13 [hipe] [threads:0] [kernel-poll] + + +=PROGRESS REPORT==== 31-Mar-2006::12:45:58 === + supervisor: {local,sasl_safe_sup} + started: [{pid,<0.33.0>}, + {name,alarm_handler}, + {mfa,{alarm_handler,start_link,[]}}, + {restart_type,permanent}, + {shutdown,2000}, + {child_type,worker}] + +=PROGRESS REPORT==== 31-Mar-2006::12:45:58 === + supervisor: {local,sasl_safe_sup} + started: [{pid,<0.34.0>}, + {name,overload}, + {mfa,{overload,start_link,[]}}, + {restart_type,permanent}, + {shutdown,2000}, + {child_type,worker}] + +=PROGRESS REPORT==== 31-Mar-2006::12:45:58 === + supervisor: {local,sasl_sup} + started: [{pid,<0.32.0>}, + {name,sasl_safe_sup}, + {mfa,{supervisor, + start_link, + [{local,sasl_safe_sup},sasl,safe]}}, + {restart_type,permanent}, + {shutdown,infinity}, + {child_type,supervisor}] + +=PROGRESS REPORT==== 31-Mar-2006::12:45:58 === + supervisor: {local,sasl_sup} + started: [{pid,<0.35.0>}, + {name,release_handler}, + {mfa,{release_handler,start_link,[]}}, + {restart_type,permanent}, + {shutdown,2000}, + {child_type,worker}] + +=PROGRESS REPORT==== 31-Mar-2006::12:45:58 === + application: sasl + started_at: nonode@nohost +Eshell V5.4.13 (abort with ^G) +1> </pre> + </section> +</chapter> + diff --git a/system/doc/system_principles/make.dep b/system/doc/system_principles/make.dep new file mode 100644 index 0000000000..28753ca5a0 --- /dev/null +++ b/system/doc/system_principles/make.dep @@ -0,0 +1,14 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex create_target.tex error_logging.tex \ + part.tex system_principles.tex + diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml new file mode 100644 index 0000000000..94bb29be57 --- /dev/null +++ b/system/doc/system_principles/part.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>System Principles</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-02-21</date> + <rev>L</rev> + <file>part.xml</file> + </header> + <xi:include href="system_principles.xml"/> + <xi:include href="error_logging.xml"/> + <xi:include href="create_target.xml"/> +</part> + diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml new file mode 100644 index 0000000000..27512a1660 --- /dev/null +++ b/system/doc/system_principles/system_principles.xml @@ -0,0 +1,236 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>System Principles</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>system_principles.xml</file> + </header> + + <section> + <title>Starting the System</title> + <p>An Erlang runtime system is started with the command <c>erl</c>:</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.5 [hipe] [threads:0] + +Eshell V5.2.3.5 (abort with ^G) +1> </pre> + <p><c>erl</c> understands a number of command line arguments, see + <c>erl(1)</c>. A number of them are also described in this + chapter.</p> + <p>Application programs can access the values of the command line + arguments by calling one of the functions + <c>init:get_argument(Key)</c>, or <c>init:get_arguments()</c>. + See <c>init(3)</c>.</p> + </section> + + <section> + <title>Restarting and Stopping the System</title> + <p>The runtime system can be halted by calling <c>halt/0,1</c>. + See <c>erlang(3)</c>.</p> + <p>The module <c>init</c> contains function for restarting, + rebooting and stopping the runtime system. See <c>init(3)</c>.</p> + <pre> +init:restart() +init:reboot() +init:stop()</pre> + <p>Also, the runtime system will terminate if the Erlang shell is + terminated.</p> + </section> + + <section> + <marker id="BOOTSCRIPT"></marker> + <title>Boot Scripts</title> + <p>The runtime system is started using a <em>boot script</em>. + The boot script contains instructions on which code to load and + which processes and applications to start.</p> + <p>A boot script file has the extension <c>.script</c>. + The runtime system uses a binary version of the script. This + <em>binary boot script</em> file has the extension <c>.boot</c>.</p> + <p>Which boot script to use is specified by the command line flag + <c>-boot</c>. The extension <c>.boot</c> should be omitted. + Example, using the boot script <c>start_all.boot</c>:</p> + <pre> +% <input>erl -boot start_all</input></pre> + <p>If no boot script is specified, it defaults to + <c>ROOT/bin/start</c>, see Default Boot Scripts below.</p> + <p>The command line flag <c>-init_debug</c> makes the <c>init</c> + process write some debug information while interpreting the boot + script:</p> + <pre> +% <input>erl -init_debug</input> +{progress,preloaded} +{progress,kernel_load_completed} +{progress,modules_loaded} +{start,heart} +{start,error_logger} +...</pre> + <p>See <c>script(4)</c> for a detailed description of the syntax + and contents of the boot script.</p> + + <section> + <title>Default Boot Scripts</title> + <p>Erlang/OTP comes with two boot scripts:</p> + <taglist> + <tag><c>start_clean.boot</c></tag> + <item> + <p>Loads the code for and starts the applications Kernel and + STDLIB.</p> + </item> + <tag><c>start_sasl.boot</c></tag> + <item> + <p>Loads the code for and starts the applications Kernel, + STDLIB and SASL.</p> + </item> + </taglist> + <p>Which of <c>start_clean</c> and <c>start_sasl</c> to use as + default is decided by the user when installing Erlang/OTP using + <c>Install</c>. The user is asked "Do you want to use a minimal + system startup instead of the SASL startup". If the answer is + yes, then <c>start_clean</c> is used, otherwise + <c>start_sasl</c> is used. A copy of the selected boot script + is made, named <c>start.boot</c> and placed in + the <c>ROOT/bin</c> directory.</p> + </section> + + <section> + <title>User-Defined Boot Scripts</title> + <p>It is sometimes useful or necessary to create a user-defined + boot script. This is true especially when running Erlang in + embedded mode, see <seealso marker="#code_loading">Code Loading Strategy</seealso>.</p> + <p>It is possible to write a boot script manually. + The recommended way to create a boot script, however, is to + generate the boot script from a release resource file + <c>Name.rel</c>, using the function + <c>systools:make_script/1,2</c>. This requires that the source + code is structured as applications according to the OTP design + principles. (The program does not have to be started in terms of + OTP applications but can be plain Erlang).</p> + <p>Read more about <c>.rel</c> files in OTP Design Principles and + <c>rel(4)</c>.</p> + <p>The binary boot script file <c>Name.boot</c> is generated from + the boot script file <c>Name.script</c> using the function + <c>systools:script2boot(File)</c>.</p> + </section> + </section> + + <section> + <marker id="code_loading"></marker> + <title>Code Loading Strategy</title> + <p>The runtime system can be started in either <em>embedded</em> or + <em>interactive</em> mode. Which one is decided by the command + line flag <c>-mode</c>.</p> + <pre> +% <input>erl -mode embedded</input></pre> + <p>Default mode is <c>interactive</c>.</p> + <list type="bulleted"> + <item>In embedded mode, all code is loaded during system start-up + according to the boot script. (Code can also be loaded later + by explicitly ordering the code server to do so).</item> + <item>In interactive mode, code is dynamically loaded when first + referenced. When a call to a function in a module is made, and + the module is not loaded, the code server searches the code path + and loads the module into the system.</item> + </list> + <p>Initially, the code path consists of the current + working directory and all object code directories under + <c>ROOT/lib</c>, where <c>ROOT</c> is the installation directory + of Erlang/OTP. Directories can be named <c>Name[-Vsn]</c> and + the code server, by default, chooses the directory with + the highest version number among those which have the same + <c>Name</c>. The <c>-Vsn</c> suffix is optional. If an + <c>ebin</c> directory exists under the <c>Name[-Vsn]</c> + directory, it is this directory which is added to the code path.</p> + <p>The code path can be extended by using the command line flags + <c>-pa Directories</c> and <c>-pz Directories</c>. These will add + <c>Directories</c> to the head or end of the code path, + respectively. Example</p> + <pre> +% <input>erl -pa /home/arne/mycode</input></pre> + <p>The code server module <c>code</c> contains a number of + functions for modifying and checking the search path, see + <c>code(3)</c>.</p> + </section> + + <section> + <title>File Types</title> + <p>The following file types are defined in Erlang/OTP:</p> + <table> + <row> + <cell align="left" valign="middle"><em>File Type</em></cell> + <cell align="left" valign="middle"><em>File Name/Extension</em></cell> + <cell align="left" valign="middle"><em>Documented in</em></cell> + </row> + <row> + <cell align="left" valign="middle">module</cell> + <cell align="left" valign="middle"><c>.erl</c></cell> + <cell align="left" valign="middle">Erlang Reference Manual</cell> + </row> + <row> + <cell align="left" valign="middle">include file</cell> + <cell align="left" valign="middle"><c>.hrl</c></cell> + <cell align="left" valign="middle">Erlang Reference Manual</cell> + </row> + <row> + <cell align="left" valign="middle">release resource file</cell> + <cell align="left" valign="middle"><c>.rel</c></cell> + <cell align="left" valign="middle"><c>rel(4)</c></cell> + </row> + <row> + <cell align="left" valign="middle">application resource file</cell> + <cell align="left" valign="middle"><c>.app</c></cell> + <cell align="left" valign="middle"><c>app(4)</c></cell> + </row> + <row> + <cell align="left" valign="middle">boot script</cell> + <cell align="left" valign="middle"><c>.script</c></cell> + <cell align="left" valign="middle"><c>script(4)</c></cell> + </row> + <row> + <cell align="left" valign="middle">binary boot script</cell> + <cell align="left" valign="middle"><c>.boot</c></cell> + <cell align="left" valign="middle">-</cell> + </row> + <row> + <cell align="left" valign="middle">configuration file</cell> + <cell align="left" valign="middle"><c>.config</c></cell> + <cell align="left" valign="middle"><c>config(4)</c></cell> + </row> + <row> + <cell align="left" valign="middle">application upgrade file</cell> + <cell align="left" valign="middle"><c>.appup</c></cell> + <cell align="left" valign="middle"><c>appup(4)</c></cell> + </row> + <row> + <cell align="left" valign="middle">release upgrade file</cell> + <cell align="left" valign="middle"><c>relup</c></cell> + <cell align="left" valign="middle"><c>relup(4)</c></cell> + </row> + <tcaption>File Types</tcaption> + </table> + </section> +</chapter> + diff --git a/system/doc/system_principles/warning.gif b/system/doc/system_principles/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/system_principles/warning.gif diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk new file mode 100644 index 0000000000..4cbc00ed52 --- /dev/null +++ b/system/doc/system_principles/xmlfiles.mk @@ -0,0 +1,22 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +SYSTEM_PRINCIPLES_CHAPTER_FILES = \ + system_principles.xml \ + error_logging.xml \ + create_target.xml diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile new file mode 100644 index 0000000000..08fe265336 --- /dev/null +++ b/system/doc/top/Makefile @@ -0,0 +1,242 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk + +APPLICATION=otp-system-documentation + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc + +GIF_FILES = + +INFO_FILES = ../../README ../../COPYRIGHT PR.template + +TOPDOCDIR=. + +TOP_HTML_GEN_FILES = \ + $(HTMLDIR)/incompatible.html \ + $(HTMLDIR)/highlights.html + +TOP_HTML_FILES = \ + $(TOP_HTML_GEN_FILES) + +include ../installation_guide/xmlfiles.mk +include ../system_principles/xmlfiles.mk +include ../embedded/xmlfiles.mk +include ../getting_started/xmlfiles.mk +include ../reference_manual/xmlfiles.mk +include ../programming_examples/xmlfiles.mk +include ../efficiency_guide/xmlfiles.mk +include ../tutorial/xmlfiles.mk +include ../design_principles/xmlfiles.mk +include ../oam/xmlfiles.mk + +XML_FILES = \ + $(INST_GUIDE_CHAPTER_FILES:%=../installation_guide/%) \ + $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=../system_principles/%) \ + $(EMBEDDED_CHAPTER_FILES:%=../embedded/%) \ + $(GETTING_STARTED_CHAPTER_FILES:%=../getting_started/%) \ + $(REF_MAN_CHAPTER_FILES:%=../reference_manual/%) \ + $(PROG_EX_CHAPTER_FILES:%=../programming_examples/%) \ + $(EFF_GUIDE_CHAPTER_FILES:%=../efficiency_guide/%) \ + $(TUTORIAL_CHAPTER_FILES:%=../tutorial/%) \ + $(DESIGN_PRINCIPLES_CHAPTER_FILES:%=../design_principles/%) \ + $(OAM_CHAPTER_FILES:%=../oam/%) \ + ../installation_guide/part.xml \ + ../system_principles/part.xml \ + ../embedded/part.xml \ + ../getting_started/part.xml \ + ../reference_manual/part.xml \ + ../programming_examples/part.xml \ + ../efficiency_guide/part.xml \ + ../tutorial/part.xml \ + ../design_principles/part.xml \ + ../oam/part.xml + +BOOK_FILES = book.xml + +HTMLDIR= ../html +PDFREFDIR= pdf + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf +TOPDOC=true + +#-------------------------------------------------------------------------- +# We generate the index page from the installed system. This make +# it important that this is done last. The file index.html.src +# is used as a template for the resulting page. + +EBIN = ebin + +INDEX_SCRIPT = $(EBIN)/erl_html_tools.$(EMULATOR) +INDEX_SRC = src/erl_html_tools.erl +INDEX_FILES = \ + $(HTMLDIR)/index.html \ + $(HTMLDIR)/applications.html + +JAVASCRIPT = $(HTMLDIR)/js/erlresolvelinks.js +JAVASCRIPT_BUILD_SCRIPT = $(EBIN)/erlresolvelinks.$(EMULATOR) +JAVASCRIPT_BUILD_SCRIPT_SRC = src/erlresolvelinks.erl + +MAN_INDEX_SCRIPT = $(ERL_TOP)/system/doc/top/bin/otp_man_index +MAN_INDEX = $(HTMLDIR)/man_index.html + +GLOSSARY = $(HTMLDIR)/glossary.html +GLOSSARY_SRC = $(ERL_TOP)/system/internal_tools/doctools/src/glossary.erl +GLOSSARY_SCRIPT = $(EBIN)/glossary.$(EMULATOR) + +#-------------------------------------------------------------------------- + +$(INDEX_SCRIPT): $(INDEX_SRC) + $(ERLC) -o$(EBIN) +warn_unused_vars $< + +# We don't list toc_*.html as targets because we don't know +$(HTMLDIR)/index.html: $(INDEX_SCRIPT) +ifneq ($(INSTALLROOT),) + echo "Generating index $@" + $(ERL) -noshell -pa $(EBIN) -s erl_html_tools top_index $(INSTALLROOT) \ + $(HTMLDIR) $(SYSTEM_VSN) -s erlang halt +else + @echo "INSTALLROOT unset, no indexes built." +endif + +#-------------------------------------------------------------------------- + +$(JAVASCRIPT_BUILD_SCRIPT): $(JAVASCRIPT_BUILD_SCRIPT_SRC) + $(ERLC) -o$(EBIN) +warn_unused_vars $< + +$(JAVASCRIPT): $(JAVASCRIPT_BUILD_SCRIPT) +ifneq ($(INSTALLROOT),) + echo "Generating javascript for resolving HTML links" + erl -noshell -pa $(EBIN) -s erlresolvelinks make $(INSTALLROOT) \ + . -s erlang halt + mkdir $(HTMLDIR)/js + mv erlresolvelinks.js $(JAVASCRIPT) # not portable !!! +else + @echo "INSTALLROOT unset, no javascript generated." +endif + +#-------------------------------------------------------------------------- + +$(MAN_INDEX): $(MAN_INDEX_SCRIPT) +ifneq ($(INSTALLROOT),) + echo "Generating index $@" + (cd $(INSTALLROOT); perl $< ) > $@ +else + @echo "INSTALLROOT unset, no manual index built." +endif +#-------------------------------------------------------------------------- + +$(HTMLDIR)/highlights.html: highlights.xml + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --output $(@) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ + --stringparam pdfdir "$(PDFREFDIR)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \ + --stringparam appver "$(VSN)" -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities \ + $(DOCGEN)/priv/xsl/db_html.xsl $< + + +$(HTMLDIR)/incompatible.html: incompatible.xml + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --output $(@) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ + --stringparam pdfdir "$(PDFREFDIR)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \ + --stringparam appver "$(VSN)" -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities \ + $(DOCGEN)/priv/xsl/db_html.xsl $< + +#-------------------------------------------------------------------------- + +$(GLOSSARY_SCRIPT): $(GLOSSARY_SRC) + $(ERLC) -o$(EBIN) $(GLOSSARY_SRC) + +$(GLOSSARY): $(GLOSSARY_SCRIPT) + $(ERL) -noshell -pa $(EBIN) \ + -s glossary make ../definitions/term.defs -s erlang halt > \ + $(GLOSSARY) + +#-------------------------------------------------------------------------- + +PR.template: PR.template.src $(ERL_TOP)/erts/vsn.mk + sed -e 's;%VSN%;$(VSN);' \ + -e 's;%SYSTEM_VSN%;$(SYSTEM_VSN);' \ + $< > $@ + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + + +docs: pdf html $(INFO_FILES) + +local_docs: PDFREFDIR=../pdf + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: $(INDEX_FILES) $(TOP_HTML_FILES) \ + $(MAN_INDEX) $(JAVASCRIPT) + +debug opt: + +clean: + rm -rf ../html/js + rm -f PR.template + rm -f $(INDEX_FILES) $(TOP_HTML_FILES) $(MAN_INDEX) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f $(INDEX_SCRIPT) $(GLOSSARY_SCRIPT) \ + $(JAVASCRIPT_BUILD_SCRIPT) + rm -f erl_crash.dump errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_docs_spec: docs + $(INSTALL_DIR) $(RELEASE_PATH) + $(INSTALL_DATA) $(INFO_FILES) $(RELEASE_PATH) + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/pdf + $(INSTALL_DATA) \ + $(TOP_PDF_FILE) $(RELSYSDIR)/pdf +#$(TOP_HTML_FILES) +ifneq ($(INSTALLROOT),) + $(INSTALL_DATA) $(INDEX_FILES) $(MAN_INDEX) $(TOP_HTML_FILES) $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/js + $(INSTALL_DATA) \ + $(JAVASCRIPT) $(RELSYSDIR)/js +endif + + +release_spec: diff --git a/system/doc/top/PR.template.src b/system/doc/top/PR.template.src new file mode 100644 index 0000000000..fb593053d9 --- /dev/null +++ b/system/doc/top/PR.template.src @@ -0,0 +1,20 @@ +>Submitter-Id: <Your id> +>Originator: <Your name> +>Organization: <The name of your company> +>Confidential: <[yes | no ] (one line)> +>Synopsis: <synopsis of the problem (one line)> +>Severity: < [non-critical | serious | critical ] (one line)> +>Priority: < [ low | medium | high ] (one line)> +>Category: <product, component or concept name> +>Class: < [ sw-bug | doc-bug | change-request | support ] (one line)> +>Release: <Release version, e.g. OTP %SYSTEM_VSN%, Erlang %VSN%> +>Environment: + <machine, os, target, libraries (multiple lines)> +>Description: + <precise description of the problem (multiple lines)> +>How-To-Repeat: + <code/input/activities to reproduce the problem (multiple lines) +>Fix: + <How to correct or work around the problem, if known + (multiple lines)> + diff --git a/system/doc/top/bin/otp_man_index b/system/doc/top/bin/otp_man_index new file mode 120000 index 0000000000..bb913b25df --- /dev/null +++ b/system/doc/top/bin/otp_man_index @@ -0,0 +1 @@ +../../../../internal_tools/integration/scripts/otp_man_index
\ No newline at end of file diff --git a/system/doc/top/book.xml b/system/doc/top/book.xml new file mode 100644 index 0000000000..96f39b0b83 --- /dev/null +++ b/system/doc/top/book.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erlang/OTP System Documentation</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2009-08-21</date> + <rev>A</rev> + <file>book.xml</file> + </header> + <insidecover> + </insidecover> + <pagetext></pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="../installation_guide/part.xml"/> + <xi:include href="../system_principles/part.xml"/> + <xi:include href="../embedded/part.xml"/> + <xi:include href="../getting_started/part.xml"/> + <xi:include href="../reference_manual/part.xml"/> + <xi:include href="../programming_examples/part.xml"/> + <xi:include href="../efficiency_guide/part.xml"/> + <xi:include href="../tutorial/part.xml"/> + <xi:include href="../design_principles/part.xml"/> + <xi:include href="../oam/part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/top/ebin/.gitignore b/system/doc/top/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/system/doc/top/ebin/.gitignore diff --git a/system/doc/top/highlights.xml b/system/doc/top/highlights.xml new file mode 100644 index 0000000000..a30742aed6 --- /dev/null +++ b/system/doc/top/highlights.xml @@ -0,0 +1,238 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Highlights</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev>A</rev> + <file>highlights.xml</file> + </header> + <p>This document lists some highlights of Erlang 5.7/OTP R13A + (unpatched), compared to the previous version Erlang 5.6/OTP R12B, + with focus on things not already released as R12B patches.</p> + <p>Note: This document was compiled at the time when R13A was released + and does not list any features introduced in R13 patches.</p> + + <section> + <title>Erlang Language and Run-time System</title> + <section> + <title>Multi-core and SMP performance improvements</title> + <p> + There SMP performance is significantly improved and will + allow most applications to scale much better on systems with many + cores or processors. Listed below are some of the most important improvements: + </p> + <list type="bulleted"> + <item> + <p> + The runtime system with SMP support now uses <em>multiple, + scheduler specific run queues</em>, instead of one globally shared + run queue. + </p> + <p> + The lock protecting the shared run queue was heavily + contended, and the shared run queue also caused Erlang + processes to randomly migrate between schedulers with + negative cache effects as a result. + </p> + <p> + With the current scheduler specific run queue solution, lock + contention due to run queue protection has been reduced, and + Erlang processes are only migrated when needed to balance the + load between the schedulers. The reduced amount of migration + also reduce lock contention on locks protecting the scheduler + specific instances of the erts internal memory allocators. + </p> + <p> + The scheduler specific run queues are also a necessity for a + lot of future planned NUMA (Non-Uniform Memory Access) + specific optimizations. + </p> + </item> + <item> + <p> + Message passing has been further optimized for parallell execution. + This makes parallell sending to one common receiver much more efficient. + </p> + </item> + <item> + <p> + Scheduler threads can now be bound to logical processors on newer + Linux ans Solaris systems. + </p> + </item> + </list> + </section> + <section> + <title>Unicode support</title> + <p> + Support for Unicode is implemented as described in EEP10. + Formatting and reading of unicode data both from terminals + and files is supported by the <c>io</c> and <c>io_lib</c> modules. + Files + can be opened in modes with automatic translation to and from + different unicode formats. The module 'unicode' contains + functions for conversion between external and internal + unicode formats and the re module has support for unicode + data. There is also language syntax for specifying string and + character data beyond the ISO-latin-1 range. + </p> + </section> + + <section> + <title>New BIF's</title> + <p> + The BIFs <c>atom_to_binary/2</c>, <c>binary_to_atom/2</c> and + <c>binary_to_existing_atom/2</c> have been added. + </p> + </section> + + <section> + <title>Independent Erlang clusters on the same host</title> + <p> + Nodes belonging to different independent clusters can now + co-exist on the same host with the help of a new + environment variable setting <c>ERL_EPMD_PORT</c>. + The environment variable is used by Erl_interface and J_interface + as well. + </p> + </section> + </section> + + <section> + <title>New Applications</title> + + <section> + <title>Reltool</title> + + <p> + Reltool is a release management tool. + It analyses a given Erlang/OTP installation and determines + various dependencies between applications. + The graphical frontend depicts the dependencies and enables + interactive customization of a target system. + The backend provides a batch interface for generation of + customized target systems. + The application is still somewhat limited and should be regarded + as experimental in this release. The intention is that this + application will be a valuable tool for making both traditional + Erlang target systems as well as standalone components in Erlang. + </p> + </section> + + <section> + <title>WxErlang</title> + <p> + wxErlang is an Erlang binding to the WxWidgets GUI library which + provides support for cross platform GUI applications. + wxErlang is still in beta status and the intention is that it shall + replace GS in a later stage. The Erlang debugger is also shipped in + a wxErlang version. + </p> + </section> + + + </section> + + <section> + <title>New features in Existing Applications</title> + + <section> + <title>Common_test</title> + + <p> + A support client module for SSH and SFTP, <c>ct_ssh</c>, has + been introduced. + </p> + <p> + Test case groups have been introduced. With this feature + it's possible to execute groups (possibly nested) + of test cases. + </p> + <p> + A group definition contains a name tag, a list of + properties and a list of test cases (including possible + nested group definitions). The properties make it possible + to execute test cases in parallel, in sequence and in + shuffled order. It is also possible to repeat test cases + according to different criteria. + </p> + </section> + + + <section> + <title>Dialyzer</title> + <p> + The analysis now accepts <em>opaque type declarations</em> and + detects + violations of opaqueness of terms of such types. Starting + with R13, many Erlang/OTP standard libraries (array, dict, + digraph, ets, gb_sets, gb_trees, queue, and sets) contain + opaque type declarations of their main data types. Dialyzer + will spit out warnings in code that explicitly depends on the + structure of these terms. + </p> + <p> + Added support for handling UTF segments in bitstreams and for + detecting obvious type errors in these segments. Warning: + This code is not terribly tested though since there are very + few Erlang programs which use Unicode-based binaries - not + surprising since this is a new language feature of R13. + </p> + <p> + Strengthened the discrepancy identification when testing for + equality and matching between terms of different types. This + detects more bugs in code. + </p> + <p> + See the Dialyzer documentation and release notes for even more + enhancements. + </p> + </section> + + <section> + <title>SSL</title> + <p> + The "new_ssl" implementation is significantly improved and should be + near product status now. + The new SSL is implemented in pure Erlang except for + the crypto routines that are implemented in the crypto driver which + is an interface to libcrypto from OpenSSL. + </p> + </section> + + <section> + <title>STDLIB</title> + + <p>The Erlang scanner has been augmented as to return white-space, + comments and exact location of tokens. + This means that the scanner can easily be used in tools such as editors, + pretty printers, syntax highlighters etc. + where it is important to be able recreate the original source document. + </p> + </section> + + </section> +</chapter> + diff --git a/system/doc/top/incompatible.xml b/system/doc/top/incompatible.xml new file mode 100644 index 0000000000..ce9522725b --- /dev/null +++ b/system/doc/top/incompatible.xml @@ -0,0 +1,383 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Potential Incompatibilities</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>incompatible.xml</file> + </header> + <p>This document contains a list of potential incompatibilities + between Erlang 5.7/OTP R12A and Erl 5.6.5/OTP R12B-5, + and is an extract from the release notes for the respective applications.</p> + + <section> + <title>compiler</title> + <list type="bulleted"> + <item> + <p> + The undocumented, unsupported, and deprecated guard BIF + <c>is_constant/1</c> has been removed.</p> + <p> + *** INCOMPATIBILITY with R12B ***</p> + <p> + Own Id: OTP-7673</p> + </item> + <item> + <p>The short-circuit operators <c>andalso</c> and + <c>orelse</c> no longer guarantees that their second + argument is either <c>true</c> or <c>false</c>. As a + consequence, <c>andalso</c>/<c>orelse</c> are now + tail-recursive.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7748</p> + </item> + <item> + <p>The compiler will refuse to a compile file where the + module name in the file differs from the output file + name.</p> + <p>When compiling using <c>erlc</c>, the current working + directory will no be included in the code path (unless + explicitly added using "-pa .").</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7793</p> + </item> + <item> + <p>If a module contains an exported function with the + same name as an auto-imported BIF (such as + <c>length/1</c>), any calls to the BIF must have an + explicit <c>erlang:</c> prefix, or there will be a + compilation error (such calls would only generate a + warning in previous releases).</p> + <p>(The reason for the change is to avoid breaking code + in a future major release, R14 or R15, in which we plan + to make calls without a module prefix always call the + local function in the same module even if there is an + auto-imported BIF with the same name.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7873</p> + </item> + </list> + </section> + + <section> + <title>Erts</title> + <list type="bulleted"> + <item> + <p>Support for Unicode is implemented as described in + EEP10. Formatting and reading of unicode data both from + terminals and files is supported by the io and io_lib + modules. Files can be opened in modes with automatic + translation to and from different unicode formats. The + module 'unicode' contains functions for conversion + between external and internal unicode formats and the re + module has support for unicode data. There is also + language syntax for specifying string and character data + beyond the ISO-latin-1 range.</p> + <p>The interactive shell will support input and output of + unicode characters when the terminal and operating system + supports it.</p> + <p>Please see the EEP and the io/io_lib manual pages as + well as the stdlib users guide for details.</p> + <p><em>I/O-protocol incompatibilities:</em></p> + <p>The io_protocol between io_Server and client is + updated to handle protocol data in unicode formats. The + updated protocol is now documented. The specification + resides in the stdlib <em>users manual</em>, which is a + new part of the manual.</p> + <p><em>io module incompatibilities:</em></p> + <p>The io:put_chars, io:get_chars and io:get_line all + handle and return unicode data. In the case where + binaries can be provided (as to io:put_chars), they shall + be encoded in UTF-8. When binaries are returned (as by + io:get_line/get_chars when the io_server is set in + <em>binary mode</em>) the returned data is also + <em>always</em> encoded as UTF-8. The file module however + still returns byte-oriented data, why file:read can be + used instead of io:get_chars to read binary data in + ISO-latin-1.</p> + <p><em>io_lib module incompatibilities:</em></p> + <p>io_lib:format can, given new format directives (i.e + "~ts" and "~tc"), return lists containing integers larger + than 255. </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7648 Aux Id: OTP-7580 OTP-7514 OTP-7494 + OTP-7443 OTP-7181 EEP10 EEP11 </p> + </item> + <item> + <p> + The undocumented, unsupported, and deprecated guard BIF + <c>is_constant/1</c> has been removed.</p> + <p> + *** INCOMPATIBILITY with R12B ***</p> + <p> + Own Id: OTP-7673</p> + </item> + <item> + <p>The short-circuit operators <c>andalso</c> and + <c>orelse</c> no longer guarantees that their second + argument is either <c>true</c> or <c>false</c>. As a + consequence, <c>andalso</c>/<c>orelse</c> are now + tail-recursive.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7748</p> + </item> + <item> + <p>The compiler will refuse to a compile file where the + module name in the file differs from the output file + name.</p> + <p>When compiling using <c>erlc</c>, the current working + directory will no be included in the code path (unless + explicitly added using "-pa .").</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7793</p> + </item> + <item> + <p>The deprecated functions <c>erlang:fault/1</c>, + <c>erlang:fault/2</c>, and <c>file:rawopen/2</c> have + been removed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7812</p> + </item> + <item> + <p>The escape sequences <c>\x</c> and <c>\{</c> have been + assigned new interpretations (they used to return the + ASCII code for <c>x</c> and <c>{</c> respectively). One + or more octal characters inside curly brackets after a + leading backslash is from now on an alternative to the + existing syntax <c>\NNN</c>, but can also be used for + codes greater than 255. In a similar fashion, one or more + hexadecimal characters can be put inside curly brackets + after a leading <c>\x</c>. Furthermore, the escape + sequences <c>\xH</c> and <c>\xHH</c>, where N is a + hexadecimal character, can be used for codes less than + 256.</p> + <p>NOTE: These new escape sequences are still considered + experimental and may be changed in the R13B release.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7855</p> + </item> + </list> + </section> + + <section> + <title>Inets</title> + <list type="bulleted"> + <item> + <p> + [httpc] - The inets http client will now use persistent + connections without pipelining as default and if a + pipeline timeout is set it will pipeline the requests on + the persistent connections.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7463</p> + </item> + </list> + </section> + + <section> + <title>Jinterface</title> + <list> + <item> + <p> + A number of fixes and improvements from the ErlIDE group; + Vlad Dumitrescu and Jakob Cederlund: JDK 1.5 is now a + minimal requirement for building Jinterface. New method: + OtpEpmd.lookupNames. OtpErlangList is now iterable. + Non-proper lists are now allowed - you have to test if a + list is proper or not. Non-proper lists can also be + created. New methods: isProper, getHead, getTail and + getNthTail. The get tail methods creates a sublist object + that re-uses the original list. OtpErlangPid is now + Comparable. Empty atoms can now be constructed, a missing + feature pointed out by Sebastien Boisgerault on + erlang-questions.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7832</p> + </item> + </list> + </section> + + <section> + <title>Kernel</title> + <list type="bulleted"> + <item> + <p>The deprecated functions <c>erlang:fault/1</c>, + <c>erlang:fault/2</c>, and <c>file:rawopen/2</c> have + been removed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7812</p> + </item> + </list> + </section> + + <section> + <title>SSH</title> + <list type="bulleted"> + <item> + <p> + Ssh timeouts will now behave as expected i.e. defaults to + infinity. Only the user of the ssh application can know of + a reasonable timeout value for their application.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7807</p> + </item> + <item> + <p> + Added the message {ssh_channel_up, ChannelId, + ConnectionManager} that shall be handled by the channel + callback handle_msg/2. This makes the function + handle_msg/2 a mandatory function for ssh channels + implementations which it was not in ssh-1.1.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7828</p> + </item> + </list> + </section> + + <section> + <title>STDLIB</title> + <list type="bulleted"> + <item> + <p>The functions <c>lists:seq/1,2</c> return the empty + list in a few cases when they used to generate an + exception, for example <c>lists:seq(1, 0)</c>. See + lists(3) for details. (Thanks to Richard O'Keefe.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7230</p> + </item> + <item> + <p>Support for Unicode is implemented as described in + EEP10. Formatting and reading of unicode data both from + terminals and files is supported by the io and io_lib + modules. Files can be opened in modes with automatic + translation to and from different unicode formats. The + module 'unicode' contains functions for conversion + between external and internal unicode formats and the re + module has support for unicode data. There is also + language syntax for specifying string and character data + beyond the ISO-latin-1 range.</p> + <p>The interactive shell will support input and output of + unicode characters when the terminal and operating system + supports it.</p> + <p>Please see the EEP and the io/io_lib manual pages as + well as the stdlib users guide for details.</p> + <p><em>I/O-protocol incompatibilities:</em></p> + <p>The io_protocol between io_Server and client is + updated to handle protocol data in unicode formats. The + updated protocol is now documented. The specification + resides in the stdlib <em>users manual</em>, which is a + new part of the manual.</p> + <p><em>io module incompatibilities:</em></p> + <p>The io:put_chars, io:get_chars and io:get_line all + handle and return unicode data. In the case where + binaries can be provided (as to io:put_chars), they shall + be encoded in UTF-8. When binaries are returned (as by + io:get_line/get_chars when the io_server is set in + <em>binary mode</em>) the returned data is also + <em>always</em> encoded as UTF-8. The file module however + still returns byte-oriented data, why file:read can be + used instead of io:get_chars to read binary data in + ISO-latin-1.</p> + <p><em>io_lib module incompatibilities:</em></p> + <p>io_lib:format can, given new format directives (i.e + "~ts" and "~tc"), return lists containing integers larger + than 255. </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7648 Aux Id: OTP-7580 OTP-7514 OTP-7494 + OTP-7443 OTP-7181 EEP10 EEP11 </p> + </item> + <item> + <p> + <c>filelib:fold_files/5</c> now uses the <c>re</c> module + instead of the <c>regexp</c> module for regular + expression matching. In practice, this change will not be + a problem for most regular expressions used for + <c>filelib:fold_files/5</c>. (The major difference in + regular expression is that parenthesis and curly brackets + is treated as literal characters by <c>regexp</c> but as + special characters by <c>re</c>; fortunately, those + characters are rarely used in filenames.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7819</p> + </item> + <item> + <p> + <c>digraph:new(Type)</c> will now cause a <c>badarg</c> + exception if <c>Type</c> is not a valid type. Similarly, + <c>digraph_utils:subgraph/2,3</c> will now cause a + <c>badarg</c> if the arguments are invalid. (Those + functions used to return error tuples if something was + wrong.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7824</p> + </item> + <item> + <p>The argument passed to <c>random:uniform/1</c> must + now be an integer (as stated in the documentation). In + previous releases, a floating point number was also + allowed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7827</p> + </item> + </list> + </section> +</chapter> + diff --git a/system/doc/top/print.html b/system/doc/top/print.html new file mode 100644 index 0000000000..b562d0e9bc --- /dev/null +++ b/system/doc/top/print.html @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<!-- This document was generated using DocBuilder-0.9.8.1 --> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>Erlang/OTP Documentation for Printing</title> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> + <style type="text/css"> +<!-- + body { font-family: Verdana, Arial, Helvetica, sans-serif } + span.bold_code { font-family: courier;font-weight: bold} + span.code { font-family: courier;font-weight: normal} +--> + </style> +</head> + +<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> + +<center> +<a href="http://www.ericsson.com/technology/opensource/erlang"> + <img alt="Ericsson AB" BORDER=0 SRC="pics/min_head.gif"> +</a> +<br> + +<font size="-1"> + [<a href="index.html">Up</a> | + <a href="http://www.ericsson.com/technology/opensource/erlang">Ericsson AB</a>] +</font> +<br/> + +<p> +<font size="+3">Documentation for Printing</font><br/> +</p> +</center> + +<p> + +You can get this documentation preformated for printing in PDF +format from the +<a href="http://www.erlang.org/doc.html"> + Erlang/OTP documentation page +</a>. Here you can find links to documentation for the latest release as well as for older releases. + +<!-- ------------------------- footer ------------------------- --> +<p> +<center> +<hr/> +<font size="-1"> + Copyright © 1991-2008 + <a href="http://www.ericsson.com/technology/opensource/erlang">Ericsson AB</a> +</font> +</center> +</body> +</html> diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl new file mode 120000 index 0000000000..35a199b08d --- /dev/null +++ b/system/doc/top/src/erl_html_tools.erl @@ -0,0 +1 @@ +../../../../internal_tools/integration/scripts/make_index/erl_html_tools.erl
\ No newline at end of file diff --git a/system/doc/top/src/erlresolvelinks.erl b/system/doc/top/src/erlresolvelinks.erl new file mode 120000 index 0000000000..8d277ad17a --- /dev/null +++ b/system/doc/top/src/erlresolvelinks.erl @@ -0,0 +1 @@ +../../../../internal_tools/integration/scripts/resolve_links/erlresolvelinks.erl
\ No newline at end of file diff --git a/system/doc/top/src/permuted_index.erl b/system/doc/top/src/permuted_index.erl new file mode 120000 index 0000000000..e65338a517 --- /dev/null +++ b/system/doc/top/src/permuted_index.erl @@ -0,0 +1 @@ +../../../../internal_tools/integration/scripts/make_index/permuted_index.erl
\ No newline at end of file diff --git a/system/doc/top/templates/applications.html.src b/system/doc/top/templates/applications.html.src new file mode 100644 index 0000000000..0251d39b28 --- /dev/null +++ b/system/doc/top/templates/applications.html.src @@ -0,0 +1,34 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>Erlang/OTP #version#</title> + <style type="text/css"> +<!-- + BODY { background: white } + + BODY { font-family: Verdana, Arial, Helvetica, sans-serif } + TH { font-family: Verdana, Arial, Helvetica, sans-serif } + TD { font-family: Verdana, Arial, Helvetica, sans-serif } + P { font-family: Verdana, Arial, Helvetica, sans-serif } + + .header { background: #222; color: #fff } + .app { background: #ccc } + + a.anum:link { color: green; text-decoration: none } + a.anum:active { color: green; text-decoration: none } + a.anum:visited { color: green; text-decoration: none } + + a:link { text-decoration: none } + a:active { text-decoration: none } + a:visited { text-decoration: none } +--> + </style> +</head> + +<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> +<center> +#groups# +</center> +</body> +</html> diff --git a/system/doc/top/templates/erlang.gif b/system/doc/top/templates/erlang.gif Binary files differnew file mode 100644 index 0000000000..91fd4b9647 --- /dev/null +++ b/system/doc/top/templates/erlang.gif diff --git a/system/doc/top/templates/first.html.src b/system/doc/top/templates/first.html.src new file mode 100644 index 0000000000..edef1c0e5c --- /dev/null +++ b/system/doc/top/templates/first.html.src @@ -0,0 +1,104 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>Erlang/OTP #release# Documentation</title> + <style type="text/css"> +<!-- + BODY { background: white } + + BODY { font-family: Verdana, Arial, Helvetica, sans-serif } + TH { font-family: Verdana, Arial, Helvetica, sans-serif } + TD { font-family: Verdana, Arial, Helvetica, sans-serif } + P { font-family: Verdana, Arial, Helvetica, sans-serif } + + .header { background: #222; color: #fff } + .app { background: #ccc } +--> + </style> +</head> +<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> +<center> +<p> +<font size="+1">Welcome to Erlang/OTP, a complete<br> +development environment<br> +for concurrent programming.</font> +</p> +</center> +<br> +<br> +<br> +<p><b> +<font size"+1"> +Some hints that may get you started faster +</font> +</b></p> + +<ul> + +<li>In addition the the documentation here Erlang is described in the book +<a href="http://www.pragprog.com/titles/jaerlang" target="_top">"Programming Erlang"</a>, ISBN 978-1-934356-00-5 which we really recommend as a start.<br/ > +The complete language is also described in the <a href="reference_manual/part_frame.html" target="_top">Erlang Reference Manual</a>. An Erlang tutorial can be found in <a href="getting_started/part_frame.html" target="_top">Getting Started With Erlang</a>. +</li> +<li>Erlang/OTP is divided into a number of OTP <a +href="applications.html">applications</a>. An application normally contains +Erlang <a href="man_index.html">modules</a>. Some OTP applications, +such as the C interface <em>Erl_Interface</em>, are written in other languages and have no Erlang +modules. + +<p> +Note that functions that are not imported or prefixed with a module +name belong to the module +<a href="#kernel#/erlang.html" target="_top">erlang</a> +(in the <em>Kernel</em> application). +</p> +<p> +<li>On a Unix system you can view the manual pages from the command +line using +<pre> + % erl -man <module> +</pre> +<p> + +<li> You can of course use any editor you like to write Erlang +programs, but if you use Emacs there exists editing support such as +indentation, syntax highlighting, electric commands, module name +verification, comment support including paragraph filling, skeletons, +tags support and more. See the <a href="#tools#/index.html" +target="_top">Tools</a> application for details. +<p> +There is also an +<a href="http://erlide.sourceforge.net" target="_top"> +Erlang plugin (ErlIde) for Eclipse</a> if you prefer a more graphical +environment. ErlIde is under development and should at the time +of writing this be quite stable and useful. +<li>When developing with Erlang/OTP you usually test your programs +from the interactive shell (see <a href="getting_started/part_frame.html" +target="_top">Getting Started With Erlang</a>) where you can call individual +functions. There is also a number of tools available, such as the graphical <a +href="#debugger#/index.html" target="_top">Debugger</a>, the process +manager <a href="#pman#/index.html" target="_top">Pman</a> and table +viewer <a href="#tv#/index.html" target="_top">TV</a>. +<p> Also note that there are some shell features like history list +(control-p and control-n), inline editing (emacs key bindings) and +module and function name completion (tab) if the module is loaded. +<p> + +<li>OpenSource users can ask questions +and share experiences on the <a href="http://www.erlang.org/faq.html" +target="_top">Erlang questions mailing list</a>. <p> + +<li>Before asking a question you can browse the <a +href="http://www.erlang.org/pipermail/erlang-questions/" +target="_top">mailing list archive</a> and read the <a +href="http://www.erlang.org/faq/faq.html" target="_top">Frequently +Asked Questions</a>. <p> + +<li>Additional information and links of interest for Erlang programmers can be found on the Erlang Open Source site +<a href="http://www.erlang.org/" target="_top">http://www.erlang.org</a>. +<p> + +</ul> + +</body> +</html> diff --git a/system/doc/top/templates/flip_closed.gif b/system/doc/top/templates/flip_closed.gif Binary files differnew file mode 100755 index 0000000000..9a27c7c25d --- /dev/null +++ b/system/doc/top/templates/flip_closed.gif diff --git a/system/doc/top/templates/flip_google.gif b/system/doc/top/templates/flip_google.gif Binary files differnew file mode 100755 index 0000000000..3f0543c2bb --- /dev/null +++ b/system/doc/top/templates/flip_google.gif diff --git a/system/doc/top/templates/flip_open.gif b/system/doc/top/templates/flip_open.gif Binary files differnew file mode 100755 index 0000000000..9dda60e73a --- /dev/null +++ b/system/doc/top/templates/flip_open.gif diff --git a/system/doc/top/templates/flip_static.gif b/system/doc/top/templates/flip_static.gif Binary files differnew file mode 100755 index 0000000000..2b3ddb5382 --- /dev/null +++ b/system/doc/top/templates/flip_static.gif diff --git a/system/doc/top/templates/flipmenu.js b/system/doc/top/templates/flipmenu.js new file mode 100755 index 0000000000..92a5a58a06 --- /dev/null +++ b/system/doc/top/templates/flipmenu.js @@ -0,0 +1,342 @@ +// ######################################################################
+
+// ## flipMenu 5.0.0 (c) J. Reijers
+// ## Last modifications: 23 March 2007
+
+// ######################################################################
+
+// ## Degree of indentation from the left.
+ flipIndentation = "5px";
+
+// ## Padding inbetween menu items.
+ flipVerticalPadding = "4px";
+
+// ## Margin between the left of the browser and the menu.
+ flipLeftMargin = "16px";
+
+// ## Margin between the top of the browser and the menu.
+ flipTopMargin = "10px";
+
+// ## Allow multiple menus to fold out without closing all the other open ones.
+ flipOpenMultipleMenus = false;
+
+// ## Preserve the current state of the menu (requires cookies).
+ flipSaveMenuState = true;
+
+// ## Use custom images for bullets
+ flipImages = true;
+
+// ## Images to use (specify full path)
+ flipImg_open = "flip_open.gif";
+ flipImg_closed = "flip_closed.gif";
+ flipImg_static = "flip_static.gif";
+
+// ## Initialise all flipMenus onload
+ flipInitOnLoad = true;
+
+// ## Message to display in status bar while loading
+ flipLoadingMessage = "Loading...";
+
+// ######################################################################
+
+function alterSize(someSize, alterAmount) {
+ someSize = String(someSize);
+ var tmpNr = parseFloat(someSize.replace(/\D/g, ""));
+ var tmpChar = someSize.replace(/\d/g, "");
+ return isNaN(tmpNr) ? someSize : ((tmpNr + alterAmount) + tmpChar);
+}
+
+isIE = (String(navigator.appVersion).indexOf("MSIE") > -1);
+if (!isIE) flipIndentation = alterSize(flipIndentation, -16);
+if (!isIE) flipLeftMargin = alterSize(flipLeftMargin, -16);
+
+document.write(
+ "<style type=\"text/css\">" +
+
+ "ul.flipMenu { margin-top: " + flipTopMargin + "; margin-left: " + flipLeftMargin + "; " + (flipImages ? "" : "list-style-type: none;") + " }" +
+ "ul.flipMenu ul, ul.flipMenu li { padding-top: " + flipVerticalPadding + "; margin-left: " + flipIndentation + "; margin-right: 0px; " + (flipImages ? "" : "list-style-type: none;") + " }" +
+
+ "li.flipFolderOpen { cursor: pointer; " + (flipImages ? "list-style-image: url(" + flipImg_open + ");" : "") + " }" +
+ "li.flipFolderClosed { cursor: pointer; " + (flipImages ? "list-style-image: url(" + flipImg_closed + ");" : "") + " }" +
+
+ "</style>"
+);
+
+if (flipImages) {
+ aFlipPreloads = [];
+ aFlipPreloads[0] = new Image;
+ aFlipPreloads[0].src = flipImg_open;
+ aFlipPreloads[1] = new Image;
+ aFlipPreloads[1].src = flipImg_closed;
+ aFlipPreloads[2] = new Image;
+ aFlipPreloads[2].src = flipImg_static;
+}
+
+function addEvent(someObj, someEvent, someFunction) {
+ if (someObj.addEventListener) { someObj.addEventListener(someEvent, someFunction, true); return true; } else if (someObj.attachEvent) return someObj.attachEvent("on" + someEvent, someFunction); else return false;
+}
+
+function openCloseFlip(theItem, newSetting, openParents) {
+ if (theItem.flipID) {
+ if (openParents) {
+ var tmpItem = theItem;
+ while (tmpItem.parentElement || tmpItem.parentNode) {
+ tmpItem = (tmpItem.parentElement) ? tmpItem.parentElement : tmpItem.parentNode;
+ openCloseFlip(tmpItem, newSetting);
+ }
+ }
+ if ((theItem.className == "flipFolderOpen" && newSetting == "closed") || (theItem.className == "flipFolderClosed" && newSetting == "open")) {
+ if (!theItem.childrenInitialised) {
+ for (var j = 0; j < theItem.childNodes.length; j++) if (theItem.childNodes[j].nodeName == "UL" && !theItem.childNodes[j].initialised) initFlip(theItem.childNodes[j]);
+ theItem.childrenInitialised = true;
+ }
+ theItem.getElementsByTagName("UL")[0].style.display = (newSetting == "open") ? "" : "none";
+ theItem.className = newSetting == "open" ? "flipFolderOpen" : "flipFolderClosed";
+ }
+ }
+}
+
+function openFlip(theItem, openParents) {
+ openCloseFlip(theItem, "open", openParents);
+}
+
+function closeFlip(theItem, closeParents) {
+ openCloseFlip(theItem, "closed", closeParents);
+}
+
+function toggleFlip(theElement) {
+ if (theElement.flipID) {
+ var theItem = theElement;
+ var isContained = true;
+ } else {
+ if (theElement && theElement.button > 0) return false;
+ var theItem = (isIE) ? event.srcElement : theElement.target;
+
+ var isContained = false;
+ if (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") isContained = true; else while (theItem.parentElement || theItem.parentNode) {
+ if (theItem.className == "flipStatic" || theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") {
+ isContained = (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed");
+ break;
+ }
+ theItem = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode;
+ }
+ }
+
+ var toOpenFlip = (isContained && theItem.className == "flipFolderClosed");
+
+ if (!flipOpenMultipleMenus && (toOpenFlip || theItem.className == "flipStatic")) {
+ if (theItem.parentElement || theItem.parentNode) {
+ var parentUL = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode;
+ for (var i = 0; i < parentUL.childNodes.length; i++) closeFlip(parentUL.childNodes[i]);
+ }
+ }
+
+ if (isContained) {
+ if (toOpenFlip) openFlip(theItem); else closeFlip(theItem);
+ }
+}
+
+function setAllFlips(startElement, newSetting) {
+ if (typeof startElement == "undefined") var startElement = document;
+ if (typeof newSetting == "undefined") var newSetting = "closed";
+
+ var aUL = startElement.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var parentFlip = aUL[i].parentElement ? aUL[i].parentElement : aUL[i].parentNode;
+ openCloseFlip(parentFlip, newSetting);
+ }
+}
+
+function openAllFlips(startElement) {
+ setAllFlips(startElement, "open");
+}
+
+function closeAllFlips(startElement) {
+ setAllFlips(startElement, "closed");
+}
+
+function initFlip(startElement) {
+ if (!document.createElement) return false;
+
+ if (!startElement || !startElement.nodeName) {
+ var aUL = document.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ if (flipLoadingMessage != "") window.status = flipLoadingMessage + " " + parseInt((i / (aUL.length - 1)) * 100, 10) + "%";
+ var curUL = aUL[i];
+ if (curUL.className == "flipMenu") {
+ initFlip(curUL);
+
+ // ## Fix text selecting problem in Mozilla
+ curUL.onselectstart = new Function("return false");
+ curUL.onmousedown = new Function("return false");
+ curUL.onclick = new Function("return true");
+ }
+ }
+
+ if (flipSaveMenuState) loadMenuState();
+
+ if (flipLoadingMessage != "") window.status = "";
+ return true;
+ }
+
+ if (startElement.className == "flipMenu") startElement.style.display = "";
+
+ if (!startElement.childNodes || startElement.childNodes.length == 0) return false;
+
+ if (typeof flipIDCur == "undefined") flipIDCur = 0;
+ if (!startElement.initialised) {
+ var aUL = startElement.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) aUL[i].style.display = "none";
+ }
+
+ for (var i = 0; i < startElement.childNodes.length; i++) {
+ var curNode = startElement.childNodes[i];
+ if (curNode.nodeName == "LI") {
+ flipIDCur++;
+ curNode.flipID = flipIDCur;
+
+ var nodeHasChildren = curNode.getElementsByTagName("UL").length > 0;
+ if (nodeHasChildren) {
+ if (flipImages && curNode.flipClosed) curNode.style.listStyleImage = "url(" + curNode.flipClosed + ")";
+
+ if (curNode.className == null || curNode.className == "") curNode.className = "flipFolderClosed";
+ } else {
+ curNode.className = "flipStatic";
+ if (flipImages && !curNode.style.listStyleImage) {
+ if (!curNode.flipStatic) curNode.flipStatic = flipImg_static;
+ curNode.style.listStyleImage = "url(" + curNode.flipStatic + ")";
+ }
+ }
+
+ if (!curNode.flipOpen) curNode.flipOpen = flipImg_open;
+ if (!curNode.flipClosed) curNode.flipClosed = flipImg_closed;
+
+ if (curNode.flipIsOpen) openFlip(curNode);
+ }
+ }
+
+ startElement.initialised = true;
+}
+
+function rootOfFlip(flipID, startElement) {
+
+ function containsFlip(startElement, flipID) {
+ var flipFound = false;
+ var i = 0;
+ while (i < startElement.childNodes.length && !flipFound) {
+ var curNode = startElement.childNodes[i];
+ flipFound = (curNode.flipID == flipID) ? true : containsFlip(curNode, flipID);
+ i++;
+ }
+ return flipFound;
+ }
+
+ var rootFlip = null;
+
+ if (!startElement || !startElement.nodeName) {
+ var aUL = document.getElementsByTagName("UL");
+ var i = 0;
+ while (rootFlip == null && i < aUL.length) {
+ var curUL = aUL[i];
+ if (curUL.nodeName == "UL" && curUL.className == "flipMenu") rootFlip = rootOfFlip(flipID, curUL);
+ i++;
+ }
+ return rootFlip;
+ }
+
+ if (startElement.childNodes) for (var i = 0; i < startElement.childNodes.length; i++) {
+ var curNode = startElement.childNodes[i];
+ if (curNode.flipID == flipID || containsFlip(curNode, flipID)) rootFlip = curNode;
+ }
+
+ return rootFlip;
+}
+
+function getCookie(cookieName) {
+ var allCookies = document.cookie;
+ var indexStr = allCookies.indexOf(cookieName + "=");
+ if (indexStr == -1) return "";
+ indexStr = allCookies.indexOf("=", indexStr) + 1;
+ var endStr = allCookies.indexOf(";", indexStr);
+ if (endStr == -1) endStr = allCookies.length;
+ return unescape(allCookies.substring(indexStr, endStr));
+}
+
+function inArray(someID, someArray) {
+ for (var i = 0; i < someArray.length; i++) if (someArray[i] == someID) return true;
+ return false;
+}
+
+function getMenuState(startElement) {
+ if (!startElement.childNodes || startElement.childNodes.length == 0) return "";
+
+ var openItems = "";
+ var aUL = startElement.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var curNode = aUL[i];
+ var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode;
+ if (curNode.style.display == "" && parentFlip.flipID) openItems += " " + parentFlip.flipID;
+ }
+ return openItems;
+}
+
+function putMenuState(startElement) {
+ if (!startElement.childNodes || startElement.childNodes.length == 0) return false;
+
+ var aUL = startElement.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var curNode = aUL[i];
+ var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode;
+ if (inArray(parentFlip.flipID, aOpenItems)) {
+ openFlip(parentFlip);
+ if (typeof prevFlipRoot == "undefined") {
+ var testRoot = rootOfFlip(parentFlip.flipID);
+ if (testRoot.flipID == parentFlip.flipID) prevFlipRoot = testRoot;
+ }
+ }
+ }
+}
+
+function saveMenuState() {
+ if (flipSaveMenuState) {
+ var aUL = document.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var curUL = aUL[i];
+ var curID = curUL.id ? curUL.id : i;
+ if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=" + getMenuState(curUL) + ";";
+ }
+ }
+}
+
+function loadMenuState() {
+ var aUL = document.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var curUL = aUL[i];
+ var curID = curUL.id ? curUL.id : i;
+ if (curUL.className == "flipMenu") {
+ var savedState = String(getCookie(cookiePrefix + curID));
+ if (savedState != "") {
+ aOpenItems = savedState.split(" ");
+ putMenuState(curUL);
+ }
+ }
+ }
+
+ addEvent(window, "unload", saveMenuState);
+}
+
+function clearMenuState(flipMenuID) {
+ if (typeof flipMenuID == "undefined") {
+ var aUL = document.getElementsByTagName("UL");
+ for (var i = 0; i < aUL.length; i++) {
+ var curUL = aUL[i];
+ var curID = curUL.id ? curUL.id : i;
+ if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=;";
+ }
+ } else document.cookie = cookiePrefix + flipMenuID + "=;";
+}
+
+cookiePrefix = document.location.pathname + "_";
+
+addEvent(document, "click", toggleFlip);
+if (flipInitOnLoad) addEvent(window, "load", initFlip);
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src new file mode 100644 index 0000000000..935bb11c80 --- /dev/null +++ b/system/doc/top/templates/index.html.src @@ -0,0 +1,180 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- +%CopyrightBegin% + +Copyright Ericsson AB 2001-2009. All Rights Reserved. + +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +%CopyrightEnd% +--> + +<html> +<head> + <link rel="stylesheet" href="otp_doc.css" type="text/css"/> + <title>Erlang/OTP #release#</title> + +<script id="js" type="text/javascript" language="JavaScript" src="js/flipmenu/flipmenu.js"> + +</script> +</head> + +<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> + +<div id="container"> +<div id="leftnav"> +<div class="innertube"> +<img alt="Erlang logo" src="erlang-logo.png"/ > +<!-- small><a href="glossary.html">Glossary</a> |--> +<small><a href="applications.html">Applications</a><br> +<a href="man_index.html">Modules</a></small> +<p/> +<small><a href="highlights.html">Release highlights</a><br> +<a href="incompatible.html">Potential incompatibilities</a><br> +</small> +<br> +<a href="javascript:openAllFlips()">Expand All</a><br> +<a href="javascript:closeAllFlips()">Contract All</a> +<p/> + +<ul class="flipMenu"> +<li>Erlang/OTP System Documentation +<ul> +<li><a href="installation_guide/users_guide.html">Installation Guide</a></li> +<li><a href="system_principles/users_guide.html">System Principles</a></li> +<li><a href="embedded/users_guide.html">Embedded System</a></li> +<li><a href="getting_started/users_guide.html">Getting Started</a></li> +<li><a href="reference_manual/users_guide.html">Erlang Reference Manual</a></li> +<li><a href="programming_examples/users_guide.html">Programming Examples</a></li> +<li><a href="efficiency_guide/users_guide.html">Efficiency Guide</a></li> +<li><a href="tutorial/users_guide.html">Interoperability Tutorial</a></li> +<li><a href="design_principles/users_guide.html">Design Principles</a></li> +<li><a href="oam/users_guide.html">OAM Principles</a></li> +</ul> +</li> + +#applinks# +</ul> + +</div> +</div> + + +<div id="content"> +<div class="innertube"> +<center> +<font size="+1"><b>Erlang/OTP #release#</b></font><br> +</center> +<center> +<p> +<font size="+1">Welcome to Erlang/OTP, a complete<br> +development environment<br> +for concurrent programming.</font> +</p> +</center> +<br> +<br> +<br> +<p><b> +<font size="+1"> +Some hints that may get you started faster +</font> +</b></p> + +<ul> + +<li> +The complete Erlang language is described in the +<a href="reference_manual/users_guide.html">Erlang Reference Manual</a>. +An Erlang tutorial can be found in +<a href="getting_started/users_guide.html"> +Getting Started With Erlang</a>. +<p> +In addition to the documentation here Erlang is described in several recent books like: +</p> +<ul> +<li> +<a href="http://oreilly.com/catalog/9780596518189">"Erlang Programming"</a> from O'Reilly. +</li> +<li> +<a href="http://www.pragprog.com/titles/jaerlang">"Programming Erlang"</a> from Pragmatic. +</li> +</ul> +<p> +These books are highly recommended as a start for learning Erlang. +</p> +</li> +<li>Erlang/OTP is divided into a number of OTP <a +href="applications.html">applications</a>. An application normally contains +Erlang <a href="man_index.html">modules</a>. Some OTP applications, +such as the C interface <em>erl_interface</em>, are written in other languages and have no Erlang +modules. + +<p> +<li>On a Unix system you can view the manual pages from the command +line using +<pre> + % erl -man <module> +</pre> +<p> + +<li> You can of course use any editor you like to write Erlang +programs, but if you use Emacs there exists editing support such as +indentation, syntax highlighting, electric commands, module name +verification, comment support including paragraph filling, skeletons, +tags support and more. See the <a href="#tools#/index.html"> +Tools</a> application for details. +<p> +There is also an +<a href="http://erlide.sourceforge.net"> +Erlang plugin (ErlIDE) for Eclipse</a> if you prefer a more graphical +environment. ErlIDE is under active development with new features in almost every release. +<li>When developing with Erlang/OTP you usually test your programs +from the interactive shell (see <a href="getting_started/users_guide.html"> +Getting Started With Erlang</a>) where you can call individual +functions. There is also a number of tools available, such as the graphical <a +href="#debugger#/index.html" >Debugger</a>, the process +manager <a href="#pman#/index.html" >Pman</a> and table +viewer <a href="#tv#/index.html">TV</a>. +<p> Also note that there are some shell features like history list +(control-p and control-n), in line editing (Emacs key bindings) and +module and function name completion (tab) if the module is loaded. +<p> + +<li>OpenSource users can ask questions +and share experiences on the <a href="http://www.erlang.org/faq.html"> +Erlang questions mailing list</a>. <p> + +<li>Before asking a question you can browse the <a +href="http://www.erlang.org/pipermail/erlang-questions/"> +mailing list archive</a> and read the <a +href="http://www.erlang.org/faq/faq.html" >Frequently +Asked Questions</a>. <p> + +<li>Additional information and links of interest for Erlang programmers can be found on the Erlang Open Source site +<a href="http://www.erlang.org/">http://www.erlang.org</a>. +<p> + +</ul> + +<center> +<small> +Copyright © 1999-2009 +<a href="http://www.ericsson.com">Ericsson AB</a> +</small> +</center> +</div> +</div> +</div> +</body> +</html> diff --git a/system/doc/top/templates/otp_top.css b/system/doc/top/templates/otp_top.css new file mode 100644 index 0000000000..1c6d27bd8d --- /dev/null +++ b/system/doc/top/templates/otp_top.css @@ -0,0 +1,53 @@ + BODY { background: white } + + BODY { font-family: Verdana, Arial, Helvetica, sans-serif } + TH { font-family: Verdana, Arial, Helvetica, sans-serif } + TD { font-family: Verdana, Arial, Helvetica, sans-serif } + P { font-family: Verdana, Arial, Helvetica, sans-serif } + + .header { background: #222; color: #fff } + .top { background: #efe } + .otp { background: #efe } + .erlang { background: #ffe } + .otp2 { background: #efe } + .app { background: #ffe } + + a:link { color: blue; text-decoration: none } + a:active { color: blue; text-decoration: none } + a:visited { color: blue; text-decoration: none } + body { + margin: 0; + padding: 0; + border: 0; + overflow: scroll; + height: 100%; + max-height: 100% + } + #container { + width: 100%; + margin: 10px auto; + background-color: #fff; + } + #leftnav { + float: left; + width: 200px; + margin: 0; + padding: 1em; + } + #content { + margin-left: 220px; /* set left value to WidthOfFrameDiv */ + border-left: 1px solid red; + } + + .innertube { + margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */ + } + + * html body{ /* IE6 hack */ + padding: 0 0 0 200px; /* Set value to (0 0 0 WidthOfFrameDiv)*/ + } + * html #maincontent{ /* IE6 hack*/ + height: 100%; + width: 100%; + } + diff --git a/system/doc/top/templates/system.html.src b/system/doc/top/templates/system.html.src new file mode 100644 index 0000000000..761bc96ed0 --- /dev/null +++ b/system/doc/top/templates/system.html.src @@ -0,0 +1,281 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>Erlang/OTP #release#</title> + <style type="text/css"> +<!-- + BODY { background: white } + + BODY { font-family: Verdana, Arial, Helvetica, sans-serif } + TH { font-family: Verdana, Arial, Helvetica, sans-serif } + TD { font-family: Verdana, Arial, Helvetica, sans-serif } + P { font-family: Verdana, Arial, Helvetica, sans-serif } + + .header { background: #222; color: #fff } + .app { background: #ccc } + + a.anum:link { color: green; text-decoration: none } + a.anum:active { color: green; text-decoration: none } + a.anum:visited { color: green; text-decoration: none } + + a:link { text-decoration: none } + a:active { text-decoration: none } + a:visited { text-decoration: none } +--> + </style> +</head> + +<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> +<center> +<table border=0 width="90%" cellspacing=3 cellpadding=5> + + <tr> + <td colspan=2 class=header> + <font size="+1"><b>General</b></font> + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="system_architecture_intro/part_frame.html" target="_top" + name=system_architecture_intro> + Introduction + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +About Erlang, OTP, Erlang/OTP and this documentation + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="installation_guide/part_frame.html" target="_top" + name=installation_guide> + Installation Guide + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +The Erlang/OTP Installation Guide + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="system_principles/part_frame.html" target="_top" + name=system_principles> + System Principles + </a> + </td> + <td align=right valign=top width=20> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Starting, stopping and configuring the Erlang runtime system + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="embedded/part_frame.html" target="_top" name=embedded> + Embedded System + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Erlang in an Embedded System + </td> + </tr> + + <tr> + <td colspan=2><font size=1> </font></td> + </tr> + +<!-- ====================================================================== --> + + <tr> + <td colspan=2 class=header> + <font size="+1"><b>Programming in Erlang</b></font> + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="reference_manual/part_frame.html" target="_top" name=reference_manual> + Erlang Reference Manual + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Description of data types, language constructs and more + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="getting_started/part_frame.html" target="_top" name=getting_started> + Getting Started + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Getting started with Erlang + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="programming_examples/part_frame.html" target="_top" name=programming_examples> + Programming Examples + </a> + </td> + <td align=right valign=top width=50> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Examples of using records, funs, list comprehensions and the bit syntax + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="efficiency_guide/part_frame.html" target="_top" name=efficiency_guide>Efficiency Guide</a> + </td> + <td align=right valign=top width=20> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Learn how to write efficient programs in Erlang + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="tutorial/part_frame.html" target="_top" name=tutorial>Interoperability Tutorial</a> + </td> + <td align=right valign=top width=20> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +About interoperating with programs written in other programming languages + </td> + </tr> + + <tr> + <td colspan=2><font size=1> </font></td> + </tr> + +<!-- ====================================================================== --> + + <tr> + <td colspan=2 class=header> + <font size="+1"><b>Working with OTP</b></font> + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="design_principles/part_frame.html" target="_top" + name=design_principles> + Design Principles + </a> + </td> + <td align=right valign=top width=20> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +Structure your programs with applications, supervisors and generic behaviors (gen_server, gen_event and gen_fsm). +Also use the built in error logger. + </td> + </tr> + + <tr class=app> + <td align=left valign=top> + <table border=0 width="100%" cellspacing=0 cellpadding=0> + <tr class=app> + <td align=left valign=top> + <a href="oam/part_frame.html" target="_top" name=oam>OAM Principles</a> + </td> + <td align=right valign=top width=20> + </td> + </tr> + </table> + </td> + <td align=left valign=top> +OTP Operation and Management Principles + </td> + </tr> + + <tr> + <td colspan=2><font size=1> </font></td> + </tr> + +</table> + +</center> +</body> +</html> + + diff --git a/system/doc/top/templates/toc_.html.src b/system/doc/top/templates/toc_.html.src new file mode 100644 index 0000000000..5e79bc0ac8 --- /dev/null +++ b/system/doc/top/templates/toc_.html.src @@ -0,0 +1,105 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>Erlang/OTP #release#</title> + <style type="text/css"> +<!-- + BODY { background: white } + + BODY { font-family: Verdana, Arial, Helvetica, sans-serif } + TH { font-family: Verdana, Arial, Helvetica, sans-serif } + TD { font-family: Verdana, Arial, Helvetica, sans-serif } + P { font-family: Verdana, Arial, Helvetica, sans-serif } + + .header { background: #222; color: #fff } + .top { background: #efe } + .otp { background: #efe } + .erlang { background: #ffe } + .otp2 { background: #efe } + .app { background: #ffe } + + a:link { color: blue; text-decoration: none } + a:active { color: blue; text-decoration: none } + a:visited { color: blue; text-decoration: none } +--> + </style> +</head> + +<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" + alink="#ff0000"> +<center> +<font size="+1"><b>Erlang/OTP #release#</b></font><br> +</center> + +<div class=top> +<small><a href="glossary.html" target=body>Glossary</a> | +<a href="man_index.html" target=body>Modules</a> | +<a href="permuted_index/pidxa.html" target=body>Index</a></small> +<p> +<small><a href="highlights.html" target=body>Release highlights</a><br> +<a href="incompatible.html" target=body>Potential incompatibilities</a> +</small> +</div> + +<p> +<div class=otp> +Erlang/OTP +<br> +·<small><a href="installation_guide/part_frame.html" target="_top" + name=installation_guide>Installation Guide</a></small> + +<br> +·<small><a href="system_principles/part_frame.html" target="_top" + name=system_principles>System Principles</a></small> + +<br> +·<small><a href="embedded/part_frame.html" target="_top" name=embedded>Embedded System</a></small> + +</div> + +<p> +<div class=erlang> +Erlang Programming +<br> +·<small><a href="getting_started/part_frame.html" target="_top" name=getting_started>Getting +Started</a></small> + +<br> +·<small><a href="reference_manual/part_frame.html" target="_top" name=reference_manual>Erlang +Reference Manual</a></small> + +<br> +·<small><a href="programming_examples/part_frame.html" target="_top" name=programming_examples>Programming +Examples</a></small> + +<br> +·<small><a href="efficiency_guide/part_frame.html" target="_top" name=efficiency_guide>Efficiency Guide</a></small> + +<br> +·<small><a href="tutorial/part_frame.html" target="_top" name=tutorial>Interoperability Tutorial</a></small> +</div> + +<p> +<div class=otp2> +Working with OTP +<br> +·<small><a href="design_principles/part_frame.html" target="_top" + name=design_principles>Design Principles</a> +</small> + +<br> +·<small><a href="oam/part_frame.html" target="_top" name=oam>OAM Principles</a></small> + +</div> + +<p> +<div class=app> +Applications +<small>#applinks#</small> +</div> + +<p> +<a href="http://www.erlang.se/" target=body>http://www.erlang.se</a> + +</body> +</html> diff --git a/system/doc/tutorial/Makefile b/system/doc/tutorial/Makefile new file mode 100644 index 0000000000..efb380248e --- /dev/null +++ b/system/doc/tutorial/Makefile @@ -0,0 +1,121 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk +#VSN=$(SYSTEM_VSN) + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/tutorial + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(TUTORIAL_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES= port.gif port_driver.gif + + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +C_FILES = \ + cnode_c.c \ + cnode_s.c \ + cnode_s2.c \ + complex.c \ + ei.c \ + erl_comm.c \ + port.c \ + port_driver.c + +ERL_FILES = \ + complex1.erl \ + complex2.erl \ + complex3.erl \ + complex4.erl \ + complex5.erl + +HTMLDIR = ../html/tutorial + +EXTRA_FILES = \ + $(C_FILES) \ + $(ERL_FILES) + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(HTML_UG_FILE) gifs + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + +release_spec: diff --git a/system/doc/tutorial/appendix.xmlsrc b/system/doc/tutorial/appendix.xmlsrc new file mode 100644 index 0000000000..faa6319df2 --- /dev/null +++ b/system/doc/tutorial/appendix.xmlsrc @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appendix - Programs</title> + <prepared>Bengt Nilsson</prepared> + <docno></docno> + <date>2000-09-04</date> + <rev></rev> + <file>appendix.xml</file> + </header> + <p>This appendix contains the programs referred to in the previous + chapters within Interoperability Tutorial.</p> + + <section> + <marker id="complex1"></marker> + <title>complex1.erl</title> + <codeinclude file="complex1.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="complex2"></marker> + <title>complex2.erl</title> + <codeinclude file="complex2.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="complex3"></marker> + <title>complex3.erl</title> + <codeinclude file="complex3.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="complex4"></marker> + <title>complex4.erl</title> + <codeinclude file="complex4.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="complex5"></marker> + <title>complex5.erl</title> + <codeinclude file="complex5.erl" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="port"></marker> + <title>port.c</title> + <codeinclude file="port.c" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="erl_comm"></marker> + <title>erl_comm.c</title> + <codeinclude file="erl_comm.c" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="ei"></marker> + <title>ei.c</title> + <codeinclude file="ei.c" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="cnode_s"></marker> + <title>cnode_s.c</title> + <codeinclude file="cnode_s.c" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="cnode_s2"></marker> + <title>cnode_s2.c</title> + <codeinclude file="cnode_s2.c" tag="" type="none"></codeinclude> + </section> + + <section> + <marker id="cnode_c"></marker> + <title>cnode_c.c</title> + <codeinclude file="cnode_c.c" tag="" type="none"></codeinclude> + </section> +</chapter> + diff --git a/system/doc/tutorial/book.xml b/system/doc/tutorial/book.xml new file mode 100644 index 0000000000..1273bbb865 --- /dev/null +++ b/system/doc/tutorial/book.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Interoperability Tutorial</title> + <prepared>Gunilla Hugosson</prepared> + <docno></docno> + <date>2000-08-21</date> + <rev>C</rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>Interoperability Tutorial</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc new file mode 100644 index 0000000000..7e6034807b --- /dev/null +++ b/system/doc/tutorial/c_port.xmlsrc @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Ports</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>c_port.xml</file> + </header> + <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a port.</p> + <image file="../tutorial/port.gif"> + <icaption>Port Communication.</icaption> + </image> + + <section> + <title>Erlang Program</title> + <p>First of all communication between Erlang and C must be established by creating the port. The Erlang process which creates a port is said to be <em>the connected process</em> of the port. All communication to and from the port should go via the connected process. If the connected process terminates, so will the port (and the external program, if it is written correctly).</p> + <p>The port is created using the BIF <c>open_port/2</c> with <c>{spawn,ExtPrg}</c> as the first argument. The string <c>ExtPrg</c> is the name of the external program, including any command line arguments. The second argument is a list of options, in this case only <c>{packet,2}</c>. This option says that a two byte length indicator will be used to simplify the communication between C and Erlang. Adding the length indicator will be done automatically by the Erlang port, but must be done explicitly in the external C program.</p> + <p>The process is also set to trap exits which makes it possible to detect if the external program fails.</p> + <pre> +-module(complex1). +-export([start/1, init/1]). + +start(ExtPrg) -> + spawn(?MODULE, init, [ExtPrg]). + +init(ExtPrg) -> + register(complex, self()), + process_flag(trap_exit, true), + Port = open_port({spawn, ExtPrg}, [{packet, 2}]), + loop(Port).</pre> + <p>Now it is possible to implement <c>complex1:foo/1</c> and <c>complex1:bar/1</c>. They both send a message to the <c>complex</c> process and receive the reply.</p> + <pre> +foo(X) -> + call_port({foo, X}). +bar(Y) -> + call_port({bar, Y}). + +call_port(Msg) -> + complex ! {call, self(), Msg}, + receive + {complex, Result} -> + Result + end.</pre> + <p>The <c>complex</c> process encodes the message into a sequence of bytes, sends it to the port, waits for a reply, decodes the reply and sends it back to the caller.</p> + <pre> +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, encode(Msg)}}, + receive +\011{Port, {data, Data}} -> + Caller ! {complex, decode(Data)} + end, + loop(Port) + end.</pre> + <p>Assuming that both the arguments and the results from the C functions will be less than 256, a very simple encoding/decoding scheme is employed where <c>foo</c> is represented by the byte 1, <c>bar</c> is represented by 2, and the argument/result is represented by a single byte as well.</p> + <pre> +encode({foo, X}) -> [1, X]; +encode({bar, Y}) -> [2, Y]. + +decode([Int]) -> Int.</pre> + <p>The resulting Erlang program, including functionality for stopping the port and detecting port failures is shown below. + </p> + <codeinclude file="complex1.erl" type="erl"/> + </section> + + <section> + <title>C Program</title> + <p>On the C side, it is necessary to write functions for receiving and sending + data with two byte length indicators from/to Erlang. By default, the C program + should read from standard input (file descriptor 0) and write to standard output + (file descriptor 1). Examples of such functions, <c>read_cmd/1</c> and + <c>write_cmd/2</c>, are shown below.</p> + <codeinclude file="erl_comm.c" type="erl"/> + <p>Note that <c>stdin</c> and <c>stdout</c> are for buffered input/output and should not be used for the communication with Erlang!</p> + <p>In the <c>main</c> function, the C program should listen for a message from Erlang and, according to the selected encoding/decoding scheme, use the first byte to determine which function to call and the second byte as argument to the function. The result of calling the function should then be sent back to Erlang.</p> + <codeinclude file="port.c" tag="" type="none"></codeinclude> + <p>Note that the C program is in a <c>while</c>-loop checking for the return value of <c>read_cmd/1</c>. The reason for this is that the C program must detect when the port gets closed and terminate.</p> + </section> + + <section> + <title>Running the Example</title> + <p>1. Compile the C code.</p> + <pre> +unix> <input>gcc -o extprg complex.c erl_comm.c port.c</input></pre> + <p>2. Start Erlang and compile the Erlang code.</p> + <pre> +unix> <input>erl</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +1> <input>c(complex1).</input> +{ok,complex1}</pre> + <p>3. Run the example.</p> + <pre> +2> <input>complex1:start("extprg").</input> +<0.34.0> +3> <input>complex1:foo(3).</input> +4 +4> <input>complex1:bar(5).</input> +10 +5> <input>complex1:stop().</input> +stop</pre> + </section> +</chapter> + diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc new file mode 100644 index 0000000000..f875fa80d2 --- /dev/null +++ b/system/doc/tutorial/c_portdriver.xmlsrc @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Port drivers</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>c_portdriver.xml</file> + </header> + <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a linked in port driver.</p> + <image file="../tutorial/port_driver.gif"> + <icaption>Port Driver Communication.</icaption> + </image> + + <section> + <title>Port Drivers</title> + <p>A port driver is a linked in driver, that is accessible as a + port from an Erlang program. It is a shared library (SO in Unix, + DLL in Windows), with special entry points. The Erlang runtime + calls these entry points, when the driver is started and when + data is sent to the port. The port driver can also send data to + Erlang.</p> + <p>Since a port driver is dynamically linked into the emulator + process, this is the fastest way of calling C-code from Erlang. + Calling functions in the port driver requires no context + switches. But it is also the least safe, because a crash in the + port driver brings the emulator down too.</p> + </section> + + <section> + <title>Erlang Program</title> + <p>Just as with a port program, the port communicates with a Erlang + process. All communication goes through one Erlang process that + is the <em>connected process</em> of the port + driver. Terminating this process closes the port driver.</p> + <p>Before the port is created, the driver must be loaded. This is + done with the function <c>erl_dll:load_driver/1</c>, with the + name of the shared library as argument.</p> + <p>The port is then created using the BIF <c>open_port/2</c> with + the tuple <c>{spawn, DriverName}</c> as the first argument. The + string <c>SharedLib</c> is the name of the port driver. The second + argument is a list of options, none in this case.</p> + <pre> +-module(complex5). +-export([start/1, init/1]). + +start(SharedLib) -> + case erl_ddll:load_driver(".", SharedLib) of + ok -> ok; +\011{error, already_loaded} -> ok; +\011_ -> exit({error, could_not_load_driver}) + end, + spawn(?MODULE, init, [SharedLib]). + +init(SharedLib) -> + register(complex, self()), + Port = open_port({spawn, SharedLib}, []), + loop(Port).</pre> + <p>Now it is possible to implement <c>complex5:foo/1</c> and + <c>complex5:bar/1</c>. They both send a message to the + <c>complex</c> process and receive the reply.</p> + <pre> +foo(X) -> + call_port({foo, X}). +bar(Y) -> + call_port({bar, Y}). + +call_port(Msg) -> + complex ! {call, self(), Msg}, + receive + {complex, Result} -> + Result + end.</pre> + <p>The <c>complex</c> process encodes the message into a sequence + of bytes, sends it to the port, waits for a reply, decodes the + reply and sends it back to the caller. + </p> + <pre> +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, encode(Msg)}}, + receive +\011 {Port, {data, Data}} -> + Caller ! {complex, decode(Data)} + end, + loop(Port) + end.</pre> + <p>Assuming that both the arguments and the results from the C + functions will be less than 256, a very simple encoding/decoding + scheme is employed where <c>foo</c> is represented by the byte + 1, <c>bar</c> is represented by 2, and the argument/result is + represented by a single byte as well. + </p> + <pre> +encode({foo, X}) -> [1, X]; +encode({bar, Y}) -> [2, Y]. + +decode([Int]) -> Int.</pre> + <p>The resulting Erlang program, including functionality for + stopping the port and detecting port failures is shown below.</p> + <codeinclude file="complex5.erl" type="erl"/> + </section> + + <section> + <title>C Driver</title> + <p>The C driver is a module that is compiled and linked into a + shared library. It uses a driver structure, and includes the + header file <c>erl_driver.h</c>.</p> + <p>The driver structure is filled with the driver name and function + pointers. It is returned from the special entry point, declared + with the macro <c><![CDATA[DRIVER_INIT(<driver_name>)]]></c>.</p> + <p>The functions for receiving and sending data, are combined into + a function, pointed out by the driver structure. The data sent + into the port is given as arguments, and the data the port + sends back is sent with the C-function <c>driver_output</c>.</p> + <p>Since the driver is a shared module, not a program, no main + function should be present. All function pointers are not used + in our example, and the corresponding fields in the + <c>driver_entry</c> structure are set to NULL.</p> + <p>All functions in the driver, takes a handle (returned from + <c>start</c>), that is just passed along by the erlang + process. This must in some way refer to the port driver + instance.</p> + <p>The example_drv_start, is the only function that is called with + a handle to the port instance, so we must save this. It is + customary to use a allocated driver-defined structure for this + one, and pass a pointer back as a reference.</p> + <p>It is not a good idea to use a global variable; since the port + driver can be spawned by multiple Erlang processes, this + driver-structure should be instantiated multiple times. + </p> + <codeinclude file="port_driver.c" tag="" type="none"></codeinclude> + </section> + + <section> + <title>Running the Example</title> + <p>1. Compile the C code.</p> + <pre> +unix> <input>gcc -o exampledrv -fpic -shared complex.c port_driver.c</input> +windows> <input>cl -LD -MD -Fe exampledrv.dll complex.c port_driver.c</input></pre> + <p>2. Start Erlang and compile the Erlang code.</p> + <pre> +> <input>erl</input> +Erlang (BEAM) emulator version 5.1 + +Eshell V5.1 (abort with ^G) +1> <input>c(complex5).</input> +{ok,complex5}</pre> + <p>3. Run the example.</p> + <pre> +2> <input>complex5:start("example_drv").</input> +<0.34.0> +3> <input>complex5:foo(3).</input> +4 +4> <input>complex5:bar(5).</input> +10 +5> <input>complex5:stop().</input> +stop</pre> + </section> +</chapter> + diff --git a/system/doc/tutorial/cnode.xmlsrc b/system/doc/tutorial/cnode.xmlsrc new file mode 100644 index 0000000000..a5443104de --- /dev/null +++ b/system/doc/tutorial/cnode.xmlsrc @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>C Nodes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>cnode.xml</file> + </header> + <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a C node. Note that a C node would not typically be used for solving a simple problem like this, a port would suffice.</p> + + <section> + <title>Erlang Program</title> + <p>From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions <c>foo</c> and <c>bar</c> only involves sending a message to the C node asking for the function to be called, and receiving the result. Sending a message requires a recipient; a process which can be defined using either a pid or a tuple consisting of a registered name and a node name. In this case a tuple is the only alternative as no pid is known.</p> + <pre> +{RegName, Node} ! Msg</pre> + <p>The node name <c>Node</c> should be the name of the C node. If short node names are used, the plain name of the node will be <c>cN</c> where <c>N</c> is an integer. If long node names are used, there is no such restriction. An example of a C node name using short node names is thus <c>c1@idril</c>, an example using long node names is <c>[email protected]</c>.</p> + <p>The registered name <c>RegName</c> could be any atom. The name can be ignored by the C code, or it could be used for example to distinguish between different types of messages. Below is an example of what the Erlang code could look like when using short node names. + </p> + <codeinclude file="complex3.erl" tag="" type="erl"></codeinclude> + <p> + When using long node names the code is slightly different as shown in the following example: + </p> + <codeinclude file="complex4.erl" tag="" type="erl"></codeinclude> + + </section> + + <section> + <title>C Program</title> + + <section> + <title>Setting Up the Communication</title> + <p>Before calling any other Erl_Interface function, the memory handling must be initiated.</p> + <pre> +erl_init(NULL, 0);</pre> + <p>Now the C node can be initiated. If short node names are used, this is done by calling <c>erl_connect_init()</c>.</p> + <pre> +erl_connect_init(1, "secretcookie", 0);</pre> + <p>The first argument is the integer which is used to construct the node name. In the example the plain node name will be <c>c1</c>. <br></br> + + The second argument is a string defining the magic cookie. <br></br> + + The third argument is an integer which is used to identify a particular instance of a C node.</p> + <p>If long node node names are used, initiation is done by calling <c>erl_connect_xinit()</c>.</p> + <pre> +erl_connect_xinit("idril", "cnode", "[email protected]", + &addr, "secretcookie", 0);</pre> + <p>The first three arguments are the host name, the plain node name, and the full node name. The fourth argument is a pointer to an <c>in_addr</c> struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.</p> + <p>The C node can act as a server or a client when setting up the communication Erlang-C. If it acts as a client, it connects to an Erlang node by calling <c>erl_connect()</c>, which will return an open file descriptor at success.</p> + <pre> +fd = erl_connect("e1@idril");</pre> + <p>If the C node acts as a server, it must first create a socket (call <c>bind()</c> and <c>listen()</c>) listening to a certain port number <c>port</c>. It then publishes its name and port number with <c>epmd</c> (the Erlang port mapper daemon, see the man page for <c>epmd</c>).</p> + <pre> +erl_publish(port);</pre> + <p>Now the C node server can accept connections from Erlang nodes.</p> + <pre> +fd = erl_accept(listen, &conn);</pre> + <p>The second argument to <c>erl_accept</c> is a struct <c>ErlConnect</c> that will contain useful information when a connection has been established; for example, the name of the Erlang node.</p> + </section> + + <section> + <title>Sending and Receiving Messages</title> + <p>The C node can receive a message from Erlang by calling <c>erl_receive msg()</c>. This function reads data from the open file descriptor <c>fd</c> into a buffer and puts the result in an <c>ErlMessage</c> struct <c>emsg</c>. <c>ErlMessage</c> has a field <c>type</c> defining which kind of data was received. In this case the type of interest is <c>ERL_REG_SEND</c> which indicates that Erlang sent a message to a registered process at the C node. The actual message, an <c>ETERM</c>, will be in the <c>msg</c> field.</p> + <p>It is also necessary to take care of the types <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c> (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.</p> + <pre> + while (loop) { + + got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); + if (got == ERL_TICK) { + /* ignore */ + } else if (got == ERL_ERROR) { + loop = 0; /* exit while loop */ + } else { + if (emsg.type == ERL_REG_SEND) {</pre> + <p>Since the message is an <c>ETERM</c> struct, Erl_Interface functions can be used to manipulate it. In this case, the message will be a 3-tuple (because that was how the Erlang code was written, see above). The second element will be the pid of the caller and the third element will be the tuple <c>{Function,Arg}</c> determining which function to call with which argument. The result of calling the function is made into an <c>ETERM</c> struct as well and sent back to Erlang using <c>erl_send()</c>, which takes the open file descriptor, a pid and a term as arguments.</p> + <pre> + fromp = erl_element(2, emsg.msg); + tuplep = erl_element(3, emsg.msg); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + resp = erl_format("{cnode, ~i}", res); + erl_send(fd, fromp, resp);</pre> + <p>Finally, the memory allocated by the <c>ETERM</c> creating functions (including <c>erl_receive_msg()</c> must be freed.</p> + <pre> + erl_free_term(emsg.from); erl_free_term(emsg.msg); + erl_free_term(fromp); erl_free_term(tuplep); + erl_free_term(fnp); erl_free_term(argp); + erl_free_term(resp);</pre> + <p>The resulting C programs can be found in looks like the following examples. First a C node server using short node names.</p> + <codeinclude file="cnode_s.c" type="c"/> + <p>Below follows a C node server using long node names.</p> + <codeinclude file="cnode_s2.c" type="c"/> + <p>And finally we have the code for the C node client.</p> + <codeinclude file="cnode_c.c" type="c"/> + </section> + </section> + + <section> + <title>Running the Example</title> + <p>1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the <c>socket</c> and <c>nsl</c> libraries.</p> + <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br> + + In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p> + <pre> + +> <input>gcc -o cserver \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_s.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input> + +unix> <input>gcc -o cserver2 \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_s2.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input> + +unix> <input>gcc -o cclient \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_c.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input></pre> + <p>2. Compile the Erlang code.</p> + <pre> +unix> <input>erl -compile complex3 complex4</input></pre> + <p>3. Run the C node server example with short node names.</p> + <p>Start the C program <c>cserver</c> and Erlang in different windows. <c>cserver</c> takes a port number as argument and must be started before trying to call the Erlang functions. The Erlang node should be given the short name <c>e1</c> and must be set to use the same magic cookie as the C node, <c>secretcookie</c>.</p> + <pre> +unix> <input>cserver 3456</input> + +unix> <input>erl -sname e1 -setcookie secretcookie</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +(e1@idril)1> <input>complex3:foo(3).</input> +4 +(e1@idril)2> <input>complex3:bar(5).</input> +10</pre> + <p>4. Run the C node client example. Terminate <c>cserver</c> but not Erlang and start <c>cclient</c>. The Erlang node must be started before the C node client is.</p> + <pre> +unix> <input>cclient</input> + +(e1@idril)3> <input>complex3:foo(3).</input> +4 +(e1@idril)4> <input>complex3:bar(5).</input> +10</pre> + <p>5. Run the C node server, long node names, example.</p> + <pre> +unix> <input>cserver2 3456</input> + +unix> <input>erl -name e1 -setcookie secretcookie</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +([email protected])1> <input>complex4:foo(3).</input> +4 +([email protected])2> <input>complex4:bar(5).</input> +10</pre> + </section> +</chapter> + diff --git a/system/doc/tutorial/cnode_c.c b/system/doc/tutorial/cnode_c.c new file mode 100644 index 0000000000..8ddb6ffece --- /dev/null +++ b/system/doc/tutorial/cnode_c.c @@ -0,0 +1,64 @@ +/* cnode_c.c */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "erl_interface.h" +#include "ei.h" + +#define BUFSIZE 1000 + +int main(int argc, char **argv) { + int fd; /* fd to Erlang node */ + + int loop = 1; /* Loop flag */ + int got; /* Result of receive */ + unsigned char buf[BUFSIZE]; /* Buffer for incoming message */ + ErlMessage emsg; /* Incoming message */ + + ETERM *fromp, *tuplep, *fnp, *argp, *resp; + int res; + + erl_init(NULL, 0); + + if (erl_connect_init(1, "secretcookie", 0) == -1) + erl_err_quit("erl_connect_init"); + + if ((fd = erl_connect("e1@idril")) < 0) + erl_err_quit("erl_connect"); + fprintf(stderr, "Connected to ei@idril\n\r"); + + while (loop) { + + got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); + if (got == ERL_TICK) { + /* ignore */ + } else if (got == ERL_ERROR) { + loop = 0; + } else { + + if (emsg.type == ERL_REG_SEND) { + fromp = erl_element(2, emsg.msg); + tuplep = erl_element(3, emsg.msg); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + resp = erl_format("{cnode, ~i}", res); + erl_send(fd, fromp, resp); + + erl_free_term(emsg.from); erl_free_term(emsg.msg); + erl_free_term(fromp); erl_free_term(tuplep); + erl_free_term(fnp); erl_free_term(argp); + erl_free_term(resp); + } + } + } +} diff --git a/system/doc/tutorial/cnode_s.c b/system/doc/tutorial/cnode_s.c new file mode 100644 index 0000000000..f79d096ced --- /dev/null +++ b/system/doc/tutorial/cnode_s.c @@ -0,0 +1,99 @@ +/* cnode_s.c */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "erl_interface.h" +#include "ei.h" + +#define BUFSIZE 1000 + +int main(int argc, char **argv) { + int port; /* Listen port number */ + int listen; /* Listen socket */ + int fd; /* fd to Erlang node */ + ErlConnect conn; /* Connection data */ + + int loop = 1; /* Loop flag */ + int got; /* Result of receive */ + unsigned char buf[BUFSIZE]; /* Buffer for incoming message */ + ErlMessage emsg; /* Incoming message */ + + ETERM *fromp, *tuplep, *fnp, *argp, *resp; + int res; + + port = atoi(argv[1]); + + erl_init(NULL, 0); + + if (erl_connect_init(1, "secretcookie", 0) == -1) + erl_err_quit("erl_connect_init"); + + /* Make a listen socket */ + if ((listen = my_listen(port)) <= 0) + erl_err_quit("my_listen"); + + if (erl_publish(port) == -1) + erl_err_quit("erl_publish"); + + if ((fd = erl_accept(listen, &conn)) == ERL_ERROR) + erl_err_quit("erl_accept"); + fprintf(stderr, "Connected to %s\n\r", conn.nodename); + + while (loop) { + + got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); + if (got == ERL_TICK) { + /* ignore */ + } else if (got == ERL_ERROR) { + loop = 0; + } else { + + if (emsg.type == ERL_REG_SEND) { + fromp = erl_element(2, emsg.msg); + tuplep = erl_element(3, emsg.msg); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + resp = erl_format("{cnode, ~i}", res); + erl_send(fd, fromp, resp); + + erl_free_term(emsg.from); erl_free_term(emsg.msg); + erl_free_term(fromp); erl_free_term(tuplep); + erl_free_term(fnp); erl_free_term(argp); + erl_free_term(resp); + } + } + } /* while */ +} + + +int my_listen(int port) { + int listen_fd; + struct sockaddr_in addr; + int on = 1; + + if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return (-1); + + setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + memset((void*) &addr, 0, (size_t) sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + return (-1); + + listen(listen_fd, 5); + return listen_fd; +} diff --git a/system/doc/tutorial/cnode_s2.c b/system/doc/tutorial/cnode_s2.c new file mode 100644 index 0000000000..46c248cc04 --- /dev/null +++ b/system/doc/tutorial/cnode_s2.c @@ -0,0 +1,102 @@ +/* cnode_s2.c */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "erl_interface.h" +#include "ei.h" + +#define BUFSIZE 1000 + +int main(int argc, char **argv) { + struct in_addr addr; /* 32-bit IP number of host */ + int port; /* Listen port number */ + int listen; /* Listen socket */ + int fd; /* fd to Erlang node */ + ErlConnect conn; /* Connection data */ + + int loop = 1; /* Loop flag */ + int got; /* Result of receive */ + unsigned char buf[BUFSIZE]; /* Buffer for incoming message */ + ErlMessage emsg; /* Incoming message */ + + ETERM *fromp, *tuplep, *fnp, *argp, *resp; + int res; + + port = atoi(argv[1]); + + erl_init(NULL, 0); + + addr.s_addr = inet_addr("134.138.177.89"); + if (erl_connect_xinit("idril", "cnode", "[email protected]", + &addr, "secretcookie", 0) == -1) + erl_err_quit("erl_connect_xinit"); + + /* Make a listen socket */ + if ((listen = my_listen(port)) <= 0) + erl_err_quit("my_listen"); + + if (erl_publish(port) == -1) + erl_err_quit("erl_publish"); + + if ((fd = erl_accept(listen, &conn)) == ERL_ERROR) + erl_err_quit("erl_accept"); + fprintf(stderr, "Connected to %s\n\r", conn.nodename); + + while (loop) { + + got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); + if (got == ERL_TICK) { + /* ignore */ + } else if (got == ERL_ERROR) { + loop = 0; + } else { + + if (emsg.type == ERL_REG_SEND) { + fromp = erl_element(2, emsg.msg); + tuplep = erl_element(3, emsg.msg); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + resp = erl_format("{cnode, ~i}", res); + erl_send(fd, fromp, resp); + + erl_free_term(emsg.from); erl_free_term(emsg.msg); + erl_free_term(fromp); erl_free_term(tuplep); + erl_free_term(fnp); erl_free_term(argp); + erl_free_term(resp); + } + } + } +} + + +int my_listen(int port) { + int listen_fd; + struct sockaddr_in addr; + int on = 1; + + if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return (-1); + + setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + memset((void*) &addr, 0, (size_t) sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + return (-1); + + listen(listen_fd, 5); + return listen_fd; +} diff --git a/system/doc/tutorial/complex.c b/system/doc/tutorial/complex.c new file mode 100644 index 0000000000..206d8abf4e --- /dev/null +++ b/system/doc/tutorial/complex.c @@ -0,0 +1,9 @@ +/* complex.c */ + +int foo(int x) { + return x+1; +} + +int bar(int y) { + return y*2; +} diff --git a/system/doc/tutorial/complex1.erl b/system/doc/tutorial/complex1.erl new file mode 100644 index 0000000000..7bad93f7d3 --- /dev/null +++ b/system/doc/tutorial/complex1.erl @@ -0,0 +1,50 @@ +-module(complex1). +-export([start/1, stop/0, init/1]). +-export([foo/1, bar/1]). + +start(ExtPrg) -> + spawn(?MODULE, init, [ExtPrg]). +stop() -> + complex ! stop. + +foo(X) -> + call_port({foo, X}). +bar(Y) -> + call_port({bar, Y}). + +call_port(Msg) -> + complex ! {call, self(), Msg}, + receive + {complex, Result} -> + Result + end. + +init(ExtPrg) -> + register(complex, self()), + process_flag(trap_exit, true), + Port = open_port({spawn, ExtPrg}, [{packet, 2}]), + loop(Port). + +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, encode(Msg)}}, + receive + {Port, {data, Data}} -> + Caller ! {complex, decode(Data)} + end, + loop(Port); + stop -> + Port ! {self(), close}, + receive + {Port, closed} -> + exit(normal) + end; + {'EXIT', Port, Reason} -> + exit(port_terminated) + end. + +encode({foo, X}) -> [1, X]; +encode({bar, Y}) -> [2, Y]. + +decode([Int]) -> Int. diff --git a/system/doc/tutorial/complex2.erl b/system/doc/tutorial/complex2.erl new file mode 100644 index 0000000000..93d00dab6b --- /dev/null +++ b/system/doc/tutorial/complex2.erl @@ -0,0 +1,45 @@ +-module(complex2). +-export([start/1, stop/0, init/1]). +-export([foo/1, bar/1]). + +start(ExtPrg) -> + spawn(?MODULE, init, [ExtPrg]). +stop() -> + complex ! stop. + +foo(X) -> + call_port({foo, X}). +bar(Y) -> + call_port({bar, Y}). + +call_port(Msg) -> + complex ! {call, self(), Msg}, + receive + {complex, Result} -> + Result + end. + +init(ExtPrg) -> + register(complex, self()), + process_flag(trap_exit, true), + Port = open_port({spawn, ExtPrg}, [{packet, 2}, binary]), + loop(Port). + +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, term_to_binary(Msg)}}, + receive + {Port, {data, Data}} -> + Caller ! {complex, binary_to_term(Data)} + end, + loop(Port); + stop -> + Port ! {self(), close}, + receive + {Port, closed} -> + exit(normal) + end; + {'EXIT', Port, Reason} -> + exit(port_terminated) + end. diff --git a/system/doc/tutorial/complex3.erl b/system/doc/tutorial/complex3.erl new file mode 100644 index 0000000000..f2e9c2c171 --- /dev/null +++ b/system/doc/tutorial/complex3.erl @@ -0,0 +1,14 @@ +-module(complex3). +-export([foo/1, bar/1]). + +foo(X) -> + call_cnode({foo, X}). +bar(Y) -> + call_cnode({bar, Y}). + +call_cnode(Msg) -> + {any, c1@idril} ! {call, self(), Msg}, + receive + {cnode, Result} -> + Result + end. diff --git a/system/doc/tutorial/complex4.erl b/system/doc/tutorial/complex4.erl new file mode 100644 index 0000000000..c1df273b60 --- /dev/null +++ b/system/doc/tutorial/complex4.erl @@ -0,0 +1,14 @@ +-module(complex4). +-export([foo/1, bar/1]). + +foo(X) -> + call_cnode({foo, X}). +bar(Y) -> + call_cnode({bar, Y}). + +call_cnode(Msg) -> + {any, '[email protected]'} ! {call, self(), Msg}, + receive + {cnode, Result} -> + Result + end. diff --git a/system/doc/tutorial/complex5.erl b/system/doc/tutorial/complex5.erl new file mode 100644 index 0000000000..473056dd11 --- /dev/null +++ b/system/doc/tutorial/complex5.erl @@ -0,0 +1,56 @@ +-module(complex5). +-export([start/1, stop/0, init/1]). +-export([foo/1, bar/1]). + +start(SharedLib) -> + case erl_ddll:load_driver(".", SharedLib) of + ok -> ok; + {error, already_loaded} -> ok; + _ -> exit({error, could_not_load_driver}) + end, + spawn(?MODULE, init, [SharedLib]). + +init(SharedLib) -> + register(complex, self()), + Port = open_port({spawn, SharedLib}, []), + loop(Port). + +stop() -> + complex ! stop. + +foo(X) -> + call_port({foo, X}). +bar(Y) -> + call_port({bar, Y}). + +call_port(Msg) -> + complex ! {call, self(), Msg}, + receive + {complex, Result} -> + Result + end. + +loop(Port) -> + receive + {call, Caller, Msg} -> + Port ! {self(), {command, encode(Msg)}}, + receive + {Port, {data, Data}} -> + Caller ! {complex, decode(Data)} + end, + loop(Port); + stop -> + Port ! {self(), close}, + receive + {Port, closed} -> + exit(normal) + end; + {'EXIT', Port, Reason} -> + io:format("~p ~n", [Reason]), + exit(port_terminated) + end. + +encode({foo, X}) -> [1, X]; +encode({bar, Y}) -> [2, Y]. + +decode([Int]) -> Int. diff --git a/system/doc/tutorial/distribution.xml b/system/doc/tutorial/distribution.xml new file mode 100644 index 0000000000..54d352dd5a --- /dev/null +++ b/system/doc/tutorial/distribution.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Distributed Erlang</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>distribution.xml</file> + </header> + + <section> + <title>What is distributed Erlang?</title> + </section> + + <section> + <title>Example</title> + </section> + + <section> + <title>When to use distributed Erlang</title> + <p></p> + </section> + + <section> + <title>Where to read more</title> + <p><em>Erlang book:</em></p> + <list type="bulleted"> + <item>Chapter 6 Distributed Programming - Describes how to write distributed Erlang applications which run on a network of Erlang nodes.</item> + <item>Chapter 11 Distributed Programming Techniques.</item> + <item>Chapter 12 Distributed Data.</item> + </list> + <p><em>Man pages:</em></p> + <list type="bulleted"> + <item>auth - The Erlang authentication server. Note: The actual authentication has been moved from this process to the handshaking procedure. The man page gives a good description of the principles behind the cookie authentication mechanism however.</item> + <item>erlang - Description of the BIFs.</item> + <item>global - A global name registration facility.</item> + <item>global_group - Grouping nodes to global name registration groups.</item> + <item>net_adm - Various net administration routines.</item> + <item>net_kernel - Networking kernel.</item> + <item>pg - Distributed named process groups, experimental implementation.</item> + <item>pg2 - Distributed named process groups.</item> + <item>pool - Load distribution facility.</item> + <item>slave - Functions for starting and controlling slave nodes.</item> + </list> + <p><em>Other:</em></p> + </section> +</chapter> + diff --git a/system/doc/tutorial/ei.c b/system/doc/tutorial/ei.c new file mode 100644 index 0000000000..b234a00768 --- /dev/null +++ b/system/doc/tutorial/ei.c @@ -0,0 +1,38 @@ +/* ei.c */ + +#include "erl_interface.h" +#include "ei.h" + +typedef unsigned char byte; + +int main() { + ETERM *tuplep, *intp; + ETERM *fnp, *argp; + int res; + byte buf[100]; + long allocated, freed; + + erl_init(NULL, 0); + + while (read_cmd(buf) > 0) { + tuplep = erl_decode(buf); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 17) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + intp = erl_mk_int(res); + erl_encode(intp, buf); + write_cmd(buf, erl_term_len(intp)); + + erl_free_compound(tuplep); + erl_free_term(fnp); + erl_free_term(argp); + erl_free_term(intp); + } +} + diff --git a/system/doc/tutorial/erl_comm.c b/system/doc/tutorial/erl_comm.c new file mode 100644 index 0000000000..303c6dc170 --- /dev/null +++ b/system/doc/tutorial/erl_comm.c @@ -0,0 +1,52 @@ +/* erl_comm.c */ + +typedef unsigned char byte; + +read_cmd(byte *buf) +{ + int len; + + if (read_exact(buf, 2) != 2) + return(-1); + len = (buf[0] << 8) | buf[1]; + return read_exact(buf, len); +} + +write_cmd(byte *buf, int len) +{ + byte li; + + li = (len >> 8) & 0xff; + write_exact(&li, 1); + + li = len & 0xff; + write_exact(&li, 1); + + return write_exact(buf, len); +} + +read_exact(byte *buf, int len) +{ + int i, got=0; + + do { + if ((i = read(0, buf+got, len-got)) <= 0) + return(i); + got += i; + } while (got<len); + + return(len); +} + +write_exact(byte *buf, int len) +{ + int i, wrote = 0; + + do { + if ((i = write(1, buf+wrote, len-wrote)) <= 0) + return (i); + wrote += i; + } while (wrote<len); + + return (len); +} diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc new file mode 100644 index 0000000000..752eec1d3e --- /dev/null +++ b/system/doc/tutorial/erl_interface.xmlsrc @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>erl_interface.xml</file> + </header> + <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a port and <c>erl_interface</c>. It is necessary to read the <seealso marker="c_port">port example</seealso> before reading this chapter.</p> + + <section> + <title>Erlang Program</title> + <p>The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.</p> + <codeinclude file="complex1.erl" type="erl"/> + <p>Compared to the Erlang module + above used for the plain port, there are two differences when using Erl_Interface on the C side: Since Erl_Interface operates on the Erlang external term format the port must be set to use binaries and, instead of inventing an encoding/decoding scheme, the BIFs <c>term_to_binary/1</c> and <c>binary_to_term/1</c> should be used. That is:</p> + <pre> +open_port({spawn, ExtPrg}, [{packet, 2}])</pre> + <p>is replaced with:</p> + <pre> +open_port({spawn, ExtPrg}, [{packet, 2}, binary])</pre> + <p>And:</p> + <pre> +Port ! {self(), {command, encode(Msg)}}, +receive + {Port, {data, Data}} -> + Caller ! {complex, decode(Data)} +end</pre> + <p>is replaced with:</p> + <pre> +Port ! {self(), {command, term_to_binary(Msg)}}, +receive + {Port, {data, Data}} -> + Caller ! {complex, binary_to_term(Data)} +end</pre> + <p>The resulting Erlang program is shown below.</p> + <codeinclude file="complex2.erl" type="erl"/> + <p>Note that calling <c>complex2:foo/1</c> and <c>complex2:bar/1</c> will result in the tuple <c>{foo,X}</c> or <c>{bar,Y}</c> being sent to the <c>complex</c> process, which will code them as binaries and send them to the port. This means that the C program must be able to handle these two tuples.</p> + </section> + + <section> + <title>C Program</title> + <p>The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.</p> + <codeinclude file="port.c" type="c"/> + <p>Compared to the C program above + used for the plain port the <c>while</c>-loop must be rewritten. Messages coming from the port will be on the Erlang external term format. They should be converted into an <c>ETERM</c> struct, a C struct similar to an Erlang term. The result of calling <c>foo()</c> or <c>bar()</c> must be converted to the Erlang external term format before being sent back to the port. But before calling any other <c>erl_interface</c> function, the memory handling must be initiated.</p> + <pre> +erl_init(NULL, 0);</pre> + <p>For reading from and writing to the port the functions <c>read_cmd()</c> and <c>write_cmd()</c> from the erl_comm.c example below + can still be used. + </p> + <codeinclude file="erl_comm.c" type="c"/> + <p>The function <c>erl_decode()</c> from <c>erl_marshal</c> will convert the binary into an <c>ETERM</c> struct.</p> + <pre> +int main() { + ETERM *tuplep; + + while (read_cmd(buf) > 0) { + tuplep = erl_decode(buf);</pre> + <p>In this case <c>tuplep</c> now points to an <c>ETERM</c> struct representing a tuple with two elements; the function name (atom) and the argument (integer). By using the function <c>erl_element()</c> from <c>erl_eterm</c> it is possible to extract these elements, which also must be declared as pointers to an <c>ETERM</c> struct.</p> + <pre> + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep);</pre> + <p>The macros <c>ERL_ATOM_PTR</c> and <c>ERL_INT_VALUE</c> from <c>erl_eterm</c> can be used to obtain the actual values of the atom and the integer. The atom value is represented as a string. By comparing this value with the strings "foo" and "bar" it can be decided which function to call.</p> + <pre> + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + }</pre> + <p>Now an <c>ETERM</c> struct representing the integer result can be constructed using the function <c>erl_mk_int()</c> from <c>erl_eterm</c>. It is also possible to use the function <c>erl_format()</c> from the module <c>erl_format</c>.</p> + <pre> + intp = erl_mk_int(res);</pre> + <p>The resulting <c>ETERM</c> struct is converted into the Erlang external term format using the function <c>erl_encode()</c> from <c>erl_marshal</c> and sent to Erlang using <c>write_cmd()</c>.</p> + <pre> + erl_encode(intp, buf); + write_cmd(buf, erl_eterm_len(intp));</pre> + <p>Last, the memory allocated by the <c>ETERM</c> creating functions must be freed.</p> + <pre> + erl_free_compound(tuplep); + erl_free_term(fnp); + erl_free_term(argp); + erl_free_term(intp);</pre> + <p>The resulting C program is shown below:</p> + <codeinclude file="ei.c" type="c"/> + </section> + + <section> + <title>Running the Example</title> + <p>1. Compile the C code, providing the paths to the include files <c>erl_interface.h</c> and <c>ei.h</c>, and to the libraries <c>erl_interface</c> and <c>ei</c>.</p> + <pre> +unix> <input>gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input> -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input> complex.c erl_comm.c ei.c -lerl_interface -lei</input></pre> + <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br> + + In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p> + <p>2. Start Erlang and compile the Erlang code.</p> + <pre> +unix> <input>erl</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +1> <input>c(complex2).</input> +{ok,complex2}</pre> + <p>3. Run the example.</p> + <pre> +2> <input>complex2:start("extprg").</input> +<0.34.0> +3> <input>complex2:foo(3).</input> +4 +4> <input>complex2:bar(5).</input> +10 +5> <input>complex2:bar(352).</input> +704 +6> <input>complex2:stop().</input> +stop</pre> + </section> +</chapter> + diff --git a/system/doc/tutorial/example.xmlsrc b/system/doc/tutorial/example.xmlsrc new file mode 100644 index 0000000000..7ee2ef6ff3 --- /dev/null +++ b/system/doc/tutorial/example.xmlsrc @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Problem Example</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>example.xml</file> + </header> + + <section> + <title>Description</title> + <p>A common interoperability situation is when there exists a piece of code solving some complex problem, and we would like to incorporate this piece of code in our Erlang program. Suppose for example we have the following C functions that we would like to be able to call from Erlang.</p> + <codeinclude file="complex.c" tag="" type="none"></codeinclude> + <p>(For the sake of keeping the example as simple as possible, the functions are not very complicated in this case).</p> + <p>Preferably we would like to able to call <c>foo</c> and <c>bar</c> without having to bother about them actually being C functions.</p> + <pre> +% Erlang code +... +Res = complex:foo(X), +...</pre> + <p>The communication with C is hidden in the implementation of <c>complex.erl</c>. In the following chapters it is shown how this module can be implemented using the different interoperability mechanisms.</p> + </section> +</chapter> + diff --git a/system/doc/tutorial/introduction.xml b/system/doc/tutorial/introduction.xml new file mode 100644 index 0000000000..0a761f77fb --- /dev/null +++ b/system/doc/tutorial/introduction.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared>Gunilla Hugosson</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>introduction.xml</file> + </header> + + <section> + <title>Purpose</title> + <p>The purpose of this tutorial is to give the reader an orientation of the different interoperability mechanisms that can be used when integrating a program written in Erlang with a program written in another programming language, from the Erlang programmer's point of view.</p> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is a skilled Erlang programmer, familiar with concepts such as Erlang data types, processes, messages and error handling.</p> + <p>To illustrate the interoperability principles C programs running in a UNIX environment have been used. It is assumed that the reader has enough knowledge to be able to apply these principles to the relevant programming languages and platforms.</p> + <note> + <p>For the sake of readability, the example code has been kept as simple as possible. It does not include functionality such as error handling, which might be vital in a real-life system.</p> + </note> + </section> +</chapter> + diff --git a/system/doc/tutorial/make.dep b/system/doc/tutorial/make.dep new file mode 100644 index 0000000000..e9f77ab439 --- /dev/null +++ b/system/doc/tutorial/make.dep @@ -0,0 +1,35 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex c_port.tex c_portdriver.tex cnode.tex \ + erl_interface.tex example.tex introduction.tex \ + overview.tex part.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +c_port.tex: port.c + +c_portdriver.tex: port_driver.c + +cnode.tex: complex3.erl + +example.tex: complex.c + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: port.ps + +book.dvi: port_driver.ps + diff --git a/system/doc/tutorial/overview.xml b/system/doc/tutorial/overview.xml new file mode 100644 index 0000000000..b8a9b88a86 --- /dev/null +++ b/system/doc/tutorial/overview.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Overview</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>overview.xml</file> + </header> + + <section> + <title>Built-In Mechanisms</title> + <p>There are two interoperability mechanisms built into the Erlang runtime system. One is <em>distributed Erlang</em> and the other one is <em>ports</em>. A variation of ports is <em>linked-in drivers</em>.</p> + <marker id="dist"></marker> + + <section> + <title>Distributed Erlang</title> + <p>An Erlang runtime system is made into a distributed Erlang node by giving it a name. A distributed Erlang node can connect to and monitor other nodes, it is also possible to spawn processes at other nodes. Message passing and error handling between processes at different nodes are transparent. There exists a number of useful <c>stdlib</c> modules intended for use in a distributed Erlang system; for example, <c>global</c> which provides global name registration. The distribution mechanism is implemented using TCP/IP sockets.</p> + <p><em>When to use:</em> Distributed Erlang is primarily used for communication Erlang-Erlang. It can also be used for communication between Erlang and C, if the C program is implemented as a <seealso marker="#cnode">C node</seealso>, see below.</p> + <p><em>Where to read more:</em> Distributed Erlang and some distributed programming techniques are described in the Erlang book. <br></br> + + In the Erlang/OTP documentation there is a chapter about distributed Erlang in "Getting Started" (User's Guide). <br></br> + + Relevant man pages are <c>erlang</c> (describes the BIFs) and <c>global</c>, <c>net_adm</c>, <c>pg2</c>, <c>rpc</c>, <c>pool</c> and <c>slave</c>.</p> + </section> + + <section> + <title>Ports and Linked-In Drivers</title> + <p>Ports provide the basic mechanism for communication with the external world, from Erlang's point of view. They provide a byte-oriented interface to an external program. When a port has been created, Erlang can communicate with it by sending and receiving lists of bytes (not Erlang terms). This means that the programmer may have to invent a suitable encoding and decoding scheme.</p> + <p>The actual implementation of the port mechanism depends on the platform. In the Unix case, pipes are used and the external program should as default read from standard input and write to standard output. Theoretically, the external program could be written in any programming language as long as it can handle the interprocess communication mechanism with which the port is implemented.</p> + <p>The external program resides in another OS process than the Erlang runtime system. In some cases this is not acceptable, consider for example drivers with very hard time requirements. It is therefore possible to write a program in C according to certain principles and dynamically link it to the Erlang runtime system, this is called a linked-in driver.</p> + <p><em>When to use:</em> Being the basic mechanism, ports can be used for all kinds of interoperability situations where the Erlang program and the other program runs on the same machine. Programming is fairly straight-forward. <br></br> + + Linked-in drivers involves writing certain call-back functions in C. Very good skills are required as the code is linked to the Erlang runtime system.</p> + <warning> + <p>An erroneous linked-in driver will cause the entire Erlang runtime system to leak memory, hang or crash.</p> + </warning> + <p><em>Where to read more:</em> Ports are described in the "Miscellaneous Items" chapter of the Erlang book. Linked-in drivers are described in Appendix E. <br></br> + + The BIF <c>open_port/2</c> is documented in the man page for <c>erlang</c>. For linked-in drivers, the programmer needs to read the information in the man page for <c>erl_ddll</c>.</p> + <p><em>Examples:</em><seealso marker="c_port">Port example</seealso>.</p> + </section> + </section> + + <section> + <title>C and Java Libraries</title> + + <section> + <title>Erl_Interface</title> + <p>Very often the program at the other side of a port is a C program. To help the C programmer a library called Erl_Interface has been developed. It consists of five parts:</p> + <list type="bulleted"> + <item><c>erl_marshal</c>, <c>erl_eterm</c>, <c>erl_format</c>, <c>erl_malloc</c> Handling of the Erlang external term format.</item> + <item><c>erl_connect</c> Communication with distributed Erlang, see <seealso marker="#cnode">C nodes</seealso> below.</item> + <item><c>erl_error</c> Error print routines.</item> + <item><c>erl_global</c> Access globally registered names.</item> + <item><c>Registry</c> Store and backup of key-value pairs.</item> + </list> + <p>The Erlang external term format is a representation of an Erlang term as a sequence of bytes, a binary. Conversion between the two representations is done using BIFs.</p> + <pre> +Binary = term_to_binary(Term) +Term = binary_to_term(Binary)</pre> + <p>A port can be set to use binaries instead of lists of bytes. It is then not necessary to invent any encoding/decoding scheme. Erl_Interface functions are used for unpacking the binary and convert it into a struct similar to an Erlang term. Such a struct can be manipulated in different ways and be converted to the Erlang external format and sent to Erlang.</p> + <p><em>When to use:</em> In C code, in conjunction with Erlang binaries.</p> + <p><em>Where to read more:</em> Read about the Erl_Interface User's Guide; Command Reference and Library Reference. In R5B and earlier versions the information can be found under the Kernel application.</p> + </section> + <p><em>Examples:</em><seealso marker="erl_interface">erl_interface example</seealso>.</p> + <marker id="cnode"></marker> + + <section> + <title>C Nodes</title> + <p>A C program which uses the Erl_Interface functions for setting up a connection to and communicating with a distributed Erlang node is called a <em>C node</em>, or a <em>hidden node</em>. The main advantage with a C node is that the communication from the Erlang programmer's point of view is extremely easy, since the C program behaves as a distributed Erlang node.</p> + <p><em>When to use:</em> C nodes can typically be used on device processors (as opposed to control processors) where C is a better choice than Erlang due to memory limitations and/or application characteristics.</p> + <p><em>Where to read more:</em> In the <c>erl_connect</c> part of the Erl_Interface documentation, see above. The programmer also needs to be familiar with TCP/IP sockets, see <seealso marker="#sockets">below</seealso>, and distributed Erlang, see <seealso marker="#dist">above</seealso>.</p> + <p><em>Examples:</em><seealso marker="cnode">C node example</seealso>.</p> + </section> + + <section> + <title>Jinterface</title> + <p>In Erlang/OTP R6B, a library similar to Erl_Interface for Java was added called <em>jinterface</em>.</p> + </section> + </section> + + <section> + <title>Standard Protocols</title> + <p>Sometimes communication between an Erlang program and another program using a standard protocol is desirable. Erlang/OTP currently supports TCP/IP and UDP <em>sockets</em>, SNMP, HTTP and IIOP (CORBA). Using one of the latter three requires good knowledge about the protocol and is not covered by this tutorial. Please refer to the documentation for the SNMP, Inets and Orber applications, respectively.</p> + <marker id="sockets"></marker> + + <section> + <title>Sockets</title> + <p>Simply put, connection-oriented socket communication (TCP/IP) consists of an initiator socket ("server") started at a certain host with a certain port number. A connector socket ("client") aware of the initiator's host name and port number can connect to it and data can be sent between them. Connection-less socket communication (UDP) consists of an initiator socket at a certain host with a certain port number and a connector socket sending data to it. For a detailed description of the socket concept, please refer to a suitable book about network programming. A suggestion is <em>UNIX Network Programming, Volume 1: Networking APIs - Sockets and XTI</em> by W. Richard Stevens, ISBN: 013490012X.</p> + <p>In Erlang/OTP, access to TCP/IP and UDP sockets is provided by the + Kernel modules <c>gen_tcp</c> and <c>gen_udp</c>. Both are easy to + use and do not require any deeper knowledge about the socket concept.</p> + <p><em>When to use:</em> For programs running on the same or on another machine than the Erlang program.</p> + <p><em>Where to read more:</em> The man pages for <c>gen_tcp</c> and <c>gen_udp</c>.</p> + </section> + </section> + + <section> + <title>IC</title> + <p>IC (IDL Compiler) is an interface generator which given an IDL interface specification automatically generates stub code in Erlang, C or Java. Please refer to the IC User's Guide and IC Reference Manual.</p> + </section> + + <section> + <title>Old Applications</title> + <p>There are two old applications of interest when talking about interoperability: <em>IG</em> which was removed in Erlang/OTP R6B and <em>Jive</em> which was removed in Erlang/OTP R7B. Both applications have been replaced by IC and are mentioned here for reference only.</p> + <p>IG (Interface Generator) automatically generated code for port or socket communication between an Erlang program and a C program, given a C header file with certain keywords. Jive provided a simple interface between an Erlang program and a Java program.</p> + </section> +</chapter> + diff --git a/system/doc/tutorial/part.xml b/system/doc/tutorial/part.xml new file mode 100644 index 0000000000..1a8a873242 --- /dev/null +++ b/system/doc/tutorial/part.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Interoperability Tutorial</title> + <prepared>Gunilla Hugosson</prepared> + <docno></docno> + <date>2000-01-18</date> + <rev>R7B</rev> + </header> + <xi:include href="introduction.xml"/> + <xi:include href="overview.xml"/> + <xi:include href="example.xml"/> + <xi:include href="c_port.xml"/> + <xi:include href="erl_interface.xml"/> + <xi:include href="c_portdriver.xml"/> + <xi:include href="cnode.xml"/> +</part> + diff --git a/system/doc/tutorial/port.c b/system/doc/tutorial/port.c new file mode 100644 index 0000000000..3a9a4e442c --- /dev/null +++ b/system/doc/tutorial/port.c @@ -0,0 +1,23 @@ +/* port.c */ + +typedef unsigned char byte; + +int main() { + int fn, arg, res; + byte buf[100]; + + while (read_cmd(buf) > 0) { + fn = buf[0]; + arg = buf[1]; + + if (fn == 1) { + res = foo(arg); + } else if (fn == 2) { + res = bar(arg); + } + + buf[0] = res; + write_cmd(buf, 1); + } +} + diff --git a/system/doc/tutorial/port.gif b/system/doc/tutorial/port.gif Binary files differnew file mode 100644 index 0000000000..1f5afd51da --- /dev/null +++ b/system/doc/tutorial/port.gif diff --git a/system/doc/tutorial/port.ps b/system/doc/tutorial/port.ps new file mode 100644 index 0000000000..c17959fbe7 --- /dev/null +++ b/system/doc/tutorial/port.ps @@ -0,0 +1,5981 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: /home/super/gunilla/tutorial/interoperability/port.ps +%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley +%%BoundingBox: 127 298 485 494 +%%Pages: 1 +%%DocumentFonts: +%%EndComments +%%EndProlog + +%%Page: 1 1 + +% remember original state +/origstate save def + +% build a temporary dictionary +20 dict begin + +% define string to hold a scanline's worth of data +/pix 1074 string def + +% define space for color conversions +/grays 358 string def % space for gray scale line +/npixls 0 def +/rgbindx 0 def + +% lower left corner +127 298 translate + +% size of image (on paper, in 1/72inch coords) +357.98400 195.98400 scale + +% define 'colorimage' if it isn't defined +% ('colortogray' and 'mergeprocs' come from xwd2ps +% via xgrab) +/colorimage where % do we know about 'colorimage'? + { pop } % yes: pop off the 'dict' returned + { % no: define one + /colortogray { % define an RGB->I function + /rgbdata exch store % call input 'rgbdata' + rgbdata length 3 idiv + /npixls exch store + /rgbindx 0 store + 0 1 npixls 1 sub { + grays exch + rgbdata rgbindx get 20 mul % Red + rgbdata rgbindx 1 add get 32 mul % Green + rgbdata rgbindx 2 add get 12 mul % Blue + add add 64 idiv % I = .5G + .31R + .18B + put + /rgbindx rgbindx 3 add store + } for + grays 0 npixls getinterval + } bind def + + % Utility procedure for colorimage operator. + % This procedure takes two procedures off the + % stack and merges them into a single procedure. + + /mergeprocs { % def + dup length + 3 -1 roll + dup + length + dup + 5 1 roll + 3 -1 roll + add + array cvx + dup + 3 -1 roll + 0 exch + putinterval + dup + 4 2 roll + putinterval + } bind def + + /colorimage { % def + pop pop % remove 'false 3' operands + {colortogray} mergeprocs + image + } bind def + } ifelse % end of 'false' case + + + +358 196 8 % dimensions of data +[358 0 0 -196 0 196] % mapping matrix +{currentfile pix readhexstring pop} +false 3 colorimage + +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000000000 +000000000000000000000000000000000000000000000000000000ffffff000000000000 +000000000000000000000000000000ffffff000000000000000000ffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffff000000ffffff000000ffffffffffffffffff000000000000000000ffffff +ffffff000000ffffffffffff000000000000ffffffffffffffffff000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000000000ffffff000000000000000000000000 +000000000000ffffffffffff000000000000ffffffffffff000000ffffff000000000000 +000000ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffff +000000ffffffffffffffffff000000000000000000000000ffffffffffff000000ffffff +000000000000ffffffffffff000000000000ffffffffffffffffffffffff000000000000 +000000000000000000ffffff000000000000ffffffffffff000000000000ffffff000000 +ffffff000000000000ffffff000000000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffffffffff000000000000ffffffffffff +ffffff000000ffffffffffffffffffffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000000000000000 +000000000000ffffffffffffffffffffffff000000ffffff000000ffffffffffff000000 +ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000000000ffffff +ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000 +000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff +000000ffffffffffff000000000000ffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000000000000000 +000000000000ffffffffffff000000000000000000000000000000ffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffff000000000000000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000 +ffffffffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffffffffff000000000000000000ffffff +000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000 +ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff +000000ffffffffffff000000ffffffffffffffffffffffff000000000000000000ffffff +000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000 +ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000 +ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000000000000000 +ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff +ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000 +ffffffffffffffffff000000000000ffffffffffff000000ffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000 +ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff +000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffffffffff000000ffffff000000ffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000000000ffffffffffff000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000000000 +000000000000000000ffffffffffff000000000000ffffff000000000000ffffffffffff +000000000000ffffffffffff000000000000000000ffffff000000000000000000ffffff +000000000000000000ffffff000000000000ffffffffffff000000000000ffffff000000 +000000000000ffffffffffffffffff000000000000000000ffffffffffff000000000000 +000000ffffffffffffffffff000000000000ffffffffffffffffffffffff000000000000 +000000ffffff000000000000000000ffffffffffffffffff000000000000ffffff000000 +000000000000ffffff000000000000ffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000000000 +000000000000000000000000000000000000ffffffffffffffffff000000000000ffffff +000000000000000000ffffffffffff000000ffffff000000000000000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000 +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000 +000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000ffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000 +000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000 +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000 +ffffffffffff000000000000ffffffffffff000000000000ffffffffffffffffffffffff +000000000000ffffff000000000000ffffff000000000000000000ffffff000000000000 +ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff +000000ffffff000000ffffff000000ffffff000000ffffff000000ffffffffffff000000 +ffffff000000000000ffffffffffffffffff000000ffffff000000000000ffffff000000 +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff +000000ffffff000000ffffff000000ffffff000000ffffff000000ffffffffffff000000 +ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffffffffffffffff000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000000000 +ffffffffffff000000ffffff000000ffffff000000ffffff000000ffffffffffffffffff +000000000000ffffff000000000000ffffff000000000000ffffff000000000000000000 +ffffffffffff000000000000000000000000000000000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000ffffff000000ffffffffffff +ffffff000000ffffffffffff000000ffffff000000000000ffffffffffff000000000000 +ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffff +ffffff000000ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +000000000000000000ffffffffffffffffff000000000000ffffffffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000000000000000ffffffffffff000000000000ffffff000000 +000000ffffffffffffffffff000000000000ffffffffffff000000000000ffffffffffff +000000000000ffffff000000000000ffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffff000000ffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000 +ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffffffffff000000ffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff +ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000 +000000ffffffffffffffffff000000000000ffffffffffff000000000000ffffff000000 +000000000000000000000000000000ffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffff000000000000000000000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffff000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffff000000000000000000000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffff000000000000000000ffffffffffffffffff000000000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffff000000000000ffffffffffffffffff +ffffff000000000000000000ffffffffffff000000000000ffffffffffff000000000000 +ffffffffffffffffff000000000000ffffffffffff000000000000ffffffffffff000000 +000000ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffffffffffffffff000000000000ffffff +ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff +000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000ffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffff +ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff +000000ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff +000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffff000000000000000000ffffffffffffffffff000000000000ffffffffffff +ffffff000000ffffff000000ffffffffffff000000ffffffffffffffffff000000000000 +ffffffffffffffffff000000000000ffffffffffff000000000000ffffff000000000000 +000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000000000ffffffffffff000000000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff +ffffff000000000000000000000000000000ffffffffffffffffff000000000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffff000000000000000000ffffffffffff000000000000ffffff000000ffffff +000000000000000000ffffff000000000000ffffffffffffffffff000000000000000000 +000000ffffff000000000000000000ffffffffffff000000000000ffffffffffff000000 +000000ffffffffffffffffff000000000000ffffffffffff000000000000ffffffffffff +000000000000ffffff000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffff +ffffffffffff000000ffffff000000ffffff000000ffffff000000ffffffffffff000000 +ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000 +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffff000000ffffffffffffffffff000000000000ffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff000000ffffff +000000ffffff000000ffffff000000ffffff000000ffffffffffff000000000000ffffff +ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff +ffffff000000ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff +ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff +ffffff000000000000000000000000000000ffffff000000ffffffffffff000000ffffff +000000000000000000ffffff000000ffffff000000ffffffffffff000000000000ffffff +ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffff000000 +000000ffffffffffffffffff000000000000ffffffffffff000000000000ffffff000000 +000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000 +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff +ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000ffffffffffffffffffffffff +ffffff000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffffffffff000000000000ffffff000000 +000000ffffff000000ffffffffffffffffff000000000000ffffff000000ffffffffffff +ffffff000000ffffff000000ffffffffffff000000000000ffffffffffff000000000000 +ffffffffffff000000000000ffffff000000000000000000ffffff000000000000000000 +000000ffffffffffff000000000000ffffff000000000000ffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff000000000000 +ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000 +ffffff000000ffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff +000000ffffff000000ffffffffffff000000000000ffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000000000 +ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffff000000ffffff +ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff000000 +ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000ffffffffffff +000000ffffff000000ffffffffffff000000000000ffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000000000000000ffffffffffffffffff000000000000ffffff000000 +ffffff000000ffffff000000ffffffffffff000000ffffff000000ffffff000000ffffff +ffffffffffff000000000000ffffffffffff000000ffffff000000ffffffffffff000000 +ffffffffffff000000000000ffffff000000000000000000ffffff000000000000ffffff +000000ffffffffffff000000000000ffffff000000ffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000ffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +showpage + +% stop using temporary dictionary +end + +% restore original state +origstate restore + +%%Trailer diff --git a/system/doc/tutorial/port_driver.c b/system/doc/tutorial/port_driver.c new file mode 100644 index 0000000000..d428d08ff3 --- /dev/null +++ b/system/doc/tutorial/port_driver.c @@ -0,0 +1,52 @@ +/* port_driver.c */ + +#include <stdio.h> +#include "erl_driver.h" + +typedef struct { + ErlDrvPort port; +} example_data; + +static ErlDrvData example_drv_start(ErlDrvPort port, char *buff) +{ + example_data* d = (example_data*)driver_alloc(sizeof(example_data)); + d->port = port; + return (ErlDrvData)d; +} + +static void example_drv_stop(ErlDrvData handle) +{ + driver_free((char*)handle); +} + +static void example_drv_output(ErlDrvData handle, char *buff, int bufflen) +{ + example_data* d = (example_data*)handle; + char fn = buff[0], arg = buff[1], res; + if (fn == 1) { + res = foo(arg); + } else if (fn == 2) { + res = bar(arg); + } + driver_output(d->port, &res, 1); +} + +ErlDrvEntry example_driver_entry = { + NULL, /* F_PTR init, N/A */ + example_drv_start, /* L_PTR start, called when port is opened */ + example_drv_stop, /* F_PTR stop, called when port is closed */ + example_drv_output, /* F_PTR output, called when erlang has sent */ + NULL, /* F_PTR ready_input, called when input descriptor ready */ + NULL, /* F_PTR ready_output, called when output descriptor ready */ + "example_drv", /* char *driver_name, the argument to open_port */ + NULL, /* F_PTR finish, called when unloaded */ + NULL, /* F_PTR control, port_command callback */ + NULL, /* F_PTR timeout, reserved */ + NULL /* F_PTR outputv, reserved */ +}; + +DRIVER_INIT(example_drv) /* must match name in driver_entry */ +{ + return &example_driver_entry; +} + diff --git a/system/doc/tutorial/port_driver.gif b/system/doc/tutorial/port_driver.gif Binary files differnew file mode 100644 index 0000000000..cf22ceef61 --- /dev/null +++ b/system/doc/tutorial/port_driver.gif diff --git a/system/doc/tutorial/port_driver.ps b/system/doc/tutorial/port_driver.ps new file mode 100644 index 0000000000..ad8a3b50f9 --- /dev/null +++ b/system/doc/tutorial/port_driver.ps @@ -0,0 +1,901 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./port_driver.tmp.eps) +%%CreationDate: (Tue Jun 12 17:25:22 2001) +%%BoundingBox: 0 43 377 246 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 43 377 246 +userdict begin +%%BeginData: +DisplayImage +0 43 +377.000000 203.000000 +12 +698 376 +1 +0 +0 +256 +000000 +000055 +0000aa +0000ff +002400 +002455 +0024aa +0024ff +004900 +004955 +0049aa +0049ff +006d00 +006d55 +006daa +006dff +009200 +009255 +0092aa +0092ff +00b600 +00b655 +00b6aa +00b6ff +00db00 +00db55 +00dbaa +00dbff +00ff00 +00ff55 +00ffaa +00ffff +240000 +240055 +2400aa +2400ff +242400 +242455 +2424aa +2424ff +244900 +244955 +2449aa +2449ff +246d00 +246d55 +246daa +246dff +249200 +249255 +2492aa +2492ff +24b600 +24b655 +24b6aa +24b6ff +24db00 +24db55 +24dbaa +24dbff +24ff00 +24ff55 +24ffaa +24ffff +490000 +490055 +4900aa +4900ff +492400 +492455 +4924aa +4924ff +494900 +494955 +4949aa +4949ff +496d00 +496d55 +496daa +496dff +499200 +499255 +4992aa +4992ff +49b600 +49b655 +49b6aa +49b6ff +49db00 +49db55 +49dbaa +49dbff +49ff00 +49ff55 +49ffaa +49ffff +6d0000 +6d0055 +6d00aa +6d00ff +6d2400 +6d2455 +6d24aa +6d24ff +6d4900 +6d4955 +6d49aa +6d49ff +6d6d00 +6d6d55 +6d6daa +6d6dff +6d9200 +6d9255 +6d92aa +6d92ff +6db600 +6db655 +6db6aa +6db6ff +6ddb00 +6ddb55 +6ddbaa +6ddbff +6dff00 +6dff55 +6dffaa +6dffff +920000 +920055 +9200aa +9200ff +922400 +922455 +9224aa +9224ff +924900 +924955 +9249aa +9249ff +926d00 +926d55 +926daa +926dff +929200 +929255 +9292aa +9292ff +92b600 +92b655 +92b6aa +92b6ff +92db00 +92db55 +92dbaa +92dbff +92ff00 +92ff55 +92ffaa +92ffff +b60000 +b60055 +b600aa +b600ff +b62400 +b62455 +b624aa +b624ff +b64900 +b64955 +b649aa +b649ff +b66d00 +b66d55 +b66daa +b66dff +b69200 +b69255 +b692aa +b692ff +b6b600 +b6b655 +b6b6aa +b6b6ff +b6db00 +b6db55 +b6dbaa +b6dbff +b6ff00 +b6ff55 +b6ffaa +b6ffff +db0000 +db0055 +db00aa +db00ff +db2400 +db2455 +db24aa +db24ff +db4900 +db4955 +db49aa +db49ff +db6d00 +db6d55 +db6daa +db6dff +db9200 +db9255 +db92aa +db92ff +dbb600 +dbb655 +dbb6aa +dbb6ff +dbdb00 +dbdb55 +dbdbaa +dbdbff +dbff00 +dbff55 +dbffaa +dbffff +ff0000 +ff0055 +ff00aa +ff00ff +ff2400 +ff2455 +ff24aa +ff24ff +ff4900 +ff4955 +ff49aa +ff49ff +ff6d00 +ff6d55 +ff6daa +ff6dff +ff9200 +ff9255 +ff92aa +ff92ff +ffb600 +ffb655 +ffb6aa +ffb6ff +ffdb00 +ffdb55 +ffdbaa +ffdbff +ffff00 +ffff55 +ffffaa +ffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff8c00ff00ff00adff0b00ff00ff00adff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ff2b00ff009effde0001ff0b0001ff2b +0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001ff2b +0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001ff2b +0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001ff2b +0000ff2b0002ffffff6d0000ffde0001ff0b0001ff2b0000ff2c0001ffffff6d0000ffde +0001ff0b0001ff2b0000ff2c0001ff100000ffffff5b0000ffde0001ff0b0001ff2b0000 +ff2c0001ff0f0001ffffff5b0000ffde0001ff0b0001ff2b0000ff2c0001ff0f0001ffff +ff5b0000ffde0001ff0b0001ff2b0000ff050003ff030002ff010002ff030002ff020002 +ff030002ff020001ff050004ff020006ff020003ff040002ff000001ffffff460000ffde +0001ff0b0001ff2b0000ff030001ff020001ff030001ff000004ff010004ff020001ff04 +0001ff020001ff040001ff010002ff030001ff030002ff010002ff030001ff000001ffff +ff460000ffde0001ff0b0001ff2b0000ff030000ff040001ff020002ff020003ff020002 +ff010001ff040001ff020001ff040001ff020001ff030001ff030001ff030001ff030002 +ffffff480000ffde0001ff0b0001ff2b0000ff020001ff040001ff020001ff040001ff04 +0001ff010001ff040001ff020001ff090001ff030001ff020001ff050001ff020001ffff +ff490000ffde0001ff0b0001ff2b0000ff020008ff020001ff040001ff040001ff010001 +ff040001ff020001ff070003ff030001ff020001ff050001ff020001ffffff490000ffde +0001ff0b0001ff2b0000ff020001ff090001ff040001ff040001ff010001ff040001ff02 +0001ff050002ff000001ff030001ff020001ff050001ff020001ffffff490000ffde0001 +ff0b0001ff2b0000ff020001ff090001ff040001ff040001ff010001ff040001ff020001 +ff040001ff020001ff030001ff020001ff050001ff020001ff9500a2ff100000ffde0001 +ff0b0001ff2b0000ff020001ff090001ff040001ff040001ff010001ff040001ff020001 +ff030001ff030001ff030001ff020001ff050001ff020001ff950000ffa00000ff100000 +ffde0001ff0b0001ff2b0000ff020002ff080001ff040001ff040001ff010001ff040001 +ff020001ff030001ff030001ff030001ff020001ff050001ff020001ff950000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff030002ff030000ff020001ff040001ff040001 +ff010002ff020002ff020001ff030001ff020002ff030001ff030001ff030001ff030001 +ff950000ffa00000ff100000ffde0001ff0b0001ff2b0000ff030006ff030001ff040001 +ff040001ff020004ff000001ff020001ff030004ff000001ff030001ff010000ff000002 +ff010002ff030001ff950000ffa00000ff100000ffde0001ff0b0001ff2b0000ff050003 +ff030003ff020003ff020003ff020002ff010002ff000003ff030002ff020001ff030002 +ff030003ff040003ff940000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ff110009ff290002ff0b0001ff490000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ff130001ff040002ff280001ff0b0001ff490000ff100000 +ffde0001ff0b0001ff2b0000ffe80000ff130001ff050001ff180000ff0e0001ff570000 +ff100000ffde0001ff0b0001ff2b0000ffe80000ff130001ff060001ff160001ff0e0001 +ff570000ff100000ffde0001ff0b0001ff2b0000ffe80000ff130001ff060001ff160001 +ff0e0001ff570000ff100000ffde0001ff0b0001ff2b0000ffe80000ff130001ff060001 +ff040003ff040002ff000001ff000006ff070002ff000001ff020002ff000001ff010002 +ff010003ff020003ff030003ff030002ff000001ff2a0000ff100000ffde0001ff0b0001 +ff2b0000ffe80000ff130001ff050001ff030002ff010002ff030001ff000001ff020001 +ff080002ff010002ff030001ff000001ff020001ff020001ff040001ff020001ff020001 +ff030001ff000001ff2a0000ff100000ffde0001ff0b0001ff2b0000ff320004ffae0002 +ff130001ff040002ff030001ff030001ff030002ff040001ff080001ff030001ff030002 +ff040001ff020001ff040000ff030000ff040001ff020002ff2c0000ff100000ffde0001 +ff0b0001ff2b0000ff2d0004ff040004ffa40004ff010000ff130007ff040001ff050001 +ff020001ff050001ff070001ff040001ff030001ff050001ff030001ff030000ff020001 +ff040001ff020001ff2d0000ff100000ffde0001ff0b0001ff2b0000ff290003ff0e0003 +ff9c0003ff060000ff130001ff0a0001ff050001ff020001ff050001ff070001ff040001 +ff030001ff050001ff030001ff030000ff020008ff020001ff2d0000ff100000ffde0001 +ff0b0001ff2b0000ff260002ff160002ff960002ff0a0000ff130001ff0a0001ff050001 +ff020001ff050001ff070001ff040001ff030001ff050001ff030001ff020000ff030001 +ff090001ff2d0000ff100000ffde0001ff0b0001ff2b0000ff240001ff1c0001ff920001 +ff0d0000ff130001ff0a0001ff050001ff020001ff050001ff070001ff040001ff030001 +ff050001ff040001ff010000ff030001ff090001ff2d0000ff100000ffde0001ff0b0001 +ff2b0000ff230000ff200000ff900000ff0f0000ff130001ff0a0001ff050001ff020001 +ff050001ff070001ff040001ff030001ff050001ff040001ff010000ff030001ff090001 +ff2d0000ff100000ffde0001ff0b0001ff2b0000ff220000ff220000ff8e0000ff100000 +ff130001ff0a0001ff050001ff020001ff050001ff070001ff040001ff030001ff050001 +ff040001ff000000ff040002ff080001ff2d0000ff100000ffde0001ff0b0001ff2b0000 +ff200001ff240001ff8a0001ff110000ff130001ff0b0001ff030001ff030001ff050001 +ff080001ff030001ff030001ff050001ff050002ff050002ff030000ff020001ff2d0000 +ff100000ffde0001ff0b0001ff2b0000ff1f0000ff280000ff880000ff130000ff130001 +ff0b0002ff010002ff030001ff050001ff010000ff050002ff010002ff030001ff050001 +ff050002ff050006ff030001ff2d0000ff100000ffde0001ff0b0001ff2b0000ff1e0000 +ff2a0000ff860000ff140000ff110005ff0b0003ff040003ff050002ff080003ff000001 +ff010003ff030003ff050000ff080003ff030003ff2c0000ff100000ffde0001ff0b0001 +ff2b0000ff1c0001ff2c0001ff820001ff150000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff1b0000ff300000ff800000ff170000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff1a0000ff320000ff7e0000ff130001ff020000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ff1a0000ff320000ff7e0000ff130005ffa00000ff100000ffde0001 +ff0b0001ff2b0000ff190000ff340000ff7c0000ff140008ff9d0000ff100000ffde0001 +ff0b0001ff2b0000ff180000ff360000ff7a0000ff15000bff9a0000ff100000ffde0001 +ff0b0001ff2b0000ff170000ff380000ff780000ff16000fff960000ff100000ffde0001 +ff0b0001ff2b0000ff170000ff380000ff780000ff160013ff920000ff100000ffde0001 +ff0b0001ff2b0000ff160000ff3a0000ff760000ff0a0023ff0a0002ff2d0002ff080002 +ff030001ff020002ff380000ff100000ffde0001ff0b0001ff2b0000ff150000ff080003 +ff010000ff2c0000ff0d0002ff630000ff180013ff0e0001ff2e0001ff090001ff030001 +ff030001ff380000ff100000ffde0001ff0b0001ff2b0000ff140000ff070001ff030002 +ff2d0000ff0d0001ff620000ff19000fff120001ff2e0001ff090001ff090001ff380000 +ff100000ffde0001ff0b0001ff2b0000ff140000ff060001ff050001ff2c0001ff0d0001 +ff620000ff19000bff160001ff2e0001ff090001ff090001ff380000ff100000ffde0001 +ff0b0001ff2b0000ff130000ff070001ff060000ff2b0001ff000000ff0c0001ff610000 +ff1a0008ff190001ff2e0001ff090001ff090001ff380000ff100000ffde0001ff0b0001 +ff2b0000ff130000ff060001ff0a0003ff020002ff010001ff010002ff010001ff030003 +ff030003ff010004ff010003ff030004ff610000ff1a0005ff130004ff030001ff010002 +ff060004ff030002ff000001ff040003ff060002ff000001ff090001ff020002ff030001 +ff000002ff040002ff000001ff030004ff030002ff000001ff000003ff020003ff0a0000 +ff100000ffde0001ff0b0001ff2b0000ff130000ff060001ff090001ff010001ff020001 +ff000003ff010001ff000003ff010001ff010001ff010001ff010001ff010001ff000000 +ff000001ff010001ff010001ff010001ff610000ff1a0001ff020000ff120000ff020001 +ff030001ff000004ff040001ff010002ff030001ff000001ff020001ff020001ff030002 +ff010002ff090001ff030001ff030002ff010002ff030001ff000001ff020001ff010002 +ff030001ff000001ff010001ff040001ff0b0000ff100000ffde0001ff0b0001ff2b0000 +ff120000ff070001ff080001ff030001ff010002ff010001ff010002ff010001ff000001 +ff030000ff000001ff060001ff010001ff030000ff000001ff020001ff600000ff200000 +ff110001ff030000ff030002ff020002ff030001ff020001ff030002ff040000ff040001 +ff020001ff030001ff090001ff030001ff030001ff030001ff030002ff040001ff020001 +ff030002ff030001ff040000ff0c0000ff100000ffde0001ff0b0001ff2b0000ff120000 +ff070001ff080001ff030001ff010001ff020001ff010001ff020001ff000006ff000001 +ff060001ff010006ff000001ff020001ff600000ff200000ff110002ff070001ff040001 +ff080001ff030001ff040001ff040001ff010001ff040001ff090001ff030001ff030001 +ff040001ff020001ff0a0001ff030001ff050001ff030000ff0c0000ff100000ffde0001 +ff0b0001ff2b0000ff120000ff070001ff080001ff030001ff010001ff020001ff010001 +ff020001ff000001ff050001ff060001ff010001ff050001ff020001ff600000ff200000 +ff120002ff060001ff040001ff060003ff030001ff040008ff010001ff040001ff090001 +ff030001ff030001ff040001ff020001ff080003ff030001ff050001ff030000ff0c0000 +ff100000ffde0001ff0b0001ff2b0000ff120000ff080001ff070001ff030001ff010001 +ff020001ff010001ff020001ff000001ff050001ff060001ff010001ff050001ff020001 +ff600000ff200000ff120004ff040001ff040001ff040002ff000001ff030001ff040001 +ff080001ff040001ff090001ff030001ff030001ff040001ff020001ff060002ff000001 +ff030001ff050001ff020000ff0d0000ff100000ffde0001ff0b0001ff2b0000ff110000 +ff090001ff050003ff030001ff010001ff020001ff010001ff020001ff000001ff050001 +ff060001ff010001ff050001ff020001ff5f0000ff210000ff140003ff030001ff040001 +ff030001ff020001ff030001ff040001ff080001ff040001ff090001ff030001ff030001 +ff040001ff020001ff050001ff020001ff030001ff060001ff010000ff0d0000ff100000 +ffde0001ff0b0001ff2b0000ff110000ff0a0002ff020001ff010001ff010001ff020001 +ff020001ff010001ff020001ff010001ff010001ff010001ff010001ff010002ff000002 +ff010001ff010001ff010001ff080000ff190001ff190007ff170000ff210000ff160002 +ff020001ff040001ff020001ff030001ff030001ff040001ff080001ff040001ff090001 +ff030001ff030001ff040001ff020001ff040001ff030001ff030001ff060001ff010000 +ff0d0000ff100000ffde0001ff0b0001ff2b0000ff110000ff0c0003ff040003ff020003 +ff010006ff010002ff010003ff030003ff030002ff000004ff030005ff040003ff190004 +ff170001ff020002ff160000ff210000ff170001ff020001ff040001ff020001ff030001 +ff030001ff040002ff070001ff040001ff090001ff030001ff030001ff040001ff020001 +ff040001ff030001ff030001ff060001ff000000ff0e0000ff100000ffde0001ff0b0001 +ff2b0000ff110000ff440000ff0e0007ff190008ff130001ff030001ff100000ff040000 +ff210000ff110000ff040001ff020001ff040001ff020001ff020002ff030001ff050002 +ff030000ff020001ff030001ff090001ff030001ff030001ff030001ff030001ff040001 +ff020002ff030001ff070002ff0e0000ff100000ffde0001ff0b0001ff2b0000ff110000 +ff440000ff0b000aff19000bff100001ff030001ff0f0001ff040000ff210000ff110001 +ff020001ff030001ff040001ff020004ff000001ff030001ff050006ff030002ff010002 +ff090001ff030001ff030002ff010002ff030001ff040004ff000001ff030001ff070002 +ff0e0000ff100000ffde0001ff0b0001ff2b0000ff100000ff460000ff06000eff19000f +ff0c0001ff030001ff010003ff020002ff000006ff010000ff220000ff110004ff040003 +ff020003ff020002ff020001ff010003ff060003ff060003ff000001ff070003ff010003 +ff020000ff000003ff040003ff040002ff020001ff010003ff070000ff0f0000ff100000 +ffde0001ff0b0001ff2b0000ff100000ff460000ff020012ff190013ff080001ff020001 +ff010001ff010001ff020001ff000001ff000001ff030000ff220000ff8e0001ff0f0000 +ff100000ffde0001ff0b0001ff2b0000ff100000ff460047ff050005ff010001ff030001 +ff010002ff020001ff030000ff220000ff8e0000ff100000ff100000ffde0001ff0b0001 +ff2b0000ff100000ff460000ff020012ff190013ff080001ff050001ff030001ff010001 +ff030001ff030000ff220000ff8d0001ff100000ff100000ffde0001ff0b0001ff2b0000 +ff100000ff460000ff06000eff19000fff0c0001ff050001ff030001ff010001ff030001 +ff030000ff220000ff8a0003ff110000ff100000ffde0001ff0b0001ff2b0000ff110000 +ff440000ff0b000aff19000bff100001ff050001ff030001ff010001ff030001ff040000 +ff210000ff8a0002ff120000ff100000ffde0001ff0b0001ff2b0000ff110000ff440000 +ff0e0007ff190008ff130001ff050001ff030001ff010001ff030001ff040000ff210000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ff110000ff070002ff000002ff010002 +ff000001ff010003ff040003ff030003ff020001ff000000ff020001ff000000ff080000 +ff120003ff190004ff170001ff060001ff010001ff020001ff030002ff030000ff210000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ff110000ff080002ff000002ff010001 +ff000001ff000001ff010001ff020001ff010001ff010001ff010001ff000000ff010001 +ff010000ff010001ff080000ff150000ff190001ff190003ff060003ff020003ff030002 +ff020000ff210000ffa00000ff100000ffde0001ff0b0001ff2b0000ff110000ff080001 +ff020001ff010002ff010001ff030001ff000001ff050001ff030000ff000001ff010000 +ff010001ff010000ff070000ff6d0000ff210000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff120000ff070001ff020001ff010001ff020001ff030001ff000001ff050006 +ff000002ff030002ff090000ff6e0000ff200000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff120000ff070001ff020001ff010001ff020001ff030001ff000001ff050001 +ff060002ff030002ff080000ff6e0000ff200000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff120000ff070001ff020001ff010001ff020001ff030001ff000001ff050001 +ff070002ff030002ff070000ff6e0000ff200000ffa00000ff100000ffde0001ff0b0001 +ff2b0000ff120000ff070001ff020001ff010001ff020001ff030001ff000001ff050001 +ff050000ff010001ff010000ff010001ff070000ff6e0000ff200000ffa00000ff100000 +ffde0001ff0b0001ff2b0000ff130000ff060002ff000001ff020001ff030001ff010001 +ff020001ff010001ff010001ff010001ff000001ff010000ff010001ff010000ff060000 +ff700000ff1f0000ff020000ff9c0000ff100000ffde0001ff0b0001ff2b0000ff130000 +ff060004ff020003ff030003ff040003ff030003ff010000ff000001ff020000ff000001 +ff070000ff700000ff1f0004ff9c0000ff100000ffde0001ff0b0001ff2b0000ff130000 +ff060001ff370000ff700000ff1c0007ff9c0000ff100000ffde0001ff0b0001ff2b0000 +ff140000ff050001ff360000ff720000ff18000aff9c0000ff100000ffde0001ff0b0001 +ff2b0000ff140000ff050001ff360000ff720000ff14000eff9c0000ff100000ffde0001 +ff0b0001ff2b0000ff150000ff030003ff340000ff740000ff0f0012ff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff160000ff3a0000ff760000ff0b0023ff8e0000ff100000 +ffde0001ff0b0001ff2b0000ff170000ff380000ff780000ff0d0012ff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff170000ff380000ff780000ff11000eff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff180000ff360000ff7a0000ff14000aff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff190000ff340000ff7c0000ff160007ff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff1a0000ff320000ff7e0000ff180004ff9c0000ff100000 +ffde0001ff0b0001ff2b0000ff1a0000ff320000ff7e0000ff180000ff020000ff9c0000 +ff100000ffde0001ff0b0001ff2b0000ff1b0000ff300000ff800000ff170000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff1c0001ff2c0001ff820001ff150000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff1e0000ff2a0000ff860000ff140000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff1f0000ff280000ff880000ff130000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff200001ff240001ff8a0001ff110000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff220000ff220000ff8e0000ff100000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff230000ff200000ff900000ff0f0000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff240001ff1c0001ff920001ff0d0000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff260002ff160002ff960002ff0a0000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff290004ff0c0004ff9c0004ff050000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff2e0003ff040003ffa60003ff010000ffa00000 +ff100000ffde0001ff0b0001ff2b0000ff320004ffae0002ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001 +ff0b0001ff2b0000ffe80000ffa00000ff100000ffde0001ff0b0001ff2b0000ffe80000 +ffa00000ff100000ffde0001ff0b0001ff2b0000ffe800a2ff100000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b0000ffffff9c0000ffde0001ff0b0001 +ff2b0000ffffff9c0000ffde0001ff0b0001ff2b00ff009effde0001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffff +ffa90001ff0b0001ff5e002fffffffffff1a0001ff0b0001ff5e0000ff2d0000ffffffff +ff1a0001ff0b0001ff5e0000ff2d0000ffffffffff1a0001ff0b0001ff5e0000ff2d0000 +ffffffffff1a0001ff0b0001ff5e0000ff2d0000ffffffffff1a0001ff0b0001ff5e0000 +ff2d0000ffffffffff1a0001ff0b0001ff5e0000ff2d0000ffffffffff1a0001ff0b0001 +ff5e0000ff2d0000ffffffffff1a0001ff0b0001ff5e0000ff2d0000ffffffffff1a0001 +ff0b0001ff5e0000ff2d0000ffffffffff1a0001ff0b0001ff5e0000ff2d0000ffffffff +ff1a0001ff0b0001ff5e0000ff2d0000ffffffffff1a0001ff0b0001ff5e0000ff2d0000 +ff0c0003ff070002ff000000fffffffc0001ff0b0001ff5e0000ff2d0000ff0a0001ff03 +0001ff040000ff020001fffffffc0001ff0b0001ff5e0000ff2d0000ff090001ff050001 +ff020001ff030000fffffffc0001ff0b0001ff5e0000ff2d0000ff090001ff050001ff02 +0001ffffffffff010001ff0b0001ff5e0000ff2d0000ff080001ff070001ff010002ff09 +0002ff000002ff010002ff000001ff020003ff040003ff030003ff020001ff000000ff01 +0001ff000000ffffffc20001ff0b0001ff5e0000ff2d0000ff080001ff070001ff020003 +ff080002ff000002ff010001ff000001ff010001ff010001ff020001ff010001ff010001 +ff010001ff000000ff010001ff000000ff010001ffffffc20001ff0b0001ff5e0000ff2d +0000ff080001ff070001ff030003ff070001ff020001ff010002ff020001ff030001ff00 +0001ff050001ff030000ff000001ff010000ff000001ff010000ffffffc20001ff0b0001 +ff5e0000ff2d0000ff080001ff070001ff050002ff060001ff020001ff010001ff030001 +ff030001ff000001ff050006ff000002ff020002ffffffc40001ff0b0001ff5e0000ff2d +0000ff080001ff070001ff060002ff050001ff020001ff010001ff030001ff030001ff00 +0001ff050001ff060002ff020002ffffffc30001ff0b0001ff5e0000ff2d0000ff090001 +ff050001ff080001ff050001ff020001ff010001ff030001ff030001ff000001ff050001 +ff070002ff020002ffffffc20001ff0b0001ff5e0000ff2d0000ff090001ff050001ff02 +0000ff040001ff050001ff020001ff010001ff030001ff030001ff000001ff050001ff05 +0000ff010001ff000000ff010001ffffffc20001ff0b0001ff5e0000ff2d0000ff0a0001 +ff030001ff030001ff020001ff060002ff000001ff020001ff040001ff010001ff020001 +ff010001ff010001ff010001ff000001ff010000ff000001ff010000ffffffc20001ff0b +0001ff5e0000ff2d0000ff0c0003ff050000ff000002ff080004ff020003ff040003ff04 +0003ff030003ff010000ff000001ff010000ff000001ffffffc30001ff0b0001ff5e0000 +ff2d0000ff240001fffffff30001ff0b0001ff5e0000ff2d0000ff240001fffffff30001 +ff0b0001ff5e0000ff2d0000ff240001fffffff30001ff0b0001ff5e0000ff2d0000ff23 +0003fffffff20001ff0b0001ff5e002fffffffffff1a0001ff0b0001ffffffffffa90001 +ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001 +ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001 +ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001 +ff0b0001ff7e0004ffffffffff250001ff0b0001ff7b0002ff040002ffffffffff220001 +ff0b0001ff790001ff0a0001ffffffffff200001ff0b0001ff780000ff0e0000ffffffff +ff1f0001ff0b0001ff770000ff100000ffffffffff1e0001ff0b0001ff760000ff120000 +ffffffffff1d0001ff0b0001ff750000ff130000ffffffffff1d0001ff0b0001ff750000 +ff140000ffffffffff1c0001ff0b0001ff740000ff160000ffffffffff1b0001ff0b0001 +ff740000ff160000ffffffffff1b0001ff0b0001ff740000ff160000ffffffffff1b0001 +ff0b0001ff730000ff170000ff090008ff070002fffffffd0001ff0b0001ff730000ff18 +0000ff090001ff030001ff080001fffffffd0001ff0b0001ff730000ff180000ff090001 +ff040000ff080001fffffffd0001ff0b0001ff730000ff180000ff090001ff0e0001ffff +fffd0001ff0b0001ff730000ff180000ff090001ff060002ff000001ff010001ff030003 +ff020002ff010001ff040004ff030002ff000002ff010002ff000001ff020003ff040003 +ff030003ff020001ff000000ff010001ff000000ffffffa90001ff0b0001ff730000ff18 +0000ff090001ff030000ff020001ff000001ff010001ff020001ff010000ff030001ff00 +0003ff010001ff010001ff050002ff000002ff010001ff000001ff010001ff010001ff02 +0001ff010001ff010001ff010001ff000000ff010001ff000000ff010001ffffffa90001 +ff0b0001ff740000ff160000ff0a0006ff020002ff030001ff020001ff010001ff020002 +ff010001ff010001ff020000ff050001ff020001ff010002ff020001ff030001ff000001 +ff050001ff030000ff000001ff010000ff000001ff010000ffffffa90001ff0b0001ff74 +0000ff160000ff0a0001ff030000ff020001ff040001ff050002ff020001ff020001ff01 +0001ff020000ff050001ff020001ff010001ff030001ff030001ff000001ff050006ff00 +0002ff020002ffffffab0001ff0b0001ff740000ff160000ff0a0001ff070001ff040001 +ff030001ff000001ff020001ff020001ff010001ff010001ff050001ff020001ff010001 +ff030001ff030001ff000001ff050001ff060002ff020002ffffffaa0001ff0b0001ff75 +0000ff140000ff0b0001ff070001ff040001ff020001ff010001ff020001ff020001ff02 +0003ff060001ff020001ff010001ff030001ff030001ff000001ff050001ff070002ff02 +0002ffffffa90001ff0b0001ff750000ff140000ff0b0001ff040000ff010001ff040001 +ff020001ff010001ff020001ff020001ff020000ff090001ff020001ff010001ff030001 +ff030001ff000001ff050001ff050000ff010001ff000000ff010001ffffffa90001ff0b +0001ff760000ff120000ff0c0001ff030001ff010001ff040001ff020005ff020001ff02 +0001ff020004ff050002ff000001ff020001ff040001ff010001ff020001ff010001ff01 +0001ff010001ff000001ff010000ff000001ff010000ffffffa90001ff0b0001ff760000 +ff120000ff0b0008ff000003ff020003ff020001ff010001ff000003ff010002ff010006 +ff030004ff020003ff040003ff040003ff030003ff010000ff000001ff010000ff000001 +ffffffaa0001ff0b0001ff770000ff100000ff350000ff040001ff030001ffffffda0001 +ff0b0001ff780001ff0c0001ff360001ff040000ff030001ffffffda0001ff0b0001ff7a +0000ff0a0000ff380002ff020000ff040001ffffffda0001ff0b0001ff7b0002ff040002 +ff3a0004ff040003ffffffd90001ff0b0001ff7e0004ffffffffff250001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffff +ffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ff77 +0001ff210003ff010000ff370001ff170001ffffffb20001ff0b0001ff770004ff1c0001 +ff030002ff370001ff170001ffffffb20001ff0b0001ff770008ff170001ff050001ff4d +0000ffffffb70001ff0b0001ff77000bff140001ff060000ff4c0001ffffffb70001ff0b +0001ff77000fff0f0001ff0a0003ff020002ff010001ff020001ff010002ff010001ff02 +0001ff000002ff010002ff010002ff010001ff010002ff030003ff030003ff010007ff03 +0003ff020002ff010001ffffffa00001ff0b0001ff770013ff0b0001ff090001ff010001 +ff020001ff000003ff000003ff010001ff000003ff000003ff000001ff020001ff020001 +ff000003ff010001ff020001ff010001ff010001ff010000ff020001ff020001ff020001 +ff010001ff020001ff000003ffffff9f0001ff0b0001ff62002bff080001ff080001ff03 +0001ff010002ff010002ff010001ff010002ff010002ff010001ff000001ff020001ff02 +0002ff010001ff010001ff010001ff060001ff010001ff010001ff020001ff010001ff03 +0001ff010002ff010001ffffff9f0001ff0b0001ff770013ff0b0001ff080001ff030001 +ff010001ff020001ff020001ff010001ff020001ff020001ff000001ff020001ff020001 +ff020001ff010001ff010001ff090002ff010001ff020001ff010001ff030001ff010001 +ff020001ffffff9f0001ff0b0001ff77000fff0f0001ff080001ff030001ff010001ff02 +0001ff020001ff010001ff020001ff020001ff000001ff020001ff020001ff020001ff01 +0001ff010001ff070001ff000001ff010001ff020001ff010001ff030001ff010001ff02 +0001ffffff9f0001ff0b0001ff77000bff140001ff070001ff030001ff010001ff020001 +ff020001ff010001ff020001ff020001ff000001ff020001ff020001ff020001ff010001 +ff010001ff060001ff010001ff010001ff020001ff010001ff030001ff010001ff020001 +ffffff9f0001ff0b0001ff770008ff170001ff050003ff030001ff010001ff020001ff02 +0001ff010001ff020001ff020001ff000001ff020001ff020001ff020001ff010001ff01 +0001ff060001ff010001ff010001ff020001ff010001ff030001ff010001ff020001ffff +ff9f0001ff0b0001ff770004ff1c0002ff020001ff010001ff010001ff020001ff020001 +ff020001ff010001ff020001ff020001ff000002ff000002ff020001ff020001ff010001 +ff020001ff010001ff010005ff010002ff000002ff020001ff010001ff020001ff020001 +ffffff9f0001ff0b0001ff770001ff210003ff040003ff020003ff000003ff000007ff00 +0003ff000003ff000002ff000002ff000003ff010006ff020003ff030001ff010001ff01 +0006ff020003ff020003ff010002ffffff9e0001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001 +ffffffffffa90001ff0b0001ffffffffffa90001ff0b0001ffffffffffa90001ff0b00ff +00ff00adff0b00ff00ff00adffffffffffffffffffffffffffffffffff34 +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 43 377 246 +%%EOF diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk new file mode 100644 index 0000000000..794ef49774 --- /dev/null +++ b/system/doc/tutorial/xmlfiles.mk @@ -0,0 +1,29 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +TUTORIAL_CHAPTER_FILES = \ + introduction.xml\ + cnode.xml\ + c_port.xml\ + erl_interface.xml \ + c_portdriver.xml \ + example.xml\ + overview.xml +# appendix.xml +# distribution.xml (to be part of tutorial later) + |