(*********************************************************************** Mathematica-Compatible Notebook This notebook can be used on any computer system with Mathematica 3.0, MathReader 3.0, or any compatible application. The data for the notebook starts with the line of stars above. To get the notebook into a Mathematica-compatible application, do one of the following: * Save the data starting with the line of stars above into a file with a name ending in .nb, then open the file inside the application; * Copy the data starting with the line of stars above to the clipboard, then use the Paste menu command inside the application. Data for notebooks contains only printable 7-bit ASCII and can be sent directly in email or through ftp in text mode. Newlines can be CR, LF or CRLF (Unix, Macintosh or MS-DOS style). NOTE: If you modify the data for this notebook not in a Mathematica- compatible application, you must delete the line below containing the word CacheID, otherwise Mathematica-compatible applications may try to use invalid cache data. For more information on notebooks and Mathematica-compatible applications, contact Wolfram Research: web: http://www.wolfram.com email: info@wolfram.com phone: +1-217-398-0700 (U.S.) Notebook reader applications are available free of charge from Wolfram Research. ***********************************************************************) (*CacheID: 232*) (*NotebookFileLineBreakTest NotebookFileLineBreakTest*) (*NotebookOptionsPosition[ 47366, 1536]*) (*NotebookOutlinePosition[ 48448, 1573]*) (* CellTagsIndexPosition[ 48404, 1569]*) (*WindowFrame->Normal*) Notebook[{ Cell[CellGroupData[{Cell[TextData["Package Design"], "Title", Evaluatable->False, AspectRatioFixed->True], Cell[TextData["Todd Gayley\nVertical Applications"], "Subtitle", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "\nGood design is the most important criterion for creating packages for \ distribution. It is easy to become immersed in the specifics of implementing \ the functions; however, it is the design that manifests itself to the user, \ not the implementation details. Even the cleverest, fastest code can be made \ useless if it is clumsily packaged. The time and thought that you put into \ design considerations will be well rewarded in increased usability, easier \ maintenance, and a shortened development cycle."], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ " It is sometimes stated that the complete design specification for a \ programming project should be created before work on the actual code begins. \ This is an extreme view, especially given the ease of incremental, \ \"build-as-you-go\" development in the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " environment. Even if you like to jump right into coding, make sure that \ you spend time considering the top-down aspects of your design.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "You are creating an interface to a suite of functionality, so keep in mind \ the primary goal of interface design: usability. The usability of your \ package will be enhanced by adhering to two simple principles: make it \"look \ and feel\" like ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[", and make it mesh well with the rest of the system.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "The built-in kernel functions and the standard packages have established \ many precedents for how ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " functions are expected to be named and to behave. Resist the temptation \ to come up with another style. No matter how sensible and logical your scheme \ seems to you, chances are it will look unfamiliar and feel uncomfortable to \ users. Don't envision that you are creating a complete stand-alone \ application; keep in mind that others will be using your package(s) in ways \ you cannot foresee. Design the functions so that they can be used as part of \ a \"pipeline\". Make sure that the input to your functions is easy to obtain \ from other ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " functions, and likewise that the output is in a form that is immediately \ useful for further processing. Another aspect of meshing with the system is \ ensuring that the state of the user's session will not be unduly modified by \ loading your package.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "The guidelines presented here will help ensure that your packages comply \ with these two principles. These are not unbendable rules, but they are \ well-tested guidelines that match users' expectations. Two important \ references on package design are Roman Maeder's ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Programming in Mathematica, ", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ "Second Edition (Addison-Wesley 1991) and Stephen Wolfram's \"Some Elements \ of ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" Design\" (", Evaluatable->False, AspectRatioFixed->True], StyleBox["The Mathematica Journal", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[", Volume 2, Number 2).", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[CellGroupData[{Cell[TextData["Naming"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "Use the conventions established by the built-in symbols for all your \ exported symbol names. Names should be full English words or sequences of \ words, with the first letter of each word capitalized. When in doubt, use the \ longer or more explicit term; avoid abbreviations and names that are not \ descriptive. If a function with similar functionality exists in ", Evaluatable->False, AspectRatioFixed->True], StyleBox[ "Mathematica, use a similar name. Think carefully before using \ abbreviations or acronyms in function names, even when they are common", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ "ly used in your specialty. Keep the number of function names to a minimum, \ and instead use options and differing argument sequences to provide different \ behaviors. To ensure portability across all platforms, keep your package \ names unique within the first eight letters.", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"] }], "Text", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["Modularity"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "The structure of a package provides a means to control which symbols will \ be exported (", Evaluatable->False, AspectRatioFixed->True], StyleBox["i.e.", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ ", visible to users after your package has loaded). Consult Maeder's book \ as the canonical reference on the structure of packages and the context \ issues that are involved. Here is the basic structure:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox["BeginPackage[\"MyPackage`\"]\n\n", AspectRatioFixed->True], StyleBox[ " Introduce all the exported symbols (including functions, variables,\n \ option names and their values, etc.) here by supplying usage\n \ messages. Any symbols that appear before ", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["Begin[\"`Private`\"]", AspectRatioFixed->True], StyleBox[ " will be\n visible to users, so make sure that only symbols you want \ exported\n appear. The method of supplying a usage message is not \ required--it is\n merely a convenient means of referring to the symbols, \ thus creating\n them in the package context, and at the same time \ ensuring that each one has\n a usage message attached.\n", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox[ "\nFirstFunction::usage = \"FirstFunction does nothing.\"\n\n\ SecondFunction::usage = \"SecondFunction does nothing.\"\n\nOrdering::usage = \ \"Ordering is an option to FirstFunction.\n It \ specifies...\"\n\n", AspectRatioFixed->True], StyleBox[" If your package will ", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["Protect", AspectRatioFixed->True], StyleBox[ " symbols it defines at the end, make sure it\n unprotects them at the \ beginning. This will avoid a long series of \"this\n symbol is \ protected\" messages if users inadvertently read your package in\n twice \ during a session:\n", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["\nUnprotect[FirstFunction, SecondFunction, Ordering]\n\n", AspectRatioFixed->True], StyleBox[ " By defining a subcontext of the package context, you hide all the \ symbols\n you introduce in the implementation of your functions. By \ convention,\n use ", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["\"`Private`\"", AspectRatioFixed->True], StyleBox[" as the name of this subcontext:\n", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["\nBegin[\"`Private`\"]\n\n", AspectRatioFixed->True], StyleBox[" All the code for implementing your package goes here.\n", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["\nEnd[]\n\n", AspectRatioFixed->True], StyleBox[" If you choose, you can ", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox["Protect", AspectRatioFixed->True], StyleBox[" the symbols you introduced:\n", AspectRatioFixed->True, FontFamily->"Times", FontWeight->"Plain"], StyleBox[ "\nProtect[FirstFunction, SecondFunction, Ordering]\n\nEndPackage[];", AspectRatioFixed->True] }], "Input", AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "It is also good to include a set of special comments at the beginning of \ the file. In addition to supplying important information to the reader, they \ can be extracted by special utilities (", Evaluatable->False, AspectRatioFixed->True], StyleBox["e.g.", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[", the function ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Annotation", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" in ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Utilities`Package`", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox["). A good example of these comments is the package ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Utilities`Package`", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". Most of the comment types are self-explanatory. The ", Evaluatable->False, AspectRatioFixed->True], StyleBox[":PackageVersion:", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " comment gives the revision number of the package itself (a number that is \ meaningful to the author), and the ", Evaluatable->False, AspectRatioFixed->True], StyleBox[":Mathematica Version:", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" comment gives the minimum version number of ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" required to run it. ", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "(* :Title: Package Utilities *)\n\n(* :Context: Utilities`Package` *)\n\n(* \ :Author: John M. Novak *)\n\n(* :Summary: \n\tThis package provides various \ utilities for\n\tsearching and working with Mathematica packages.\n*)\n\n(* \ :Package Version: 1.0 *)\n\n(* :Mathematica Version: 2.1 *)\n\n(* :Copyright: \ Copyright 1992-1993, Wolfram Research, Inc. *)\n\n(* :History:\n\tV. 1.0 \ June 92, by John M. Novak.\n*)\n\n(* :Keywords:\n\tpackages, path, keywords\n\ *)\n\n(* :Limitations: *)\n\n(* :Discussion: *)"], "Input", AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["Programming Style"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "A few quick comments on programming style are appropriate here. (Longer \ discussions of this issue can be found elsewhere.) Use transformation rules \ and functional programming where possible; procedural programming is less \ efficient, longer, and clumsier in ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ ". You have achieved this goal to the extent that functions like ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Map", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Apply", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Replace", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Table", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Fold", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Function", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" appear in your code, and ones like ", Evaluatable->False, AspectRatioFixed->True], StyleBox["For", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Do", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["While", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Append", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" do not.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox["Make sparing use of the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Print", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " function. You will notice that it is virtually never used by the built-in \ functions or the standard packages. If you have information to present to the \ user that is a warning or an error, use the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Message", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " function. Chances are that anything else truly meaningful should be \ returned from your function not printed out so it can be used in further \ processing. The liberal use of ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Print", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " statements is a habit forged by use of more traditional languages like C \ and FORTRAN, which are not interactive and are locked into a small set of \ rigid data types. The same comments apply to the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Input", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" function. If you find yourself coding many ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Input", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" statements to get input from the user and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Print", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " statements to display results, this is a good indication that you have \ not made the shift to a ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " mindset, and others will find using your package unfamiliar and \ inconvenient. In cases where you want to provide diagnostic output (for \ example, to alert users to the progress of a calculation), make printed \ output an option. I suggest the name ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Verbose->(True", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" or ", Evaluatable->False, AspectRatioFixed->True], StyleBox["False)", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", with ", Evaluatable->False, AspectRatioFixed->True], StyleBox["False", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" being the default.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["Argument Handling"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "If there are built-in functions that take similar arguments to your \ functions, use the same argument order. For example, in virtually all \ functions that take a filename or stream as an argument, it is the first \ argument. "], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "Proper use of patterns on the left-hand side of function definitions can \ greatly simplify the code required on the right-hand side. For example, you \ could write a single rule with a generic pattern that requires you to do a \ lot of argument testing on the right-hand side:"], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "f[args___] := Module[{var},\n If[Head[{args}[[1]]] =!= \ List,\n do something\n ];\n \ If[Length[{args}] == 1,\n do \ something,\n (* else *)\n do \ something else\n ];\n etc...\n \ ]"], "Input", AspectRatioFixed->True], Cell[TextData[ "Instead, define multiple rules that match specific cases:"], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "f[x_List, y_] := something...\n\nf[x_] := something...\n\netc..."], "Input", AspectRatioFixed->True], Cell[TextData[ "You might also want to write a \"fall-through\" pattern that catches any \ cases not matched by the other definitions. This definition can trigger an \ appropriate error message and then return unevaluated. This technique is \ demonstrated in the \"Error Handling\" section that follows.\n "], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ " Learning to write nontrivial patterns is time well spent, as it will save \ you a lot of work validating arguments in the body of your functions; consult \ Section 2.3 of The ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" Book for more information.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "There are two ways of supplying nonrequired arguments to a function. The \ first, and most common, is to use ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Options", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". The second is to use the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Optional", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " pattern type. There are no hard and fast rules on when to use an ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Optional", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" pattern, but it should be used sparingly, and only one ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Optional", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " pattern should appear in any function definition (you will understand why \ if you try to write a definition with multiple ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Optional", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " objects). Examples of built-in functions that use optional arguments are \ ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Log", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" (where the optional argument is the base) and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Map", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " (where it is a level specification). The order in which the various types \ should appear in a definition is always required arguments first, followed by \ ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Optional", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" ones, followed by ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Options", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". For example:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[" f[x_, level_Integer:1, opts___?OptionQ] := body..."], "Input", AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "Inside the body of the above function you can use the parameter ", Evaluatable->False, AspectRatioFixed->True], StyleBox["level", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " and be sure that it has a value--it will be 1 if the user left it out (as \ in ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f[a]", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox["). The ", Evaluatable->False, AspectRatioFixed->True], StyleBox["opts___?OptionQ", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" pattern is a standard idiom in ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ ". It will match a (possibly empty) sequence of rules or a list of rules. \ The function ", Evaluatable->False, AspectRatioFixed->True], StyleBox["OptionQ", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" is not documented in The ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " Book, but it is an established part of the kernel since Version 2.0. It \ is a very clean and self-documenting way of matching options.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ " There is also a standard way of extracting the values of options. This is \ discussed more completely in Maeder's book, but here is a brief example. \ Let's say the function ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" takes one option, ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Method", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", which has possible values ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Quick", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Dirty", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". You might write a function like:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "Options[f] = {Method->Quick}\n\nf[a_, opts___?OptionQ] :=\n \ Module[{meth},\n meth = Method /. {opts} /. Options[f];\n \ etc...\n ]"], "Input", AspectRatioFixed->True], Cell[TextData[{ StyleBox["Using this technique, ", Evaluatable->False, AspectRatioFixed->True], StyleBox["meth", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" will be whatever value the user specified for the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Method", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" option, or the default value ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Quick", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" if the option was not specified.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["Error Handling"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "User errors should be detected whenever possible, and meaningful messages \ should be generated. This is often overlooked in ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " programming, probably because it is not seen as a high priority and \ because it requires careful, and sometimes clever, programming for which \ there are few well-known idioms.\n ", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ " When bad input is given to a function, or an error is detected during \ execution, you generally have three choices: try to recover from the error \ condition and continue with the calculation, bail out of the calculation and \ return the symbol ", Evaluatable->False, AspectRatioFixed->True], StyleBox["$Failed", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ ", or bail out and return the input \"unevaluated\". If the error is not \ fatal, so that continuation is possible, it is generally a good idea to issue \ a ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Message", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " indicating what has happened (for example, an invalid option value was \ given, and the default is being used instead). If the evaluation cannot be \ performed, it is simplest to just return ", Evaluatable->False, AspectRatioFixed->True], StyleBox["$Failed", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". Any time you return ", Evaluatable->False, AspectRatioFixed->True], StyleBox["$Failed", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", a message should also be issued.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "Most built-in functions return \"unevaluated\" when given inappropriate \ input. \"Unevaluated\" is in quotes because, of course, the functions have \ been evaluated--they are just unchanged by evaluation. Imitating this \ behavior in your own functions is a bit more complicated than returning ", Evaluatable->False, AspectRatioFixed->True], StyleBox["$Failed", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ ". For many types of inappropriate input, your functions will behave this \ way without any effort on your part. For example, if you only define a rule \ for ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" when given a list as an argument and a user executes ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f[1]", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " it will return unevaluated. Ideally, though, your function should issue \ an error message before returning. Here's how you could do that:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "f::list1 = \"The first argument to f must be a list.\";\n\nf[a_List] := \ something\n\nf[_] := holycow /; Message[f::list1]"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[CellGroupData[{Cell[TextData["f[1]"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[TextData["f::list1: The first argument to f must be a list."], "Message", Evaluatable->False, AspectRatioFixed->True], Cell[OutputFormData["\<\ f[1]\ \>", "\<\ f[1]\ \>"], "Output", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[TextData[{ StyleBox["The last definition for ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" is a \"catch-all\" case that traps any calls to ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" where the first argument is not a list. The statement ", Evaluatable->False, AspectRatioFixed->True], StyleBox["holycow", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" is never executed because the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Message", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" function, which is the test in the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Condition", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", doesn't return ", Evaluatable->False, AspectRatioFixed->True], StyleBox["True", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". In other words, you write a phony rule for ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" that will never match any input (because the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Condition", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " always fails), but which triggers a side effect of displaying a ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Message", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[".", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "In the above example, we knew from pattern-matching that the input was \ invalid. If a more complex test of the input is required, you can put the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Condition", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" as the last statement in a ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Module", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[":", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "f[x_List] := Module[{result, test},\n some calculations \ here...\n test = true or false depending on calculations\n \ result /; test\n ]"], "Input", AspectRatioFixed->True], Cell[TextData[{ StyleBox["If test is set to ", Evaluatable->False, AspectRatioFixed->True], StyleBox["False", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Condition", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" fails and ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" pretends that the match to ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f[x_List]", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" never happened, moving on to try other rules for ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". This is a little-known tidbit of ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" programming. Note that ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Condition", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" must be the last statement in the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Module", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" (or ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Block", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" or ", Evaluatable->False, AspectRatioFixed->True], StyleBox["CompoundExpression", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[") for it to work.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox["A good practice is to use preexisting ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ " messages. Many messages are used by more than one built-in function, and \ they are generally defined as though they belonged to the symbol ", Evaluatable->False, AspectRatioFixed->True], StyleBox["General", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". When ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Mathematica", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[" looks for a message with name ", Evaluatable->False, AspectRatioFixed->True], StyleBox["func::tag", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ ", it first looks to see if there is a definition for this specific \ message. If not, it looks for a message of the form ", Evaluatable->False, AspectRatioFixed->True], StyleBox["General::tag", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[", and if such a message exists it uses its text for the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["func::tag", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " message. In this way many symbols can share a set of messages. In the \ example above I used ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f::list1", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " to indicate that a list is needed in argument 1. In fact, a message that \ expresses this is already available, ", Evaluatable->False, AspectRatioFixed->True], StyleBox["General::list", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[":", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[CellGroupData[{Cell[TextData["General::list"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[OutputFormData["\<\ \"List expected at position `2` in `1`.\"\ \>", "\<\ List expected at position `2` in `1`.\ \>"], "Output", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["ComposeList[a,b]"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[TextData[ "ComposeList::list: List expected at position 1 in ComposeList[a, b]."], "Message", Evaluatable->False, AspectRatioFixed->True], Cell[OutputFormData["\<\ ComposeList[a, b]\ \>", "\<\ ComposeList[a, b]\ \>"], "Output", Evaluatable->False, AspectRatioFixed->True]}, Open]], Cell[TextData[{ StyleBox["Note, though, that the placeholder `1` needs to be the entire ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f[...]", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" expression. Here's how you can get at this value:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "Clear[f]\n\nf[a_List] := something\n\np:Literal[f[a_]] := holycow /; \ Message[f::list, HoldForm[p], 1]"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[TextData[{ StyleBox["Now ", Evaluatable->False, AspectRatioFixed->True], StyleBox["f", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" behaves just like a built-in function:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[CellGroupData[{Cell[TextData["f[1]"], "Input", InitializationCell->True, AspectRatioFixed->True], Cell[TextData["f::list: List expected at position 1 in f[1]."], "Message", Evaluatable->False, AspectRatioFixed->True], Cell[OutputFormData["\<\ f[1]\ \>", "\<\ f[1]\ \>"], "Output", Evaluatable->False, AspectRatioFixed->True]}, Open]]}, Open]], Cell[CellGroupData[{Cell[TextData["Tread Lightly on the System"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "The state of a user's session should not be unnecessarily changed by \ loading your package or evaluating one of its functions. For example, don't ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Unprotect", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " and modify system symbols unless absolutely necessary, and never change \ their ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Attributes", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[". Similarly, avoid changing global variables (", Evaluatable->False, AspectRatioFixed->True], StyleBox["i.e.", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[", ", Evaluatable->False, AspectRatioFixed->True], StyleBox["System`", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" globals, whose names usually begin with a ", Evaluatable->False, AspectRatioFixed->True], StyleBox["$", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox["). Your package should never put symbols in the ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Global`", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " context or rely on the presence of certain symbols in that context.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox["If you must ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Unprotect", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[ " symbols other than your own, make sure that you restore them to their \ previous protection state. You can do this by using the idiom introduced by \ Maeder:", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "protected = Unprotect[Symbol1, Symbol2]\n\nmodify Symbol1 and Symbol2....\n\n\ Protect[Evaluate[protected]]"], "Input", AspectRatioFixed->True], Cell[TextData[ "If you turn off messages temporarily, make certain that you restore them to \ their original state, whether that was on or off. This is a particularly \ common error (you can see several examples in the standard packages). Here is \ a code fragment that shows how to properly turn messages off and back on:"], "Text", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[ "wasOn = Head[f::msg] =!= $Off;\nOff[f::msg];\n\ncode that would trigger the \ f::msg message....\n\nIf[wasOn, On[f::msg]];"], "Input", AspectRatioFixed->True]}, Open]], Cell[CellGroupData[{Cell[TextData["Testing"], "Section", Evaluatable->False, AspectRatioFixed->True], Cell[TextData[{ StyleBox[ "Testing is important for any package, no matter how small. Developing a \ standard test suite for each package will not only help you find most of the \ bugs (you never find all of them), it will also help you maintain your code \ and serve as an invaluable final check on the design and implementation. \ Wolfram Research has a package called ", Evaluatable->False, AspectRatioFixed->True], StyleBox["Testing.m", Evaluatable->False, AspectRatioFixed->True, FontFamily->"Courier", FontWeight->"Bold"], StyleBox[" (available on ", Evaluatable->False, AspectRatioFixed->True], StyleBox["MathSource", Evaluatable->False, AspectRatioFixed->True, FontSlant->"Italic"], StyleBox[ ") that will help you create and manage a test suite. Ideally, the tests \ should exercise every branch of every function, including error conditions. \ Pay special attention to checking that your functions do something sensible \ with any type of input, no matter how improper.", Evaluatable->False, AspectRatioFixed->True] }], "Text", Evaluatable->False, AspectRatioFixed->True]}, Open]]}, Open]] }, FrontEndVersion->"Macintosh 3.0", ScreenRectangle->{{0, 640}, {0, 460}}, AutoGeneratedPackage->None, WindowToolbars->{}, CellGrouping->Manual, WindowSize->{520, 365}, WindowMargins->{{44, Automatic}, {Automatic, 1}}, PrivateNotebookOptions->{"ColorPalette"->{RGBColor, -1}}, ShowCellLabel->True, ShowCellTags->False, RenderingOptions->{"ObjectDithering"->True, "RasterDithering"->False}, MacintoshSystemPageSetup->"\<\ AVU/IFiQKFD000000V7E<09QgO0000000OZ:d096/NP0AP1Y06`0I@1^0642HMD` 0V7N40000001nXZ`0TJaj000000000000000009QeC0000000000000000000000 00000000000000000000000000000000\>" ] (*********************************************************************** Cached data follows. If you edit this Notebook file directly, not using Mathematica, you must remove the line containing CacheID at the top of the file. The cache data will then be recreated when you save this file from within Mathematica. ***********************************************************************) (*CellTagsOutline CellTagsIndex->{} *) (*CellTagsIndex CellTagsIndex->{} *) (*NotebookFileOutline Notebook[{ Cell[CellGroupData[{ Cell[1731, 51, 89, 2, 70, "Title", Evaluatable->False], Cell[1823, 55, 112, 2, 70, "Subtitle", Evaluatable->False], Cell[1938, 59, 586, 9, 70, "Text", Evaluatable->False], Cell[2527, 70, 716, 19, 70, "Text", Evaluatable->False], Cell[3246, 91, 615, 17, 70, "Text", Evaluatable->False], Cell[3864, 110, 1397, 34, 70, "Text", Evaluatable->False], Cell[5264, 146, 1075, 33, 70, "Text", Evaluatable->False], Cell[CellGroupData[{ Cell[6362, 181, 83, 2, 70, "Section", Evaluatable->False], Cell[6448, 185, 1113, 25, 70, "Text", Evaluatable->False] }, Closed]], Cell[CellGroupData[{ Cell[7593, 212, 87, 2, 70, "Section", Evaluatable->False], Cell[7683, 216, 605, 18, 70, "Text", Evaluatable->False], Cell[8291, 236, 2965, 78, 70, "Input"], Cell[11259, 316, 1998, 65, 70, "Text", Evaluatable->False], Cell[13260, 383, 572, 8, 70, "Input"] }, Closed]], Cell[CellGroupData[{ Cell[13864, 393, 94, 2, 70, "Section", Evaluatable->False], Cell[13961, 397, 2633, 98, 70, "Text", Evaluatable->False], Cell[16597, 497, 3139, 100, 70, "Text", Evaluatable->False] }, Closed]], Cell[CellGroupData[{ Cell[19768, 599, 94, 2, 70, "Section", Evaluatable->False], Cell[19865, 603, 302, 6, 70, "Text", Evaluatable->False], Cell[20170, 611, 352, 6, 70, "Text", Evaluatable->False], Cell[20525, 619, 444, 7, 70, "Input"], Cell[20972, 628, 132, 3, 70, "Text", Evaluatable->False], Cell[21107, 633, 118, 2, 70, "Input"], Cell[21228, 637, 368, 6, 70, "Text", Evaluatable->False], Cell[21599, 645, 520, 16, 70, "Text", Evaluatable->False], Cell[22122, 663, 2595, 88, 70, "Text", Evaluatable->False], Cell[24720, 753, 104, 1, 70, "Input"], Cell[24827, 756, 1710, 59, 70, "Text", Evaluatable->False], Cell[26540, 817, 1171, 41, 70, "Text", Evaluatable->False], Cell[27714, 860, 236, 4, 70, "Input"], Cell[27953, 866, 854, 30, 70, "Text", Evaluatable->False] }, Closed]], Cell[CellGroupData[{ Cell[28839, 898, 91, 2, 70, "Section", Evaluatable->False], Cell[28933, 902, 629, 18, 70, "Text", Evaluatable->False], Cell[29565, 922, 1578, 48, 70, "Text", Evaluatable->False], Cell[31146, 972, 1369, 39, 70, "Text", Evaluatable->False], Cell[32518, 1013, 205, 4, 70, "Input", InitializationCell->True], Cell[CellGroupData[{ Cell[32746, 1019, 85, 2, 70, "Input", InitializationCell->True], Cell[32834, 1023, 126, 2, 70, "Message", Evaluatable->False], Cell[32963, 1027, 110, 6, 70, "Output", Evaluatable->False] }, Open ]], Cell[33085, 1035, 2243, 79, 70, "Text", Evaluatable->False], Cell[35331, 1116, 710, 24, 70, "Text", Evaluatable->False], Cell[36044, 1142, 260, 4, 70, "Input"], Cell[36307, 1148, 2277, 84, 70, "Text", Evaluatable->False], Cell[38587, 1234, 2280, 76, 70, "Text", Evaluatable->False], Cell[CellGroupData[{ Cell[40890, 1312, 94, 2, 70, "Input", InitializationCell->True], Cell[40987, 1316, 181, 7, 70, "Output", Evaluatable->False] }, Open ]], Cell[CellGroupData[{ Cell[41200, 1325, 97, 2, 70, "Input", InitializationCell->True], Cell[41300, 1329, 149, 4, 70, "Message", Evaluatable->False], Cell[41452, 1335, 137, 7, 70, "Output", Evaluatable->False] }, Open ]], Cell[41601, 1344, 447, 14, 70, "Text", Evaluatable->False], Cell[42051, 1360, 185, 4, 70, "Input", InitializationCell->True], Cell[42239, 1366, 373, 14, 70, "Text", Evaluatable->False], Cell[CellGroupData[{ Cell[42635, 1382, 85, 2, 70, "Input", InitializationCell->True], Cell[42723, 1386, 122, 2, 70, "Message", Evaluatable->False], Cell[42848, 1390, 110, 6, 70, "Output", Evaluatable->False] }, Open ]] }, Closed]], Cell[CellGroupData[{ Cell[42999, 1398, 104, 2, 70, "Section", Evaluatable->False], Cell[43106, 1402, 1725, 59, 70, "Text", Evaluatable->False], Cell[44834, 1463, 511, 17, 70, "Text", Evaluatable->False], Cell[45348, 1482, 161, 3, 70, "Input"], Cell[45512, 1487, 384, 7, 70, "Text", Evaluatable->False], Cell[45899, 1496, 176, 3, 70, "Input"] }, Closed]], Cell[CellGroupData[{ Cell[46107, 1501, 84, 2, 70, "Section", Evaluatable->False], Cell[46194, 1505, 1151, 30, 70, "Text", Evaluatable->False] }, Closed]] }, Open ]] } ] *) (*********************************************************************** End of Mathematica Notebook file. ***********************************************************************)