From a7855e20a8b1b8e35bd7dac0718e2fd76d3b09c0 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Mon, 22 Aug 2011 15:00:05 -0600 Subject: [PATCH] add `raco link' includes a rewrite the "Module Basics" section of the Guide --- collects/compiler/compiler-unit.rkt | 59 +- collects/config/.gitignore | 1 + collects/racket/sandbox.rkt | 1 + .../scribblings/guide/hash-languages.scrbl | 70 +- .../scribblings/guide/module-basics.scrbl | 262 ++++- collects/scribblings/guide/module-hier.rkt | 97 ++ collects/scribblings/guide/welcome.scrbl | 11 +- collects/scribblings/raco/common.rkt | 6 +- collects/scribblings/raco/link.scrbl | 107 ++ collects/scribblings/raco/raco.scrbl | 1 + collects/scribblings/raco/setup.scrbl | 29 +- collects/scribblings/reference/collects.scrbl | 74 +- .../scribblings/reference/filesystem.scrbl | 11 +- collects/scribblings/reference/mz.rkt | 6 +- collects/scribblings/reference/startup.scrbl | 14 +- collects/setup/collects.rkt | 2 +- collects/setup/commands/link.rkt | 74 ++ collects/setup/getinfo.rkt | 29 +- collects/setup/info.rkt | 3 +- collects/setup/link.rkt | 157 +++ collects/setup/private/omitted-paths.rkt | 13 +- collects/setup/private/path-utils.rkt | 4 +- collects/setup/scribble.rkt | 11 +- collects/setup/setup-unit.rkt | 177 ++-- collects/setup/xref.rkt | 9 +- doc/release-notes/racket/HISTORY.txt | 4 + src/racket/cmdline.inc | 38 +- src/racket/include/scheme.h | 1 + src/racket/include/schthread.h | 2 + src/racket/src/cstartup.inc | 910 ++++++++++-------- src/racket/src/file.c | 50 +- src/racket/src/schpriv.h | 2 + src/racket/src/schvers.h | 4 +- src/racket/src/startup.inc | 349 +++++-- src/racket/src/startup.rktl | 423 +++++--- src/racket/src/thread.c | 1 + 36 files changed, 2180 insertions(+), 832 deletions(-) create mode 100644 collects/config/.gitignore create mode 100644 collects/scribblings/guide/module-hier.rkt create mode 100644 collects/scribblings/raco/link.scrbl create mode 100644 collects/setup/commands/link.rkt create mode 100644 collects/setup/link.rkt diff --git a/collects/compiler/compiler-unit.rkt b/collects/compiler/compiler-unit.rkt index 43d7c509ba..c6906efd8b 100644 --- a/collects/compiler/compiler-unit.rkt +++ b/collects/compiler/compiler-unit.rkt @@ -144,12 +144,12 @@ (let ([zo (append-zo-suffix b)]) (compile-to-zo f zo n prefix verbose? mod?))))) - (define (compile-directory-visitor dir info worker - #:verbose [verbose? #t] - #:skip-path [orig-skip-path #f] - #:skip-doc-sources? [skip-docs? #f]) + (define (compile-directory-visitor dir info worker omit-root + #:verbose [verbose? #t] + #:skip-path [orig-skip-path #f] + #:skip-doc-sources? [skip-docs? #f]) (define info* (or info (lambda (key mk-default) (mk-default)))) - (define omit-paths (omitted-paths dir c-get-info/full)) + (define omit-paths (omitted-paths dir c-get-info/full omit-root)) (define skip-path (and orig-skip-path (path->bytes (simplify-path (if (string? orig-skip-path) (string->path orig-skip-path) @@ -191,10 +191,10 @@ (for/fold ([init init]) ([p (directory-list dir)]) (let ([p* (build-path dir p)]) (if (and (directory-exists? p*) (not (member p omit-paths))) - (compile-directory-visitor p* (c-get-info/full p*) worker + (compile-directory-visitor p* (c-get-info/full p*) worker omit-root #:verbose verbose? - #:skip-path skip-path - #:skip-doc-sources? skip-docs?) + #:skip-path skip-path + #:skip-doc-sources? skip-docs?) init)))) init)))) (define (compile-directory dir info @@ -202,34 +202,43 @@ #:skip-path [orig-skip-path #f] #:skip-doc-sources? [skip-docs? #f] #:managed-compile-zo [managed-compile-zo - (make-caching-managed-compile-zo)]) + (make-caching-managed-compile-zo)] + #:omit-root [omit-root dir]) (define (worker prev sses) (for-each managed-compile-zo sses)) - (compile-directory-visitor dir info worker - #:verbose verbose? - #:skip-path orig-skip-path - #:skip-doc-sources? skip-docs?)) - + (compile-directory-visitor dir info worker omit-root + #:verbose verbose? + #:skip-path orig-skip-path + #:skip-doc-sources? skip-docs?)) + (define (get-compile-directory-srcs dir info - #:verbose [verbose? #t] - #:skip-path [orig-skip-path #f] - #:skip-doc-sources? [skip-docs? #f] - #:managed-compile-zo [managed-compile-zo - (make-caching-managed-compile-zo)]) - (compile-directory-visitor dir info append - #:verbose verbose? - #:skip-path orig-skip-path - #:skip-doc-sources? skip-docs? - #:managed-compile-zo managed-compile-zo)) + #:verbose [verbose? #t] + #:skip-path [orig-skip-path #f] + #:skip-doc-sources? [skip-docs? #f] + #:managed-compile-zo [managed-compile-zo + (make-caching-managed-compile-zo)] + #:omit-root [omit-root dir]) + (compile-directory-visitor dir info append omit-root + #:verbose verbose? + #:skip-path orig-skip-path + #:skip-doc-sources? skip-docs? + #:managed-compile-zo managed-compile-zo)) + + (define unspec (gensym)) (define (compile-collection-zos collection #:skip-path [skip-path #f] #:skip-doc-sources? [skip-docs? #f] #:managed-compile-zo [managed-compile-zo (make-caching-managed-compile-zo)] + #:omit-root [omit-root unspec] . cp) - (compile-directory (apply collection-path collection cp) + (define dir (apply collection-path collection cp)) + (compile-directory dir (c-get-info (cons collection cp)) + #:omit-root (if (eq? omit-root unspec) + dir + omit-root) #:verbose #f #:skip-path skip-path #:skip-doc-sources? skip-docs? diff --git a/collects/config/.gitignore b/collects/config/.gitignore new file mode 100644 index 0000000000..664f8291f2 --- /dev/null +++ b/collects/config/.gitignore @@ -0,0 +1 @@ +/links.rktd diff --git a/collects/racket/sandbox.rkt b/collects/racket/sandbox.rkt index 766c8623ea..0fb9aa9106 100644 --- a/collects/racket/sandbox.rkt +++ b/collects/racket/sandbox.rkt @@ -890,6 +890,7 @@ (current-library-collection-paths)) (read-bytecode ,(PLANET-BASE-DIR)) (exists ,(find-system-path 'addon-dir)) + (read ,(find-system-path 'links-file)) ,@(compute-permissions allow) ,@(sandbox-path-permissions))] ;; general info diff --git a/collects/scribblings/guide/hash-languages.scrbl b/collects/scribblings/guide/hash-languages.scrbl index 4cf5b57aee..3ffb116aaa 100644 --- a/collects/scribblings/guide/hash-languages.scrbl +++ b/collects/scribblings/guide/hash-languages.scrbl @@ -203,32 +203,50 @@ access languages like @filepath{literal.rkt} and @filepath{literal.rkt} into a Racket @tech{collection} named @filepath{literal}. -To install a collection, you can create a directory either in the main -Racket installation or in a user-specific directory. Use -@racket[find-collects-dir] or @racket[find-user-collects-dir] from -@racketmodname[setup/dirs] to find the directory: +There are two ways to create the @filepath{literal} collection (see +also @secref["link-collection"]): -@interaction[ -(require setup/dirs) -(eval:alts (find-user-collects-dir) - (build-path "/home/racketeer/.racket/" - (version) - "collects")) -] +@itemlist[ -Move @filepath{literal.rkt} to @filepath{literal/lang/reader.rkt} -within the directory reported by @racket[find-collects-dir] or -@racket[find-user-collects-dir]. That is, the file -@filepath{literal.rkt} must be renamed to @filepath{reader.rkt} and -placed in a @filepath{lang} sub-directory of the @filepath{literal} -collection. + @item{You can create a directory either in the main Racket + installation or in a user-specific directory. Use + @racket[find-collects-dir] or @racket[find-user-collects-dir] + from @racketmodname[setup/dirs] to find the directory: + + @interaction[ + (require setup/dirs) + (eval:alts (find-user-collects-dir) + (build-path "/home/racketeer/.racket/" + (version) + "collects")) + ] + + Move @filepath{literal.rkt} to + @filepath{literal/lang/reader.rkt} within the directory reported + by @racket[find-collects-dir] or + @racket[find-user-collects-dir]. That is, the file + @filepath{literal.rkt} must be renamed to @filepath{reader.rkt} + and placed in a @filepath{lang} sub-directory of the + @filepath{literal} collection. + + @racketblock[ + .... @#,elem{(the main installation or the user's space)} + !- @#,filepath{collects} + !- @#,filepath{literal} + !- @#,filepath{lang} + !- @#,filepath{reader.rkt} + ]} + + @item{Alternatively, move @filepath{literal.rkt} to + @filepath{literal/lang/reader.rkt} for any directory name + @filepath{literal}. Then, in the directory that contains + @filepath{literal}, use the command line + + @commandline{raco link literal} + + to register the @filepath{literal} directory as the + @filepath{literal} collection.} -@racketblock[ -.... @#,elem{(the main installation or the user's space)} - !- @#,filepath{collects} - !- @#,filepath{literal} - !- @#,filepath{lang} - !- @#,filepath{reader.rkt} ] After moving the file, you can use @racket[literal] directly after @@ -247,17 +265,17 @@ for more information on using @exec{raco}.} You can also package a collection for others to install by using the @exec{raco pack} command-line tool: -@commandline{raco pack --collection literal.plt literal} +@commandline{raco pack --collect literal.plt literal} Then, others can install the @filepath{literal} collection using @exec{raco setup}: -@commandline{raco setup literal.plt} +@commandline{raco setup -A literal.plt} @margin-note{See @other-manual['(lib "planet/planet.scrbl")] for more information about @|PLaneT| packages.} -A better approach may be to distribute your language as a @|PLaneT| +Another approach is to distribute your language as a @|PLaneT| package. A drawback of using a @|PLaneT| package is that users must type @racket[@#,hash-lang[] @#,racketmodname[planet]] followed by a @|PLaneT| path to access the language. The great advantages are that the diff --git a/collects/scribblings/guide/module-basics.scrbl b/collects/scribblings/guide/module-basics.scrbl index 666d4cdf29..e475f2851e 100644 --- a/collects/scribblings/guide/module-basics.scrbl +++ b/collects/scribblings/guide/module-basics.scrbl @@ -1,38 +1,47 @@ #lang scribble/doc -@(require scribble/manual scribble/eval "guide-utils.rkt" - (for-label setup/dirs)) +@(require scribble/manual + scribble/eval + "guide-utils.rkt" + "module-hier.rkt" + (for-label setup/dirs + setup/link + racket/date)) @title[#:tag "module-basics"]{Module Basics} -The space of module names is distinct from the space of normal Racket -definitions. Indeed, since modules typically reside in files, the -space of module names is explicitly tied to the filesystem at run -time. For example, if the file @filepath{/home/molly/cake.rkt} contains +Each Racket module typically resides in its own file. For example, +suppose the file @filepath{cake.rkt} contains the following module: @racketmod[ +#:file "cake.rkt" racket (provide print-cake) (code:comment @#,t{draws a cake with @racket[n] candles}) (define (print-cake n) - (printf " ~a \n" (make-string n #\.)) - (printf " .-~a-.\n" (make-string n #\|)) - (printf " | ~a |\n" (make-string n #\space)) - (printf "---~a---\n" (make-string n #\-))) + (show " ~a " n #\.) + (show " .-~a-. " n #\|) + (show " | ~a | " n #\space) + (show "---~a---" n #\-)) + +(define (show fmt n ch) + (printf fmt (make-string n ch)) + (newline)) ] -then it can be used as the source of a module whose full name is based -on the path @filepath{/home/molly/cake.rkt}. The @racket[provide] line -exports the definition @racket[print-cake] so that it can be used -outside the module. +Then, other modules can import @filepath{cake.rkt} to use the +@racket[print-cake] function, since the @racket[provide] line in +@filepath{cake.rkt} explicitly exports the definition +@racket[print-cake]. The @racket[show] function is private to +@filepath{cake.rkt} (i.e., it cannot be used from other modules), +since @racket[show] is not exported. -Instead of using its full path, a module is more likely to be -referenced by a relative path. For example, a file -@filepath{/home/molly/random-cake.rkt} could use the @filepath{cake.rkt} module -like this: +The following @filepath{random-cake.rkt} module imports +@filepath{cake.rkt}: @racketmod[ +#:file "random-cake.rkt" racket (require "cake.rkt") @@ -41,17 +50,90 @@ racket ] The relative reference @racket["cake.rkt"] in the import -@racket[(require "cake.rkt")] works because the @filepath{cake.rkt} module -source is in the same directory as the @filepath{random-cake.rkt} -file. (Unix-style relative paths are used for relative module -references on all platforms, much like relative URLs.) +@racket[(require "cake.rkt")] works if the @filepath{cake.rkt} and +@filepath{random-cake.rkt} modules are in the same +directory. (Unix-style relative paths are used for relative module +references on all platforms, much like relative URLs in HTML pages.) -Library modules that are distributed with Racket are usually -referenced through an unquoted, suffixless path. The path is relative -to the library installation directory, which contains directories for -individual library @deftech{collections}. The module below refers to -the @filepath{date.rkt} library that is part of the @filepath{racket} -@tech{collection}. +@; ---------------------------------------- +@section[#:tag "module-org"]{Organizing Modules} + +The @filepath{cake.rkt} and @filepath{random-cake.rkt} example +demonstrates the most common way to organize a program into modules: +put all module files in a single directory (perhaps with +subdirectories), and then have the modules reference each other +through relative paths. A directory of modules can act as a +project, since it can be moved around on the filesystem or copied to +other machines, and relative paths preserve the connections among +modules. + +As another example, if you are building a candy-sorting program, you +might have a main @filepath{sort.rkt} module that uses other modules +to access a candy database and a control sorting machine. If the +candy-database module itself is organized into sub-modules that handle +barcode and manufacturer information, then the database module could +be @filepath{db/lookup.rkt} that uses helper modules +@filepath{db/barcodes.rkt} and @filepath{db/makers.rkt}. Similarly, +the sorting-machine driver @filepath{machine/control.rkt} might use +helper modules @filepath{machine/sensors.rkt} and +@filepath{machine/actuators.rkt}. + +@centerline[module-hierarchy] + +The @filepath{sort.rkt} module uses the relative paths +@filepath{db/lookup.rkt} and @filepath{machine/control.rkt} to import +from the database and machine-control libraries: + +@racketmod[ +#:file "sort.rkt" +racket +(require "db/lookup.rkt" "machine/control.rkt") +....] + +The @filepath{db/lookup.rkt} module similarly uses paths relative to +its own source to access the @filepath{db/barcodes.rkt} and +@filepath{db/makers.rkt} modules: + + +@racketmod[ +#:file "db/lookup.rkt" +racket +(require "barcode.rkt" "makers.rkt") +....] + +Ditto for @filepath{machine/control.rkt}: + +@racketmod[ +#:file "machine/control.rkt" +racket +(require "sensors.rkt" "actuators.rkt") +....] + +Racket tools all work automatically with relative paths. For example, + +@commandline{racket sort.rkt} + +on the comamnd line runs the @filepath{sort.rkt} program and +automatically loads and compiles required modules. With a large enough +program, compilation from source can take too long, so use + +@commandline{raco make sort.rkt} + +to compile @filepath{sort.rkt} and all its dependencies to bytecode +files. Running @exec{racket sort.rkt} will automatically use bytecode +files when they are present. + +@margin-note{See @secref[#:doc '(lib "scribblings/raco/raco.scrbl") +"make"] for more information on @exec{raco make}.} + +@; ---------------------------------------- +@section{Library Collections} + +A @deftech{collection} is a set of installed library modules. A +module in a @tech{collection} is referenced through an unquoted, +suffixless path. For example, the following module refers to the +@filepath{date.rkt} library that is part of the @filepath{racket} +@tech{collection}: @racketmod[ racket @@ -62,12 +144,41 @@ racket (date->string (seconds->date (current-seconds)))) ] -In addition to the main @tech{collection} directory, which contains -all collections that are part of the installation, collections can -also be installed in a user-specific location. Finally, additional -collection directories can be specified in configuration files or -through the @envvar{PLTCOLLECTS} search path. Try running the -following program to find out where your collections are: +When you search the online Racket documentation, the search results +indicate the module that provides each binding. Alternatively, if you +reach a binding's documentation by clicking on hyperlinks, you can +hover over the binding name to find out which modules provide +it. + +A module reference like @racketmodname[racket/date] looks like an +identifier, but it is not treated in the same way as @racket[printf] +or @racket[date->string]. Instead, when @racket[require] sees a module +reference that is unquoted, it converts the reference to a +collection-based module path: + +@itemlist[ + + @item{First, if the unquoted path contains no @litchar{/}, then + @racket[require] automatically adds a @filepath{/main} to the + reference. For example, @racket[(require + @#,racketmodname[slideshow])] is equivalent to @racket[(require + slideshow/main)].} + + @item{Second, @racket[require] implicitly adds a @filepath{.rkt} + suffix to the path.} + + @item{Finally, @racket[require] treats the path as relative to the + installation location of the collection, instead of relative to + the enclosing module's path.} + +] + +The @filepath{racket} collection is located in a directory with the +Racket installation. A user-specific directory can contain additional +collections, and even more collection directories can be specified in +configuration files or through the @envvar{PLTCOLLECTS} search +path. Try running the following program to find out how your +collection search path is configured: @racketmod[ racket @@ -79,5 +190,84 @@ racket (get-collects-search-dirs) (code:comment @#,t{complete search path}) ] -We discuss more forms of module reference later in -@secref["module-paths"]. +@; ---------------------------------------- +@section[#:tag "link-collection"]{Adding Collections} + +Looking back at the candy-sorting example of @secref["module-org"], +suppose that modules in @filepath{db/} and @filepath{machine/} need a +common set of helper functions. Helper functions could be put in a +@filepath{utils/} directory, and modules in @filepath{db/} or +@filepath{machine/} could access utility modules with relative paths +that start @filepath{../utils/}. As long as a set of modules work +together in a single project, it's best to stick with relative paths. +A programmer can follow relative-path references without knowing about +your Racket configuration. + +Some libraries are meant to be used across multiple projects, so that +keeping the library source in a directory with its uses does not make +sense. In that case, you have two options: + +@itemlist[ + + @item{Add the library to a new or existing @tech{collection}. After + the library is in a collection, it can be referenced with an + unquoted path, just like libraries that are included with the + Racket distribution.} + + @item{Add the library a new or existing @|PLaneT| package. Libraries + in a @|PLaneT| package are referenced with a path of the form + @racket[(planet ....)] path. + + @margin-note{See @other-doc['(lib "planet/planet.scrbl")] + for more information on @|PLaneT|.}} + +] + +The simplest option is to add a new collection. You could add a new +collection by placing files in the Racket installation or one of the +directories reported by @racket[(get-collects-search-dirs)]---perhaps +setting the @envvar{PLTCOLLECTS} environment variable to extend the +search path---but using @exec{raco link} is usually the best approach. + +The @exec{raco link} command-line tool creates a link from a collection +name to a directory for the collection's modules. For example, suppose +you have a directory @filepath{/usr/molly/bakery} that contains the +@filepath{cake.rkt} module (from the +@seclink["module-basics"]{beginning} of this section) and other +related modules. To make the modules available as a @filepath{bakery} +collection, use + +@commandline{raco link /usr/molly/bakery} + +Afterward, @racket[(require bakery/cake)] from any module will import +the @racket[print-cake] function from +@filepath{/usr/molly/bakery/cake.rkt}. + +To make a collection name different from the name of the directory +that contains the collection's modules, use the @DFlag{name} or +@Flag{n} option for @exec{raco link}. By default, @exec{raco link} +installs a collection link only for the current user, but you can +supply the @DFlag{installation} or @Flag{i} flag to install the link +for all users of your Racket installation. + +@margin-note{See @secref[#:doc '(lib "scribblings/raco/raco.scrbl") +"link"] for more information on @exec{raco link}.} + +If you intend to distribute your library collection to others, choose +the collection name carefully. The collection namespace is +hierarchical, but (unlike @|PLaneT|) the collection system has no +built-in feature to avoid conflicts from different producers or +different versions. Consider putting one-off libraries under some +top-level name like @filepath{molly} that identifies the producer. +Use a collection name like @filepath{bakery} when producing the +definitive collection of baked-goods libraries. + +After your libraries are in a @tech{collection}, then you can still +use @exec{raco make} to compile the library sources, but it's better +and more convenient to use @exec{raco setup}. The @exec{raco setup} +command takes a collection name (as opposed to a file name) and +compiles all libraries within the collection. In addition, it can +build documentation for the collection and add it to the documentation +index, as specified by a @filepath{info.rkt} module in the collection. +See @secref[#:doc '(lib "scribblings/raco/raco.scrbl") "setup"] for +more information on @exec{raco setup}. diff --git a/collects/scribblings/guide/module-hier.rkt b/collects/scribblings/guide/module-hier.rkt new file mode 100644 index 0000000000..ab2196aa54 --- /dev/null +++ b/collects/scribblings/guide/module-hier.rkt @@ -0,0 +1,97 @@ +#lang racket/base +(require slideshow/pict + racket/draw + racket/class + racket/math) + +(provide module-hierarchy) + +(define GAP 12) + +(define file-color (make-object color% #xEC #xF5 #xF5)) + +(define folder + (let () + (define W 200) + (define H 144) + (define dy (* -8/3 2)) + (define p (make-object dc-path%)) + (send p move-to 0 50) + (send p arc 0 (+ 22 dy) 8 8 pi (/ pi 2) #f) + (send p arc 2 (+ 18 dy) 4 4 (/ pi -2) 0 #t) + (send p arc 6 0 20 20 pi (/ pi 2) #f) + (send p line-to 60 0) + (send p arc 50 0 20 20 (/ pi 2) 0 #f) + (send p arc 70 (+ 22 dy) 2 2 pi (* 3/2 pi)) + (send p arc 180 (+ 24 dy) 20 20 (/ pi 2) 0 #f) + (send p arc 180 120 20 20 0 (/ pi -2) #f) + (send p arc 0 120 20 20 (/ pi -2) (- pi) #f) + (send p close) + + (scale + (dc (lambda (dc x y) + (define b (send dc get-brush)) + (send dc set-brush file-color 'solid) + (send dc draw-path p x y) + (send dc set-brush b)) + W H) + 12/32))) + +(define file + (file-icon (/ 75 2) 54 file-color)) + +(define (lbl i t) + (vc-append 4 i (text t '(bold . modern) 12))) + +(define (listing p) + (frame (inset p GAP) + #:color "blue")) + +(define db-folder (launder folder)) +(define mach-folder (launder folder)) +(define db-listing + (listing + (vc-append + GAP + (lbl file "control.rkt") + (hc-append (* 2 GAP) + (lbl file "sensors.rkt") + (lbl file "actuators.rkt"))))) +(define mach-listing + (listing + (vc-append + GAP + (lbl file "lookup.rkt") + (hc-append (* 2 GAP) + (lbl file "barcodes.rkt") + (lbl file "makers.rkt"))))) + +(define (zoom from to p) + (pin-line + (pin-line p + from lb-find + to lt-find + #:style 'dot) + from rb-find + to rt-find + #:style 'dot)) + + +(define module-hierarchy + (inset + (zoom + db-folder db-listing + (zoom + mach-folder mach-listing + (vc-append + (* 3 GAP) + (listing + (hc-append (* 4 GAP) + (lbl file "sort.rkt") + (lbl db-folder "db") + (lbl mach-folder "machine"))) + (hc-append + (* 2 GAP) + db-listing + mach-listing)))) + 2)) diff --git a/collects/scribblings/guide/welcome.scrbl b/collects/scribblings/guide/welcome.scrbl index cad0a39f76..a5fab120c0 100644 --- a/collects/scribblings/guide/welcome.scrbl +++ b/collects/scribblings/guide/welcome.scrbl @@ -162,9 +162,14 @@ racket (extract "the cat out of the bag") ] -then it is a complete program that prints ``cat'' when run. To -package this program as an executable, choose one of the following -options: +then it is a complete program that prints ``cat'' when run. You can +run the program within DrRacket or using @racket[enter!] in +@exec{racket}, but if the program is saved in @nonterm{src-filename}, +you can also run it from a command line with + +@commandline{racket @nonterm{src-filename}} + +To package the program as an executable, you have a few options: @itemize[ diff --git a/collects/scribblings/raco/common.rkt b/collects/scribblings/raco/common.rkt index 378cffeaff..983db069ba 100644 --- a/collects/scribblings/raco/common.rkt +++ b/collects/scribblings/raco/common.rkt @@ -1,7 +1,11 @@ #lang scheme/base (require scribble/manual) -(provide inside-doc) +(provide inside-doc + reference-doc) (define inside-doc '(lib "scribblings/inside/inside.scrbl")) + +(define reference-doc + '(lib "scribblings/reference/reference.scrbl")) diff --git a/collects/scribblings/raco/link.scrbl b/collects/scribblings/raco/link.scrbl new file mode 100644 index 0000000000..452471e6f6 --- /dev/null +++ b/collects/scribblings/raco/link.scrbl @@ -0,0 +1,107 @@ +#lang scribble/doc +@(require scribble/manual + scribble/bnf + "common.rkt" + (for-label racket/base)) + +@title[#:tag "link"]{@exec{raco link}: Library Collection Links} + +The @exec{raco link} command inspects and modifies a @tech[#:doc +reference-doc]{collection links file} to display, add, or remove +mappings from collection names to filesystem directories. + +For example, the command + +@commandline{raco link maze} + +installs a user-specific link for the @racket["maze"] collection, +mapping it to the @filepath{maze} subdirectory of the current +directory. Supply multiple directory paths to create multiple links at +once, especially with a command-shell wildcard: + +@commandline{raco link *} + +By default, the linked collection name is the same as each directory's +name, but the collection name can be set separately for a single +directory with the @DFlag{name} flag. + +To remove the link created by the first example above, use + +@commandline{raco link --remove maze} + +or + +@commandline{raco link -r maze} + +Like link-adding mode, removing mode accepts multiple directory paths to +remove multiple links, and all links that match any directory are +removed. If @DFlag{name} is used with @DFlag{remove}, then only +links matching both the collection name and directory are removed. + +Full command-line options: + +@itemlist[ + + @item{@Flag{s} or @DFlag{show} --- Shows the current link table. If + any other command-line arguments are provided that modify the + link table, the table is shown after modifications. If no + directory arguments are provided, and if none of @Flag{r}, + @DFlag{remove}, @Flag{i}, @DFlag{installation}, @Flag{f}, or + @DFlag{file} are specified, then the link table is shown for + both the user-specific and installation-wide @tech[#:doc + reference-doc]{collection links files}.} + + @item{@Flag{n} @nonterm{name} or @DFlag{name} @nonterm{name} --- Sets + the collection name for adding or removing a single link. By + default, the collection name for an added link is derived from + the directory name. When the @Flag{r} or @DFlag{remove} flag is + also used, only links with a collection name matching + @nonterm{name} are removed.} + + @item{@Flag{x} @nonterm{regexp} or @DFlag{version-regexp} + @nonterm{regexp} --- Sets a version regexp that limits the link + to use only by Racket versions (as reported by + @racket[version]) matching @nonterm{regexp}. When the @Flag{r} + or @DFlag{remove} flag is also used, only links with a + version regexp matching @nonterm{regexp} are removed.} + + @item{@Flag{i} or @DFlag{installation} --- Reads and writes links in + installation-wide @tech[#:doc reference-doc]{collection links + file} instead of the user-specific @tech[#:doc + reference-doc]{collection links file}. This flag is mutally + exclusive with @Flag{f} and @DFlag{file}.} + + @item{@Flag{f} @nonterm{file} or @DFlag{file} @nonterm{file} --- + Reads and writes links in @nonterm{file} instead of the + user-specific @tech[#:doc reference-doc]{collection links + file}. This flag is mutally exclusive with @Flag{i} and + @DFlag{installation}.} + + @item{@DFlag{repair} --- Enables repairs to the existing file content + when the content is erroneous. The file is repaired by deleting + individual links when possible.} + +] + +@; ---------------------------------------- + +@section{API for Collection Links} + +@defmodule[setup/link] + +@defproc[(links [dirs (listof path?)] + [#:file file path-string? (find-system-path 'links-file)] + [#:name name (or/c string? #f) #f] + [#:version-regexp version-regexp (or/c regexp? #f) #f] + [#:error error-proc (symbol? string? any/c ... . -> . any) error] + [#:remove? remove? any/c #f] + [#:show? show? any/c #f] + [#:repair? repair? any/c #f]) + (listof string?)]{ + +A function version of the @exec{raco link} command. The +@racket[error-proc] argument is called to raise exceptions that would +be fatal to the @exec{raco link} command. + +The result is a list of top-level collections that are mapped by +@racket[file] and that apply to the running version of Racket.} diff --git a/collects/scribblings/raco/raco.scrbl b/collects/scribblings/raco/raco.scrbl index a5585a65b6..e14f55ef57 100644 --- a/collects/scribblings/raco/raco.scrbl +++ b/collects/scribblings/raco/raco.scrbl @@ -16,6 +16,7 @@ a typical Racket installation. @table-of-contents[] @include-section["make.scrbl"] +@include-section["link.scrbl"] @include-section["exe.scrbl"] @include-section["dist.scrbl"] @include-section["plt.scrbl"] diff --git a/collects/scribblings/raco/setup.scrbl b/collects/scribblings/raco/setup.scrbl index ff878e8e37..367a5d1772 100644 --- a/collects/scribblings/raco/setup.scrbl +++ b/collects/scribblings/raco/setup.scrbl @@ -2,6 +2,7 @@ @(require scribble/manual scribble/bnf + "common.rkt" (for-label racket racket/future setup/setup-unit @@ -1086,16 +1087,13 @@ An @deftech{unpackable} is one of the following: @defproc[(find-relevant-directories (syms (listof symbol?)) - (mode (symbols 'preferred 'all-available) 'preferred)) (listof path?)]{ + (mode (or/c 'preferred 'all-available 'no-planet) 'preferred)) (listof path?)]{ Returns a list of paths identifying installed directories (i.e., collections and installed @|PLaneT| packages) whose @filepath{info.rkt} file defines one or more of the given symbols. The result is based on a cache that is computed by - @exec{raco setup} and stored in the @indexed-file{info-domain} - sub-directory of each collection directory (as determined by the - @envvar{PLT_COLLECTION_PATHS} environment variable, etc.) and the - file @filepath{cache.rkt} in the user add-on directory. + @exec{raco setup}. Note that the cache may be out of date by the time you call @racket[get-info/full], so do not assume that it won't return @racket[#f]. @@ -1105,20 +1103,27 @@ An @deftech{unpackable} is one of the following: providing to @racket[get-info/full]. If @racket[mode] is specified, it must be either - @racket['preferred] (the default) or @racket['all-available]. If - mode is @racket['all-available], @racket[find-relevant-collections] + @racket['preferred] (the default), @racket['all-available], or @racket[no-planet]. If + @racket[mode] is @racket['all-available], @racket[find-relevant-collections] returns all installed directories whose info files contain the specified symbols---for instance, all installed PLaneT packages - will be searched if @racket['all-available] is specified. If mode + will be searched if @racket['all-available] is specified. If @racket[mode] is @racket['preferred], then only a subset of ``preferred'' - packages will be searched, and in particular only the directory + packages will be searched: only the directory containing the most recent version of any PLaneT package will be - returned. + returned. If @racket[mode] is @racket['no-planet], then only PLaneT + packages are not included in the search. No matter what @racket[mode] is specified, if more than one collection has the same name, @racket[find-relevant-directories] - will only search the one that occurs first in the - @envvar{PLT_COLLECTION_PATHS} environment variable.} + will only search the one that occurs first in a search that through + the directories of @racket[current-library-collection-paths]. + Collection links from the installation-wide @tech[#:doc + reference-doc]{collection links file} are cached with the + installation's main @filepath{collects} directory, and links from + the user-specific @tech[#:doc reference-doc]{collection links file} + are cached with the user-specific directory @racket[(build-path + (find-system-path 'addon-dir) (version) "collects")].} @defproc[(find-relevant-directory-records [syms (listof symbol?)] diff --git a/collects/scribblings/reference/collects.scrbl b/collects/scribblings/reference/collects.scrbl index 950be7f835..d26e60ca84 100644 --- a/collects/scribblings/reference/collects.scrbl +++ b/collects/scribblings/reference/collects.scrbl @@ -5,10 +5,10 @@ A @deftech{library} is @racket[module] declaration for use by multiple programs. Racket further groups libraries into @deftech{collections} -that can be easily distributed and easily added to a local Racket +that can be easily distributed and added to a local Racket installation. -Some collections are distributed via @|PLaneT|. Such collections are +Some libraries are distributed via @|PLaneT| packages. Such libraries are referenced through a @racket[planet] module path (see @racket[require]) and are downloaded by Racket on demand. @@ -17,9 +17,11 @@ collection is a directory that is located in a @filepath{collects} directory relative to the Racket executable. A collection can also be installed in a user-specific directory. More generally, the search path for installed collections can be configured through the -@racket[current-library-collection-paths] parameter. In all of these -cases, the collections are referenced through @racket[lib] paths (see -@racket[require]). +@racket[current-library-collection-paths] parameter. Finally, the +location of collections can be specified through the @tech{collection +links files}; see @secref["links-file"] for more information. In all +of these cases, the collections are referenced through @racket[lib] +paths (see @racket[require]) or symbolic shorthands. For example, the following module uses the @filepath{getinfo.rkt} library module from the @filepath{setup} collection, and the @@ -33,7 +35,8 @@ racket .... ] -This example is more compactly and more commonly written as +This example is more compactly and more commonly written using +symbolic shorthands: @racketmod[ racket @@ -60,14 +63,16 @@ resolver}, as specified by the @racket[current-module-name-resolver] parameter. For the default @tech{module name resolver}, the search path for -collections is determined by the -@racket[current-library-collection-paths] parameter. The list of paths -in @racket[current-library-collection-paths] is searched from first to +collections is determined by the content of @racket[(find-system-path +'links-file)] (if it exists) and the +@racket[current-library-collection-paths] parameter. The collection +links and then list of paths in +@racket[current-library-collection-paths] is searched from first to last to locate the first that contains @racket[_rel-string]. In other -words, the filesystem tree for each element in the search path is -spliced together with the filesystem trees of other path -elements. Some Racket tools rely on unique resolution of module path -names, so an installation and +words, the filesystem tree for each element in the link table and +search path is spliced together with the filesystem trees of other +path elements. Some Racket tools rely on unique resolution of module +path names, so an installation and @racket[current-library-collection-paths] configuration should not allow multiple files to match the same collection and file name. @@ -156,3 +161,46 @@ the directory produced by @racket[(find-system-path 'addon-dir)], are included in search paths for collections and other files. For example, @racket[find-library-collection-paths] omits the user-specific collection directory when this parameter's value is @racket[#f].} + +@; ---------------------------------------------------------------------- + +@section[#:tag "links-file"]{Collection Links} + +The @deftech{collection links files} are used by +@racket[collection-file-path], @racket[collection-path], and the +default @tech{module name resolver} to locate collections before +trying the @racket[(current-library-collection-paths)] search +path. Furthermore, a user-specific @tech{collection links file} takes +precedence over an installation-wide @tech{collection links file}, but +the user-specific @tech{collection links file} is used only the +@racket[use-user-specific-search-paths] parameter is set to +@racket[#t]. + +The path of the user-specific @tech{collection links file} is by +@racket[(find-system-path 'links-file)], while an installation-wide +@tech{collection links file} is @filepath{links.rktd} in the +@filepath{config} collection within the installation's main collection +directory. Each @tech{collection links file} is cached by Racket, but +the file is re-read if its timestamp changes. + +Each @tech{collection links file} is @racket[read] with default reader +parameter settings to obtain a list. Every element of the list must be +a link specification with either the form @racket[(_string _path)] or +the form @racket[(_string _path _regexp)]. In both cases, the +@racket[_string] names a top-level @tech{collection}, and +@racket[_path] is a path that can be used as the collection's path +(directly, as opposed to a subdirectory of @racket[_path] named by +@racket[_string]). If @racket[_path] is a relative path, it is +relative to the directory containing the @tech{collection links +file}. If @racket[_regexp] is specified in a link, then the link is +used only if @racket[(regexp-match? _regexp (version))] produces a +true result. + +A single top-level collection can have multiple links in a +@tech{collection links file}. The corresponding paths are effectively +spliced together, since the paths are tried in order to locate a file +or sub-collection. + +The @exec{raco link} command-link tool can display, install, and +remove links in the @tech{collection links file}. See @secref[#:doc +raco-doc "link"] in @other-manual[raco-doc] for more information. diff --git a/collects/scribblings/reference/filesystem.scrbl b/collects/scribblings/reference/filesystem.scrbl index 7c6923c6fe..65a4e3accc 100644 --- a/collects/scribblings/reference/filesystem.scrbl +++ b/collects/scribblings/reference/filesystem.scrbl @@ -85,8 +85,17 @@ by @racket[kind], which must be one of the following: ]} + @item{@indexed-racket['links-file] --- the user-specific + @tech{collection links file} for specifying the location of library + @tech{collections}. This file is specified by the + @indexed-envvar{PLTLINKSFILE} environment variable, and it can be + overridden by the @DFlag{links} or @Flag{C} command-line flag. If no + environment variable or flag is specified, or if the value is not a + legal path name, then this file defaults to @filepath{links.rktd} in + the directory reported by @racket[(find-system-path 'addon-dir)].} + @item{@indexed-racket['addon-dir] --- a directory for installing - Racket extensions. This directory is specified by the + user-specific Racket extensions. This directory is specified by the @indexed-envvar{PLTADDONDIR} environment variable, and it can be overridden by the @DFlag{addon} or @Flag{A} command-line flag. If no environment variable or flag is specified, or if the value is not a diff --git a/collects/scribblings/reference/mz.rkt b/collects/scribblings/reference/mz.rkt index 241cb8afcf..61b42f2d18 100644 --- a/collects/scribblings/reference/mz.rkt +++ b/collects/scribblings/reference/mz.rkt @@ -91,7 +91,8 @@ (provide margin-note/ref refalso moreref Guide guideintro guidealso guidesecref - HonuManual) + HonuManual + raco-doc) (define (margin-note/ref . s) (apply margin-note @@ -127,6 +128,9 @@ (define HonuManual (other-manual '(lib "scribblings/honu/honu.scrbl"))) + + (define raco-doc + '(lib "scribblings/raco/raco.scrbl")) (provide speed) (define-syntax speed diff --git a/collects/scribblings/reference/startup.scrbl b/collects/scribblings/reference/startup.scrbl index 228ac08e93..fcca28afc8 100644 --- a/collects/scribblings/reference/startup.scrbl +++ b/collects/scribblings/reference/startup.scrbl @@ -250,6 +250,15 @@ flags: the @Flag{S}/@DFlag{dir} flag is supplied multiple times, the search order is as supplied.} + @item{@FlagFirst{A} @nonterm{dir} or @DFlagFirst{addon} + @nonterm{dir} : Sets the directory that is returned by + @racket[(find-system-path 'addon-dir)].} + + @item{@FlagFirst{C} @nonterm{file} or @DFlagFirst{links} + @nonterm{file} : Sets the user-specific @tech{collection links file} path + that is returned by @racket[(find-system-path 'links-file)]; + see also @secref["links-file"].} + @item{@FlagFirst{U} or @DFlagFirst{no-user-path} : Omits user-specific paths in the search for collections, C libraries, etc. by initializing the @@ -405,8 +414,9 @@ language specifies run-time configuration by A @racket['configure-runtime] query returns a list of vectors, instead of directly configuring the environment, so that the indicated modules -to be bundled with a program when creating a stand-alone -executable; see @secref[#:doc '(lib "scribblings/raco/raco.scrbl") "exe"]. +to be bundled with a program when creating a stand-alone executable; +see @secref[#:doc raco-doc "exe"] in +@other-manual[raco-doc]. For information on defining a new @hash-lang[] language, see @racketmodname[syntax/module-reader]. diff --git a/collects/setup/collects.rkt b/collects/setup/collects.rkt index e000181383..31c5c7d6fc 100644 --- a/collects/setup/collects.rkt +++ b/collects/setup/collects.rkt @@ -3,6 +3,6 @@ (provide (struct-out cc)) (define-struct cc - (collection path name info root-dir info-path shadowing-policy) + (collection path name info omit-root info-root info-path info-path-mode shadowing-policy) #:inspector #f) diff --git a/collects/setup/commands/link.rkt b/collects/setup/commands/link.rkt new file mode 100644 index 0000000000..0fc453197b --- /dev/null +++ b/collects/setup/commands/link.rkt @@ -0,0 +1,74 @@ +#lang scheme/base +(require racket/cmdline + raco/command-name + "../link.rkt") + +(define link-file (make-parameter #f)) +(define link-name (make-parameter #f)) +(define link-version (make-parameter #f)) +(define remove-mode (make-parameter #f)) +(define repair-mode (make-parameter #f)) +(define show-mode (make-parameter #f)) +(define user-mode (make-parameter #t)) + +(define link-symbol (string->symbol (short-program+command-name))) + +(define dirs + (command-line + #:program (short-program+command-name) + #:once-each + [("-s" "--show") "Show the link table (after changes)" + (show-mode #t)] + [("-n" "--name") name "Set the collection name (for a single directory)" + (link-name name)] + [("-x" "--version-regexp") regexp "Set the version pregexp" + (with-handlers ([exn:fail:contract? (lambda (exn) + (raise-user-error link-symbol + "bad version regexp: ~a" + regexp))]) + (link-version (pregexp regexp)))] + [("-r" "--remove") "Remove links for the specified directories" + (remove-mode #t)] + #:once-any + [("-i" "--installation") "Adjust user-independent links in the installation" + (user-mode #f)] + [("-f" "--file") file "Select an alternate link file" + (link-file (path->complete-path file))] + #:once-each + [("--repair") "Enable repair mode to fix existing links" + (repair-mode #t)] + #:args + dir dir)) + +(when (and (link-name) + (not (= 1 (length dirs)))) + (raise-user-error link-symbol + "expected a single directory for `--name' mode")) + +(define show-both? + (and (null? dirs) + (show-mode) + (user-mode) + (not (remove-mode)) + (not (link-file)))) + +(when show-both? + (printf "User links:\n")) + +(void + (apply links + dirs + #:user? (user-mode) + #:file (link-file) + #:name (link-name) + #:version-regexp (link-version) + #:error (lambda (who . args) + (apply raise-user-error link-symbol args)) + #:remove? (remove-mode) + #:show? (show-mode) + #:repair? (repair-mode))) + +(when show-both? + (printf "Installation links:\n") + (void (links #:user? #f #:show? #t))) + diff --git a/collects/setup/getinfo.rkt b/collects/setup/getinfo.rkt index 6b03ae72ec..748a625ee0 100644 --- a/collects/setup/getinfo.rkt +++ b/collects/setup/getinfo.rkt @@ -88,6 +88,7 @@ (define preferred-table #f) (define all-available-table #f) +(define no-planet-table #f) ;; reset-relevant-directories-state! : -> void (define (reset-relevant-directories-state!) @@ -104,7 +105,8 @@ (list i) l)))) #f #f)) - (set! all-available-table (make-table cons #f #f))) + (set! all-available-table (make-table cons #f #f)) + (set! no-planet-table (make-table cons #f #f))) (reset-relevant-directories-state!) @@ -160,20 +162,23 @@ (define t (cond [(eq? key 'preferred) preferred-table] [(eq? key 'all-available) all-available-table] + [(eq? key 'no-planet) no-planet-table] [else (error 'find-relevant-directories "Invalid key: ~s" key)])) ;; A list of (cons cache.rktd-path root-dir-path) ;; If root-dir-path is not #f, then paths in the cache.rktd ;; file are relative to it. #f is used for the planet cache.rktd file. (define search-path - (cons (cons user-infotable #f) - (map (lambda (coll) - (cons (build-path coll "info-domain" "compiled" "cache.rktd") - coll)) - (current-library-collection-paths)))) - (unless (equal? (table-paths t) search-path) - (set-table-ht! t (make-hasheq)) - (set-table-paths! t search-path) - (populate-table! t)) + ((if (eq? key 'no-planet) (lambda (a l) l) cons) + (cons user-infotable #f) + (map (lambda (coll) + (cons (build-path coll "info-domain" "compiled" "cache.rktd") + coll)) + (current-library-collection-paths)))) + (when t + (unless (equal? (table-paths t) search-path) + (set-table-ht! t (make-hasheq)) + (set-table-paths! t search-path) + (populate-table! t))) (let ([unsorted (if (= (length syms) 1) ;; Simple case: look up in table @@ -205,7 +210,7 @@ (get-info/full ((path?) (#:namespace (or/c namespace? #f)) . ->* . (or/c info? boolean?))) (find-relevant-directories (->* [(listof symbol?)] - [(lambda (x) (memq x '(preferred all-available)))] + [(lambda (x) (memq x '(preferred all-available no-planet)))] (listof path?))) (struct directory-record ([maj integer?] @@ -215,5 +220,5 @@ [syms (listof symbol?)])) (find-relevant-directory-records (->* [(listof symbol?)] - [(or/c 'preferred 'all-available)] + [(or/c 'preferred 'all-available 'no-planet)] (listof directory-record?)))) diff --git a/collects/setup/info.rkt b/collects/setup/info.rkt index 3d15e3543c..6af9d1548a 100644 --- a/collects/setup/info.rkt +++ b/collects/setup/info.rkt @@ -5,4 +5,5 @@ (define mzscheme-launcher-libraries '("main.rkt")) (define mzscheme-launcher-names '("Setup PLT")) -(define raco-commands '(("setup" setup/main "install and build libraries and documentation" 90))) +(define raco-commands '(("setup" setup/main "install and build libraries and documentation" 90) + ("link" setup/commands/link "manage library-collection directories" 80))) diff --git a/collects/setup/link.rkt b/collects/setup/link.rkt new file mode 100644 index 0000000000..cd659bf72e --- /dev/null +++ b/collects/setup/link.rkt @@ -0,0 +1,157 @@ +#lang scheme/base +(require racket/file + setup/dirs) + +(provide links) + +(define (links #:error [error error] + #:user? [user? #t] + #:file [in-file #f] + #:name [name #f] + #:version-regexp [version-regexp #f] + #:remove? [remove? #f] + #:show? [show? #f] + #:repair? [repair? #f] + . dirs) + (define file (or in-file + (if user? + (find-system-path 'links-file) + (let ([d (find-collects-dir)]) + (if d + (build-path d "config" "links.rktd") + (error 'links + "cannot find installation collections path")))))) + + (define need-repair? #f) + + (define (content-error str v) + (if repair? + (begin + (log-warning (format "~a~e" str v)) + (set! need-repair? #t) + #f) + (error 'links "~a~e" str v))) + + (define table + (with-handlers ([exn:fail? + (lambda (exn) + (let ([msg (format + "error reading from link file: ~s: ~a" + file + (exn-message exn))]) + (if repair? + (begin + (log-warning msg) + (set! need-repair? #t) + null) + (error 'links "~a" msg))))]) + (if (file-exists? file) + (let ([l (with-input-from-file file read)]) + (if (list? l) + (for/list ([e (in-list l)] + #:when + (or (and (list? e) + (or (= 2 (length e)) + (= 3 (length e)))) + (content-error "entry is a not a 2- or 3-element list: " e)) + #:when + (or (string? (car e)) + (content-error "entry's first element is not a string: " e)) + #:when + (or (path-string? (cadr e)) + (content-error "entry's second element is not a path string: " e)) + #:when + (or (null? (cddr e)) + (regexp? (caddr e)) + (content-error "entry's third element is not a version regexp: " e))) + e) + (begin + (content-error "content is not a list: " l) + null))) + null))) + + (define mapped (make-hash)) + + (define (add-entry! e) + (hash-set! mapped + (car e) + (cons (cdr e) (hash-ref mapped (car e) null)))) + + + (for ([e (in-list table)]) (add-entry! e)) + + (define new-table + (reverse + (for/fold ([table (reverse table)]) ([d (in-list dirs)]) + (let* ([dp (path->complete-path d)] + [a-name (or name + (let-values ([(base name dir?) (split-path dp)]) + (path-element->string name)))] + [rx version-regexp] + [d (path->string dp)]) + (unless remove? + (unless (directory-exists? dp) + (error 'links + "no such directory for link: ~a" + dp))) + (if remove? + (filter (lambda (e) + (or (not (equal? (cadr e) d)) + (and name + (not (equal? (car e) name))) + (and version-regexp + (pair? (cddr e)) + (not (equal? (caddr e) version-regexp))))) + table) + (let ([l (hash-ref mapped a-name null)] + [e (list* a-name + d + (if rx (list rx) null))]) + (if (member (cdr e) l) + table + (let () + (add-entry! e) + (cons e table))))))))) + + (unless (and (not need-repair?) + (equal? new-table table)) + (let ([dir (let-values ([(base name dir?) (split-path file)]) + base)]) + (make-directory* dir) + (let ([tmp (make-temporary-file "links~a.rktd" + #f + dir)]) + (with-output-to-file tmp + #:exists 'truncate + (lambda () + (printf "(") + (let loop ([l new-table] [prefix ""]) + (cond + [(null? l) (printf ")\n")] + [else + (printf "~a~s" prefix (car l)) + (unless (null? (cdr l)) (newline)) + (loop (cdr l) " ")])))) + (with-handlers ([exn:fail? (lambda (exn) + (with-handlers ([exn:fail? void]) + (delete-file tmp)) + (raise exn))]) + (rename-file-or-directory tmp file #t))))) + + (when show? + (for ([e (in-list new-table)]) + (printf " collection: ~s path: ~s~a\n" + (car e) + (cadr e) + (if (null? (cddr e)) + "" + (format " version: ~s" + (caddr e)))))) + + ;; Return list of collections mapped for this version: + (let ([ht (make-hash)]) + (for ([e (in-list new-table)]) + (when (or (null? (cddr e)) + (regexp-match? (caddr e) (version))) + (hash-set! ht (car e) #t))) + (hash-map ht (lambda (k e) k)))) diff --git a/collects/setup/private/omitted-paths.rkt b/collects/setup/private/omitted-paths.rkt index cda020a68c..41286b1260 100644 --- a/collects/setup/private/omitted-paths.rkt +++ b/collects/setup/private/omitted-paths.rkt @@ -82,7 +82,7 @@ implicit? get-info/full))))))) -(define (omitted-paths* dir get-info/full) +(define (omitted-paths* dir get-info/full root-dir) (unless (and (path-string? dir) (complete-path? dir) (directory-exists? dir)) (raise-type-error 'omitted-paths "complete path to an existing directory" dir)) @@ -90,8 +90,13 @@ [r (ormap (lambda (root+table) (let ([r (relative-from dir* (car root+table))]) (and r (cons (reverse r) root+table)))) - (force roots))] + (if root-dir + (list (list (explode-path root-dir) + (make-hash) + #t)) + (force roots)))] [r (and r (apply accumulate-omitted get-info/full r))]) + (unless r (error 'omitted-paths "given directory path is not in any collection root: ~e" dir)) @@ -101,5 +106,5 @@ (define omitted-paths-memo (make-hash)) -(define (omitted-paths dir get-info/full) - (with-memo omitted-paths-memo dir (omitted-paths* dir get-info/full))) +(define (omitted-paths dir get-info/full [root-dir #f]) + (with-memo omitted-paths-memo dir (omitted-paths* dir get-info/full root-dir))) diff --git a/collects/setup/private/path-utils.rkt b/collects/setup/private/path-utils.rkt index 90bd6de733..558aa76608 100644 --- a/collects/setup/private/path-utils.rkt +++ b/collects/setup/private/path-utils.rkt @@ -5,7 +5,7 @@ (provide doc-path) ;; user-doc-mode can be `false-if-missing' or `never' -(define (doc-path dir name flags [user-doc-mode #f]) +(define (doc-path dir name flags under-main? [user-doc-mode #f]) (define (user-doc [sub #f]) (and (not (eq? 'never user-doc-mode)) (let ([d (find-user-doc-dir)]) @@ -15,6 +15,6 @@ (cond [(memq 'main-doc-root flags) (find-doc-dir)] [(memq 'user-doc-root flags) (user-doc)] [(memq 'user-doc flags) (user-doc name)] - [(or (memq 'main-doc flags) (pair? (path->main-collects-relative dir))) + [(or under-main? (memq 'main-doc flags) (pair? (path->main-collects-relative dir))) (build-path (find-doc-dir) name)] [else (build-path dir "doc" name)])) diff --git a/collects/setup/scribble.rkt b/collects/setup/scribble.rkt index c19124364d..6bb685c592 100644 --- a/collects/setup/scribble.rkt +++ b/collects/setup/scribble.rkt @@ -95,7 +95,7 @@ (apply validate i))) infos)]) (and (not (memq #f infos)) infos)))) - (define (get-docs i rec) + (define ((get-docs main-dirs) i rec) (let ([s (validate-scribblings-infos (i 'scribblings))] [dir (directory-record-path rec)]) (if s @@ -106,6 +106,7 @@ (not (memq 'user-doc-root flags)) (not (memq 'user-doc flags)) (or (memq 'main-doc flags) + (hash-ref main-dirs dir #f) (pair? (path->main-collects-relative dir))))]) (make-doc dir (let ([spec (directory-record-spec rec)]) @@ -117,7 +118,7 @@ (list '= (directory-record-min rec))))) (cdr spec)))) (build-path dir (car d)) - (doc-path dir (cadddr d) flags) + (doc-path dir (cadddr d) flags under-main?) flags under-main? (caddr d)))) s) (begin (setup-printf @@ -126,8 +127,12 @@ null)))) (define docs (let* ([recs (find-relevant-directory-records '(scribblings) 'all-available)] + [main-dirs (parameterize ([current-library-collection-paths + (list (find-collects-dir))]) + (for/hash ([k (in-list (find-relevant-directories '(scribblings) 'no-planet))]) + (values k #t)))] [infos (map get-info/full (map directory-record-path recs))]) - (filter-user-docs (append-map get-docs infos recs) make-user?))) + (filter-user-docs (append-map (get-docs main-dirs) infos recs) make-user?))) (define-values (main-docs user-docs) (partition doc-under-main? docs)) (define (can-build*? docs) (can-build? only-dirs docs)) (define auto-main? (and auto-start-doc? (ormap can-build*? main-docs))) diff --git a/collects/setup/setup-unit.rkt b/collects/setup/setup-unit.rkt index d494f983bd..6cc099bcf6 100644 --- a/collects/setup/setup-unit.rkt +++ b/collects/setup/setup-unit.rkt @@ -1,3 +1,4 @@ + ;; Expects parameters to be set before invocation. ;; Calls `exit' when done. @@ -27,7 +28,8 @@ "path-to-relative.rkt" "private/omitted-paths.rkt" "parallel-build.rkt" - "collects.rkt") + "collects.rkt" + "link.rkt") (define-namespace-anchor anchor) ;; read info files using whatever namespace, .zo-use, and compilation @@ -168,7 +170,7 @@ ;; Find Collections ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (define (make-cc* collection path root-dir info-path shadowing-policy) + (define (make-cc* collection path omit-root info-root info-path info-path-mode shadowing-policy) (define info (or (with-handlers ([exn:fail? (warning-handler #f)]) (getinfo path)) (lambda (flag mk-default) (mk-default)))) @@ -186,12 +188,15 @@ "ignoring `compile-subcollections' entry in info ~a" path-name)) ;; this check is also done in compiler/compiler-unit, in compile-directory - (and (not (eq? 'all (omitted-paths path getinfo))) + (and (not (eq? 'all (omitted-paths path getinfo omit-root))) (make-cc collection path (if name (format "~a (~a)" path-name name) path-name) - info root-dir info-path shadowing-policy))) + info + omit-root + info-root info-path info-path-mode + shadowing-policy))) (define ((warning-handler v) exn) (setup-printf "WARNING" "~a" (exn->string exn)) @@ -199,23 +204,39 @@ ;; collection->cc : listof path -> cc/#f (define collection->cc-table (make-hash)) - (define (collection->cc collection-p) + (define (collection->cc collection-p + #:omit-root [omit-root #f] + #:info-root [given-info-root #f] + #:info-path [info-path #f] + #:info-path-mode [info-path-mode 'relative]) (hash-ref! collection->cc-table collection-p (lambda () - (define root-dir - (ormap (lambda (p) - (parameterize ([current-library-collection-paths (list p)]) - (and (with-handlers ([exn:fail? (lambda (x) #f)]) - (apply collection-path collection-p)) - p))) - (current-library-collection-paths))) - (make-cc* collection-p - (apply collection-path collection-p) - root-dir - (build-path root-dir "info-domain" "compiled" "cache.rktd") - ;; by convention, all collections have "version" 1 0. This - ;; forces them to conflict with each other. - (list (cons 'lib (map path->string collection-p)) 1 0))))) + (define info-root + (or given-info-root + (ormap (lambda (p) + (parameterize ([current-library-collection-paths (list p)] + ;; to disable collection links file: + [use-user-specific-search-paths #f]) + (and (with-handlers ([exn:fail? (lambda (x) #f)]) + (apply collection-path collection-p)) + p))) + (current-library-collection-paths)))) + (let ([dir (apply collection-path collection-p)]) + (unless (directory-exists? dir) + (error name-sym "directory does not exist for collection: ~s" + (string-join (map path->string collection-p) "/"))) + (make-cc* collection-p + dir + (if (eq? omit-root 'dir) + dir + omit-root) ; #f => `omitted-paths' can reconstruct it + info-root + (or info-path + (build-path info-root "info-domain" "compiled" "cache.rktd")) + info-path-mode + ;; by convention, all collections have "version" 1 0. This + ;; forces them to conflict with each other. + (list (cons 'lib (map path->string collection-p)) 1 0)))))) ;; planet-spec->planet-list : (list string string nat nat) -> (list path string string (listof string) nat nat) | #f ;; converts a planet package spec into the information needed to create a cc structure @@ -241,8 +262,10 @@ (and (directory-exists? path) (make-cc* #f path - #f ; don't need root-dir; absolute paths in cache.rktd will be ok + path + #f ; don't need info-root; absolute paths in cache.rktd will be ok (get-planet-cache-path) + 'abs (list `(planet ,owner ,pkg-file ,@extra-path) maj min)))) ;; planet-cc->sub-cc : cc (listof bytes [encoded path]) -> cc @@ -268,6 +291,23 @@ (lambda () (let ([cc (collection->cc (list collection))]) (when cc (hash-set! ht collection cc)))))) + (let ([main-collects (find-collects-dir)]) + (for ([c (in-list (links #:user? #f))]) + (let* ([c (string->path c)] + [cc (collection->cc (list c) + #:info-root main-collects + #:info-path-mode 'abs-in-relative + #:omit-root 'dir)]) + (when cc (hash-set! ht c cc))))) + (when (make-user) + (let ([user-collects (find-user-collects-dir)]) + (for ([c (in-list (links))]) + (let* ([c (string->path c)] + [cc (collection->cc (list c) + #:info-root user-collects + #:info-path-mode 'abs-in-relative + #:omit-root 'dir)]) + (when cc (hash-set! ht c cc)))))) (hash-map ht (lambda (k v) v)))) ;; Close over sub-collections @@ -279,7 +319,7 @@ ;; collection should not have been included, but we might ;; jump in if a command-line argument specified a ;; coll/subcoll - [omit (omitted-paths ccp getinfo)] + [omit (omitted-paths ccp getinfo (cc-omit-root cc))] [subs (if (eq? 'all omit) '() (filter (lambda (p) @@ -292,7 +332,8 @@ (append-map (lambda (cc) (cons cc (loop (get-subs cc)))) l)))) (define (collection-tree-map collections-to-compile - #:skip-path [orig-skip-path (and (avoid-main-installation) (find-collects-dir))]) + #:skip-path [orig-skip-path (and (avoid-main-installation) + (find-collects-dir))]) (define skip-path (and orig-skip-path (path->bytes (simplify-path (if (string? orig-skip-path) (string->path orig-skip-path) @@ -308,14 +349,18 @@ (define (build-collection-tree cc) (define (make-child-cc parent-cc name) - (collection->cc (append (cc-collection parent-cc) (list name)))) + (collection->cc (append (cc-collection parent-cc) (list name)) + #:info-root (cc-info-root cc) + #:info-path (cc-info-path cc) + #:info-path-mode (cc-info-path-mode cc) + #:omit-root (cc-omit-root cc))) (let* ([info (cc-info cc)] [ccp (cc-path cc)] ;; note: omit can be 'all, if this happens then this ;; collection should not have been included, but we might ;; jump in if a command-line argument specified a ;; coll/subcoll - [omit (omitted-paths ccp getinfo)]) + [omit (omitted-paths ccp getinfo (cc-omit-root cc))]) (let-values ([(dirs files) (if (eq? 'all omit) (values null null) @@ -325,7 +370,6 @@ (skip-path? p)))) (directory-list ccp))))]) (let ([children-ccs (map build-collection-tree (filter-map (lambda (x) (make-child-cc cc x)) dirs))] - [srcs (append (filter extract-base-filename/ss files) (if (make-docs) @@ -342,7 +386,11 @@ (define (plt-collection-closure collections-to-compile) (define (make-children-ccs cc children) (map (lambda (child) - (collection->cc (append (cc-collection cc) (list child)))) + (collection->cc (append (cc-collection cc) (list child)) + #:info-root (cc-info-root cc) + #:info-path (cc-info-path cc) + #:info-path-mode (cc-info-path-mode cc) + #:omit-root (cc-omit-root cc))) children)) (collection-closure collections-to-compile make-children-ccs)) @@ -668,6 +716,7 @@ [info (cc-info cc)]) (clean-cc dir info) (compile-directory-zos dir info + #:omit-root (cc-omit-root cc) #:managed-compile-zo caching-managed-compile-zo #:skip-path (and (avoid-main-installation) (find-collects-dir)) #:skip-doc-sources? (not (make-docs)))))))) @@ -748,7 +797,7 @@ (warning-handler null)]) (with-input-from-file p read)) null))]) - ;; Convert list to hash table. Incluse only well-formed + ;; Convert list to hash table. Include only well-formed ;; list elements, and only elements whose corresponding ;; collection exists. (let ([t (make-hash)] @@ -757,28 +806,32 @@ (set! all-ok? #t) (for ([i l]) (match i - [(list - (? (lambda (a) - (and (bytes? a) - (let ([p (bytes->path a)]) - ;; If we have a root directory, - ;; then the path must be relative - ;; to it, otherwise it must be - ;; absolute: - (and (if (cc-root-dir cc) - (relative-path? p) - (complete-path? p)) - (let ([dir (if (cc-root-dir cc) - (build-path (cc-root-dir cc) p) - p)]) - (or (file-exists? (build-path dir "info.rkt")) - (file-exists? (build-path dir "info.ss")))))))) - a) - (list (? symbol? b) ...) - c - (? integer? d) - (? integer? e)) - (hash-set! t a (list b c d e))] + [(list (? bytes? a) (list (? symbol? b) ...) c (? integer? d) (? integer? e)) + (let ([p (bytes->path a)]) + ;; Check that the path is suitably absolute or relative: + (let ([dir (case (cc-info-path-mode cc) + [(relative abs-in-relative) + (or (and (relative-path? p) + (build-path (cc-info-root cc) p)) + (and (complete-path? p) + ;; `c' must be `(lib ...)' + (list? c) + (pair? c) + (eq? 'lib (car c)) + (pair? (cdr c)) + (andmap string? (cdr c)) + ;; Path must match collection resolution: + (with-handlers ([exn:fail? (lambda (exn) #f)]) + (equal? p (apply collection-path (cdr c)))) + p))] + [(abs) + (and (complete-path? p) + p)])]) + (if (and dir + (or (file-exists? (build-path dir "info.rkt")) + (file-exists? (build-path dir "info.ss")))) + (hash-set! t a (list b c d e)) + (set! all-ok? #f))))] [_ (set! all-ok? #f)]))) ;; Record the table loaded for this collection root ;; in the all-roots table: @@ -792,7 +845,7 @@ ;; Add this collection's info to the table, replacing any information ;; already there. (hash-set! t - (path->bytes (if (cc-root-dir cc) + (path->bytes (if (eq? (cc-info-path-mode cc) 'relative) ;; Use relative path: (apply build-path (cc-collection cc)) ;; Use absolute path: @@ -802,20 +855,16 @@ (hash-for-each ht (lambda (info-path ht) (unless (equal? ht (hash-ref ht-orig info-path)) - (let-values ([(base name must-be-dir?) (split-path info-path)]) - (unless (path? base) - (error 'make-info-domain - "Internal error: cc had invalid info-path: ~e" - info-path)) - (make-directory* base) - (let ([p info-path]) - (setup-printf "updating" "~a" (path->relative-string/setup p)) - (with-handlers ([exn:fail? (warning-handler (void))]) - (with-output-to-file p - #:exists 'truncate/replace - (lambda () - (write (hash-map ht cons)) - (newline))))))))))) + (define-values (base name dir?) (split-path info-path)) + (make-directory* base) + (let ([p info-path]) + (setup-printf "updating" "~a" (path->relative-string/setup p)) + (with-handlers ([exn:fail? (warning-handler (void))]) + (with-output-to-file p + #:exists 'truncate/replace + (lambda () + (write (hash-map ht cons)) + (newline)))))))))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Docs ;; diff --git a/collects/setup/xref.rkt b/collects/setup/xref.rkt index ab67b094ff..13432ec826 100644 --- a/collects/setup/xref.rkt +++ b/collects/setup/xref.rkt @@ -3,6 +3,7 @@ (require scribble/xref scheme/fasl scheme/path + setup/dirs "getinfo.rkt" "private/path-utils.rkt") @@ -11,6 +12,12 @@ (define cached-xref #f) (define (get-dests) + (define main-dirs + (parameterize ([current-library-collection-paths + (let ([d (find-collects-dir)]) + (if d (list d) null))]) + (for/hash ([k (in-list (find-relevant-directories '(scribblings) 'no-planet))]) + (values k #t)))) (for*/list ([dir (find-relevant-directories '(scribblings) 'all-available)] [d ((get-info/full dir) 'scribblings)]) (unless (and (list? d) (pair? d)) @@ -23,7 +30,7 @@ (path-replace-suffix (file-name-from-path (car d)) #"")))]) (and (not (and (len . >= . 3) (memq 'omit (caddr d)))) - (let* ([d (doc-path dir name flags 'false-if-missing)] + (let* ([d (doc-path dir name flags (hash-ref main-dirs dir #f) 'false-if-missing)] [p (and d (build-path d "out.sxref"))]) (and p (file-exists? p) p)))))) diff --git a/doc/release-notes/racket/HISTORY.txt b/doc/release-notes/racket/HISTORY.txt index a025903eb4..5828286a26 100644 --- a/doc/release-notes/racket/HISTORY.txt +++ b/doc/release-notes/racket/HISTORY.txt @@ -1,3 +1,7 @@ +Version 5.1.3.4 +Add support for the collection links file, including + (find-system-path 'links-file) and the raco link command + Version 5.1.3.3 unsafe/ffi: added support for C arrays and unions diff --git a/src/racket/cmdline.inc b/src/racket/cmdline.inc index a836aab046..bca89ee316 100644 --- a/src/racket/cmdline.inc +++ b/src/racket/cmdline.inc @@ -556,6 +556,7 @@ static int run_from_cmd_line(int argc, char *_argv[], char *prog, *sprog = NULL; Scheme_Object *sch_argv; Scheme_Object *collects_path = NULL, *collects_extra = NULL, *addon_dir = NULL; + Scheme_Object *links_file = NULL; #ifndef NO_FILE_SYSTEM_UTILS Scheme_Object *collects_paths_l, *collects_paths_r; #endif @@ -804,6 +805,8 @@ static int run_from_cmd_line(int argc, char *_argv[], argv[0] = "-S"; else if (!strcmp("--addon", argv[0])) argv[0] = "-A"; + else if (!strcmp("--links", argv[0])) + argv[0] = "-C"; # ifdef CMDLINE_STDIO_FLAG else if (!strcmp("--stdio", argv[0])) argv[0] = "-z"; @@ -860,6 +863,17 @@ static int run_from_cmd_line(int argc, char *_argv[], addon_dir = scheme_make_path(argv[0]); was_config_flag = 1; break; + case 'C': + if (argc < 2) { + PRINTF("%s: missing path after %s switch\n", + prog, real_switch); + goto show_need_help; + } + argv++; + --argc; + links_file = scheme_make_path(argv[0]); + was_config_flag = 1; + break; case 'U': scheme_set_ignore_user_paths(1); was_config_flag = 1; @@ -1204,7 +1218,28 @@ static int run_from_cmd_line(int argc, char *_argv[], } } # endif - if (addon_dir) scheme_set_addon_dir(addon_dir); + if (addon_dir) { + addon_dir = scheme_path_to_complete_path(addon_dir, NULL); + scheme_set_addon_dir(addon_dir); + } +#endif /* NO_FILE_SYSTEM_UTILS */ + +#ifndef NO_FILE_SYSTEM_UTILS + /* Setup path for "links" file: */ +# ifdef GETENV_FUNCTION + if (!links_file) { + char *s; + s = getenv("PLTLINKSFILE"); + if (s) { + s = scheme_expand_filename(s, -1, NULL, NULL, 0); + if (s) links_file = scheme_make_path(s); + } + } +# endif + if (links_file) { + links_file = scheme_path_to_complete_path(links_file, NULL); + scheme_set_links_file(links_file); + } #endif /* NO_FILE_SYSTEM_UTILS */ /* Creates the main kernel environment */ @@ -1292,6 +1327,7 @@ static int run_from_cmd_line(int argc, char *_argv[], " -X , --collects : Main collects at \n" " -S , --search : More collects at (after main collects)\n" " -A , --addon : Addon directory at \n" + " -K , --links : Collection links at \n" " -U, --no-user-path : Ignore user-specific collects, etc.\n" " -N , --name : Sets `(find-system-path 'run-file)' to \n" # ifdef MZ_USE_JIT diff --git a/src/racket/include/scheme.h b/src/racket/include/scheme.h index 62beb416c0..7e07afc5a0 100644 --- a/src/racket/include/scheme.h +++ b/src/racket/include/scheme.h @@ -1801,6 +1801,7 @@ MZ_EXTERN Scheme_Object *scheme_set_run_cmd(char *s); MZ_EXTERN void scheme_set_collects_path(Scheme_Object *p); MZ_EXTERN void scheme_set_original_dir(Scheme_Object *d); MZ_EXTERN void scheme_set_addon_dir(Scheme_Object *p); +MZ_EXTERN void scheme_set_links_file(Scheme_Object *p); MZ_EXTERN void scheme_set_command_line_arguments(Scheme_Object *vec); MZ_EXTERN void scheme_set_compiled_file_paths(Scheme_Object *list); diff --git a/src/racket/include/schthread.h b/src/racket/include/schthread.h index 271725e7e4..e4755fbf28 100644 --- a/src/racket/include/schthread.h +++ b/src/racket/include/schthread.h @@ -273,6 +273,7 @@ typedef struct Thread_Local_Variables { int env_uid_counter_; int scheme_overflow_count_; struct Scheme_Object *original_pwd_; + struct Scheme_Object *inst_links_path_; void *file_path_wc_buffer_; intptr_t scheme_hash_request_count_; intptr_t scheme_hash_iteration_count_; @@ -605,6 +606,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL; #define env_uid_counter XOA (scheme_get_thread_local_variables()->env_uid_counter_) #define scheme_overflow_count XOA (scheme_get_thread_local_variables()->scheme_overflow_count_) #define original_pwd XOA (scheme_get_thread_local_variables()->original_pwd_) +#define inst_links_path XOA (scheme_get_thread_local_variables()->inst_links_path_) #define file_path_wc_buffer XOA (scheme_get_thread_local_variables()->file_path_wc_buffer_) #define scheme_hash_request_count XOA (scheme_get_thread_local_variables()->scheme_hash_request_count_) #define scheme_hash_iteration_count XOA (scheme_get_thread_local_variables()->scheme_hash_iteration_count_) diff --git a/src/racket/src/cstartup.inc b/src/racket/src/cstartup.inc index 3fce116853..7650cfec55 100644 --- a/src/racket/src/cstartup.inc +++ b/src/racket/src/cstartup.inc @@ -1,5 +1,5 @@ { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,50,0,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,53,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,51,0,0,0,1,0,0,10,0,13,0,22, 0,26,0,31,0,38,0,51,0,58,0,63,0,68,0,72,0,79,0,82,0, 85,0,91,0,105,0,119,0,122,0,128,0,132,0,134,0,145,0,147,0,161, @@ -15,12 +15,12 @@ 116,120,61,115,70,108,101,116,45,118,97,108,117,101,115,61,120,73,108,101,116, 114,101,99,45,118,97,108,117,101,115,66,108,97,109,98,100,97,1,20,112,97, 114,97,109,101,116,101,114,105,122,97,116,105,111,110,45,107,101,121,61,118,73, -100,101,102,105,110,101,45,118,97,108,117,101,115,97,36,11,8,240,72,76,0, +100,101,102,105,110,101,45,118,97,108,117,101,115,97,36,11,8,240,112,76,0, 0,95,159,2,17,36,36,159,2,16,36,36,159,2,16,36,36,16,20,2,4, -2,2,2,6,2,2,2,7,2,2,2,8,2,2,2,9,2,2,2,10,2, +2,2,2,6,2,2,2,8,2,2,2,7,2,2,2,9,2,2,2,10,2, 2,2,11,2,2,2,5,2,2,2,12,2,2,2,13,2,2,97,37,11,8, -240,72,76,0,0,93,159,2,16,36,37,16,2,2,3,161,2,2,37,2,3, -2,2,2,3,96,38,11,8,240,72,76,0,0,16,0,96,11,11,8,240,72, +240,112,76,0,0,93,159,2,16,36,37,16,2,2,3,161,2,2,37,2,3, +2,2,2,3,96,11,11,8,240,112,76,0,0,16,0,96,38,11,8,240,112, 76,0,0,16,0,18,98,64,104,101,114,101,13,16,5,36,2,14,2,2,11, 11,8,32,8,31,8,30,8,29,27,248,22,155,4,195,249,22,148,4,80,158, 39,36,251,22,83,2,18,248,22,98,199,12,249,22,73,2,19,248,22,100,201, @@ -30,14 +30,14 @@ 74,193,249,22,148,4,80,158,39,36,251,22,83,2,18,248,22,74,199,249,22, 73,2,11,248,22,75,201,11,18,100,10,13,16,5,36,2,14,2,2,11,11, 8,32,8,31,8,30,8,29,16,4,11,11,2,20,3,1,8,101,110,118,49, -52,55,51,57,16,4,11,11,2,21,3,1,8,101,110,118,49,52,55,52,48, +52,55,57,57,16,4,11,11,2,21,3,1,8,101,110,118,49,52,56,48,48, 27,248,22,75,248,22,155,4,196,28,248,22,81,193,20,14,159,37,36,37,28, 248,22,81,248,22,75,194,248,22,74,193,249,22,148,4,80,158,39,36,250,22, 83,2,22,248,22,83,249,22,83,248,22,83,2,23,248,22,74,201,251,22,83, 2,18,2,23,2,23,249,22,73,2,13,248,22,75,204,18,100,11,13,16,5, 36,2,14,2,2,11,11,8,32,8,31,8,30,8,29,16,4,11,11,2,20, -3,1,8,101,110,118,49,52,55,52,50,16,4,11,11,2,21,3,1,8,101, -110,118,49,52,55,52,51,248,22,155,4,193,27,248,22,155,4,194,249,22,73, +3,1,8,101,110,118,49,52,56,48,50,16,4,11,11,2,21,3,1,8,101, +110,118,49,52,56,48,51,248,22,155,4,193,27,248,22,155,4,194,249,22,73, 248,22,83,248,22,74,196,248,22,75,195,27,248,22,75,248,22,155,4,23,197, 1,249,22,148,4,80,158,39,36,28,248,22,58,248,22,149,4,248,22,74,23, 198,2,27,249,22,2,32,0,88,163,8,36,37,43,11,9,222,33,40,248,22, @@ -67,8 +67,8 @@ 140,9,248,22,149,4,248,22,74,200,64,101,108,115,101,10,248,22,74,197,250, 22,84,2,22,9,248,22,75,200,249,22,73,2,5,248,22,75,202,99,13,16, 5,36,2,14,2,2,11,11,8,32,8,31,8,30,8,29,16,4,11,11,2, -20,3,1,8,101,110,118,49,52,55,54,53,16,4,11,11,2,21,3,1,8, -101,110,118,49,52,55,54,54,18,158,94,10,64,118,111,105,100,8,48,27,248, +20,3,1,8,101,110,118,49,52,56,50,53,16,4,11,11,2,21,3,1,8, +101,110,118,49,52,56,50,54,18,158,94,10,64,118,111,105,100,8,48,27,248, 22,75,248,22,155,4,196,249,22,148,4,80,158,39,36,28,248,22,58,248,22, 149,4,248,22,74,197,250,22,83,2,28,248,22,83,248,22,74,199,248,22,98, 198,27,248,22,149,4,248,22,74,197,250,22,83,2,28,248,22,83,248,22,74, @@ -98,410 +98,496 @@ EVAL_ONE_SIZED_STR((char *)expr, 2004); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,50,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,82,0,0,0,1,0,0,8,0,21,0,26, -0,43,0,58,0,76,0,92,0,106,0,128,0,146,0,166,0,182,0,200,0, -231,0,4,1,26,1,40,1,46,1,60,1,65,1,75,1,83,1,111,1,143, -1,188,1,194,1,201,1,207,1,252,1,20,2,59,2,73,2,76,2,79,2, -89,2,100,2,113,2,115,2,117,2,27,3,117,4,231,4,89,5,130,5,203, -6,33,7,119,7,219,7,47,8,61,8,194,8,168,9,252,9,10,10,31,11, -235,11,249,11,141,16,156,17,45,18,30,19,12,20,19,20,98,20,179,20,122, -21,136,21,146,21,187,22,33,23,56,23,73,23,21,25,124,25,138,25,42,26, -235,27,244,27,253,27,23,28,151,28,0,0,2,32,0,0,67,35,37,117,116, -105,108,115,72,112,97,116,104,45,115,116,114,105,110,103,63,64,98,115,98,115, -76,110,111,114,109,97,108,45,99,97,115,101,45,112,97,116,104,74,45,99,104, -101,99,107,45,114,101,108,112,97,116,104,77,45,99,104,101,99,107,45,99,111, -108,108,101,99,116,105,111,110,75,99,111,108,108,101,99,116,105,111,110,45,112, -97,116,104,73,102,105,110,100,45,99,111,108,45,102,105,108,101,1,20,99,111, -108,108,101,99,116,105,111,110,45,102,105,108,101,45,112,97,116,104,77,99,104, -101,99,107,45,115,117,102,102,105,120,45,99,97,108,108,79,112,97,116,104,45, -114,101,112,108,97,99,101,45,115,117,102,102,105,120,75,112,97,116,104,45,97, -100,100,45,115,117,102,102,105,120,77,108,111,97,100,47,117,115,101,45,99,111, -109,112,105,108,101,100,1,29,102,105,110,100,45,108,105,98,114,97,114,121,45, -99,111,108,108,101,99,116,105,111,110,45,112,97,116,104,115,1,27,112,97,116, -104,45,108,105,115,116,45,115,116,114,105,110,103,45,62,112,97,116,104,45,108, -105,115,116,1,20,102,105,110,100,45,101,120,101,99,117,116,97,98,108,101,45, -112,97,116,104,73,101,109,98,101,100,100,101,100,45,108,111,97,100,65,113,117, -111,116,101,29,94,2,18,68,35,37,112,97,114,97,109,122,11,64,108,111,111, -112,69,101,120,101,99,45,102,105,108,101,67,119,105,110,100,111,119,115,6,25, -25,112,97,116,104,32,111,114,32,118,97,108,105,100,45,112,97,116,104,32,115, -116,114,105,110,103,6,29,29,126,97,58,32,105,110,118,97,108,105,100,32,114, -101,108,97,116,105,118,101,32,112,97,116,104,58,32,126,115,6,42,42,126,97, -58,32,99,111,108,108,101,99,116,105,111,110,32,110,111,116,32,102,111,117,110, -100,58,32,126,115,32,105,110,32,97,110,121,32,111,102,58,32,126,115,65,99, -108,111,111,112,6,4,4,46,114,107,116,6,3,3,46,115,115,6,42,42,112, -97,116,104,32,40,102,111,114,32,97,110,121,32,115,121,115,116,101,109,41,32, -111,114,32,118,97,108,105,100,45,112,97,116,104,32,115,116,114,105,110,103,6, -21,21,115,116,114,105,110,103,32,111,114,32,98,121,116,101,32,115,116,114,105, -110,103,6,36,36,99,97,110,110,111,116,32,97,100,100,32,97,32,115,117,102, -102,105,120,32,116,111,32,97,32,114,111,111,116,32,112,97,116,104,58,32,6, -11,11,80,76,84,67,79,76,76,69,67,84,83,6,0,0,6,0,0,69,97, -100,100,111,110,45,100,105,114,6,8,8,99,111,108,108,101,99,116,115,72,99, -111,108,108,101,99,116,115,45,100,105,114,5,0,5,0,27,20,13,159,80,159, -37,52,37,250,80,159,40,53,37,249,22,27,11,80,159,42,52,37,22,186,13, -10,248,22,190,5,23,196,2,28,248,22,189,6,23,194,2,12,86,94,248,22, -148,9,23,194,1,27,20,13,159,80,159,38,52,37,250,80,159,41,53,37,249, -22,27,11,80,159,43,52,37,22,186,13,10,248,22,190,5,23,197,2,28,248, -22,189,6,23,194,2,12,86,94,248,22,148,9,23,194,1,27,20,13,159,80, -159,39,52,37,250,80,159,42,53,37,249,22,27,11,80,159,44,52,37,22,186, -13,10,248,22,190,5,23,198,2,28,248,22,189,6,23,194,2,12,86,94,248, -22,148,9,23,194,1,248,80,159,40,57,39,197,28,248,22,81,23,195,2,9, -27,248,22,74,23,196,2,27,28,248,22,172,14,23,195,2,23,194,1,28,248, -22,171,14,23,195,2,249,22,173,14,23,196,1,250,80,158,43,50,248,22,188, -14,2,21,11,10,250,80,158,41,50,248,22,188,14,2,21,23,197,1,10,28, -23,193,2,249,22,73,248,22,175,14,249,22,173,14,23,198,1,247,22,189,14, -27,248,22,75,23,200,1,28,248,22,81,23,194,2,9,27,248,22,74,23,195, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,53,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,107,0,0,0,1,0,0,8,0,21,0,26, +0,43,0,65,0,94,0,109,0,127,0,143,0,157,0,179,0,195,0,212,0, +234,0,245,0,251,0,4,1,11,1,18,1,30,1,46,1,70,1,102,1,120, +1,140,1,156,1,174,1,205,1,219,1,224,1,234,1,242,1,251,1,253,1, +255,1,27,2,59,2,72,2,78,2,117,2,121,2,166,2,190,2,229,2,243, +2,246,2,249,2,3,3,14,3,181,3,25,5,143,5,5,6,46,6,119,7, +142,7,159,7,107,9,210,9,224,9,128,10,57,12,66,12,75,12,89,12,99, +12,140,13,242,13,72,14,158,14,2,15,86,15,100,15,214,15,42,16,56,16, +9,17,17,17,123,17,172,17,174,17,18,18,78,18,83,18,189,18,10,19,168, +20,190,20,199,20,192,21,210,21,224,21,183,22,202,22,140,25,4,30,110,30, +255,30,240,31,222,32,229,32,54,33,137,33,222,33,248,33,121,34,0,0,221, +38,0,0,67,35,37,117,116,105,108,115,72,112,97,116,104,45,115,116,114,105, +110,103,63,64,98,115,98,115,76,110,111,114,109,97,108,45,99,97,115,101,45, +112,97,116,104,1,20,102,105,110,100,45,101,120,101,99,117,116,97,98,108,101, +45,112,97,116,104,1,27,112,97,116,104,45,108,105,115,116,45,115,116,114,105, +110,103,45,62,112,97,116,104,45,108,105,115,116,74,45,99,104,101,99,107,45, +114,101,108,112,97,116,104,77,45,99,104,101,99,107,45,99,111,108,108,101,99, +116,105,111,110,75,99,111,108,108,101,99,116,105,111,110,45,112,97,116,104,73, +102,105,110,100,45,99,111,108,45,102,105,108,101,1,20,99,111,108,108,101,99, +116,105,111,110,45,102,105,108,101,45,112,97,116,104,75,117,115,101,114,45,108, +105,110,107,115,45,112,97,116,104,76,117,115,101,114,45,108,105,110,107,115,45, +99,97,99,104,101,1,20,117,115,101,114,45,108,105,110,107,115,45,116,105,109, +101,115,116,97,109,112,70,108,105,110,107,115,45,112,97,116,104,65,113,117,111, +116,101,68,35,37,112,97,114,97,109,122,29,94,2,16,2,17,11,29,94,2, +16,2,17,11,71,108,105,110,107,115,45,99,97,99,104,101,75,108,105,110,107, +115,45,116,105,109,101,115,116,97,109,112,1,22,103,101,116,45,108,105,110,107, +101,100,45,99,111,108,108,101,99,116,105,111,110,115,1,30,110,111,114,109,97, +108,105,122,101,45,99,111,108,108,101,99,116,105,111,110,45,114,101,102,101,114, +101,110,99,101,77,99,104,101,99,107,45,115,117,102,102,105,120,45,99,97,108, +108,79,112,97,116,104,45,114,101,112,108,97,99,101,45,115,117,102,102,105,120, +75,112,97,116,104,45,97,100,100,45,115,117,102,102,105,120,77,108,111,97,100, +47,117,115,101,45,99,111,109,112,105,108,101,100,1,29,102,105,110,100,45,108, +105,98,114,97,114,121,45,99,111,108,108,101,99,116,105,111,110,45,112,97,116, +104,115,73,101,109,98,101,100,100,101,100,45,108,111,97,100,64,108,111,111,112, +69,101,120,101,99,45,102,105,108,101,67,119,105,110,100,111,119,115,68,114,101, +108,97,116,105,118,101,5,0,5,0,6,25,25,112,97,116,104,32,111,114,32, +118,97,108,105,100,45,112,97,116,104,32,115,116,114,105,110,103,6,29,29,126, +97,58,32,105,110,118,97,108,105,100,32,114,101,108,97,116,105,118,101,32,112, +97,116,104,58,32,126,115,72,99,111,108,108,101,99,116,115,45,100,105,114,65, +101,114,114,111,114,6,36,36,101,114,114,111,114,32,114,101,97,100,105,110,103, +32,108,105,110,107,101,100,32,99,111,108,108,101,99,116,105,111,110,115,58,32, +126,97,6,1,1,47,6,42,42,112,97,116,104,32,40,102,111,114,32,97,110, +121,32,115,121,115,116,101,109,41,32,111,114,32,118,97,108,105,100,45,112,97, +116,104,32,115,116,114,105,110,103,6,21,21,115,116,114,105,110,103,32,111,114, +32,98,121,116,101,32,115,116,114,105,110,103,6,36,36,99,97,110,110,111,116, +32,97,100,100,32,97,32,115,117,102,102,105,120,32,116,111,32,97,32,114,111, +111,116,32,112,97,116,104,58,32,6,11,11,80,76,84,67,79,76,76,69,67, +84,83,6,0,0,6,0,0,69,97,100,100,111,110,45,100,105,114,6,8,8, +99,111,108,108,101,99,116,115,27,20,13,159,80,159,37,51,37,250,80,159,40, +52,37,249,22,27,11,80,159,42,51,37,22,186,13,10,248,22,190,5,23,196, +2,28,248,22,189,6,23,194,2,12,86,94,248,22,148,9,23,194,1,27,20, +13,159,80,159,38,51,37,250,80,159,41,52,37,249,22,27,11,80,159,43,51, +37,22,186,13,10,248,22,190,5,23,197,2,28,248,22,189,6,23,194,2,12, +86,94,248,22,148,9,23,194,1,27,20,13,159,80,159,39,51,37,250,80,159, +42,52,37,249,22,27,11,80,159,44,51,37,22,186,13,10,248,22,190,5,23, +198,2,28,248,22,189,6,23,194,2,12,86,94,248,22,148,9,23,194,1,248, +80,159,40,8,31,39,197,28,248,22,81,23,195,2,9,27,248,22,74,23,196, 2,27,28,248,22,172,14,23,195,2,23,194,1,28,248,22,171,14,23,195,2, -249,22,173,14,23,196,1,250,80,158,48,50,248,22,188,14,2,21,11,10,250, -80,158,46,50,248,22,188,14,2,21,23,197,1,10,28,23,193,2,249,22,73, -248,22,175,14,249,22,173,14,23,198,1,247,22,189,14,248,80,159,46,56,39, -248,22,75,23,199,1,86,94,23,193,1,248,80,159,44,56,39,248,22,75,23, +249,22,173,14,23,196,1,250,80,159,43,39,39,248,22,188,14,2,31,11,10, +250,80,159,41,39,39,248,22,188,14,2,31,23,197,1,10,28,23,193,2,249, +22,73,248,22,175,14,249,22,173,14,23,198,1,247,22,189,14,27,248,22,75, +23,200,1,28,248,22,81,23,194,2,9,27,248,22,74,23,195,2,27,28,248, +22,172,14,23,195,2,23,194,1,28,248,22,171,14,23,195,2,249,22,173,14, +23,196,1,250,80,159,48,39,39,248,22,188,14,2,31,11,10,250,80,159,46, +39,39,248,22,188,14,2,31,23,197,1,10,28,23,193,2,249,22,73,248,22, +175,14,249,22,173,14,23,198,1,247,22,189,14,248,80,159,46,8,30,39,248, +22,75,23,199,1,86,94,23,193,1,248,80,159,44,8,30,39,248,22,75,23, 197,1,86,94,23,193,1,27,248,22,75,23,198,1,28,248,22,81,23,194,2, 9,27,248,22,74,23,195,2,27,28,248,22,172,14,23,195,2,23,194,1,28, -248,22,171,14,23,195,2,249,22,173,14,23,196,1,250,80,158,46,50,248,22, -188,14,2,21,11,10,250,80,158,44,50,248,22,188,14,2,21,23,197,1,10, -28,23,193,2,249,22,73,248,22,175,14,249,22,173,14,23,198,1,247,22,189, -14,248,80,159,44,56,39,248,22,75,23,199,1,248,80,159,42,56,39,248,22, -75,196,28,248,22,81,23,195,2,9,27,248,22,74,23,196,2,27,28,248,22, -172,14,23,195,2,23,194,1,28,248,22,171,14,23,195,2,249,22,173,14,23, -196,1,250,80,158,43,50,248,22,188,14,2,21,11,10,250,80,158,41,50,248, -22,188,14,2,21,23,197,1,10,28,23,193,2,249,22,73,248,22,175,14,249, -22,173,14,23,198,1,247,22,189,14,248,80,159,41,55,39,248,22,75,23,200, -1,248,80,159,39,55,39,248,22,75,197,28,248,22,81,23,195,2,9,27,248, -22,74,23,196,2,27,28,248,22,172,14,23,195,2,23,194,1,28,248,22,171, -14,23,195,2,249,22,173,14,23,196,1,250,80,158,43,50,248,22,188,14,2, -21,11,10,250,80,158,41,50,248,22,188,14,2,21,23,197,1,10,28,23,193, -2,249,22,73,248,22,175,14,249,22,173,14,23,198,1,247,22,189,14,248,80, -159,41,54,39,248,22,75,23,200,1,248,80,159,39,54,39,248,22,75,197,27, -248,22,148,14,23,195,2,28,23,193,2,192,86,94,23,193,1,28,248,22,130, -7,23,195,2,27,248,22,170,14,195,28,192,192,248,22,171,14,195,11,86,94, -28,28,248,22,149,14,23,195,2,10,28,248,22,148,14,23,195,2,10,28,248, -22,130,7,23,195,2,28,248,22,170,14,23,195,2,10,248,22,171,14,23,195, -2,11,12,250,22,176,9,76,110,111,114,109,97,108,45,112,97,116,104,45,99, -97,115,101,6,42,42,112,97,116,104,32,40,102,111,114,32,97,110,121,32,115, -121,115,116,101,109,41,32,111,114,32,118,97,108,105,100,45,112,97,116,104,32, -115,116,114,105,110,103,23,197,2,28,28,248,22,149,14,23,195,2,249,22,140, -9,248,22,150,14,23,197,2,2,22,249,22,140,9,247,22,152,8,2,22,27, -28,248,22,130,7,23,196,2,23,195,2,248,22,142,8,248,22,153,14,23,197, -2,28,249,22,139,15,0,21,35,114,120,34,94,91,92,92,93,91,92,92,93, -91,63,93,91,92,92,93,34,23,195,2,28,248,22,130,7,195,248,22,156,14, -195,194,27,248,22,169,7,23,195,1,249,22,157,14,248,22,145,8,250,22,147, -15,0,6,35,114,120,34,47,34,28,249,22,139,15,0,22,35,114,120,34,91, -47,92,92,93,91,46,32,93,43,91,47,92,92,93,42,36,34,23,201,2,23, -199,1,250,22,147,15,0,19,35,114,120,34,91,32,46,93,43,40,91,47,92, -92,93,42,41,36,34,23,202,1,6,2,2,92,49,80,159,44,37,38,2,22, -28,248,22,130,7,194,248,22,156,14,194,193,86,94,28,28,248,22,148,14,23, -195,2,10,28,248,22,130,7,23,195,2,28,248,22,170,14,23,195,2,10,248, -22,171,14,23,195,2,11,12,250,22,176,9,23,196,2,2,23,23,197,2,28, -248,22,170,14,23,195,2,12,248,22,162,12,249,22,168,11,248,22,159,7,250, -22,178,7,2,24,23,200,1,23,201,1,247,22,23,86,94,28,28,248,22,148, -14,23,195,2,10,28,248,22,130,7,23,195,2,28,248,22,170,14,23,195,2, -10,248,22,171,14,23,195,2,11,12,250,22,176,9,23,196,2,2,23,23,197, -2,28,248,22,170,14,23,195,2,12,248,22,162,12,249,22,168,11,248,22,159, -7,250,22,178,7,2,24,23,200,1,23,201,1,247,22,23,86,94,86,94,28, -28,248,22,148,14,23,195,2,10,28,248,22,130,7,23,195,2,28,248,22,170, -14,23,195,2,10,248,22,171,14,23,195,2,11,12,250,22,176,9,195,2,23, -23,197,2,28,248,22,170,14,23,195,2,12,248,22,162,12,249,22,168,11,248, -22,159,7,250,22,178,7,2,24,199,23,201,1,247,22,23,249,22,3,88,163, -8,36,37,50,11,9,223,2,33,47,196,86,94,28,28,248,22,148,14,23,194, -2,10,28,248,22,130,7,23,194,2,28,248,22,170,14,23,194,2,10,248,22, -171,14,23,194,2,11,12,250,22,176,9,2,7,2,23,23,196,2,28,248,22, -170,14,23,194,2,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178, -7,2,24,2,7,23,200,1,247,22,23,32,50,88,163,8,36,41,56,11,2, -26,222,33,51,28,248,22,81,23,197,2,86,94,23,196,1,28,23,197,2,196, -86,94,23,197,1,248,22,162,12,249,22,137,12,251,22,178,7,2,25,2,7, -28,248,22,81,23,203,2,86,94,23,202,1,23,201,1,250,22,1,22,166,14, -23,204,1,23,205,1,23,200,1,247,22,23,27,249,22,166,14,248,22,74,23, -200,2,23,197,2,28,248,22,161,14,23,194,2,27,250,22,1,22,166,14,23, -197,1,199,28,248,22,161,14,193,192,252,2,50,199,200,201,248,22,75,203,203, -252,2,50,198,199,200,248,22,75,202,202,86,94,86,94,86,94,28,28,248,22, +248,22,171,14,23,195,2,249,22,173,14,23,196,1,250,80,159,46,39,39,248, +22,188,14,2,31,11,10,250,80,159,44,39,39,248,22,188,14,2,31,23,197, +1,10,28,23,193,2,249,22,73,248,22,175,14,249,22,173,14,23,198,1,247, +22,189,14,248,80,159,44,8,30,39,248,22,75,23,199,1,248,80,159,42,8, +30,39,248,22,75,196,28,248,22,81,23,195,2,9,27,248,22,74,23,196,2, +27,28,248,22,172,14,23,195,2,23,194,1,28,248,22,171,14,23,195,2,249, +22,173,14,23,196,1,250,80,159,43,39,39,248,22,188,14,2,31,11,10,250, +80,159,41,39,39,248,22,188,14,2,31,23,197,1,10,28,23,193,2,249,22, +73,248,22,175,14,249,22,173,14,23,198,1,247,22,189,14,248,80,159,41,8, +29,39,248,22,75,23,200,1,248,80,159,39,8,29,39,248,22,75,197,28,248, +22,81,23,195,2,9,27,248,22,74,23,196,2,27,28,248,22,172,14,23,195, +2,23,194,1,28,248,22,171,14,23,195,2,249,22,173,14,23,196,1,250,80, +159,43,39,39,248,22,188,14,2,31,11,10,250,80,159,41,39,39,248,22,188, +14,2,31,23,197,1,10,28,23,193,2,249,22,73,248,22,175,14,249,22,173, +14,23,198,1,247,22,189,14,248,80,159,41,8,28,39,248,22,75,23,200,1, +248,80,159,39,8,28,39,248,22,75,197,27,248,22,148,14,23,195,2,28,23, +193,2,192,86,94,23,193,1,28,248,22,130,7,23,195,2,27,248,22,170,14, +195,28,192,192,248,22,171,14,195,11,86,94,28,28,248,22,149,14,23,195,2, +10,28,248,22,148,14,23,195,2,10,28,248,22,130,7,23,195,2,28,248,22, +170,14,23,195,2,10,248,22,171,14,23,195,2,11,12,250,22,176,9,76,110, +111,114,109,97,108,45,112,97,116,104,45,99,97,115,101,6,42,42,112,97,116, +104,32,40,102,111,114,32,97,110,121,32,115,121,115,116,101,109,41,32,111,114, +32,118,97,108,105,100,45,112,97,116,104,32,115,116,114,105,110,103,23,197,2, +28,28,248,22,149,14,23,195,2,249,22,140,9,248,22,150,14,23,197,2,2, +32,249,22,140,9,247,22,152,8,2,32,27,28,248,22,130,7,23,196,2,23, +195,2,248,22,142,8,248,22,153,14,23,197,2,28,249,22,139,15,0,21,35, +114,120,34,94,91,92,92,93,91,92,92,93,91,63,93,91,92,92,93,34,23, +195,2,28,248,22,130,7,195,248,22,156,14,195,194,27,248,22,169,7,23,195, +1,249,22,157,14,248,22,145,8,250,22,147,15,0,6,35,114,120,34,47,34, +28,249,22,139,15,0,22,35,114,120,34,91,47,92,92,93,91,46,32,93,43, +91,47,92,92,93,42,36,34,23,201,2,23,199,1,250,22,147,15,0,19,35, +114,120,34,91,32,46,93,43,40,91,47,92,92,93,42,41,36,34,23,202,1, +6,2,2,92,49,80,159,44,37,38,2,32,28,248,22,130,7,194,248,22,156, +14,194,193,32,56,88,163,8,36,39,53,11,70,102,111,117,110,100,45,101,120, +101,99,222,33,59,32,57,88,163,8,36,40,58,11,64,110,101,120,116,222,33, +58,27,248,22,174,14,23,196,2,28,249,22,142,9,23,195,2,23,197,1,11, +28,248,22,170,14,23,194,2,27,249,22,166,14,23,197,1,23,196,1,28,23, +197,2,90,159,39,11,89,161,39,36,11,248,22,169,14,23,197,2,86,95,23, +195,1,23,194,1,27,28,23,202,2,27,248,22,174,14,23,199,2,28,249,22, +142,9,23,195,2,23,200,2,11,28,248,22,170,14,23,194,2,250,2,56,23, +205,2,23,206,2,249,22,166,14,23,200,2,23,198,1,250,2,56,23,205,2, +23,206,2,23,196,1,11,28,23,193,2,192,86,94,23,193,1,27,28,248,22, +148,14,23,196,2,27,249,22,166,14,23,198,2,23,205,2,28,28,248,22,161, +14,193,10,248,22,160,14,193,192,11,11,28,23,193,2,192,86,94,23,193,1, +28,23,203,2,11,27,248,22,174,14,23,200,2,28,249,22,142,9,23,195,2, +23,201,1,11,28,248,22,170,14,23,194,2,250,2,56,23,206,1,23,207,1, +249,22,166,14,23,201,1,23,198,1,250,2,56,205,206,195,192,86,94,23,194, +1,28,23,196,2,90,159,39,11,89,161,39,36,11,248,22,169,14,23,197,2, +86,95,23,195,1,23,194,1,27,28,23,201,2,27,248,22,174,14,23,199,2, +28,249,22,142,9,23,195,2,23,200,2,11,28,248,22,170,14,23,194,2,250, +2,56,23,204,2,23,205,2,249,22,166,14,23,200,2,23,198,1,250,2,56, +23,204,2,23,205,2,23,196,1,11,28,23,193,2,192,86,94,23,193,1,27, +28,248,22,148,14,23,196,2,27,249,22,166,14,23,198,2,23,204,2,28,28, +248,22,161,14,193,10,248,22,160,14,193,192,11,11,28,23,193,2,192,86,94, +23,193,1,28,23,202,2,11,27,248,22,174,14,23,200,2,28,249,22,142,9, +23,195,2,23,201,1,11,28,248,22,170,14,23,194,2,250,2,56,23,205,1, +23,206,1,249,22,166,14,23,201,1,23,198,1,250,2,56,204,205,195,192,28, +23,193,2,90,159,39,11,89,161,39,36,11,248,22,169,14,23,199,2,86,95, +23,195,1,23,194,1,27,28,23,198,2,251,2,57,23,198,2,23,203,2,23, +201,2,23,202,2,11,28,23,193,2,192,86,94,23,193,1,27,28,248,22,148, +14,195,27,249,22,166,14,197,200,28,28,248,22,161,14,193,10,248,22,160,14, +193,192,11,11,28,192,192,28,198,11,251,2,57,198,203,201,202,194,32,60,88, +163,8,36,40,58,11,2,30,222,33,61,28,248,22,81,23,197,2,11,27,248, +22,173,14,248,22,74,23,199,2,27,249,22,166,14,23,196,1,23,197,2,28, +248,22,160,14,23,194,2,250,2,56,198,199,195,86,94,23,193,1,27,248,22, +75,23,200,1,28,248,22,81,23,194,2,11,27,248,22,173,14,248,22,74,23, +196,2,27,249,22,166,14,23,196,1,23,200,2,28,248,22,160,14,23,194,2, +250,2,56,201,202,195,86,94,23,193,1,27,248,22,75,23,197,1,28,248,22, +81,23,194,2,11,27,248,22,173,14,248,22,74,195,27,249,22,166,14,23,196, +1,202,28,248,22,160,14,193,250,2,56,204,205,195,251,2,60,204,205,206,248, +22,75,199,86,95,28,28,248,22,148,14,23,195,2,10,28,248,22,130,7,23, +195,2,28,248,22,170,14,23,195,2,10,248,22,171,14,23,195,2,11,12,250, +22,176,9,2,5,6,25,25,112,97,116,104,32,111,114,32,115,116,114,105,110, +103,32,40,115,97,110,115,32,110,117,108,41,23,197,2,28,28,23,195,2,28, +28,248,22,148,14,23,196,2,10,28,248,22,130,7,23,196,2,28,248,22,170, +14,23,196,2,10,248,22,171,14,23,196,2,11,248,22,170,14,23,196,2,11, +10,12,250,22,176,9,2,5,6,29,29,35,102,32,111,114,32,114,101,108,97, +116,105,118,101,32,112,97,116,104,32,111,114,32,115,116,114,105,110,103,23,198, +2,28,28,248,22,170,14,23,195,2,90,159,39,11,89,161,39,36,11,248,22, +169,14,23,198,2,249,22,140,9,194,2,33,11,27,248,22,150,8,6,4,4, +80,65,84,72,27,28,23,194,2,27,249,80,158,41,40,23,197,1,9,28,249, +22,140,9,247,22,152,8,2,32,249,22,73,248,22,157,14,5,1,46,194,192, +86,94,23,194,1,9,28,248,22,81,23,194,2,11,27,248,22,173,14,248,22, +74,23,196,2,27,249,22,166,14,23,196,1,23,200,2,28,248,22,160,14,23, +194,2,250,2,56,201,202,195,86,94,23,193,1,27,248,22,75,23,197,1,28, +248,22,81,23,194,2,11,27,248,22,173,14,248,22,74,23,196,2,27,249,22, +166,14,23,196,1,23,203,2,28,248,22,160,14,23,194,2,250,2,56,204,205, +195,86,94,23,193,1,27,248,22,75,23,197,1,28,248,22,81,23,194,2,11, +27,248,22,173,14,248,22,74,195,27,249,22,166,14,23,196,1,205,28,248,22, +160,14,193,250,2,56,23,15,23,16,195,251,2,60,23,15,23,16,23,17,248, +22,75,199,27,248,22,173,14,23,196,1,28,248,22,160,14,193,250,2,56,198, +199,195,11,250,80,159,39,39,39,196,197,11,250,80,159,39,39,39,196,11,11, +32,65,88,163,8,36,39,57,11,2,30,222,33,67,0,8,35,114,120,35,34, +92,34,34,27,249,22,135,15,23,197,2,23,198,2,28,23,193,2,86,94,23, +196,1,27,248,22,98,23,195,2,27,27,248,22,107,23,197,1,27,249,22,135, +15,23,201,2,23,196,2,28,23,193,2,86,94,23,194,1,27,248,22,98,23, +195,2,27,250,2,65,23,203,2,23,204,1,248,22,107,23,199,1,28,249,22, +191,7,23,196,2,2,34,249,22,87,23,202,2,194,249,22,73,248,22,157,14, +28,249,22,140,9,247,22,152,8,2,32,250,22,147,15,2,66,23,200,1,2, +35,23,197,1,194,86,95,23,199,1,23,193,1,28,249,22,191,7,23,196,2, +2,34,249,22,87,23,200,2,9,249,22,73,248,22,157,14,28,249,22,140,9, +247,22,152,8,2,32,250,22,147,15,2,66,23,200,1,2,35,23,197,1,9, +28,249,22,191,7,23,196,2,2,34,249,22,87,197,194,86,94,23,196,1,249, +22,73,248,22,157,14,28,249,22,140,9,247,22,152,8,2,32,250,22,147,15, +2,66,23,200,1,2,35,23,197,1,194,86,94,23,193,1,28,249,22,191,7, +23,198,2,2,34,249,22,87,195,9,86,94,23,194,1,249,22,73,248,22,157, +14,28,249,22,140,9,247,22,152,8,2,32,250,22,147,15,2,66,23,202,1, +2,35,23,199,1,9,86,95,28,28,248,22,183,7,194,10,248,22,130,7,194, +12,250,22,176,9,2,6,6,21,21,98,121,116,101,32,115,116,114,105,110,103, +32,111,114,32,115,116,114,105,110,103,196,28,28,248,22,82,195,249,22,4,22, +148,14,196,11,12,250,22,176,9,2,6,6,13,13,108,105,115,116,32,111,102, +32,112,97,116,104,115,197,250,2,65,197,195,28,248,22,130,7,197,248,22,144, +8,197,196,86,94,28,28,248,22,148,14,23,195,2,10,28,248,22,130,7,23, +195,2,28,248,22,170,14,23,195,2,10,248,22,171,14,23,195,2,11,12,250, +22,176,9,23,196,2,2,36,23,197,2,28,248,22,170,14,23,195,2,12,248, +22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37,23,200,1,23, +201,1,247,22,23,86,94,28,28,248,22,148,14,23,195,2,10,28,248,22,130, +7,23,195,2,28,248,22,170,14,23,195,2,10,248,22,171,14,23,195,2,11, +12,250,22,176,9,23,196,2,2,36,23,197,2,28,248,22,170,14,23,195,2, +12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37,23,200, +1,23,201,1,247,22,23,86,94,86,94,28,28,248,22,148,14,23,195,2,10, +28,248,22,130,7,23,195,2,28,248,22,170,14,23,195,2,10,248,22,171,14, +23,195,2,11,12,250,22,176,9,195,2,36,23,197,2,28,248,22,170,14,23, +195,2,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37, +199,23,201,1,247,22,23,249,22,3,88,163,8,36,37,50,11,9,223,2,33, +70,196,86,94,28,28,248,22,148,14,23,194,2,10,28,248,22,130,7,23,194, +2,28,248,22,170,14,23,194,2,10,248,22,171,14,23,194,2,11,12,250,22, +176,9,2,9,2,36,23,196,2,28,248,22,170,14,23,194,2,12,248,22,162, +12,249,22,168,11,248,22,159,7,250,22,178,7,2,37,2,9,23,200,1,247, +22,23,248,22,162,12,249,22,137,12,23,196,1,247,22,23,86,94,86,94,86, +94,28,28,248,22,148,14,194,10,28,248,22,130,7,194,28,248,22,170,14,194, +10,248,22,171,14,194,11,12,250,22,176,9,2,9,2,36,196,28,248,22,170, +14,194,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37, +2,9,200,247,22,23,249,22,3,32,0,88,163,8,36,37,49,11,9,222,33, +72,196,252,80,158,41,44,2,9,32,0,88,163,8,36,37,45,11,9,222,33, +73,198,199,11,86,94,28,28,248,22,148,14,23,194,2,10,28,248,22,130,7, +23,194,2,28,248,22,170,14,23,194,2,10,248,22,171,14,23,194,2,11,12, +250,22,176,9,2,11,2,36,23,196,2,28,248,22,170,14,23,194,2,12,248, +22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37,2,11,23,200, +1,247,22,23,248,22,162,12,249,22,137,12,23,196,1,247,22,23,86,95,86, +94,28,28,248,22,148,14,194,10,28,248,22,130,7,194,28,248,22,170,14,194, +10,248,22,171,14,194,11,12,250,22,176,9,2,11,2,36,196,28,248,22,170, +14,194,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37, +2,11,200,247,22,23,86,94,86,94,28,28,248,22,148,14,23,196,2,10,28, +248,22,130,7,23,196,2,28,248,22,170,14,23,196,2,10,248,22,171,14,23, +196,2,11,12,250,22,176,9,2,11,2,36,23,198,2,28,248,22,170,14,23, +196,2,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7,2,37, +2,11,23,202,2,247,22,23,249,22,3,32,0,88,163,8,36,37,49,11,9, +222,33,75,23,198,2,249,22,166,14,252,80,158,43,44,2,11,32,0,88,163, +8,36,37,45,11,9,222,33,76,23,202,1,23,203,1,200,195,0,6,45,105, +110,102,46,48,27,248,22,188,14,2,38,27,28,248,22,171,14,23,195,2,193, +20,13,159,80,159,38,51,37,250,80,159,41,52,37,249,22,27,11,80,159,43, +51,37,22,189,14,248,22,188,14,68,111,114,105,103,45,100,105,114,27,248,22, +188,14,2,31,250,80,159,42,39,39,23,196,1,23,198,1,11,28,192,250,22, +166,14,195,6,6,6,99,111,110,102,105,103,6,10,10,108,105,110,107,115,46, +114,107,116,100,11,86,94,27,247,22,131,10,28,249,22,188,9,23,195,2,2, +39,251,22,191,9,23,197,1,2,39,249,22,178,7,2,40,248,22,160,11,23, +202,1,247,22,23,12,248,193,247,22,133,2,2,78,86,95,27,247,22,131,10, +28,249,22,188,9,23,195,2,2,39,251,22,191,9,23,197,1,2,39,249,22, +178,7,2,40,248,22,160,11,23,205,1,247,22,23,12,28,192,28,194,86,94, +20,18,159,11,80,158,39,47,247,22,133,2,20,18,159,11,80,158,39,48,192, +86,94,20,18,159,11,80,158,39,53,247,22,133,2,20,18,159,11,80,158,39, +54,192,12,248,194,247,22,133,2,20,20,94,248,22,190,5,23,194,2,28,248, +22,189,6,248,22,190,5,23,195,1,12,248,22,173,9,6,30,30,101,120,112, +101,99,116,101,100,32,97,32,115,105,110,103,108,101,32,83,45,101,120,112,114, +101,115,115,105,111,110,248,22,178,5,193,28,248,22,82,23,194,2,28,28,249, +22,184,3,38,248,22,86,23,196,2,10,249,22,184,3,39,248,22,86,23,196, +2,28,248,22,130,7,248,22,74,23,195,2,28,27,248,22,98,194,28,248,22, 148,14,23,194,2,10,28,248,22,130,7,23,194,2,28,248,22,170,14,23,194, -2,10,248,22,171,14,23,194,2,11,12,250,22,176,9,2,7,2,23,23,196, -2,28,248,22,170,14,23,194,2,12,248,22,162,12,249,22,168,11,248,22,159, -7,250,22,178,7,2,24,2,7,23,200,2,247,22,23,249,22,3,32,0,88, -163,8,36,37,49,11,9,222,33,49,23,196,2,27,247,22,190,14,28,248,22, -81,23,194,2,248,22,162,12,249,22,137,12,251,22,178,7,2,25,2,7,28, -248,22,81,23,203,2,86,94,23,202,1,23,201,1,250,22,1,22,166,14,23, -204,1,23,205,1,23,200,1,247,22,23,27,249,22,166,14,248,22,74,23,197, -2,23,197,2,28,248,22,161,14,23,194,2,27,250,22,1,22,166,14,23,197, -1,199,28,248,22,161,14,193,192,252,2,50,199,200,201,248,22,75,200,11,252, -2,50,198,199,200,248,22,75,199,11,86,94,28,28,248,22,148,14,23,194,2, -10,28,248,22,130,7,23,194,2,28,248,22,170,14,23,194,2,10,248,22,171, -14,23,194,2,11,12,250,22,176,9,2,9,2,23,23,196,2,28,248,22,170, -14,23,194,2,12,248,22,162,12,249,22,168,11,248,22,159,7,250,22,178,7, -2,24,2,9,23,200,1,247,22,23,32,54,88,163,8,36,42,59,11,2,26, -222,33,55,28,248,22,81,23,198,2,86,95,23,197,1,23,194,1,28,23,198, -2,197,86,94,23,198,1,248,22,162,12,249,22,137,12,251,22,178,7,2,25, -2,9,28,248,22,81,23,204,2,86,94,23,203,1,23,202,1,250,22,1,22, -166,14,23,205,1,23,206,1,23,200,1,247,22,23,27,249,22,166,14,248,22, -74,23,201,2,23,198,2,28,248,22,161,14,23,194,2,27,250,22,1,22,166, -14,23,197,1,23,201,2,28,248,22,161,14,23,194,2,28,23,196,2,28,28, -248,22,160,14,249,22,166,14,195,198,10,27,28,248,22,148,14,197,248,22,152, -14,197,196,27,248,22,133,7,23,195,2,27,28,249,22,188,3,23,196,2,40, -28,249,22,136,7,2,27,249,22,152,7,23,199,2,249,22,176,3,23,200,2, -40,249,22,153,7,250,22,152,7,23,200,1,36,249,22,176,3,23,201,1,40, -2,28,86,95,23,195,1,23,194,1,11,11,28,23,193,2,248,22,160,14,249, -22,166,14,198,23,196,1,11,192,253,2,54,200,201,202,203,248,22,75,205,28, -205,205,198,192,253,2,54,200,201,202,203,248,22,75,205,205,253,2,54,199,200, -201,202,248,22,75,204,204,86,95,86,94,28,28,248,22,148,14,193,10,28,248, -22,130,7,193,28,248,22,170,14,193,10,248,22,171,14,193,11,12,250,22,176, -9,2,9,2,23,195,28,248,22,170,14,193,12,248,22,162,12,249,22,168,11, -248,22,159,7,250,22,178,7,2,24,2,9,199,247,22,23,86,94,86,94,28, -28,248,22,148,14,23,195,2,10,28,248,22,130,7,23,195,2,28,248,22,170, -14,23,195,2,10,248,22,171,14,23,195,2,11,12,250,22,176,9,2,9,2, -23,23,197,2,28,248,22,170,14,23,195,2,12,248,22,162,12,249,22,168,11, -248,22,159,7,250,22,178,7,2,24,2,9,23,201,2,247,22,23,249,22,3, -32,0,88,163,8,36,37,49,11,9,222,33,53,23,197,2,249,22,166,14,27, -247,22,190,14,253,2,54,23,199,2,201,23,203,1,23,204,1,23,199,1,11, -194,32,57,88,163,36,44,8,29,11,2,26,222,33,58,28,248,22,81,23,200, -2,86,95,23,199,1,23,198,1,28,23,200,2,199,86,94,23,200,1,248,23, -196,1,251,22,178,7,2,25,23,199,1,28,248,22,81,23,203,2,86,94,23, -202,1,23,201,1,250,22,1,22,166,14,23,204,1,23,205,1,23,198,1,27, -249,22,166,14,248,22,74,23,203,2,23,199,2,28,248,22,161,14,23,194,2, -27,250,22,1,22,166,14,23,197,1,23,202,2,28,248,22,161,14,23,194,2, -28,23,200,2,28,28,248,22,160,14,249,22,166,14,23,196,2,23,203,2,10, -27,28,248,22,148,14,23,202,2,248,22,152,14,23,202,2,23,201,2,27,248, -22,133,7,23,195,2,27,28,249,22,188,3,23,196,2,40,28,249,22,136,7, -2,27,249,22,152,7,23,199,2,249,22,176,3,23,200,2,40,249,22,153,7, -250,22,152,7,23,200,1,36,249,22,176,3,23,201,1,40,2,28,86,95,23, -195,1,23,194,1,11,11,28,23,193,2,248,22,160,14,249,22,166,14,23,199, -2,23,196,1,11,192,27,248,22,75,23,203,1,27,28,23,204,2,86,94,23, -195,1,23,204,1,86,94,23,204,1,23,195,1,28,248,22,81,23,195,2,86, -95,23,202,1,23,194,1,28,23,193,2,192,86,94,23,193,1,248,23,200,1, -251,22,178,7,2,25,23,203,1,28,248,22,81,23,207,2,86,94,23,206,1, -23,205,1,250,22,1,22,166,14,23,208,1,23,209,1,23,202,1,27,249,22, -166,14,248,22,74,23,198,2,23,203,2,28,248,22,161,14,23,194,2,27,250, -22,1,22,166,14,23,197,1,23,206,2,28,248,22,161,14,23,194,2,28,23, -204,2,28,28,248,22,160,14,249,22,166,14,195,206,10,27,28,248,22,148,14, -205,248,22,152,14,205,204,27,248,22,133,7,23,195,2,27,28,249,22,188,3, -23,196,2,40,28,249,22,136,7,2,27,249,22,152,7,23,199,2,249,22,176, -3,23,200,2,40,249,22,153,7,250,22,152,7,23,200,1,36,249,22,176,3, -23,201,1,40,2,28,86,95,23,195,1,23,194,1,11,11,28,23,193,2,248, -22,160,14,249,22,166,14,198,23,196,1,11,192,26,8,2,57,206,23,15,23, -16,23,17,23,18,23,19,248,22,75,204,28,202,202,200,192,26,8,2,57,206, -23,15,23,16,23,17,23,18,23,19,248,22,75,204,202,26,8,2,57,205,206, -23,15,23,16,23,17,23,18,248,22,75,203,201,192,27,248,22,75,23,203,1, -28,248,22,81,23,194,2,86,95,23,201,1,23,193,1,28,23,203,2,202,86, -94,23,203,1,248,23,199,1,251,22,178,7,2,25,23,202,1,28,248,22,81, -23,206,2,86,94,23,205,1,23,204,1,250,22,1,22,166,14,23,207,1,23, -208,1,23,201,1,27,249,22,166,14,248,22,74,23,197,2,23,202,2,28,248, -22,161,14,23,194,2,27,250,22,1,22,166,14,23,197,1,23,205,2,28,248, -22,161,14,23,194,2,28,23,203,2,28,28,248,22,160,14,249,22,166,14,195, -205,10,27,28,248,22,148,14,204,248,22,152,14,204,203,27,248,22,133,7,23, -195,2,27,28,249,22,188,3,23,196,2,40,28,249,22,136,7,2,27,249,22, -152,7,23,199,2,249,22,176,3,23,200,2,40,249,22,153,7,250,22,152,7, -23,200,1,36,249,22,176,3,23,201,1,40,2,28,86,95,23,195,1,23,194, -1,11,11,28,23,193,2,248,22,160,14,249,22,166,14,198,23,196,1,11,192, -26,8,2,57,205,206,23,15,23,16,23,17,23,18,248,22,75,203,28,23,20, -23,20,200,192,26,8,2,57,205,206,23,15,23,16,23,17,23,18,248,22,75, -203,23,20,26,8,2,57,204,205,206,23,15,23,16,23,17,248,22,75,202,23, -19,86,94,23,193,1,27,248,22,75,23,202,1,28,248,22,81,23,194,2,86, -95,23,200,1,23,193,1,28,23,202,2,201,86,94,23,202,1,248,23,198,1, -251,22,178,7,2,25,23,201,1,28,248,22,81,23,205,2,86,94,23,204,1, -23,203,1,250,22,1,22,166,14,23,206,1,23,207,1,23,200,1,27,249,22, -166,14,248,22,74,23,197,2,23,201,2,28,248,22,161,14,23,194,2,27,250, -22,1,22,166,14,23,197,1,23,204,2,28,248,22,161,14,23,194,2,28,23, -202,2,28,28,248,22,160,14,249,22,166,14,195,204,10,27,28,248,22,148,14, -203,248,22,152,14,203,202,27,248,22,133,7,23,195,2,27,28,249,22,188,3, -23,196,2,40,28,249,22,136,7,2,27,249,22,152,7,23,199,2,249,22,176, -3,23,200,2,40,249,22,153,7,250,22,152,7,23,200,1,36,249,22,176,3, -23,201,1,40,2,28,86,95,23,195,1,23,194,1,11,11,28,23,193,2,248, -22,160,14,249,22,166,14,198,23,196,1,11,192,26,8,2,57,204,205,206,23, -15,23,16,23,17,248,22,75,203,28,23,19,23,19,200,192,26,8,2,57,204, -205,206,23,15,23,16,23,17,248,22,75,203,23,19,26,8,2,57,203,204,205, -206,23,15,23,16,248,22,75,202,23,18,27,247,22,190,14,28,248,22,81,23, -194,2,86,94,23,198,1,248,23,196,1,251,22,178,7,2,25,23,199,1,28, -248,22,81,23,203,2,86,94,23,202,1,23,201,1,250,22,1,22,166,14,23, -204,1,23,205,1,23,198,1,27,249,22,166,14,248,22,74,23,197,2,23,199, -2,28,248,22,161,14,23,194,2,27,250,22,1,22,166,14,23,197,1,23,202, -2,28,248,22,161,14,23,194,2,28,23,200,2,28,28,248,22,160,14,249,22, -166,14,195,202,10,27,28,248,22,148,14,201,248,22,152,14,201,200,27,248,22, -133,7,23,195,2,27,28,249,22,188,3,23,196,2,40,28,249,22,136,7,2, -27,249,22,152,7,23,199,2,249,22,176,3,23,200,2,40,249,22,153,7,250, -22,152,7,23,200,1,36,249,22,176,3,23,201,1,40,2,28,86,95,23,195, +2,10,248,22,171,14,23,194,1,11,27,248,22,81,248,22,100,195,28,192,192, +248,22,148,15,248,22,107,195,11,11,11,11,28,28,248,22,81,248,22,100,23, +197,2,10,249,22,139,15,248,22,107,23,198,2,247,22,148,8,27,248,22,61, +248,22,74,23,198,2,250,22,151,2,23,197,2,23,196,2,249,22,73,248,22, +125,249,22,173,14,248,22,98,23,205,1,23,203,1,250,22,153,2,23,202,1, +23,201,1,9,12,20,13,159,80,159,37,56,37,88,163,36,37,51,11,9,223, +2,33,80,27,250,22,183,14,28,23,197,2,80,159,41,46,38,80,159,41,49, +38,11,32,0,88,163,8,36,36,41,11,9,222,33,81,28,249,22,186,3,23, +195,2,28,23,196,2,80,158,40,48,80,158,40,54,20,13,159,80,159,38,56, +37,20,20,94,88,163,36,37,54,8,240,0,24,6,0,9,226,2,1,3,0, +33,82,23,196,1,20,13,159,80,159,38,51,37,26,29,80,159,8,31,52,37, +249,22,27,11,80,159,8,33,51,37,22,182,13,10,22,183,13,10,22,184,13, +10,22,187,13,10,22,186,13,10,22,188,13,10,22,185,13,10,22,189,13,10, +22,190,13,10,22,191,13,10,22,128,14,10,22,129,14,10,22,130,14,11,22, +180,13,11,27,249,22,169,5,28,196,80,159,41,46,38,80,159,41,49,38,66, +98,105,110,97,114,121,27,250,22,40,22,31,88,163,8,36,36,44,11,9,223, +4,33,83,20,20,94,88,163,36,36,43,11,9,223,4,33,84,23,197,1,86, +94,28,28,248,22,82,23,194,2,249,22,4,32,0,88,163,8,36,37,45,11, +9,222,33,85,23,195,2,11,12,248,22,173,9,6,18,18,105,108,108,45,102, +111,114,109,101,100,32,99,111,110,116,101,110,116,27,247,22,133,2,27,90,159, +39,11,89,161,39,36,11,248,22,169,14,28,201,80,159,46,46,38,80,159,46, +49,38,192,86,95,249,22,3,20,20,94,88,163,8,36,37,54,11,9,224,2, +3,33,86,23,195,1,23,197,1,28,197,86,94,20,18,159,11,80,158,42,47, +193,20,18,159,11,80,158,42,48,196,86,94,20,18,159,11,80,158,42,53,193, +20,18,159,11,80,158,42,54,196,193,28,193,80,158,38,47,80,158,38,53,248, +22,8,88,163,8,32,37,8,40,8,240,0,188,23,0,9,224,1,2,33,87, +0,7,35,114,120,34,47,43,34,28,248,22,130,7,23,195,2,27,249,22,137, +15,2,89,196,28,192,28,249,22,184,3,248,22,97,195,248,22,174,3,248,22, +133,7,198,249,22,7,250,22,152,7,199,36,248,22,97,198,197,249,22,7,250, +22,152,7,199,36,248,22,97,198,249,22,73,249,22,152,7,200,248,22,99,199, +199,249,22,7,196,197,90,159,39,11,89,161,39,36,11,248,22,169,14,23,198, +1,86,94,23,195,1,28,249,22,140,9,23,195,2,2,33,249,22,7,195,199, +27,249,22,73,23,197,1,23,201,1,28,248,22,130,7,23,195,2,27,249,22, +137,15,2,89,196,28,192,28,249,22,184,3,248,22,97,195,248,22,174,3,248, +22,133,7,198,249,22,7,250,22,152,7,199,36,248,22,97,198,195,249,22,7, +250,22,152,7,199,36,248,22,97,198,249,22,73,249,22,152,7,200,248,22,99, +199,197,249,22,7,196,195,90,159,39,11,89,161,39,36,11,248,22,169,14,23, +198,1,28,249,22,140,9,194,2,33,249,22,7,195,197,249,80,159,45,57,39, +194,249,22,73,197,199,32,91,88,163,36,44,8,36,11,65,99,108,111,111,112, +222,33,96,32,92,88,163,8,36,37,55,11,2,30,222,33,93,28,248,22,81, +248,22,75,23,195,2,248,22,83,27,248,22,74,23,196,1,28,248,22,148,14, +23,194,2,248,22,152,14,23,194,1,192,250,22,84,27,248,22,74,23,198,2, +28,248,22,148,14,23,194,2,248,22,152,14,23,194,1,192,2,41,27,248,22, +75,23,198,1,28,248,22,81,248,22,75,23,195,2,248,22,83,27,248,22,74, +23,196,1,28,248,22,148,14,23,194,2,248,22,152,14,23,194,1,192,250,22, +84,27,248,22,74,23,198,2,28,248,22,148,14,23,194,2,248,22,152,14,23, +194,1,192,2,41,27,248,22,75,23,198,1,28,248,22,81,248,22,75,23,195, +2,248,22,83,27,248,22,74,23,196,1,28,248,22,148,14,23,194,2,248,22, +152,14,23,194,1,192,250,22,84,27,248,22,74,23,198,2,28,248,22,148,14, +23,194,2,248,22,152,14,23,194,1,192,2,41,248,2,92,248,22,75,23,198, +1,32,94,88,163,8,36,38,57,11,66,102,105,108,116,101,114,222,33,95,28, +248,22,81,23,195,2,9,28,248,23,194,2,248,22,74,23,196,2,249,22,73, +248,22,74,23,197,2,27,248,22,75,23,198,1,28,248,22,81,23,194,2,9, +28,248,23,197,2,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,27, +248,22,75,23,197,1,28,248,22,81,23,194,2,9,28,248,23,200,2,248,22, +74,23,195,2,249,22,73,248,22,74,23,196,2,27,248,22,75,23,197,1,28, +248,22,81,23,194,2,9,28,248,23,203,2,248,22,74,23,195,2,249,22,73, +248,22,74,23,196,2,249,2,94,23,206,1,248,22,75,23,198,1,249,2,94, +23,204,1,248,22,75,23,196,1,27,248,22,75,23,195,1,28,248,22,81,23, +194,2,9,28,248,23,201,2,248,22,74,23,195,2,249,22,73,248,22,74,23, +196,2,249,2,94,23,204,1,248,22,75,23,198,1,249,2,94,23,202,1,248, +22,75,23,196,1,27,248,22,75,23,195,1,28,248,22,81,23,194,2,9,28, +248,23,198,2,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,27,248, +22,75,23,197,1,28,248,22,81,23,194,2,9,28,248,23,201,2,248,22,74, +23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,23,204,1,248,22,75, +23,198,1,249,2,94,23,202,1,248,22,75,23,196,1,27,248,22,75,23,195, +1,28,248,22,81,23,194,2,9,28,248,23,199,2,248,22,74,23,195,2,249, +22,73,248,22,74,23,196,2,249,2,94,23,202,1,248,22,75,23,198,1,249, +2,94,23,200,1,248,22,75,23,196,1,27,248,22,75,23,196,1,28,248,22, +81,23,194,2,9,28,248,23,195,2,248,22,74,23,195,2,249,22,73,248,22, +74,23,196,2,27,248,22,75,23,197,1,28,248,22,81,23,194,2,9,28,248, +23,198,2,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,27,248,22, +75,23,197,1,28,248,22,81,23,194,2,9,28,248,23,201,2,248,22,74,23, +195,2,249,22,73,248,22,74,23,196,2,249,2,94,23,204,1,248,22,75,23, +198,1,249,2,94,23,202,1,248,22,75,23,196,1,27,248,22,75,23,195,1, +28,248,22,81,23,194,2,9,28,248,23,199,2,248,22,74,23,195,2,249,22, +73,248,22,74,23,196,2,249,2,94,23,202,1,248,22,75,23,198,1,249,2, +94,23,200,1,248,22,75,23,196,1,27,248,22,75,23,195,1,28,248,22,81, +23,194,2,9,28,248,23,196,2,248,22,74,23,195,2,249,22,73,248,22,74, +23,196,2,27,248,22,75,23,197,1,28,248,22,81,23,194,2,9,28,248,23, +199,2,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,23, +202,1,248,22,75,23,198,1,249,2,94,23,200,1,248,22,75,23,196,1,27, +248,22,75,23,195,1,28,248,22,81,23,194,2,9,28,248,23,197,2,248,22, +74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,23,200,1,248,22, +75,23,198,1,249,2,94,197,248,22,75,195,28,248,22,81,23,200,2,86,95, +23,199,1,23,198,1,28,23,200,2,199,86,94,23,200,1,27,28,248,22,81, +23,197,2,6,0,0,249,22,1,22,153,7,248,2,92,23,199,2,248,23,199, +1,252,22,178,7,6,44,44,126,97,58,32,99,111,108,108,101,99,116,105,111, +110,32,110,111,116,32,102,111,117,110,100,58,32,126,115,32,105,110,32,97,110, +121,32,111,102,58,32,126,115,126,97,23,203,1,28,248,22,81,23,203,1,28, +248,22,148,14,23,202,2,248,22,152,14,23,202,1,23,201,1,250,22,153,7, +28,248,22,148,14,23,205,2,248,22,152,14,23,205,1,23,204,1,6,1,1, +47,23,202,2,28,248,22,81,23,201,2,9,28,248,22,148,14,248,22,74,23, +202,2,249,22,73,248,22,74,23,203,2,27,248,22,75,23,204,2,28,248,22, +81,23,194,2,9,28,248,22,148,14,248,22,74,23,195,2,249,22,73,248,22, +74,23,196,2,27,248,22,75,23,197,1,28,248,22,81,23,194,2,9,28,248, +22,148,14,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94, +22,148,14,248,22,75,23,198,1,249,2,94,22,148,14,248,22,75,23,196,1, +27,248,22,75,23,195,1,28,248,22,81,23,194,2,9,28,248,22,148,14,248, +22,74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,22,148,14,248, +22,75,23,198,1,249,2,94,22,148,14,248,22,75,23,196,1,27,248,22,75, +23,202,2,28,248,22,81,23,194,2,9,28,248,22,148,14,248,22,74,23,195, +2,249,22,73,248,22,74,23,196,2,27,248,22,75,23,197,1,28,248,22,81, +23,194,2,9,28,248,22,148,14,248,22,74,23,195,2,249,22,73,248,22,74, +23,196,2,249,2,94,22,148,14,248,22,75,23,198,1,249,2,94,22,148,14, +248,22,75,23,196,1,27,248,22,75,23,195,1,28,248,22,81,23,194,2,9, +28,248,22,148,14,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,249, +2,94,22,148,14,248,22,75,23,198,1,249,2,94,22,148,14,248,22,75,23, +196,1,28,249,22,5,22,127,23,202,2,250,22,178,7,6,21,21,32,111,114, +58,32,126,115,32,105,110,32,97,110,121,32,111,102,58,32,126,115,23,202,1, +249,22,2,22,128,2,28,248,22,81,23,206,2,86,94,23,205,1,9,28,248, +22,127,248,22,74,23,207,2,249,22,73,248,22,74,23,208,2,27,248,22,75, +23,209,1,28,248,22,81,23,194,2,9,28,248,22,127,248,22,74,23,195,2, +249,22,73,248,22,74,23,196,2,27,248,22,75,23,197,1,28,248,22,81,23, +194,2,9,28,248,22,127,248,22,74,23,195,2,249,22,73,248,22,74,23,196, +2,249,2,94,22,127,248,22,75,23,198,1,249,2,94,22,127,248,22,75,23, +196,1,27,248,22,75,23,195,1,28,248,22,81,23,194,2,9,28,248,22,127, +248,22,74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,22,127,248, +22,75,23,198,1,249,2,94,22,127,248,22,75,23,196,1,27,248,22,75,23, +207,1,28,248,22,81,23,194,2,9,28,248,22,127,248,22,74,23,195,2,249, +22,73,248,22,74,23,196,2,27,248,22,75,23,197,1,28,248,22,81,23,194, +2,9,28,248,22,127,248,22,74,23,195,2,249,22,73,248,22,74,23,196,2, +249,2,94,22,127,248,22,75,23,198,1,249,2,94,22,127,248,22,75,23,196, +1,27,248,22,75,23,195,1,28,248,22,81,23,194,2,9,28,248,22,127,248, +22,74,23,195,2,249,22,73,248,22,74,23,196,2,249,2,94,22,127,248,22, +75,23,198,1,249,2,94,22,127,248,22,75,23,196,1,86,94,23,199,1,6, +0,0,27,248,22,74,23,201,2,27,28,248,22,148,14,23,195,2,249,22,166, +14,23,196,1,23,198,2,248,22,128,2,23,195,1,28,28,248,22,148,14,248, +22,74,23,203,2,248,22,161,14,23,194,2,10,27,250,22,1,22,166,14,23, +197,1,23,201,2,28,28,248,22,81,23,199,2,10,248,22,161,14,23,194,2, +28,23,201,2,28,28,248,22,160,14,249,22,166,14,195,203,10,27,28,248,22, +148,14,202,248,22,152,14,202,201,27,248,22,133,7,23,195,2,27,28,249,22, +188,3,23,196,2,40,28,249,22,136,7,6,4,4,46,114,107,116,249,22,152, +7,23,199,2,249,22,176,3,23,200,2,40,249,22,153,7,250,22,152,7,23, +200,1,36,249,22,176,3,23,201,1,40,6,3,3,46,115,115,86,95,23,195, 1,23,194,1,11,11,28,23,193,2,248,22,160,14,249,22,166,14,198,23,196, -1,11,192,26,8,2,57,202,203,204,205,206,23,15,248,22,75,203,200,192,26, -8,2,57,202,203,204,205,206,23,15,248,22,75,203,11,26,8,2,57,201,202, -203,204,205,206,248,22,75,202,11,86,95,28,28,248,22,149,14,23,194,2,10, -28,248,22,148,14,23,194,2,10,28,248,22,130,7,23,194,2,28,248,22,170, -14,23,194,2,10,248,22,171,14,23,194,2,11,12,252,22,176,9,23,200,2, -2,29,36,23,198,2,23,199,2,28,28,248,22,130,7,23,195,2,10,248,22, -183,7,23,195,2,86,94,23,194,1,12,252,22,176,9,23,200,2,2,30,37, -23,198,2,23,199,1,90,159,39,11,89,161,39,36,11,248,22,169,14,23,197, -2,86,94,23,195,1,86,94,28,192,12,250,22,177,9,23,201,1,2,31,23, -199,1,249,22,7,194,195,90,159,38,11,89,161,38,36,11,86,95,28,28,248, -22,149,14,23,196,2,10,28,248,22,148,14,23,196,2,10,28,248,22,130,7, -23,196,2,28,248,22,170,14,23,196,2,10,248,22,171,14,23,196,2,11,12, -252,22,176,9,2,11,2,29,36,23,200,2,23,201,2,28,28,248,22,130,7, -23,197,2,10,248,22,183,7,23,197,2,12,252,22,176,9,2,11,2,30,37, -23,200,2,23,201,2,90,159,39,11,89,161,39,36,11,248,22,169,14,23,199, -2,86,94,23,195,1,86,94,28,192,12,250,22,177,9,2,11,2,31,23,201, -2,249,22,7,194,195,27,249,22,158,14,250,22,146,15,0,20,35,114,120,35, -34,40,63,58,91,46,93,91,94,46,93,42,124,41,36,34,248,22,154,14,23, -201,1,28,248,22,130,7,23,203,2,249,22,145,8,23,204,1,8,63,23,202, +1,11,192,26,8,2,91,203,204,205,206,23,15,23,16,248,22,75,23,18,28, +23,18,23,18,200,192,26,8,2,91,203,204,205,206,23,15,23,16,248,22,75, +23,18,23,18,26,8,2,91,202,203,204,205,206,23,15,248,22,75,23,17,23, +17,90,159,38,11,89,161,38,36,11,249,80,159,40,57,39,23,200,1,23,201, +1,27,248,22,61,28,248,22,148,14,195,248,22,152,14,195,194,27,250,22,87, +28,247,22,128,15,250,22,153,2,248,80,159,47,55,39,10,23,200,2,9,9, +28,80,159,43,49,38,250,22,153,2,248,80,159,47,55,39,11,23,200,1,9, +86,94,23,197,1,9,247,22,190,14,26,8,2,91,200,202,203,205,206,23,17, +200,11,86,95,28,28,248,22,149,14,23,194,2,10,28,248,22,148,14,23,194, +2,10,28,248,22,130,7,23,194,2,28,248,22,170,14,23,194,2,10,248,22, +171,14,23,194,2,11,12,252,22,176,9,23,200,2,2,42,36,23,198,2,23, +199,2,28,28,248,22,130,7,23,195,2,10,248,22,183,7,23,195,2,86,94, +23,194,1,12,252,22,176,9,23,200,2,2,43,37,23,198,2,23,199,1,90, +159,39,11,89,161,39,36,11,248,22,169,14,23,197,2,86,94,23,195,1,86, +94,28,192,12,250,22,177,9,23,201,1,2,44,23,199,1,249,22,7,194,195, +90,159,38,11,89,161,38,36,11,86,95,28,28,248,22,149,14,23,196,2,10, +28,248,22,148,14,23,196,2,10,28,248,22,130,7,23,196,2,28,248,22,170, +14,23,196,2,10,248,22,171,14,23,196,2,11,12,252,22,176,9,2,25,2, +42,36,23,200,2,23,201,2,28,28,248,22,130,7,23,197,2,10,248,22,183, +7,23,197,2,12,252,22,176,9,2,25,2,43,37,23,200,2,23,201,2,90, +159,39,11,89,161,39,36,11,248,22,169,14,23,199,2,86,94,23,195,1,86, +94,28,192,12,250,22,177,9,2,25,2,44,23,201,2,249,22,7,194,195,27, +249,22,158,14,250,22,146,15,0,20,35,114,120,35,34,40,63,58,91,46,93, +91,94,46,93,42,124,41,36,34,248,22,154,14,23,201,1,28,248,22,130,7, +23,203,2,249,22,145,8,23,204,1,8,63,23,202,1,28,248,22,149,14,23, +199,2,248,22,150,14,23,199,1,86,94,23,198,1,247,22,151,14,28,248,22, +148,14,194,249,22,166,14,195,194,192,90,159,38,11,89,161,38,36,11,86,95, +28,28,248,22,149,14,23,196,2,10,28,248,22,148,14,23,196,2,10,28,248, +22,130,7,23,196,2,28,248,22,170,14,23,196,2,10,248,22,171,14,23,196, +2,11,12,252,22,176,9,2,26,2,42,36,23,200,2,23,201,2,28,28,248, +22,130,7,23,197,2,10,248,22,183,7,23,197,2,12,252,22,176,9,2,26, +2,43,37,23,200,2,23,201,2,90,159,39,11,89,161,39,36,11,248,22,169, +14,23,199,2,86,94,23,195,1,86,94,28,192,12,250,22,177,9,2,26,2, +44,23,201,2,249,22,7,194,195,27,249,22,158,14,249,22,131,8,250,22,147, +15,0,9,35,114,120,35,34,91,46,93,34,248,22,154,14,23,203,1,6,1, +1,95,28,248,22,130,7,23,202,2,249,22,145,8,23,203,1,8,63,23,201, 1,28,248,22,149,14,23,199,2,248,22,150,14,23,199,1,86,94,23,198,1, -247,22,151,14,28,248,22,148,14,194,249,22,166,14,195,194,192,90,159,38,11, -89,161,38,36,11,86,95,28,28,248,22,149,14,23,196,2,10,28,248,22,148, -14,23,196,2,10,28,248,22,130,7,23,196,2,28,248,22,170,14,23,196,2, -10,248,22,171,14,23,196,2,11,12,252,22,176,9,2,12,2,29,36,23,200, -2,23,201,2,28,28,248,22,130,7,23,197,2,10,248,22,183,7,23,197,2, -12,252,22,176,9,2,12,2,30,37,23,200,2,23,201,2,90,159,39,11,89, -161,39,36,11,248,22,169,14,23,199,2,86,94,23,195,1,86,94,28,192,12, -250,22,177,9,2,12,2,31,23,201,2,249,22,7,194,195,27,249,22,158,14, -249,22,131,8,250,22,147,15,0,9,35,114,120,35,34,91,46,93,34,248,22, -154,14,23,203,1,6,1,1,95,28,248,22,130,7,23,202,2,249,22,145,8, -23,203,1,8,63,23,201,1,28,248,22,149,14,23,199,2,248,22,150,14,23, -199,1,86,94,23,198,1,247,22,151,14,28,248,22,148,14,194,249,22,166,14, -195,194,192,249,247,22,158,5,194,11,27,247,22,128,15,249,80,158,39,49,28, -23,195,2,27,248,22,150,8,2,32,28,192,192,2,33,2,34,27,28,23,196, -1,250,22,166,14,248,22,188,14,2,35,247,22,148,8,2,36,11,27,248,80, -159,42,54,39,250,22,87,9,248,22,83,248,22,188,14,2,37,9,28,193,249, -22,73,195,194,192,27,247,22,128,15,249,80,158,39,49,28,23,195,2,27,248, -22,150,8,2,32,28,192,192,2,33,2,34,27,28,23,196,1,250,22,166,14, -248,22,188,14,2,35,247,22,148,8,2,36,11,27,248,80,159,42,55,39,250, -22,87,23,203,1,248,22,83,248,22,188,14,2,37,9,28,193,249,22,73,195, -194,192,27,247,22,128,15,249,80,158,39,49,28,23,195,2,27,248,22,150,8, -2,32,28,192,192,2,33,2,34,27,28,23,196,1,250,22,166,14,248,22,188, -14,2,35,247,22,148,8,2,36,11,27,27,250,22,87,23,203,1,248,22,83, -248,22,188,14,2,37,23,204,1,28,248,22,81,23,194,2,9,27,248,22,74, -23,195,2,27,28,248,22,172,14,23,195,2,23,194,1,28,248,22,171,14,23, -195,2,249,22,173,14,23,196,1,250,80,158,49,50,248,22,188,14,2,21,11, -10,250,80,158,47,50,248,22,188,14,2,21,23,197,1,10,28,23,193,2,249, -22,73,248,22,175,14,249,22,173,14,23,198,1,247,22,189,14,248,80,159,47, -56,39,248,22,75,23,199,1,86,94,23,193,1,248,80,159,45,56,39,248,22, -75,23,197,1,28,193,249,22,73,195,194,192,32,67,88,163,8,36,39,57,11, -2,20,222,33,69,0,8,35,114,120,35,34,92,34,34,27,249,22,135,15,23, -197,2,23,198,2,28,23,193,2,86,94,23,196,1,27,248,22,98,23,195,2, -27,27,248,22,107,23,197,1,27,249,22,135,15,23,201,2,23,196,2,28,23, -193,2,86,94,23,194,1,27,248,22,98,23,195,2,27,250,2,67,23,203,2, -23,204,1,248,22,107,23,199,1,28,249,22,191,7,23,196,2,2,38,249,22, -87,23,202,2,194,249,22,73,248,22,157,14,28,249,22,140,9,247,22,152,8, -2,22,250,22,147,15,2,68,23,200,1,2,39,23,197,1,194,86,95,23,199, -1,23,193,1,28,249,22,191,7,23,196,2,2,38,249,22,87,23,200,2,9, -249,22,73,248,22,157,14,28,249,22,140,9,247,22,152,8,2,22,250,22,147, -15,2,68,23,200,1,2,39,23,197,1,9,28,249,22,191,7,23,196,2,2, -38,249,22,87,197,194,86,94,23,196,1,249,22,73,248,22,157,14,28,249,22, -140,9,247,22,152,8,2,22,250,22,147,15,2,68,23,200,1,2,39,23,197, -1,194,86,94,23,193,1,28,249,22,191,7,23,198,2,2,38,249,22,87,195, -9,86,94,23,194,1,249,22,73,248,22,157,14,28,249,22,140,9,247,22,152, -8,2,22,250,22,147,15,2,68,23,202,1,2,39,23,199,1,9,86,95,28, -28,248,22,183,7,194,10,248,22,130,7,194,12,250,22,176,9,2,15,6,21, -21,98,121,116,101,32,115,116,114,105,110,103,32,111,114,32,115,116,114,105,110, -103,196,28,28,248,22,82,195,249,22,4,22,148,14,196,11,12,250,22,176,9, -2,15,6,13,13,108,105,115,116,32,111,102,32,112,97,116,104,115,197,250,2, -67,197,195,28,248,22,130,7,197,248,22,144,8,197,196,32,71,88,163,8,36, -39,53,11,70,102,111,117,110,100,45,101,120,101,99,222,33,74,32,72,88,163, -8,36,40,58,11,64,110,101,120,116,222,33,73,27,248,22,174,14,23,196,2, -28,249,22,142,9,23,195,2,23,197,1,11,28,248,22,170,14,23,194,2,27, -249,22,166,14,23,197,1,23,196,1,28,23,197,2,90,159,39,11,89,161,39, -36,11,248,22,169,14,23,197,2,86,95,23,195,1,23,194,1,27,28,23,202, -2,27,248,22,174,14,23,199,2,28,249,22,142,9,23,195,2,23,200,2,11, -28,248,22,170,14,23,194,2,250,2,71,23,205,2,23,206,2,249,22,166,14, -23,200,2,23,198,1,250,2,71,23,205,2,23,206,2,23,196,1,11,28,23, -193,2,192,86,94,23,193,1,27,28,248,22,148,14,23,196,2,27,249,22,166, -14,23,198,2,23,205,2,28,28,248,22,161,14,193,10,248,22,160,14,193,192, -11,11,28,23,193,2,192,86,94,23,193,1,28,23,203,2,11,27,248,22,174, -14,23,200,2,28,249,22,142,9,23,195,2,23,201,1,11,28,248,22,170,14, -23,194,2,250,2,71,23,206,1,23,207,1,249,22,166,14,23,201,1,23,198, -1,250,2,71,205,206,195,192,86,94,23,194,1,28,23,196,2,90,159,39,11, -89,161,39,36,11,248,22,169,14,23,197,2,86,95,23,195,1,23,194,1,27, -28,23,201,2,27,248,22,174,14,23,199,2,28,249,22,142,9,23,195,2,23, -200,2,11,28,248,22,170,14,23,194,2,250,2,71,23,204,2,23,205,2,249, -22,166,14,23,200,2,23,198,1,250,2,71,23,204,2,23,205,2,23,196,1, -11,28,23,193,2,192,86,94,23,193,1,27,28,248,22,148,14,23,196,2,27, -249,22,166,14,23,198,2,23,204,2,28,28,248,22,161,14,193,10,248,22,160, -14,193,192,11,11,28,23,193,2,192,86,94,23,193,1,28,23,202,2,11,27, -248,22,174,14,23,200,2,28,249,22,142,9,23,195,2,23,201,1,11,28,248, -22,170,14,23,194,2,250,2,71,23,205,1,23,206,1,249,22,166,14,23,201, -1,23,198,1,250,2,71,204,205,195,192,28,23,193,2,90,159,39,11,89,161, -39,36,11,248,22,169,14,23,199,2,86,95,23,195,1,23,194,1,27,28,23, -198,2,251,2,72,23,198,2,23,203,2,23,201,2,23,202,2,11,28,23,193, -2,192,86,94,23,193,1,27,28,248,22,148,14,195,27,249,22,166,14,197,200, -28,28,248,22,161,14,193,10,248,22,160,14,193,192,11,11,28,192,192,28,198, -11,251,2,72,198,203,201,202,194,32,75,88,163,8,36,40,58,11,2,20,222, -33,76,28,248,22,81,23,197,2,11,27,248,22,173,14,248,22,74,23,199,2, -27,249,22,166,14,23,196,1,23,197,2,28,248,22,160,14,23,194,2,250,2, -71,198,199,195,86,94,23,193,1,27,248,22,75,23,200,1,28,248,22,81,23, -194,2,11,27,248,22,173,14,248,22,74,23,196,2,27,249,22,166,14,23,196, -1,23,200,2,28,248,22,160,14,23,194,2,250,2,71,201,202,195,86,94,23, -193,1,27,248,22,75,23,197,1,28,248,22,81,23,194,2,11,27,248,22,173, -14,248,22,74,195,27,249,22,166,14,23,196,1,202,28,248,22,160,14,193,250, -2,71,204,205,195,251,2,75,204,205,206,248,22,75,199,86,95,28,28,248,22, -148,14,23,195,2,10,28,248,22,130,7,23,195,2,28,248,22,170,14,23,195, -2,10,248,22,171,14,23,195,2,11,12,250,22,176,9,2,16,6,25,25,112, -97,116,104,32,111,114,32,115,116,114,105,110,103,32,40,115,97,110,115,32,110, -117,108,41,23,197,2,28,28,23,195,2,28,28,248,22,148,14,23,196,2,10, -28,248,22,130,7,23,196,2,28,248,22,170,14,23,196,2,10,248,22,171,14, -23,196,2,11,248,22,170,14,23,196,2,11,10,12,250,22,176,9,2,16,6, -29,29,35,102,32,111,114,32,114,101,108,97,116,105,118,101,32,112,97,116,104, -32,111,114,32,115,116,114,105,110,103,23,198,2,28,28,248,22,170,14,23,195, -2,90,159,39,11,89,161,39,36,11,248,22,169,14,23,198,2,249,22,140,9, -194,68,114,101,108,97,116,105,118,101,11,27,248,22,150,8,6,4,4,80,65, -84,72,27,28,23,194,2,27,249,80,159,41,49,38,23,197,1,9,28,249,22, -140,9,247,22,152,8,2,22,249,22,73,248,22,157,14,5,1,46,194,192,86, -94,23,194,1,9,28,248,22,81,23,194,2,11,27,248,22,173,14,248,22,74, -23,196,2,27,249,22,166,14,23,196,1,23,200,2,28,248,22,160,14,23,194, -2,250,2,71,201,202,195,86,94,23,193,1,27,248,22,75,23,197,1,28,248, -22,81,23,194,2,11,27,248,22,173,14,248,22,74,23,196,2,27,249,22,166, -14,23,196,1,23,203,2,28,248,22,160,14,23,194,2,250,2,71,204,205,195, -86,94,23,193,1,27,248,22,75,23,197,1,28,248,22,81,23,194,2,11,27, -248,22,173,14,248,22,74,195,27,249,22,166,14,23,196,1,205,28,248,22,160, -14,193,250,2,71,23,15,23,16,195,251,2,75,23,15,23,16,23,17,248,22, -75,199,27,248,22,173,14,23,196,1,28,248,22,160,14,193,250,2,71,198,199, -195,11,250,80,159,39,50,39,196,197,11,250,80,159,39,50,39,196,11,11,86, -94,249,22,183,6,247,22,154,5,195,248,22,145,6,249,22,128,4,36,249,22, -176,3,197,198,27,28,23,197,2,86,95,23,196,1,23,195,1,23,197,1,86, -94,23,197,1,27,248,22,188,14,2,21,27,250,80,159,42,50,39,23,197,1, -11,11,27,248,22,131,4,23,199,1,27,28,23,194,2,23,194,1,86,94,23, -194,1,36,27,248,22,131,4,23,202,1,27,28,23,194,2,23,194,1,86,94, -23,194,1,36,249,22,185,5,23,199,1,20,20,95,88,163,8,36,36,48,11, -9,224,4,2,33,80,23,195,1,23,197,1,27,248,22,170,5,23,195,1,248, -80,159,39,57,39,193,159,36,20,112,159,36,16,1,11,16,0,20,26,142,2, -1,2,1,29,11,11,11,11,11,10,43,80,158,36,36,20,112,159,40,16,18, -2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2,11,2, -12,2,13,2,14,2,15,2,16,2,17,30,2,19,1,20,112,97,114,97,109, -101,116,101,114,105,122,97,116,105,111,110,45,107,101,121,5,30,2,19,1,23, -101,120,116,101,110,100,45,112,97,114,97,109,101,116,101,114,105,122,97,116,105, -111,110,3,16,0,16,0,36,16,0,36,16,4,2,6,2,5,2,3,2,10, -40,11,11,39,36,11,11,16,12,2,9,2,7,2,17,2,8,2,16,2,14, -2,13,2,4,2,12,2,15,2,11,2,2,16,12,11,11,11,11,11,11,11, -11,11,11,11,11,16,12,2,9,2,7,2,17,2,8,2,16,2,14,2,13, -2,4,2,12,2,15,2,11,2,2,48,48,37,11,11,16,0,16,0,16,0, -36,36,11,11,11,16,0,16,0,16,0,36,36,16,0,16,20,20,15,16,2, -88,163,8,36,37,51,8,240,0,0,35,0,2,20,223,0,33,40,80,159,36, -57,39,20,15,16,2,88,163,8,36,37,56,8,240,0,64,16,0,2,20,223, -0,33,41,80,159,36,56,39,20,15,16,2,88,163,8,36,37,51,8,240,0, -64,8,0,2,20,223,0,33,42,80,159,36,55,39,20,15,16,2,88,163,8, -36,37,51,8,240,0,64,4,0,2,20,223,0,33,43,80,159,36,54,39,20, -15,16,2,32,0,88,163,36,37,45,11,2,2,222,33,44,80,159,36,36,37, -20,15,16,2,249,22,132,7,7,92,7,92,80,159,36,37,37,20,15,16,2, -88,163,36,37,54,38,2,4,223,0,33,45,80,159,36,38,37,20,15,16,2, -32,0,88,163,8,36,38,50,11,2,5,222,33,46,80,159,36,39,37,20,15, -16,2,32,0,88,163,8,36,39,51,11,2,6,222,33,48,80,159,36,40,37, -20,15,16,2,32,0,88,163,8,45,38,54,11,2,7,222,33,52,80,159,36, -41,37,20,15,16,2,32,0,88,163,45,39,53,11,2,9,222,33,56,80,159, -36,43,37,20,15,16,2,32,0,88,163,36,41,59,11,2,8,222,33,59,80, -159,36,42,37,20,15,16,2,32,0,88,163,36,39,50,11,2,10,222,33,60, -80,159,36,44,37,20,15,16,2,32,0,88,163,36,38,53,11,2,11,222,33, -61,80,159,36,45,37,20,15,16,2,32,0,88,163,36,38,54,11,2,12,222, -33,62,80,159,36,46,37,20,15,16,2,32,0,88,163,36,37,44,11,2,13, -222,33,63,80,159,36,47,37,20,15,16,2,20,25,96,2,14,88,163,36,36, -53,8,240,0,32,4,0,9,223,0,33,64,88,163,36,37,54,8,240,0,32, -8,0,9,223,0,33,65,88,163,36,38,58,8,240,0,96,16,0,9,223,0, -33,66,80,159,36,48,37,20,15,16,2,27,248,22,131,15,248,22,144,8,27, -28,249,22,140,9,247,22,152,8,2,22,6,1,1,59,6,1,1,58,250,22, -178,7,6,14,14,40,91,94,126,97,93,42,41,126,97,40,46,42,41,23,196, -2,23,196,1,88,163,8,36,38,48,11,2,15,223,0,33,70,80,159,36,49, -37,20,15,16,2,20,25,96,2,16,88,163,8,36,39,8,24,8,128,128,9, -223,0,33,77,88,163,8,36,38,47,8,240,0,64,0,0,9,223,0,33,78, -88,163,8,36,37,46,8,240,0,64,0,0,9,223,0,33,79,80,159,36,50, -37,20,15,16,2,88,163,8,36,39,54,8,240,0,64,32,0,2,17,223,0, -33,81,80,159,36,51,37,94,29,94,2,18,68,35,37,107,101,114,110,101,108, -11,29,94,2,18,69,35,37,109,105,110,45,115,116,120,11,9,9,9,36,0}; - EVAL_ONE_SIZED_STR((char *)expr, 8399); +247,22,151,14,28,248,22,148,14,194,249,22,166,14,195,194,192,249,247,22,158, +5,194,11,27,247,22,128,15,249,80,159,39,40,38,28,23,195,2,27,248,22, +150,8,2,45,28,192,192,2,46,2,47,27,28,23,196,1,250,22,166,14,248, +22,188,14,2,48,247,22,148,8,2,49,11,27,248,80,159,42,8,28,39,250, +22,87,9,248,22,83,248,22,188,14,2,38,9,28,193,249,22,73,195,194,192, +27,247,22,128,15,249,80,159,39,40,38,28,23,195,2,27,248,22,150,8,2, +45,28,192,192,2,46,2,47,27,28,23,196,1,250,22,166,14,248,22,188,14, +2,48,247,22,148,8,2,49,11,27,248,80,159,42,8,29,39,250,22,87,23, +203,1,248,22,83,248,22,188,14,2,38,9,28,193,249,22,73,195,194,192,27, +247,22,128,15,249,80,159,39,40,38,28,23,195,2,27,248,22,150,8,2,45, +28,192,192,2,46,2,47,27,28,23,196,1,250,22,166,14,248,22,188,14,2, +48,247,22,148,8,2,49,11,27,248,80,159,42,8,30,39,250,22,87,23,203, +1,248,22,83,248,22,188,14,2,38,23,204,1,28,193,249,22,73,195,194,192, +86,94,249,22,183,6,247,22,154,5,195,248,22,145,6,249,22,128,4,36,249, +22,176,3,197,198,27,28,23,197,2,86,95,23,196,1,23,195,1,23,197,1, +86,94,23,197,1,27,248,22,188,14,2,31,27,250,80,159,42,39,39,23,197, +1,11,11,27,248,22,131,4,23,199,1,27,28,23,194,2,23,194,1,86,94, +23,194,1,36,27,248,22,131,4,23,202,1,27,28,23,194,2,23,194,1,86, +94,23,194,1,36,249,22,185,5,23,199,1,20,20,95,88,163,8,36,36,48, +11,9,224,4,2,33,105,23,195,1,23,197,1,27,248,22,170,5,23,195,1, +248,80,159,39,8,31,39,193,159,36,20,112,159,36,16,1,11,16,0,20,26, +142,2,1,2,1,29,11,11,11,11,11,10,43,80,158,36,36,20,112,159,40, +16,28,2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2, +11,2,12,2,13,2,14,2,15,30,2,18,76,102,105,110,100,45,108,105,110, +107,115,45,112,97,116,104,33,4,30,2,19,1,20,112,97,114,97,109,101,116, +101,114,105,122,97,116,105,111,110,45,107,101,121,6,30,2,19,1,23,101,120, +116,101,110,100,45,112,97,114,97,109,101,116,101,114,105,122,97,116,105,111,110, +3,2,20,2,21,2,22,30,2,18,1,21,101,120,99,101,112,116,105,111,110, +45,104,97,110,100,108,101,114,45,107,101,121,2,2,23,2,24,2,25,2,26, +2,27,2,28,2,29,16,0,16,0,36,16,0,36,16,12,2,8,2,7,2, +3,2,24,2,22,2,20,2,15,2,21,2,23,2,13,2,12,2,14,48,11, +11,39,36,11,11,16,12,2,11,2,9,2,29,2,10,2,5,2,28,2,27, +2,4,2,26,2,6,2,25,2,2,16,12,11,11,11,11,11,11,11,11,11, +11,11,11,16,12,2,11,2,9,2,29,2,10,2,5,2,28,2,27,2,4, +2,26,2,6,2,25,2,2,48,48,37,11,11,16,0,16,0,16,0,36,36, +11,11,11,16,0,16,0,16,0,36,36,16,0,16,28,20,15,16,2,88,163, +8,36,37,51,16,2,8,240,0,128,0,0,8,240,1,128,0,0,2,30,223, +0,33,50,80,159,36,8,31,39,20,15,16,2,88,163,8,36,37,56,16,2, +44,8,240,0,64,0,0,2,30,223,0,33,51,80,159,36,8,30,39,20,15, +16,2,88,163,8,36,37,51,16,2,44,8,128,128,2,30,223,0,33,52,80, +159,36,8,29,39,20,15,16,2,88,163,8,36,37,51,16,2,44,8,128,64, +2,30,223,0,33,53,80,159,36,8,28,39,20,15,16,2,32,0,88,163,36, +37,45,11,2,2,222,33,54,80,159,36,36,37,20,15,16,2,249,22,132,7, +7,92,7,92,80,159,36,37,37,20,15,16,2,88,163,36,37,54,38,2,4, +223,0,33,55,80,159,36,38,37,20,15,16,2,20,25,96,2,5,88,163,8, +36,39,8,24,52,9,223,0,33,62,88,163,36,38,47,44,9,223,0,33,63, +88,163,36,37,46,44,9,223,0,33,64,80,159,36,39,37,20,15,16,2,27, +248,22,131,15,248,22,144,8,27,28,249,22,140,9,247,22,152,8,2,32,6, +1,1,59,6,1,1,58,250,22,178,7,6,14,14,40,91,94,126,97,93,42, +41,126,97,40,46,42,41,23,196,2,23,196,1,88,163,8,36,38,48,11,2, +6,223,0,33,68,80,159,36,40,37,20,15,16,2,32,0,88,163,8,36,38, +50,11,2,7,222,33,69,80,159,36,41,37,20,15,16,2,32,0,88,163,8, +36,39,51,11,2,8,222,33,71,80,159,36,42,37,20,15,16,2,88,163,45, +38,51,8,128,4,2,9,223,0,33,74,80,159,36,43,37,20,15,16,2,88, +163,45,39,52,8,128,4,2,11,223,0,33,77,80,159,36,45,37,20,15,16, +2,248,22,188,14,70,108,105,110,107,115,45,102,105,108,101,80,159,36,46,37, +20,15,16,2,247,22,133,2,80,158,36,47,20,15,16,2,2,78,80,158,36, +48,20,15,16,2,248,80,159,37,50,37,88,163,36,36,49,8,240,8,128,1, +0,9,223,1,33,79,80,159,36,49,37,20,15,16,2,247,22,133,2,80,158, +36,53,20,15,16,2,2,78,80,158,36,54,20,15,16,2,88,163,36,37,44, +8,240,0,188,23,0,2,22,223,0,33,88,80,159,36,55,37,20,15,16,2, +88,163,36,38,56,8,240,0,0,32,0,2,23,223,0,33,90,80,159,36,57, +37,20,15,16,2,88,163,36,41,59,8,240,0,32,40,0,2,10,223,0,33, +97,80,159,36,44,37,20,15,16,2,32,0,88,163,36,39,50,11,2,24,222, +33,98,80,159,36,58,37,20,15,16,2,32,0,88,163,36,38,53,11,2,25, +222,33,99,80,159,36,59,37,20,15,16,2,32,0,88,163,36,38,54,11,2, +26,222,33,100,80,159,36,8,24,37,20,15,16,2,32,0,88,163,36,37,44, +11,2,27,222,33,101,80,159,36,8,25,37,20,15,16,2,20,25,96,2,28, +88,163,36,36,53,16,2,52,8,128,64,9,223,0,33,102,88,163,36,37,54, +16,2,52,8,128,128,9,223,0,33,103,88,163,36,38,55,16,2,52,8,240, +0,64,0,0,9,223,0,33,104,80,159,36,8,26,37,20,15,16,2,88,163, +8,36,39,54,16,2,44,8,240,0,128,0,0,2,29,223,0,33,106,80,159, +36,8,27,37,95,29,94,2,16,68,35,37,107,101,114,110,101,108,11,29,94, +2,16,69,35,37,109,105,110,45,115,116,120,11,2,18,9,9,9,36,0}; + EVAL_ONE_SIZED_STR((char *)expr, 10204); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,50,0,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,53,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,12,0,0,0,1,0,0,15,0,40,0,57, 0,75,0,97,0,120,0,140,0,162,0,169,0,176,0,183,0,0,0,178,1, 0,0,74,35,37,112,108,97,99,101,45,115,116,114,117,99,116,1,23,115,116, @@ -528,7 +614,7 @@ EVAL_ONE_SIZED_STR((char *)expr, 499); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,50,0,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,53,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,65,0,0,0,1,0,0,7,0,18,0,45, 0,51,0,64,0,73,0,80,0,102,0,124,0,150,0,158,0,170,0,185,0, 201,0,219,0,239,0,251,0,11,1,34,1,46,1,77,1,84,1,89,1,94, @@ -788,14 +874,14 @@ 142,2,1,2,1,29,11,11,11,11,11,10,38,80,158,36,36,20,112,159,40, 16,26,2,2,2,3,30,2,5,72,112,97,116,104,45,115,116,114,105,110,103, 63,11,30,2,5,75,112,97,116,104,45,97,100,100,45,115,117,102,102,105,120, -8,30,2,7,2,8,5,30,2,7,1,23,101,120,116,101,110,100,45,112,97, +8,30,2,7,2,8,6,30,2,7,1,23,101,120,116,101,110,100,45,112,97, 114,97,109,101,116,101,114,105,122,97,116,105,111,110,3,2,9,2,10,2,11, 2,12,2,13,2,14,2,15,2,16,2,17,2,18,2,19,2,20,2,21,30, -2,22,2,8,5,30,2,5,79,112,97,116,104,45,114,101,112,108,97,99,101, +2,22,2,8,6,30,2,5,79,112,97,116,104,45,114,101,112,108,97,99,101, 45,115,117,102,102,105,120,10,30,2,5,73,102,105,110,100,45,99,111,108,45, 102,105,108,101,3,30,2,5,76,110,111,114,109,97,108,45,99,97,115,101,45, 112,97,116,104,7,2,23,2,24,30,2,22,74,114,101,112,97,114,97,109,101, -116,101,114,105,122,101,6,16,0,16,0,36,16,0,36,16,14,2,15,2,16, +116,101,114,105,122,101,7,16,0,16,0,36,16,0,36,16,14,2,15,2,16, 2,10,2,12,2,17,2,18,2,11,2,3,2,9,2,2,2,13,2,14,2, 19,2,21,50,11,11,39,36,11,11,16,3,2,23,2,20,2,24,16,3,11, 11,11,16,3,2,23,2,20,2,24,39,39,37,11,11,16,0,16,0,16,0, @@ -829,7 +915,7 @@ EVAL_ONE_SIZED_STR((char *)expr, 6244); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,50,0,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,53,46,49,46,51,46,53,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,11,0,0,0,1,0,0,10,0,16,0,29, 0,44,0,58,0,78,0,90,0,104,0,118,0,170,0,0,0,97,1,0,0, 69,35,37,98,117,105,108,116,105,110,65,113,117,111,116,101,29,94,2,2,67, @@ -837,7 +923,7 @@ 107,11,29,94,2,2,68,35,37,112,97,114,97,109,122,11,29,94,2,2,74, 35,37,112,108,97,99,101,45,115,116,114,117,99,116,11,29,94,2,2,66,35, 37,98,111,111,116,11,29,94,2,2,68,35,37,101,120,112,111,98,115,11,29, -94,2,2,68,35,37,107,101,114,110,101,108,11,97,36,11,8,240,204,77,0, +94,2,2,68,35,37,107,101,114,110,101,108,11,97,36,11,8,240,28,78,0, 0,100,159,2,3,36,36,159,2,4,36,36,159,2,5,36,36,159,2,6,36, 36,159,2,7,36,36,159,2,8,36,36,159,2,9,36,36,159,2,9,36,36, 16,0,159,36,20,112,159,36,16,1,11,16,0,20,26,142,2,1,2,1,29, diff --git a/src/racket/src/file.c b/src/racket/src/file.c index 1d5aab7208..c3ce91d3ae 100644 --- a/src/racket/src/file.c +++ b/src/racket/src/file.c @@ -227,12 +227,15 @@ READ_ONLY static Scheme_Object *doc_dir_symbol, *desk_dir_symbol; READ_ONLY static Scheme_Object *init_dir_symbol, *init_file_symbol, *sys_dir_symbol; READ_ONLY static Scheme_Object *exec_file_symbol, *run_file_symbol, *collects_dir_symbol; READ_ONLY static Scheme_Object *pref_file_symbol, *orig_dir_symbol, *addon_dir_symbol; +READ_ONLY static Scheme_Object *links_file_symbol; SHARED_OK static Scheme_Object *exec_cmd; SHARED_OK static Scheme_Object *run_cmd; SHARED_OK static Scheme_Object *collects_path; THREAD_LOCAL_DECL(static Scheme_Object *original_pwd); SHARED_OK static Scheme_Object *addon_dir; +SHARED_OK static Scheme_Object *links_file; +THREAD_LOCAL_DECL(static Scheme_Object *inst_links_path); #endif READ_ONLY static Scheme_Object *windows_symbol, *unix_symbol; @@ -275,6 +278,7 @@ void scheme_init_file(Scheme_Env *env) REGISTER_SO(collects_dir_symbol); REGISTER_SO(orig_dir_symbol); REGISTER_SO(addon_dir_symbol); + REGISTER_SO(links_file_symbol); #endif REGISTER_SO(windows_symbol); REGISTER_SO(unix_symbol); @@ -302,6 +306,7 @@ void scheme_init_file(Scheme_Env *env) collects_dir_symbol = scheme_intern_symbol("collects-dir"); orig_dir_symbol = scheme_intern_symbol("orig-dir"); addon_dir_symbol = scheme_intern_symbol("addon-dir"); + links_file_symbol = scheme_intern_symbol("links-file"); #endif windows_symbol = scheme_intern_symbol("windows"); @@ -5826,7 +5831,8 @@ enum { id_init_dir, id_init_file, id_sys_dir, - id_addon_dir + id_addon_dir, + id_links_file }; Scheme_Object *scheme_get_run_cmd(void) @@ -5877,6 +5883,15 @@ find_system_path(int argc, Scheme_Object **argv) } else if (argv[0] == addon_dir_symbol) { if (addon_dir) return addon_dir; which = id_addon_dir; + } else if (argv[0] == links_file_symbol) { + if (links_file) return links_file; + if (addon_dir) { + Scheme_Object *pa[2]; + pa[0] = addon_dir; + pa[1] = scheme_make_path("links.rktd"); + return scheme_build_path(2, pa); + } + which = id_links_file; } else { scheme_wrong_type("find-system-path", "system-path-symbol", 0, argc, argv); @@ -5919,9 +5934,11 @@ find_system_path(int argc, Scheme_Object **argv) if ((which == id_pref_dir) || (which == id_pref_file) - || (which == id_addon_dir)) { + || (which == id_addon_dir) + || (which == id_links_file)) { #if defined(OS_X) && !defined(XONX) - if (which == id_addon_dir) + if ((which == id_addon_dir) + || (which == id_links_file)) home_str = "~/Library/Racket/"; else home_str = "~/Library/Preferences/"; @@ -5968,6 +5985,8 @@ find_system_path(int argc, Scheme_Object **argv) return append_path(home, scheme_make_path("/racket-prefs.rktd" + ends_in_slash)); #endif } + if (which == id_links_file) + return append_path(home, scheme_make_path("/links.rktd" + ends_in_slash)); } #endif @@ -6005,7 +6024,8 @@ find_system_path(int argc, Scheme_Object **argv) if ((which == id_addon_dir) || (which == id_pref_dir) - || (which == id_pref_file)) + || (which == id_pref_file) + || (which == id_links_file)) which_folder = CSIDL_APPDATA; else if (which == id_doc_dir) { # ifndef CSIDL_PERSONAL @@ -6109,6 +6129,8 @@ find_system_path(int argc, Scheme_Object **argv) return append_path(home, scheme_make_path("\\racketrc.rktl" + ends_in_slash)); if (which == id_pref_file) return append_path(home, scheme_make_path("\\racket-prefs.rktd" + ends_in_slash)); + if (which == id_links_file) + return append_path(home, scheme_make_path("\\links.rktd" + ends_in_slash)); return home; } #endif @@ -6177,6 +6199,26 @@ void scheme_set_addon_dir(Scheme_Object *p) addon_dir = p; } +/* should only called from main */ +void scheme_set_links_file(Scheme_Object *p) +{ + if (!links_file) { + REGISTER_SO(links_file); + } + links_file = p; +} + +Scheme_Object *scheme_find_links_path(int argc, Scheme_Object *argv[]) +{ + if (inst_links_path) + return inst_links_path; + + REGISTER_SO(inst_links_path); + inst_links_path = scheme_apply(argv[0], 0, NULL); + + return inst_links_path; +} + /********************************************************************************/ #ifdef DOS_FILE_SYSTEM diff --git a/src/racket/src/schpriv.h b/src/racket/src/schpriv.h index b6bd7b94fd..5f8ab1d2ae 100644 --- a/src/racket/src/schpriv.h +++ b/src/racket/src/schpriv.h @@ -3358,6 +3358,8 @@ Scheme_Object *scheme_get_fd_identity(Scheme_Object *port, intptr_t fd, char *pa Scheme_Object *scheme_extract_relative_to(Scheme_Object *obj, Scheme_Object *dir); +Scheme_Object *scheme_find_links_path(int argc, Scheme_Object *argv[]); + #ifdef DOS_FILE_SYSTEM # define WIDE_PATH(s) scheme_convert_to_wchar(s, 0) # define WIDE_PATH_COPY(s) scheme_convert_to_wchar(s, 1) diff --git a/src/racket/src/schvers.h b/src/racket/src/schvers.h index 6c0e045afb..7640e37ea3 100644 --- a/src/racket/src/schvers.h +++ b/src/racket/src/schvers.h @@ -13,12 +13,12 @@ consistently.) */ -#define MZSCHEME_VERSION "5.1.3.3" +#define MZSCHEME_VERSION "5.1.3.5" #define MZSCHEME_VERSION_X 5 #define MZSCHEME_VERSION_Y 1 #define MZSCHEME_VERSION_Z 3 -#define MZSCHEME_VERSION_W 3 +#define MZSCHEME_VERSION_W 5 #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) diff --git a/src/racket/src/startup.inc b/src/racket/src/startup.inc index b9c500d4ab..ef9b325a41 100644 --- a/src/racket/src/startup.inc +++ b/src/racket/src/startup.inc @@ -133,7 +133,7 @@ ); EVAL_ONE_STR( "(module #%utils '#%kernel" -"(#%require '#%min-stx)" +"(#%require '#%min-stx '#%paramz)" "(#%provide path-string?" " normal-case-path" " path-replace-suffix" @@ -178,6 +178,83 @@ " 'windows)))))" "((string? s)(string->path s))" "(else s))))" +"(define-values(find-executable-path)" +"(case-lambda " +"((program libpath reverse?)" +"(unless(path-string? program) " +" (raise-type-error 'find-executable-path \"path or string (sans nul)\" program))" +"(unless(or(not libpath)(and(path-string? libpath) " +"(relative-path? libpath)))" +" (raise-type-error 'find-executable-path \"#f or relative path or string\" libpath))" +"(letrec((found-exec" +"(lambda(exec-name)" +"(if libpath" +"(let-values(((base name isdir?)(split-path exec-name)))" +"(let((next" +"(lambda()" +"(let((resolved(resolve-path exec-name)))" +"(cond" +"((equal? resolved exec-name) #f)" +"((relative-path? resolved)" +"(found-exec(build-path base resolved)))" +"(else(found-exec resolved)))))))" +"(or(and reverse?(next))" +"(if(path? base)" +"(let((lib(build-path base libpath)))" +"(and(or(directory-exists? lib) " +"(file-exists? lib))" +" lib))" +" #f)" +"(and(not reverse?)(next)))))" +" exec-name))))" +"(if(and(relative-path? program)" +"(let-values(((base name dir?)(split-path program)))" +"(eq? base 'relative)))" +" (let ((paths-str (getenv \"PATH\"))" +"(win-add(lambda(s)(if(eq?(system-type) 'windows) " +" (cons (bytes->path #\".\") s) " +" s))))" +"(let loop((paths(if paths-str " +"(win-add(path-list-string->path-list paths-str null))" +" null)))" +"(if(null? paths)" +" #f" +"(let*((base(path->complete-path(car paths)))" +"(name(build-path base program)))" +"(if(file-exists? name)" +"(found-exec name)" +"(loop(cdr paths)))))))" +"(let((p(path->complete-path program)))" +"(and(file-exists? p)(found-exec p))))))" +"((program libpath)(find-executable-path program libpath #f))" +"((program)(find-executable-path program #f #f))))" +"(define-values(path-list-string->path-list)" +"(let((r(byte-regexp(string->bytes/utf-8" +"(let((sep(if(eq?(system-type) 'windows)" +" \";\"\n" +" \":\")))" +" (format \"([^~a]*)~a(.*)\" sep sep)))))" +"(cons-path(lambda(default s l) " +" (if (bytes=? s #\"\")" +"(append default l)" +"(cons(bytes->path(if(eq?(system-type) 'windows)" +" (regexp-replace* #rx#\"\\\"\" s #\"\")" +" s))" +" l)))))" +"(lambda(s default)" +"(unless(or(bytes? s)" +"(string? s))" +" (raise-type-error 'path-list-string->path-list \"byte string or string\" s))" +"(unless(and(list? default)" +"(andmap path? default))" +" (raise-type-error 'path-list-string->path-list \"list of paths\" default))" +"(let loop((s(if(string? s)" +"(string->bytes/utf-8 s)" +" s)))" +"(let((m(regexp-match r s)))" +"(if m" +"(cons-path default(cadr m)(loop(caddr m)))" +"(cons-path default s null)))))))" "(define-values(-check-relpath)" "(lambda(who s)" "(unless(path-string? s)" @@ -210,23 +287,196 @@ " collection collection-path" " file-name)" " file-name)))" +"(define-values(user-links-path)(find-system-path 'links-file))" +"(define-values(user-links-cache)(make-hasheq))" +"(define-values(user-links-timestamp) -inf.0)" +"(define-values(links-path)(find-links-path!" +"(lambda()" +"(let((d(let((c(find-system-path 'collects-dir)))" +"(if(absolute-path? c)" +" c" +"(parameterize((current-directory(find-system-path 'orig-dir)))" +"(find-executable-path(find-system-path 'exec-file) c))))))" +"(and d" +" (build-path d \"config\" \"links.rktd\"))))))" +"(define-values(links-cache)(make-hasheq))" +"(define-values(links-timestamp) -inf.0)" +"(define-values(get-linked-collections)" +"(lambda(user?)" +"(call/ec(lambda(esc)" +"(define-values(make-handler)" +"(lambda(ts)" +"(lambda(exn)" +"(let((l(current-logger)))" +"(when(log-level? l 'error)" +"(log-message l 'error " +"(format" +" \"error reading linked collections: ~a\"" +"(exn-message exn))" +"(current-continuation-marks))))" +"(when ts" +"(if user?" +"(begin" +"(set! user-links-cache(make-hasheq))" +"(set! user-links-timestamp ts))" +"(begin" +"(set! links-cache(make-hasheq))" +"(set! links-timestamp ts))))" +"(esc(make-hasheq)))))" +"(with-continuation-mark" +" exception-handler-key" +"(make-handler #f)" +"(let((ts(file-or-directory-modify-seconds(if user?" +" user-links-path" +" links-path)" +" #f " +"(lambda() -inf.0))))" +"(if(ts . > .(if user? user-links-timestamp links-timestamp))" +"(with-continuation-mark" +" exception-handler-key" +"(make-handler ts)" +"(parameterize((read-case-sensitive #t)" +"(read-square-bracket-as-paren #t)" +"(read-curly-brace-as-paren #t)" +"(read-accept-box #t)" +"(read-accept-compiled #t)" +"(read-accept-bar-quote #t)" +"(read-accept-graph #t)" +"(read-decimal-as-inexact #t)" +"(read-accept-dot #t)" +"(read-accept-infix-dot #t)" +"(read-accept-quasiquote #t)" +"(read-accept-reader #t)" +"(read-accept-lang #f)" +"(current-readtable #f))" +"(let((v(let((p(open-input-file(if user? user-links-path links-path)" +" 'binary)))" +"(dynamic-wind" +" void" +"(lambda() " +"(begin0" +"(read p)" +"(unless(eof-object?(read p))" +" (error \"expected a single S-expression\"))))" +"(lambda()(close-input-port p))))))" +"(unless(and(list? v)" +"(andmap(lambda(p)" +"(and(list? p)" +"(or(= 2(length p))" +"(= 3(length p)))" +"(string?(car p))" +"(path-string?(cadr p))" +"(or(null?(cddr p))" +"(regexp?(caddr p)))))" +" v))" +" (error \"ill-formed content\"))" +"(let((ht(make-hasheq))" +"(dir(let-values(((base name dir?)(split-path(if user?" +" user-links-path" +" links-path))))" +" base)))" +"(for-each" +"(lambda(p)" +"(when(or(null?(cddr p))" +"(regexp-match?(caddr p)(version)))" +"(let((s(string->symbol(car p))))" +"(hash-set! ht s(cons(box(path->complete-path(cadr p) dir))" +"(hash-ref ht s null))))))" +" v)" +"(if user?" +"(begin" +"(set! user-links-cache ht)" +"(set! user-links-timestamp ts))" +"(begin" +"(set! links-cache ht)" +"(set! links-timestamp ts)))" +" ht))))" +"(if user?" +" user-links-cache" +" links-cache))))))))" +"(define-values(normalize-collection-reference)" +"(lambda(collection collection-path)" +"(cond" +"((string? collection)" +" (let ((m (regexp-match-positions #rx\"/+\" collection)))" +"(if m" +"(cond" +"((=(caar m)(sub1(string-length collection)))" +"(values(substring collection 0(caar m)) collection-path))" +"(else" +"(values(substring collection 0(caar m))" +"(cons(substring collection(cdar m))" +" collection-path))))" +"(values collection collection-path))))" +"(else" +"(let-values(((base name dir?)(split-path collection)))" +"(if(eq? base 'relative)" +"(values name collection-path)" +"(normalize-collection-reference base(cons name collection-path))))))))" "(define-values(find-col-file)" "(lambda(who fail collection collection-path file-name)" -"(let((all-paths(current-library-collection-paths)))" +"(let-values(((collection collection-path)" +"(normalize-collection-reference collection collection-path)))" +"(let((all-paths(let((sym(string->symbol(if(path? collection)" +"(path->string collection)" +" collection))))" +"(append" +"(if(use-user-specific-search-paths)" +"(hash-ref(get-linked-collections #t) sym null)" +" null)" +"(if links-path" +"(hash-ref(get-linked-collections #f) sym null)" +" null)" +"(current-library-collection-paths)))))" +"(define-values(*build-path-rep)" +"(lambda(p c)" +"(if(path? p)" +"(build-path p c)" +"(unbox p))))" +"(define-values(*directory-exists?)" +"(lambda(orig p)" +"(if(path? orig)" +"(directory-exists? p)" +" #t)))" +"(define-values(to-string)(lambda(p)(if(path? p)(path->string p) p)))" "(let cloop((paths all-paths)(found-col #f))" "(if(null? paths)" "(if found-col" " found-col" +"(let((rest-coll" +"(if(null? collection-path)" +" \"\"" +"(apply" +" string-append" +"(let loop((cp collection-path))" +"(if(null?(cdr cp))" +"(list(to-string(car cp)))" +" (list* (to-string (car cp)) \"/\" (loop (cdr cp)))))))))" +"(define-values(filter)" +"(lambda(f l)" +"(if(null? l)" +" null" +"(if(f(car l))" +"(cons(car l)(filter f(cdr l)))" +"(filter f(cdr l))))))" "(fail" -" (format \"~a: collection not found: ~s in any of: ~s\" " -" who(if(null? collection-path)" -" collection" -"(apply build-path collection collection-path))" -" all-paths)))" -"(let((dir(build-path(car paths) collection)))" -"(if(directory-exists? dir)" +" (format \"~a: collection not found: ~s in any of: ~s~a\" " +" who" +"(if(null? collection-path)" +"(to-string collection)" +" (string-append (to-string collection) \"/\" rest-coll))" +"(filter path? all-paths)" +"(if(ormap box? all-paths)" +" (format \" or: ~s in any of: ~s\" " +" rest-coll " +"(map unbox(filter box? all-paths)))" +" \"\")))))" +"(let((dir(*build-path-rep(car paths) collection)))" +"(if(*directory-exists?(car paths) dir)" "(let((cpath(apply build-path dir collection-path)))" -"(if(directory-exists? cpath)" +"(if(if(null? collection-path)" +" #t" +"(directory-exists? cpath))" "(if file-name" "(if(or(file-exists?(build-path cpath file-name))" "(let((alt-file-name" @@ -243,7 +493,7 @@ "(cloop(cdr paths)(or found-col cpath)))" " cpath)" "(cloop(cdr paths) found-col)))" -"(cloop(cdr paths) found-col))))))))" +"(cloop(cdr paths) found-col)))))))))" "(define-values(check-suffix-call)" "(lambda(s sfx who)" "(unless(or(path-for-some-system? s)" @@ -324,83 +574,6 @@ "(cons(simplify-path(path->complete-path v(current-directory)))" "(loop(cdr l)))" "(loop(cdr l))))))))))))" -"(define-values(path-list-string->path-list)" -"(let((r(byte-regexp(string->bytes/utf-8" -"(let((sep(if(eq?(system-type) 'windows)" -" \";\"\n" -" \":\")))" -" (format \"([^~a]*)~a(.*)\" sep sep)))))" -"(cons-path(lambda(default s l) " -" (if (bytes=? s #\"\")" -"(append default l)" -"(cons(bytes->path(if(eq?(system-type) 'windows)" -" (regexp-replace* #rx#\"\\\"\" s #\"\")" -" s))" -" l)))))" -"(lambda(s default)" -"(unless(or(bytes? s)" -"(string? s))" -" (raise-type-error 'path-list-string->path-list \"byte string or string\" s))" -"(unless(and(list? default)" -"(andmap path? default))" -" (raise-type-error 'path-list-string->path-list \"list of paths\" default))" -"(let loop((s(if(string? s)" -"(string->bytes/utf-8 s)" -" s)))" -"(let((m(regexp-match r s)))" -"(if m" -"(cons-path default(cadr m)(loop(caddr m)))" -"(cons-path default s null)))))))" -"(define-values(find-executable-path)" -"(case-lambda " -"((program libpath reverse?)" -"(unless(path-string? program) " -" (raise-type-error 'find-executable-path \"path or string (sans nul)\" program))" -"(unless(or(not libpath)(and(path-string? libpath) " -"(relative-path? libpath)))" -" (raise-type-error 'find-executable-path \"#f or relative path or string\" libpath))" -"(letrec((found-exec" -"(lambda(exec-name)" -"(if libpath" -"(let-values(((base name isdir?)(split-path exec-name)))" -"(let((next" -"(lambda()" -"(let((resolved(resolve-path exec-name)))" -"(cond" -"((equal? resolved exec-name) #f)" -"((relative-path? resolved)" -"(found-exec(build-path base resolved)))" -"(else(found-exec resolved)))))))" -"(or(and reverse?(next))" -"(if(path? base)" -"(let((lib(build-path base libpath)))" -"(and(or(directory-exists? lib) " -"(file-exists? lib))" -" lib))" -" #f)" -"(and(not reverse?)(next)))))" -" exec-name))))" -"(if(and(relative-path? program)" -"(let-values(((base name dir?)(split-path program)))" -"(eq? base 'relative)))" -" (let ((paths-str (getenv \"PATH\"))" -"(win-add(lambda(s)(if(eq?(system-type) 'windows) " -" (cons (bytes->path #\".\") s) " -" s))))" -"(let loop((paths(if paths-str " -"(win-add(path-list-string->path-list paths-str null))" -" null)))" -"(if(null? paths)" -" #f" -"(let*((base(path->complete-path(car paths)))" -"(name(build-path base program)))" -"(if(file-exists? name)" -"(found-exec name)" -"(loop(cdr paths)))))))" -"(let((p(path->complete-path program)))" -"(and(file-exists? p)(found-exec p))))))" -"((program libpath)(find-executable-path program libpath #f))" -"((program)(find-executable-path program #f #f))))" "(define(embedded-load start end str)" "(let*((s(if str" " str" diff --git a/src/racket/src/startup.rktl b/src/racket/src/startup.rktl index e347a6af7a..60796ff4b3 100644 --- a/src/racket/src/startup.rktl +++ b/src/racket/src/startup.rktl @@ -179,7 +179,7 @@ ;; (along with much of '#%kernel) (module #%utils '#%kernel - (#%require '#%min-stx) + (#%require '#%min-stx '#%paramz) (#%provide path-string? normal-case-path @@ -230,6 +230,87 @@ [(string? s) (string->path s)] [else s]))) + ;; ------------------------------ executable path ------------------------------ + + (define-values (find-executable-path) + (case-lambda + [(program libpath reverse?) + (unless (path-string? program) + (raise-type-error 'find-executable-path "path or string (sans nul)" program)) + (unless (or (not libpath) (and (path-string? libpath) + (relative-path? libpath))) + (raise-type-error 'find-executable-path "#f or relative path or string" libpath)) + (letrec ([found-exec + (lambda (exec-name) + (if libpath + (let-values ([(base name isdir?) (split-path exec-name)]) + (let ([next + (lambda () + (let ([resolved (resolve-path exec-name)]) + (cond + [(equal? resolved exec-name) #f] + [(relative-path? resolved) + (found-exec (build-path base resolved))] + [else (found-exec resolved)])))]) + (or (and reverse? (next)) + (if (path? base) + (let ([lib (build-path base libpath)]) + (and (or (directory-exists? lib) + (file-exists? lib)) + lib)) + #f) + (and (not reverse?) (next))))) + exec-name))]) + (if (and (relative-path? program) + (let-values ([(base name dir?) (split-path program)]) + (eq? base 'relative))) + (let ([paths-str (getenv "PATH")] + [win-add (lambda (s) (if (eq? (system-type) 'windows) + (cons (bytes->path #".") s) + s))]) + (let loop ([paths (if paths-str + (win-add (path-list-string->path-list paths-str null)) + null)]) + (if (null? paths) + #f + (let* ([base (path->complete-path (car paths))] + [name (build-path base program)]) + (if (file-exists? name) + (found-exec name) + (loop (cdr paths))))))) + (let ([p (path->complete-path program)]) + (and (file-exists? p) (found-exec p)))))] + [(program libpath) (find-executable-path program libpath #f)] + [(program) (find-executable-path program #f #f)])) + + (define-values (path-list-string->path-list) + (let ((r (byte-regexp (string->bytes/utf-8 + (let ((sep (if (eq? (system-type) 'windows) + ";" + ":"))) + (format "([^~a]*)~a(.*)" sep sep))))) + (cons-path (lambda (default s l) + (if (bytes=? s #"") + (append default l) + (cons (bytes->path (if (eq? (system-type) 'windows) + (regexp-replace* #rx#"\"" s #"") + s)) + l))))) + (lambda (s default) + (unless (or (bytes? s) + (string? s)) + (raise-type-error 'path-list-string->path-list "byte string or string" s)) + (unless (and (list? default) + (andmap path? default)) + (raise-type-error 'path-list-string->path-list "list of paths" default)) + (let loop ([s (if (string? s) + (string->bytes/utf-8 s) + s)]) + (let ([m (regexp-match r s)]) + (if m + (cons-path default (cadr m) (loop (caddr m))) + (cons-path default s null))))))) + ;; ------------------------------ Collections ------------------------------ (define-values (-check-relpath) @@ -268,45 +349,232 @@ file-name) file-name))) + (define-values (user-links-path) (find-system-path 'links-file)) + (define-values (user-links-cache) (make-hasheq)) + (define-values (user-links-timestamp) -inf.0) + + (define-values (links-path) (find-links-path! + ;; This thunk is called once per place, and the result + ;; is remembered for later invocations. Otherwise, the + ;; search for the config file can trip over filesystem + ;; restrictions imposed by security guards. + (lambda () + (let ([d (let ([c (find-system-path 'collects-dir)]) + (if (absolute-path? c) + c + (parameterize ([current-directory (find-system-path 'orig-dir)]) + (find-executable-path (find-system-path 'exec-file) c))))]) + (and d + (build-path d "config" "links.rktd")))))) + (define-values (links-cache) (make-hasheq)) + (define-values (links-timestamp) -inf.0) + + (define-values (get-linked-collections) + (lambda (user?) + (call/ec (lambda (esc) + (define-values (make-handler) + (lambda (ts) + (lambda (exn) + (let ([l (current-logger)]) + (when (log-level? l 'error) + (log-message l 'error + (format + "error reading linked collections: ~a" + (exn-message exn)) + (current-continuation-marks)))) + (when ts + (if user? + (begin + (set! user-links-cache (make-hasheq)) + (set! user-links-timestamp ts)) + (begin + (set! links-cache (make-hasheq)) + (set! links-timestamp ts)))) + (esc (make-hasheq))))) + (with-continuation-mark + exception-handler-key + (make-handler #f) + (let ([ts (file-or-directory-modify-seconds (if user? + user-links-path + links-path) + #f + (lambda () -inf.0))]) + (if (ts . > . (if user? user-links-timestamp links-timestamp)) + (with-continuation-mark + exception-handler-key + (make-handler ts) + (parameterize ([read-case-sensitive #t] + [read-square-bracket-as-paren #t] + [read-curly-brace-as-paren #t] + [read-accept-box #t] + [read-accept-compiled #t] + [read-accept-bar-quote #t] + [read-accept-graph #t] + [read-decimal-as-inexact #t] + [read-accept-dot #t] + [read-accept-infix-dot #t] + [read-accept-quasiquote #t] + [read-accept-reader #t] + [read-accept-lang #f] + [current-readtable #f]) + (let ([v (let ([p (open-input-file (if user? user-links-path links-path) + 'binary)]) + (dynamic-wind + void + (lambda () + (begin0 + (read p) + (unless (eof-object? (read p)) + (error "expected a single S-expression")))) + (lambda () (close-input-port p))))]) + (unless (and (list? v) + (andmap (lambda (p) + (and (list? p) + (or (= 2 (length p)) + (= 3 (length p))) + (string? (car p)) + (path-string? (cadr p)) + (or (null? (cddr p)) + (regexp? (caddr p))))) + v)) + (error "ill-formed content")) + (let ([ht (make-hasheq)] + [dir (let-values ([(base name dir?) (split-path (if user? + user-links-path + links-path))]) + base)]) + (for-each + (lambda (p) + (when (or (null? (cddr p)) + (regexp-match? (caddr p) (version))) + (let ([s (string->symbol (car p))]) + (hash-set! ht s (cons (box (path->complete-path (cadr p) dir)) + (hash-ref ht s null)))))) + v) + (if user? + (begin + (set! user-links-cache ht) + (set! user-links-timestamp ts)) + (begin + (set! links-cache ht) + (set! links-timestamp ts))) + ht)))) + (if user? + user-links-cache + links-cache)))))))) + + (define-values (normalize-collection-reference) + (lambda (collection collection-path) + ;; make sure that `collection' is a top-level collection name, + (cond + [(string? collection) + (let ([m (regexp-match-positions #rx"/+" collection)]) + (if m + (cond + [(= (caar m) (sub1 (string-length collection))) + (values (substring collection 0 (caar m)) collection-path)] + [else + (values (substring collection 0 (caar m)) + (cons (substring collection (cdar m)) + collection-path))]) + (values collection collection-path)))] + [else + (let-values ([(base name dir?) (split-path collection)]) + (if (eq? base 'relative) + (values name collection-path) + (normalize-collection-reference base (cons name collection-path))))]))) + (define-values (find-col-file) (lambda (who fail collection collection-path file-name) - (let ([all-paths (current-library-collection-paths)]) - (let cloop ([paths all-paths][found-col #f]) - (if (null? paths) - (if found-col - found-col - (fail - (format "~a: collection not found: ~s in any of: ~s" - who (if (null? collection-path) - collection - (apply build-path collection collection-path)) - all-paths))) - (let ([dir (build-path (car paths) collection)]) - (if (directory-exists? dir) - (let ([cpath (apply build-path dir collection-path)]) - (if (directory-exists? cpath) - (if file-name - (if (or (file-exists? (build-path cpath file-name)) - (let ([alt-file-name - (let* ([file-name (if (path? file-name) - (path->string file-name) - file-name)] - [len (string-length file-name)]) - (and (len . >= . 4) - (string=? ".rkt" (substring file-name (- len 4))) - (string-append (substring file-name 0 (- len 4)) ".ss")))]) - (and alt-file-name - (file-exists? (build-path cpath alt-file-name))))) - cpath - ;; Look further for specific file, but remember - ;; first found directory - (cloop (cdr paths) (or found-col cpath))) - ;; Just looking for dir; found it: - cpath) - ;; sub-collection not here; try next instance - ;; of the top-level collection - (cloop (cdr paths) found-col))) - (cloop (cdr paths) found-col)))))))) + (let-values ([(collection collection-path) + (normalize-collection-reference collection collection-path)]) + (let ([all-paths (let ([sym (string->symbol (if (path? collection) + (path->string collection) + collection))]) + (append + ;; list of (box path)s: + (if (use-user-specific-search-paths) + (hash-ref (get-linked-collections #t) sym null) + null) + ;; list of (box path)s: + (if links-path + (hash-ref (get-linked-collections #f) sym null) + null) + ;; list of paths: + (current-library-collection-paths)))]) + (define-values (*build-path-rep) + (lambda (p c) + (if (path? p) + (build-path p c) + ;; box => from links table for c + (unbox p)))) + (define-values (*directory-exists?) + (lambda (orig p) + (if (path? orig) + (directory-exists? p) + ;; orig is box => from links table + #t))) + (define-values (to-string) (lambda (p) (if (path? p) (path->string p) p))) + (let cloop ([paths all-paths] [found-col #f]) + (if (null? paths) + (if found-col + found-col + (let ([rest-coll + (if (null? collection-path) + "" + (apply + string-append + (let loop ([cp collection-path]) + (if (null? (cdr cp)) + (list (to-string (car cp))) + (list* (to-string (car cp)) "/" (loop (cdr cp)))))))]) + (define-values (filter) + (lambda (f l) + (if (null? l) + null + (if (f (car l)) + (cons (car l) (filter f (cdr l))) + (filter f (cdr l)))))) + (fail + (format "~a: collection not found: ~s in any of: ~s~a" + who + (if (null? collection-path) + (to-string collection) + (string-append (to-string collection) "/" rest-coll)) + (filter path? all-paths) + (if (ormap box? all-paths) + (format " or: ~s in any of: ~s" + rest-coll + (map unbox (filter box? all-paths))) + ""))))) + (let ([dir (*build-path-rep (car paths) collection)]) + (if (*directory-exists? (car paths) dir) + (let ([cpath (apply build-path dir collection-path)]) + (if (if (null? collection-path) + #t + (directory-exists? cpath)) + (if file-name + (if (or (file-exists? (build-path cpath file-name)) + (let ([alt-file-name + (let* ([file-name (if (path? file-name) + (path->string file-name) + file-name)] + [len (string-length file-name)]) + (and (len . >= . 4) + (string=? ".rkt" (substring file-name (- len 4))) + (string-append (substring file-name 0 (- len 4)) ".ss")))]) + (and alt-file-name + (file-exists? (build-path cpath alt-file-name))))) + cpath + ;; Look further for specific file, but remember + ;; first found directory + (cloop (cdr paths) (or found-col cpath))) + ;; Just looking for dir; found it: + cpath) + ;; sub-collection not here; try next instance + ;; of the top-level collection + (cloop (cdr paths) found-col))) + (cloop (cdr paths) found-col))))))))) (define-values (check-suffix-call) (lambda (s sfx who) @@ -393,85 +661,6 @@ (cons (simplify-path (path->complete-path v (current-directory))) (loop (cdr l))) (loop (cdr l)))))))))])) - - (define-values (path-list-string->path-list) - (let ((r (byte-regexp (string->bytes/utf-8 - (let ((sep (if (eq? (system-type) 'windows) - ";" - ":"))) - (format "([^~a]*)~a(.*)" sep sep))))) - (cons-path (lambda (default s l) - (if (bytes=? s #"") - (append default l) - (cons (bytes->path (if (eq? (system-type) 'windows) - (regexp-replace* #rx#"\"" s #"") - s)) - l))))) - (lambda (s default) - (unless (or (bytes? s) - (string? s)) - (raise-type-error 'path-list-string->path-list "byte string or string" s)) - (unless (and (list? default) - (andmap path? default)) - (raise-type-error 'path-list-string->path-list "list of paths" default)) - (let loop ([s (if (string? s) - (string->bytes/utf-8 s) - s)]) - (let ([m (regexp-match r s)]) - (if m - (cons-path default (cadr m) (loop (caddr m))) - (cons-path default s null))))))) - - (define-values (find-executable-path) - (case-lambda - [(program libpath reverse?) - (unless (path-string? program) - (raise-type-error 'find-executable-path "path or string (sans nul)" program)) - (unless (or (not libpath) (and (path-string? libpath) - (relative-path? libpath))) - (raise-type-error 'find-executable-path "#f or relative path or string" libpath)) - (letrec ([found-exec - (lambda (exec-name) - (if libpath - (let-values ([(base name isdir?) (split-path exec-name)]) - (let ([next - (lambda () - (let ([resolved (resolve-path exec-name)]) - (cond - [(equal? resolved exec-name) #f] - [(relative-path? resolved) - (found-exec (build-path base resolved))] - [else (found-exec resolved)])))]) - (or (and reverse? (next)) - (if (path? base) - (let ([lib (build-path base libpath)]) - (and (or (directory-exists? lib) - (file-exists? lib)) - lib)) - #f) - (and (not reverse?) (next))))) - exec-name))]) - (if (and (relative-path? program) - (let-values ([(base name dir?) (split-path program)]) - (eq? base 'relative))) - (let ([paths-str (getenv "PATH")] - [win-add (lambda (s) (if (eq? (system-type) 'windows) - (cons (bytes->path #".") s) - s))]) - (let loop ([paths (if paths-str - (win-add (path-list-string->path-list paths-str null)) - null)]) - (if (null? paths) - #f - (let* ([base (path->complete-path (car paths))] - [name (build-path base program)]) - (if (file-exists? name) - (found-exec name) - (loop (cdr paths))))))) - (let ([p (path->complete-path program)]) - (and (file-exists? p) (found-exec p)))))] - [(program libpath) (find-executable-path program libpath #f)] - [(program) (find-executable-path program #f #f)])) ;; used for the -k command-line argument: (define (embedded-load start end str) diff --git a/src/racket/src/thread.c b/src/racket/src/thread.c index a8ee52fabe..fe26d20705 100644 --- a/src/racket/src/thread.c +++ b/src/racket/src/thread.c @@ -636,6 +636,7 @@ void scheme_init_paramz(Scheme_Env *env) GLOBAL_PRIM_W_ARITY("check-for-break" , check_break_now , 0, 0, newenv); GLOBAL_PRIM_W_ARITY("reparameterize" , reparameterize , 1, 1, newenv); GLOBAL_PRIM_W_ARITY("make-custodian-from-main", make_custodian_from_main, 0, 0, newenv); + GLOBAL_PRIM_W_ARITY("find-links-path!" , scheme_find_links_path , 1, 1, newenv); scheme_finish_primitive_module(newenv); scheme_protect_primitive_provide(newenv, NULL);