From fb05266ad26ea4565665597f2c61ed104b95b715 Mon Sep 17 00:00:00 2001 From: Stephen Bloch Date: Tue, 28 Dec 2010 16:27:04 -0500 Subject: [PATCH] Rewriting map-image to work with 5.1. Also added a bunch of test cases to map-image-bsl-tests.rkt. --- collects/picturing-programs/book-pictures.rkt | 16 + collects/picturing-programs/doc.html | 56 + collects/picturing-programs/doc.scrbl | 336 ++ collects/picturing-programs/dummy.rkt | 4 + collects/picturing-programs/info.rkt | 24 + collects/picturing-programs/io-stuff.rkt | 30 + collects/picturing-programs/main.rkt | 20 + collects/picturing-programs/map-image.rkt | 431 +++ .../picturing-programs/pictures/bloch.jpg | Bin 0 -> 10927 bytes .../picturing-programs/pictures/calendar.png | Bin 0 -> 339 bytes .../pictures/mad_hacker.png | Bin 0 -> 2475 bytes .../picturing-programs/pictures/qbook.png | Bin 0 -> 748 bytes .../pictures/schemelogo.png | Bin 0 -> 4107 bytes .../pictures/small_hieroglyphics.png | Bin 0 -> 1474 bytes .../pictures/stick-figure.png | Bin 0 -> 2920 bytes collects/picturing-programs/racket.css | 188 + collects/picturing-programs/scheme.css | 166 + .../picturing-programs/scribble-common.js | 153 + .../picturing-programs/scribble-style.css | 0 collects/picturing-programs/scribble.css | 429 +++ collects/picturing-programs/tests/README | 11 + collects/picturing-programs/tests/bad-draw.ss | 12 + collects/picturing-programs/tests/balls.ss | 87 + collects/picturing-programs/tests/design.txt | 34 + .../tests/full-scene-visible.ss | 15 + .../tests/image-equality-performance.ss | 908 +++++ .../tests/install-teachpack.ss | 2 + .../tests/map-image-bsl-tests.rkt | 196 ++ .../tests/map-image-isl-tests.rkt | 3128 +++++++++++++++++ .../picturing-programs/tests/perform-robby.ss | 21 + collects/picturing-programs/tests/player | 15 + .../picturing-programs/tests/profile-robby.ss | 18 + .../tests/robby-optimization-gone.ss | 20 + .../tests/rotating-triangle.ss | 24 + collects/picturing-programs/tests/sam.ss | 7 + collects/picturing-programs/tests/shared.ss | 74 + collects/picturing-programs/tests/stop.ss | 21 + collects/picturing-programs/tests/stripes.rkt | 99 + .../picturing-programs/tests/test-image.ss | 1561 ++++++++ .../picturing-programs/tests/ufo-rename.ss | 15 + .../picturing-programs/tests/world0-stops.ss | 13 + collects/picturing-programs/tests/xrun | 3 + collects/picturing-programs/tiles.rkt | 143 + 43 files changed, 8280 insertions(+) create mode 100644 collects/picturing-programs/book-pictures.rkt create mode 100644 collects/picturing-programs/doc.html create mode 100644 collects/picturing-programs/doc.scrbl create mode 100644 collects/picturing-programs/dummy.rkt create mode 100644 collects/picturing-programs/info.rkt create mode 100644 collects/picturing-programs/io-stuff.rkt create mode 100644 collects/picturing-programs/main.rkt create mode 100644 collects/picturing-programs/map-image.rkt create mode 100644 collects/picturing-programs/pictures/bloch.jpg create mode 100644 collects/picturing-programs/pictures/calendar.png create mode 100644 collects/picturing-programs/pictures/mad_hacker.png create mode 100644 collects/picturing-programs/pictures/qbook.png create mode 100644 collects/picturing-programs/pictures/schemelogo.png create mode 100644 collects/picturing-programs/pictures/small_hieroglyphics.png create mode 100644 collects/picturing-programs/pictures/stick-figure.png create mode 100644 collects/picturing-programs/racket.css create mode 100644 collects/picturing-programs/scheme.css create mode 100644 collects/picturing-programs/scribble-common.js create mode 100644 collects/picturing-programs/scribble-style.css create mode 100644 collects/picturing-programs/scribble.css create mode 100644 collects/picturing-programs/tests/README create mode 100644 collects/picturing-programs/tests/bad-draw.ss create mode 100644 collects/picturing-programs/tests/balls.ss create mode 100644 collects/picturing-programs/tests/design.txt create mode 100644 collects/picturing-programs/tests/full-scene-visible.ss create mode 100644 collects/picturing-programs/tests/image-equality-performance.ss create mode 100644 collects/picturing-programs/tests/install-teachpack.ss create mode 100755 collects/picturing-programs/tests/map-image-bsl-tests.rkt create mode 100755 collects/picturing-programs/tests/map-image-isl-tests.rkt create mode 100644 collects/picturing-programs/tests/perform-robby.ss create mode 100644 collects/picturing-programs/tests/player create mode 100644 collects/picturing-programs/tests/profile-robby.ss create mode 100644 collects/picturing-programs/tests/robby-optimization-gone.ss create mode 100644 collects/picturing-programs/tests/rotating-triangle.ss create mode 100644 collects/picturing-programs/tests/sam.ss create mode 100644 collects/picturing-programs/tests/shared.ss create mode 100644 collects/picturing-programs/tests/stop.ss create mode 100644 collects/picturing-programs/tests/stripes.rkt create mode 100644 collects/picturing-programs/tests/test-image.ss create mode 100644 collects/picturing-programs/tests/ufo-rename.ss create mode 100644 collects/picturing-programs/tests/world0-stops.ss create mode 100644 collects/picturing-programs/tests/xrun create mode 100644 collects/picturing-programs/tiles.rkt diff --git a/collects/picturing-programs/book-pictures.rkt b/collects/picturing-programs/book-pictures.rkt new file mode 100644 index 0000000000..a9f98657d3 --- /dev/null +++ b/collects/picturing-programs/book-pictures.rkt @@ -0,0 +1,16 @@ +#lang racket +; Initial version, Dec. 13, 2010. +; Doesn't work with a literal image, but it works to use a "bitmap" +; reference to a file that's included with the teachpacks. Dec. 21, 2010. + +(require 2htdp/image) + +(provide (all-defined-out)) + +(define bloch (bitmap "pictures/bloch.jpg")) +(define hieroglyphics (bitmap "pictures/small_hieroglyphics.png")) +(define hacker (bitmap "pictures/mad_hacker.png")) +(define book (bitmap "pictures/qbook.png")) +(define stick-figure (bitmap "pictures/stick-figure.png")) +(define scheme-logo (bitmap "pictures/schemelogo.png")) +(define calendar (bitmap "pictures/calendar.png")) diff --git a/collects/picturing-programs/doc.html b/collects/picturing-programs/doc.html new file mode 100644 index 0000000000..d4c2de466a --- /dev/null +++ b/collects/picturing-programs/doc.html @@ -0,0 +1,56 @@ + +Picturing Programs Teachpack
Version: 5.0.0.6

Picturing Programs Teachpack

Stephen Bloch

 (require (planet sbloch/picturing-programs))

1 About This Teachpack

Provides a variety of functions for combining and manipulating images +and running interactive animations. +It’s intended to be used with the textbook +Picturing Programs.

2 Installation

If you’re reading this, you’ve probably already installed the teachpack successfully, +but if you need to install it on a different machine, ... +
  1. start DrScheme

  2. switch languages to “Use the language declared in the +source” and click “Run”

  3. in the Interactions pane, type +
      (require (planet sbloch/picturing-programs:2))

  4. after a few seconds, you should see the message

    Wrote file “picturing-programs.rkt” to installed-teachpacks directory.

  5. switch languages back to one of the HtDP languages, like Beginning Student

  6. either +
    • in the Definitions pane, type +
        (require installed-teachpacks/picturing-programs)
      or

    • from the Language menu, choose "Add +Teachpack..." and select "picturing-programs.rkt"

  7. click "Run"

3 Functions from image.rkt and universe.rkt

This package includes all of +the image teachpack and +and +the universe teachpack, +so if you’re using this teachpack, don’t also load either of those. +See the above links for how to use those teachpacks.

It also supersedes the older tiles and sb-world teachpacks, +so if you have those, don’t load them either; use this instead.

This package also provides the following additional functions:

4 New image functions

(rotate-cw img)  image?
  img : image?
Rotates an image 90 degrees clockwise.

(rotate-ccw img)  image?
  img : image?
Rotates an image 90 degrees counterclockwise.

(rotate-180 img)  image?
  img : image?
Rotates an image 180 degrees around its center.

(crop-top img pixels)  image?
  img : image?
  pixels : natural-number/c
Chops off the specified number of pixels from the top of the image.

(crop-bottom img pixels)  image?
  img : image?
  pixels : natural-number/c
Chops off the specified number of pixels from the bottom of the image.

(crop-left img pixels)  image?
  img : image?
  pixels : natural-number/c
Chops off the specified number of pixels from the left side of the image.

(crop-right img pixels)  image?
  img : image?
  pixels : natural-number/c
Chops off the specified number of pixels from the right side of the image.

(show-it img)  image?
  img : image?
Returns the given image unaltered. Useful as a draw handler for animations whose model is an image.

(reflect-vert img)  image?
  img : image?
The same as flip-vertical; retained for compatibility.

(reflect-horiz img)  image?
  img : image?
The same as flip-horizontal; retained for compatibility.

5 Pixel functions

The above functions allow you to operate on a picture as a whole, but sometimes +you want to manipulate a picture pixel-by-pixel.

5.1 Colors and pixels

(name->color name)  (or/c color? false/c)
  name : string?
Given a color name like "red", "turquoise", "forest green", etc., returns the corresponding +color struct, showing the red, green, and blue components. If the name isn’t +recognized, returns false.

(get-pixel-color x y pic)  color?
  x : natural-number/c
  y : natural-number/c
  pic : image?
Gets the color of a specified pixel in the given image. If x and/or y are outside the +bounds of the image, returns black.

5.2 Specifying the color of each pixel of an image

(map-image f img)  image?
  f : (-> natural-number/c natural-number/c color? color?)
  img : image?
Applies the given function to each pixel in a given image, producing a new image the same +size and shape. For example, +
  (define (lose-red x y old-color)
    (make-color 0 (color-green old-color) (color-blue old-color)))
  
  (map-image lose-red my-picture)
produces a copy of my-picture with all the red leached out, +leaving only the blue and green components.

  (define (apply-gradient x y old-color)
    (make-color (min (* 3 x) 255) 0 (min (* 3 y) 255)))
  
  (map-image apply-gradient my-picture)
produces a picture the same size and shape as my-picture, +but with a smooth color gradient with red increasing from left to +right and blue increasing from top to bottom.

(build-image width height f)  image?
  width : natural-number/c
  height : natural-number/c
  f : (-> natural-number/c natural-number/c color?)
Builds an image of the specified size and shape by calling the specified function +on the coordinates of each pixel. For example, +
  (define (fuzz pic)
    (local [(define (near-pixel x y)
              (get-pixel-color (+ x -3 (random 7))
                               (+ y -3 (random 7))
                               pic))]
      (build-image (image-width pic)
                   (image-height pic)
                   near-pixel)))
produces a fuzzy version of the given picture by replacing each pixel with a +randomly chosen pixel near it.

(change-to-color new-color)
  (->* (natural-number/c natural-number/c) (color?) color?)
  new-color : (or/c string? color?)
Returns a constant-valued function suitable for use in map-image or build-image. +The input to change-to-color may be either a color struct or a color name from +the standard color-name database. For example, +
  (map-image (change-to-color "turquoise") my-picture)
returns a picture with the same size, shape, and mask as my-picture, but all turquoise, while +
  (build-image 50 30 (change-to-color (make-color 0 100 200)))
is equivalent to (rectangle 50 30 "solid" (make-color 0 100 200))

(real->int num)  integer?
  num : real?
Not specific to colors, but useful if you’re building colors by arithmetic. +For example, +
  (define (bad-gradient x y)
    (make-color (* 2.5 x) (* 1.6 y) 0))
  (build-image 50 30 bad-gradient)
  (define (good-gradient x y)
    (make-color (real->int (* 2.5 x)) (real->int (* 1.6 y)) 0))
  (build-image 50 30 good-gradient)
The version using bad-gradient crashes because color components must be exact integers. +The version using good-gradient works.

5.3 Transparency

Some image formats support transparency, meaning that part of the image is +ignored when layering it with other images.

(pixel-visible? x y pic)  boolean?
  x : natural-number/c
  y : natural-number/c
  pic : image?
Checks transparency: returns false if the specified pixel in the image is transparent, +true if not.

A maybe-color is either a color or false, which is treated as transparent.

(maybe-color? thing)  boolean?
  thing : any/c
Tests whether the argument is a maybe-color.

(map-masked-image f pic)  image?
  f : (-> natural-number/c natural-number/c maybe-color? maybe-color?)
  pic : image?
Like map-image, but the function will receive false for any transparent pixel, and +any place that it returns false will be treated as a transparent pixel.

(build-masked-image width height f)  image?
  width : natural-number/c
  height : natural-number/c
  f : (-> natural-number/c natural-number/c maybe-color?)
Like build-image, but any place that the function returns false will be treated +as a transparent pixel.

6 Input and Output

This teachpack also provides several functions to help in testing +I/O functions (in Advanced Student language; ignore this section if +you’re in a Beginner or Intermediate language):

(with-input-from-string input thunk)  any/c
  input : string?
  thunk : (-> any/c)
Calls thunk, which presumably uses read, +in such a way that read reads from input rather than from +the keyboard.

(with-output-to-string thunk)  string?
  thunk : (-> any/c)
Calls thunk, which presumably uses display, print, +write, and/or printf, in such a way that its output is +accumlated into a string, which is then returned.

(with-input-from-file filename thunk)  any/c
  filename : string?
  thunk : (-> any/c)
Calls thunk, which presumably uses read, +in such a way that read reads from the specified file +rather than from the keyboard.

(with-output-to-file filename thunk)  any/c
  filename : string?
  thunk : (-> any/c)
Calls thunk, which presumably uses display, print, +write, and/or printf, in such a way that its output is +redirected into the specified file.

(with-input-from-url url thunk)  any/c
  url : string?
  thunk : (-> any/c)
Calls thunk, which presumably uses read, +in such a way that read reads from the HTML source of the +Web page at the specified URL rather than from the keyboard.

(with-io-strings input thunk)  string?
  input : string?
  thunk : (-> any/c)
Combines with-input-from-string and with-output-to-string: +calls thunk with its input coming from input and accumulates +its output into a string, which is returned. Especially useful for testing: +
  (define (ask question)
    (begin (display question)
           (read)))
  (define (greet)
    (local [(define name (ask "What is your name?"))]
      (printf "Hello, ~a!" name)))
  (check-expect
   (with-io-strings "Steve" greet)
   "What is your name?Hello, Steve!")

 
\ No newline at end of file diff --git a/collects/picturing-programs/doc.scrbl b/collects/picturing-programs/doc.scrbl new file mode 100644 index 0000000000..94e295e0f8 --- /dev/null +++ b/collects/picturing-programs/doc.scrbl @@ -0,0 +1,336 @@ +#lang scribble/manual +@(require + (for-label racket + "main.rkt" + "io-stuff.rkt" + ; "sb-universe.rkt" + "tiles.rkt" + "map-image.rkt" + 2htdp/image + teachpack/2htdp/universe + (only-in lang/htdp-beginner check-expect) + )) + +@; teachpack["picturing-programs"]{Picturing Programs} +@title{Picturing Programs Teachpack} +@author{Stephen Bloch} + +@; defmodule[installed-teachpack/picturing-programs] +@defmodule[(planet sbloch/picturing-programs)] + +@section{About This Teachpack} + +@;Testing, testing: @racket[(list 'testing 1 2 3)]. +@; +@;This is a reference to the @racket[list] function. +@;Now a reference to @racket[triangle], +@;and @racket[big-bang], +@;and @racket[show-it], +@;and @racket[crop-top], +@;and @racket[map-image], +@;and @racket[with-input-from-url], +@;which are defined in several different places. + +Provides a variety of functions for combining and manipulating images +and running interactive animations. +It's intended to be used with the textbook +@hyperlink["http://www.picturingprograms.com" "Picturing Programs"]. + +@section{Installation} +If you're reading this, you've probably already installed the teachpack successfully, +but if you need to install it on a different machine, ... +@itemize[#:style 'ordered + @item{start DrScheme} + @item{switch languages to ``Use the language declared in the + source'' and click ``Run''} + @item{in the Interactions pane, type + @racketblock[(require (planet sbloch/picturing-programs:2))]} + @item{after a few seconds, you should see the message + + @racketoutput{Wrote file ``picturing-programs.rkt'' to installed-teachpacks directory.}} + @item{switch languages back to one of the HtDP languages, like Beginning Student} + @item{either + @itemize{ + @item{in the Definitions pane, type + @racketblock[(require installed-teachpacks/picturing-programs)] + or} + @item{from the Language menu, choose "Add + Teachpack..." and select "picturing-programs.rkt"} + } + } + @item{click "Run"} + ] + +@section{Functions from image.rkt and universe.rkt} + +This package includes all of +@racketmodlink[2htdp/image]{the image teachpack} and +and +@racketmodlink[2htdp/universe]{the universe teachpack}, +so if you're using this teachpack, @emph{don't} also load either of those. +See the above links for how to use those teachpacks. + +It also supersedes the older @racket[tiles] and @racket[sb-world] teachpacks, +so if you have those, don't load them either; use this instead. + +This package also provides the following additional functions: + +@; @include-section{image.rkt} + +@section{New image functions} + +@defproc[(rotate-cw [img image?]) + image?]{Rotates an image 90 degrees clockwise.} + +@defproc[(rotate-ccw [img image?]) + image?]{Rotates an image 90 degrees counterclockwise.} + +@defproc[(rotate-180 [img image?]) + image?]{Rotates an image 180 degrees around its center.} + +@defproc[(crop-top [img image?] [pixels natural-number/c]) + image?]{Chops off the specified number of pixels from the top of the image.} + +@defproc[(crop-bottom [img image?] [pixels natural-number/c]) + image?]{Chops off the specified number of pixels from the bottom of the image.} + +@defproc[(crop-left [img image?] [pixels natural-number/c]) + image?]{Chops off the specified number of pixels from the left side of the image.} + +@defproc[(crop-right [img image?] [pixels natural-number/c]) + image?]{Chops off the specified number of pixels from the right side of the image.} + +@defproc[(show-it [img image?]) + image?]{Returns the given image unaltered. Useful as a draw handler for animations whose model is an image.} + +@defproc[(reflect-vert [img image?]) + image?]{The same as @racket[flip-vertical]; retained for compatibility.} + +@defproc[(reflect-horiz [img image?]) + image?]{The same as @racket[flip-horizontal]; retained for compatibility.} + +@section{Variables} +This teachpack also defines variable names for some of the pictures used in the textbook. + +@defthing[pic:bloch image?]{A picture of the author, c. 2005.} +@defthing[pic:hieroglyphics image?]{A picture of a stone tablet with +hieroglyphics on it.} +@defthing[pic:hacker image?]{A picture of a student sitting at a +computer.} +@defthing[pic:book image?]{A picture of a book with a question mark.} +@defthing[pic:stick-figure image?]{A picture of a stick figure, built +from geometric primitives.} +@defthing[pic:scheme-logo image?]{A picture of a DrScheme/DrRacket +logo.} +@defthing[pic:calendar image?]{A picture of an appointment calendar.} + +Note that these seven variable names happen to start with "pic:", to +distinguish them from anything you might define that happens to be named +"calendar" or "book", but you can name a variable anything you want; in +particular, there's no requirement that your names start with "pic:". + +@section{Pixel functions} +The above functions allow you to operate on a picture as a whole, but sometimes +you want to manipulate a picture pixel-by-pixel. + +@subsection{Colors and pixels} + +@defproc[(name->color [name string?]) + (or/c color? false/c)]{ + +Given a color name like "red", "turquoise", "forest green", @italic{etc.}, returns the corresponding +color struct, showing the red, green, and blue components. If the name isn't +recognized, returns @racket[false].} + +@defproc[(get-pixel-color [x natural-number/c] [y natural-number/c] [pic image?]) + color?]{ + +Gets the color of a specified pixel in the given image. If x and/or y are outside the +bounds of the image, returns black.} + +@subsection{Specifying the color of each pixel of an image} +@defproc[(build-image [width natural-number/c] + [height natural-number/c] + [f (-> natural-number/c natural-number/c color?)]) + image?]{ + +Builds an image of the specified size and shape by calling the specified function +on the coordinates of each pixel. For example, +@racketblock[ + (define (fuzz pic) + (local [(define (near-pixel x y) + (get-pixel-color (+ x -3 (random 7)) + (+ y -3 (random 7)) + pic))] + (build-image (image-width pic) + (image-height pic) + near-pixel))) + ] +produces a fuzzy version of the given picture by replacing each pixel with a +randomly chosen pixel near it.} + +@defproc[(build3-image [width natural-number/c] [height natural-number/c] + [red-function (-> natural-number/c natural-number/c natural-number/c)] + [green-function (-> natural-number/c natural-number/c natural-number/c)] + [blue-function (-> natural-number/c natural-number/c natural-number/c)]) + image?]{ +A version of @racket[build-image] for students who don't know about structs yet. +Each of the three functions takes in the x and y coordinates of a pixel, and +should return an integer from 0 through 255 to determine that color component.} + +@defproc[(map-image [f (-> natural-number/c natural-number/c color? color?)] [img image?]) + image?]{ + +Applies the given function to each pixel in a given image, producing a new image the same +size and shape. For example, +@racketblock[ + (define (lose-red x y old-color) + (make-color 0 (color-green old-color) (color-blue old-color))) + + (map-image lose-red my-picture)] +produces a copy of @racket[my-picture] with all the red leached out, +leaving only the blue and green components. + +@racketblock[ + (define (apply-gradient x y old-color) + (make-color (min (* 3 x) 255) 0 (min (* 3 y) 255))) + + (map-image apply-gradient my-picture)] +produces a picture the same size and shape as @racket[my-picture], +but with a smooth color gradient with red increasing from left to +right and blue increasing from top to bottom.} + +@defproc[(map3-image +[red-func (-> natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c)] +[green-func (-> natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c)] +[blue-func (-> natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c natural-number/c)] +[img image?]) +image?]{ + +A version of map-image for students who don't know about structs yet. Each of the three given functions is assumed +to have the contract @racketblock[num(x) num(y) num(r) num(g) num(b) -> num ] +For each pixel in the original picture, applies the three +functions to the x coordinate, y coordinate, red, green, and blue components of the picture. +The result of the first function is used as the red component, the second as green, and the third as blue +in the corresponding pixel of the resulting picture. + +For example, +@racketblock[ +(define (zero x y r g b) 0) +(define (same-g x y r g b) g) +(define (same-b x y r g b) b) +(map3-image zero same-g same-b my-picture)] +produces a copy of @racket[my-picture] with all the red leached out, +leaving only the blue and green components. + +@racketblock[ +(define (3x x y r g b) (min (* 3 x) 255)) +(define (3y x y r g b) (min (* 3 y) 255)) +(map3-image 3x zero 3y my-picture)] +produces a picture the same size and shape as @racket[my-picture], +but with a smooth color gradient with red increasing from left to +right and blue increasing from top to bottom.} + +@defproc[(real->int [num real?]) + integer?]{ + +Not specific to colors, but useful if you're building colors by arithmetic. +For example, +@racketblock[ + (define (bad-gradient x y) + (make-color (* 2.5 x) (* 1.6 y) 0)) + (build-image 50 30 bad-gradient) + (define (good-gradient x y) + (make-color (real->int (* 2.5 x)) (real->int (* 1.6 y)) 0)) + (build-image 50 30 good-gradient) + ] +The version using @racket[bad-gradient] crashes because color components must be exact integers. +The version using @racket[good-gradient] works.} + + +@subsection{Transparency} +Some image formats support @italic{transparency}, meaning that part of the image is +ignored when layering it with other images. + +@defproc[(pixel-visible? [x natural-number/c] [y natural-number/c] [pic image?]) + boolean?]{ + +Checks transparency: returns @racket[false] if the specified pixel in the image is transparent, +@racket[true] if not.} + +A @deftech{maybe-color} is either a color or @racket[false], which is treated as transparent. + +@defproc[(maybe-color? [thing any/c]) + boolean?]{ + +Tests whether the argument is a @tech{maybe-color}.} + +@defproc[(map-masked-image [f (-> natural-number/c natural-number/c maybe-color? maybe-color?)] [pic image?]) + image?]{ + +Like @racket[map-image], but the function will receive @racket[false] for any transparent pixel, and +any place that it returns @racket[false] will be treated as a transparent pixel.} + +@defproc[(build-masked-image [width natural-number/c] + [height natural-number/c] + [f (-> natural-number/c natural-number/c maybe-color?)]) + image?]{ + +Like @racket[build-image], but any place that the function returns @racket[false] will be treated +as a transparent pixel.} + +@section{Input and Output} +This teachpack also provides several functions to help in testing +I/O functions (in Advanced Student language; ignore this section if +you're in a Beginner or Intermediate language): + +@defproc[(with-input-from-string [input string?] + [thunk (-> any/c)]) + any/c]{ + +Calls @tt{thunk}, which presumably uses @racket[read], +in such a way that @racket[read] reads from @tt{input} rather than from +the keyboard.} + +@defproc[(with-output-to-string [thunk (-> any/c)]) + string?]{ + +Calls @tt{thunk}, which presumably uses @racket[display], @racket[print], +@racket[write], and/or @racket[printf], in such a way that its output is +accumlated into a string, which is then returned.} + +@defproc[(with-input-from-file [filename string?] + [thunk (-> any/c)]) any/c]{ +Calls @tt{thunk}, which presumably uses @racket[read], +in such a way that @racket[read] reads from the specified file +rather than from the keyboard.} + +@defproc[(with-output-to-file (filename string?) (thunk (-> any/c))) any/c]{ +Calls @tt{thunk}, which presumably uses @racket[display], @racket[print], +@racket[write], and/or @racket[printf], in such a way that its output is +redirected into the specified file.} + +@defproc[(with-input-from-url (url string?) (thunk (-> any/c))) any/c]{ +Calls @tt{thunk}, which presumably uses @racket[read], +in such a way that @racket[read] reads from the HTML source of the +Web page at the specified URL rather than from the keyboard.} + +@defproc[(with-io-strings (input string?) (thunk (-> any/c))) string?]{ +Combines @racket[with-input-from-string] and @racket[with-output-to-string]: +calls @tt{thunk} with its input coming from @tt{input} and accumulates +its output into a string, which is returned. Especially useful for testing: +@racketblock[ + (define (ask question) + (begin (display question) + (read))) + (define (greet) + (local [(define name (ask "What is your name?"))] + (printf "Hello, ~a!" name))) + (check-expect + (with-io-strings "Steve" greet) + "What is your name?Hello, Steve!")] +} + +@; @include-section{worlds.scrbl} + +@; @include-section{universes.scrbl} diff --git a/collects/picturing-programs/dummy.rkt b/collects/picturing-programs/dummy.rkt new file mode 100644 index 0000000000..1f553a05c6 --- /dev/null +++ b/collects/picturing-programs/dummy.rkt @@ -0,0 +1,4 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-beginner-reader.ss" "lang")((modname dummy) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) +(require "main.rkt") \ No newline at end of file diff --git a/collects/picturing-programs/info.rkt b/collects/picturing-programs/info.rkt new file mode 100644 index 0000000000..3d1da14c09 --- /dev/null +++ b/collects/picturing-programs/info.rkt @@ -0,0 +1,24 @@ +#lang setup/infotab + (define name "picturing-programs") + (define categories '(media)) + (define can-be-loaded-with 'all) + (define required-core-version "5.0.0.1") + (define primary-file "main.rkt") + (define scribblings '(("doc.scrbl" ()))) + (define repositories '("4.x")) + (define blurb + `("The picturing-programs collection supersedes the tiles and sb-world collections. It provides functions to rotate, etc. images, as well as a slightly modified version of the universe teachpack.")) + (define release-notes '( +(p "Version 2.5: Re-enabled diagonal reflection. Moved into the bundle +(so it doesn't require a PLaneT install). Added some picture variables.") +(p "Version 2.4: Added change-to-color and map3-image. Cleaned up documentation.") +(p "Version 2.3: Renamed files from .ss to .rkt, so they work better with Racket. Added map-image, build-image, name->color, and friends; re-fixed bug in rotate-cw and rotate-ccw.") +(p "Version 2.2: Fixed bug in rotate-cw and rotate-ccw; restored reflect-vert and reflect-horiz; added with-input-from-url.") +(p "Version 2.1: Added argument type-checking. And reflection primitives are now present but produce error message, rather than being missing.") +(p "Version 2.0: now fully compatible with 2htdp/image and 2htdp/universe. No pinholes; temporarily disabled reflection primitives.") +(p "Version 1.6: fixed same transparency bug for 4.2.4") +(p "Version 1.5: fixed same transparency bug for 4.2.3") +(p "Version 1.4: fixed transparency bug for 4.2.2") +(p "Version 1.3: initial release, for DrScheme 4.2.4") +(p "Version 1.2: initial release, for DrScheme 4.2.3") +(p "Version 1.1: initial release, for DrScheme 4.2.2"))) diff --git a/collects/picturing-programs/io-stuff.rkt b/collects/picturing-programs/io-stuff.rkt new file mode 100644 index 0000000000..f5141e6064 --- /dev/null +++ b/collects/picturing-programs/io-stuff.rkt @@ -0,0 +1,30 @@ +#lang racket +(require racket/port lang/error net/url) +(provide with-input-from-string + with-output-to-string + with-input-from-file + with-output-to-file + with-input-from-url + with-io-strings) + +; with-io-strings : input(string) thunk -> string +(define (with-io-strings input thunk) + (check-arg 'with-io-strings (string? input) "string" "first" input) + (check-arg 'with-io-strings (and (procedure? thunk) + (procedure-arity-includes? thunk 0)) + "0-parameter function" "second" thunk) + (with-output-to-string + (lambda () + (with-input-from-string input thunk)))) + +; with-input-from-url : url(string) thunk -> nothing +(define (with-input-from-url url-string thunk) + (check-arg 'with-input-from-url (string? url-string) "string" "first" url-string) + (check-arg 'with-input-from-url (and (procedure? thunk) + (procedure-arity-includes? thunk 0)) + "0-parameter function" "second" thunk) + (call/input-url (string->url url-string) + get-pure-port + (lambda (port) + (current-input-port port) + (thunk)))) diff --git a/collects/picturing-programs/main.rkt b/collects/picturing-programs/main.rkt new file mode 100644 index 0000000000..6422d398c9 --- /dev/null +++ b/collects/picturing-programs/main.rkt @@ -0,0 +1,20 @@ +#lang racket +(require 2htdp/universe + htdp/error ; check-arg + "tiles.rkt" + "io-stuff.rkt" + "map-image.rkt" + "book-pictures.rkt") +(provide (all-from-out "tiles.rkt") ; includes all-from-out 2htdp/image, plus a few simple add-ons + (all-from-out "io-stuff.rkt") ; includes with-{input-from,output-to}-{string,file}, with-io-strings + (all-from-out "map-image.rkt") ; includes (map,build)-[masked-]image, real->int, maybe-color?, name->color, + ; get-pixel-color, pixel-visible? + (prefix-out pic: (all-from-out "book-pictures.rkt")) ; pic:calendar, pp:hacker, etc. + ) +(provide show-it) +(provide (all-from-out 2htdp/universe)) + + +(define (show-it img) + (check-arg 'show-it (image? img) "image" "first" img) + img) diff --git a/collects/picturing-programs/map-image.rkt b/collects/picturing-programs/map-image.rkt new file mode 100644 index 0000000000..128c854586 --- /dev/null +++ b/collects/picturing-programs/map-image.rkt @@ -0,0 +1,431 @@ +#lang racket/base +; Spring 2010: started trying to get this to work. +; Late June 2010: Got build-image and map-image working. +; Added name->color and get-pixel-color. +; Added build-masked-image and map-masked-image. +; July 6, 2010: added change-to-color +; July 28, 2010: added map3-image and build3-image. Is change-to-color really useful? +; Dec. 26, 2010: added color=? to export (duh!) +; Dec. 26, 2010: API for bitmaps has changed for 5.1, so I need to rewrite to match it. +; Dec. 28, 2010: Robby added alphas into the "color" type, and provided an implementation +; of map-image. He recommends using racket/draw bitmaps rather than 2htdp/image bitmaps. + +(require racket/draw + racket/snip + racket/class + 2htdp/image + (only-in mrlib/image-core render-image)) +(require picturing-programs/book-pictures) + +;(require mrlib/image-core) +;(require 2htdp/private/image-more) +;; (require 2htdp/private/img-err) +;(require scheme/gui) +(require lang/prim) + +(provide-primitives real->int + ; maybe-color? + name->color + get-pixel-color + ;pixel-visible? + ; change-to-color + color=? + ) +(provide-higher-order-primitive map-image (f _)) +(provide-higher-order-primitive map3-image (rfunc gfunc bfunc _)) +(provide-higher-order-primitive map4-image (rfunc gfunc bfunc afunc _)) +;(provide-higher-order-primitive map-masked-image (f _)) +(provide-higher-order-primitive build-image (_ _ f)) +(provide-higher-order-primitive build3-image (_ _ rfunc gfunc bfunc)) +(provide-higher-order-primitive build4-image (_ _ rfunc gfunc bfunc afunc)) +;(provide-higher-order-primitive build-masked-image (_ _ f)) + +(define transparent (make-color 0 0 0 0)) + +(define (maybe-color? thing) + (or (color? thing) + (eqv? thing #f) + ; (image-color? thing) ; handles string & symbol color names + )) + +(define (broad-color? thing) + (or (maybe-color? thing) + (image-color? thing))) + +; color->color% : does the obvious +; Note that color% doesn't have an alpha component, so alpha is lost. +(define (color->color% c) + (if (string? c) + c + (make-object color% + (color-red c) + (color-green c) + (color-blue c)))) + +; color%->color : does the obvious, with alpha defaulting to full-opaque. +(define (color%->color c) + (make-color (send c red) + (send c green) + (send c blue))) + +; name->color : string-or-symbol -> maybe-color +(define (name->color name) + (unless (or (string? name) (symbol? name)) + (error 'name->color "argument must be a string or symbol")) + (let [[result (send the-color-database find-color + (if (string? name) + name + (symbol->string name)))]] + (if result + (color%->color result) + #f))) + +;; lookup-if-nec : maybe-color -> maybe-color +;(define (lookup-if-nec c) +; (cond [(color? c)) c] +; [(or (string? c) (symbol? c)) (name->color c)] +; [(eqv? c #f) transparent] +; [else (error 'lookup-if-nec "Unrecognized type")])) + + +; colorize : broad-color -> color -- returns #f for unrecognized names +(define (colorize thing) + (cond [(color? thing) thing] + [(eqv? thing #f) transparent] + [(image-color? thing) (name->color thing)] + [else (error 'colorize "Unrecognized type")])) + +; colorize-func : (... -> broad-color) -> (... -> color) +(define (colorize-func f) + (compose colorize f)) + + +; natural? : anything -> boolean +(define (natural? it) + (and (integer? it) + (>= it 0))) + +; color=? : broad-color broad-color -> boolean +(define (color=? c1 c2) + (let [[rc1 (colorize c1)] + [rc2 (colorize c2)]] + (unless (and (color? rc1) (color? rc2)) + (error 'color=? "Expected two colors or color names as arguments")) + (and (= (color-alpha rc1) (color-alpha rc2)) ; Both alphas MUST be equal. + (or (= (color-alpha rc1) 0) ; If both are transparent, ignore rgb. + (and (= (color-red rc1) (color-red rc2)) + (= (color-green rc1) (color-green rc2)) + (= (color-blue rc1) (color-blue rc2))))))) + +;; build-image-internal : nat(width) nat(height) (nat nat -> color) bitmap% -> image +;(define (build-image-internal width height f mask-bm) +;; (unless (and (natural? width) (natural? height)) +;; (error 'build-image "Expected natural numbers as first two arguments")) +;; (unless (procedure-arity-includes? f 2) +;; (error 'build-image "Expected function with contract number number -> color as third argument")) +; (let* [[bm (make-bitmap width height)] +; [bmdc (make-object bitmap-dc% bm)] +; ] +; (for* ((y (in-range height)) +; (x (in-range width))) +; (send bmdc set-pixel x y (color->color% (f x y))) +; )) +; (send bmdc set-bitmap #f) +; (make-image +; (make-translate (quotient width 2) (quotient height 2) +; (make-bitmap bm mask-bm 0 1 1 #f #f)) +; (make-bb width height height) +; #f ; not normalized +; ) +; ) + +;; build-image : natural(width) natural(height) (nat nat -> color) -> image +;(define (build-image width height f) +; (unless (and (natural? width) (natural? height)) +; (error 'build-image "Expected natural numbers as first two arguments")) +; (unless (procedure-arity-includes? f 2) +; (error 'build-image "Expected function with contract number number -> color as third argument")) +; (if (or (zero? width) (zero? height)) ; bitmap% doesn't like zero-sized images +; (rectangle width height "solid" "white") +; (let* [[mask-bm (make-object bitmap% width height #t)] ; monochrome +; [mask-bmdc (make-object bitmap-dc% mask-bm)] +; [black (make-object color% 0 0 0)]] +; (send mask-bmdc set-background black) +; (send mask-bmdc clear) +; ; (for ((y (in-range height))) +; ; (for ((x (in-range width))) +; ; (send mask-bmdc set-pixel x y black))) +; ; can we replace this with (send mask-bmdc clear)? +; (send mask-bmdc set-bitmap #f) +; (build-image-internal width height f mask-bm) +; ) +; ) +; ) +; +;; build3-image: nat(width) nat(height) (nat nat -> nat) (nat nat -> nat) (nat nat -> nat) -> image +;(define (build3-image width height rfunc gfunc bfunc) +; (unless (and (natural? width) (natural? height)) +; (error 'build3-image "Expected natural numbers as first two arguments")) +; (unless (procedure-arity-includes? rfunc 2) +; (error 'build3-image "Expected function with contract number number -> number as third argument")) +; (unless (procedure-arity-includes? gfunc 2) +; (error 'build3-image "Expected function with contract number number -> number as fourth argument")) +; (unless (procedure-arity-includes? bfunc 2) +; (error 'build3-image "Expected function with contract number number -> number as fifth argument")) +; (build-image width height +; (lambda (x y) (make-color (rfunc x y) (gfunc x y) (bfunc x y))))) +; +;; build-masked-image : nat(width) nat(height) (nat nat -> maybe-color) -> image +;(define (build-masked-image width height f) +; (unless (and (natural? width) (natural? height)) +; (error 'build-masked-image "Expected natural numbers as first two arguments")) +; (unless (procedure-arity-includes? f 2) +; (error 'build-masked-image "Expected function with contract number number -> maybe-color as third argument")) +; (if (or (zero? width) (zero? height)) ; bitmap% doesn't like zero-sized images +; (rectangle width height "solid" "white") +; (let* [[bm (make-object bitmap% width height)] +; [bmdc (make-object bitmap-dc% bm)] +; [mask-bm (make-object bitmap% width height #t)] ; monochrome +; [mask-bmdc (make-object bitmap-dc% mask-bm)] +; [visible (make-object color% 0 0 0)] +; [transparent (make-object color% 255 255 255)]] +; (for ((y (in-range height))) +; (for ((x (in-range width))) +; (let* [[mc (f x y)] +; [color (if mc (color->color% mc) transparent)] +; [mask (if mc visible transparent)]] +; (send bmdc set-pixel x y color) +; (send mask-bmdc set-pixel x y mask) +; ))) +; (send bmdc set-bitmap #f) +; (send mask-bmdc set-bitmap #f) +; (make-image +; (make-translate (quotient width 2) (quotient height 2) +; (make-bitmap bm mask-bm 0 1 1 #f #f)) +; (make-bb width height height) +; #f ; not normalized +; ) +; ))) + + + + +(define (real->int num) + (inexact->exact (round num))) + + +; get-px : x y w h bytes -> color +(define (get-px x y w h bytes) + (define offset (* 4 (+ x (* y w)))) + (make-color (bytes-ref bytes (+ offset 1)) + (bytes-ref bytes (+ offset 2)) + (bytes-ref bytes (+ offset 3)) + (bytes-ref bytes offset))) + +; set-px! : bytes x y w h color -> void +(define (set-px! bytes x y w h new-color) + (define offset (* 4 (+ x (* y w)))) + (bytes-set! bytes offset (color-alpha new-color)) + (bytes-set! bytes (+ offset 1) (color-red new-color)) + (bytes-set! bytes (+ offset 2) (color-green new-color)) + (bytes-set! bytes (+ offset 3) (color-blue new-color))) + +; get-pixel-color : x y image -> color +; This will remember the last image on which it was called. +; Really terrible performance if you call it in alternation +; on two different images, but should be OK if you call it +; lots of times on the same image. +; Returns transparent if you ask about a position outside the picture. +(define get-pixel-color + (let [[last-image #f] + [last-bytes #f]] + (lambda (x y pic) + (define w (image-width pic)) + (define h (image-height pic)) + (unless (eqv? pic last-image) + ; assuming nobody mutates an image between one get-pixel-color and the next + (set! last-image pic) + (define bm (make-bitmap w h)) + (define bmdc (make-object bitmap-dc% bm)) + (set! last-bytes (make-bytes (* 4 w h))) + (render-image pic bmdc 0 0) + (send bmdc set-bitmap #f) + (send bm get-argb-pixels 0 0 w h last-bytes)) + (if (and (<= 0 x (sub1 w)) + (<= 0 y (sub1 h))) + (get-px x y w h last-bytes) + transparent)))) + +;; pixel-visible? : nat(x) nat(y) image -> boolean +;; similar +;(define pixel-visible? +; (let [[last-image #f] +; [last-bm #f] +; [last-bmdc #f]] +; (lambda (x y pic) +; (unless (eqv? pic last-image) +; (set! last-image pic) +; (set! last-bm (get-mask pic)) +; (set! last-bmdc (make-object bitmap-dc% last-bm))) +; (let [[mask-pix (get-px x y last-bmdc)]] ; assumes this doesn't crash if out of bounds +; (and (equal? mask-pix (make-color 0 0 0)) ; treat anything else as transparent +; (>= x 0) +; (>= y 0) +; (< x (image-width pic)) +; (< y (image-height pic)) +; ))))) +; + +; build-image-internal : natural(width) natural(height) (nat nat -> color) -> image +(define (build-image-internal w h f) + (define bm (make-bitmap w h)) + (define bdc (make-object bitmap-dc% bm)) + (define bytes (make-bytes (* w h 4))) + (for* ((y (in-range 0 h)) + (x (in-range 0 w))) + (set-px! bytes x y w h (f x y))) + (send bm set-argb-pixels 0 0 w h bytes) + (make-object image-snip% bm)) + +; build-image : natural(width) natural(height) (nat nat -> broad-color) -> image +(define (build-image w h f) + (unless (natural? w) + (error 'build-image "Expected natural number as first argument")) + (unless (natural? h) + (error 'build-image "Expected natural number as second argument")) + (unless (procedure-arity-includes? f 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as third argument")) + (build-image-internal w h (colorize-func f))) + +; build3-image : nat(width) nat(height) rfunc gfunc bfunc -> image +; where each of rfunc, gfunc, bfunc is (nat(x) nat(y) -> nat) +(define (build3-image w h rfunc gfunc bfunc) + (unless (natural? w) + (error 'build-image "Expected natural number as first argument")) + (unless (natural? h) + (error 'build-image "Expected natural number as second argument")) + (unless (procedure-arity-includes? rfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as third argument")) + (unless (procedure-arity-includes? gfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as fourth argument")) + (unless (procedure-arity-includes? bfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as fifth argument")) + (build-image-internal w h + (lambda (x y) + (make-color (rfunc x y) (gfunc x y) (bfunc x y))))) + +; build4-image : nat(width) nat(height) rfunc gfunc bfunc afunc -> image +; where each of rfunc, gfunc, bfunc, afunc is (nat(x) nat(y) -> nat) +(define (build4-image w h rfunc gfunc bfunc afunc) + (unless (natural? w) + (error 'build-image "Expected natural number as first argument")) + (unless (natural? h) + (error 'build-image "Expected natural number as second argument")) + (unless (procedure-arity-includes? rfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as third argument")) + (unless (procedure-arity-includes? gfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as fourth argument")) + (unless (procedure-arity-includes? bfunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as fifth argument")) + (unless (procedure-arity-includes? afunc 2) + (error 'build-image "Expected function with contract num(x) num(y) -> color as sixth argument")) + (build-image-internal w h + (lambda (x y) + (make-color (rfunc x y) (gfunc x y) (bfunc x y) (afunc x y))))) + + + +; map-image-internal : (int int color -> color) image -> image +(define (map-image-internal f img) + (define w (image-width img)) + (define h (image-height img)) + (define bm (make-bitmap w h)) + (define bdc (make-object bitmap-dc% bm)) + (render-image img bdc 0 0) + (send bdc set-bitmap #f) + (define bytes (make-bytes (* w h 4))) + (send bm get-argb-pixels 0 0 w h bytes) + (for* ((y (in-range 0 h)) + (x (in-range 0 w))) + (set-px! bytes x y w h (f x y (get-px x y w h bytes)))) + (send bm set-argb-pixels 0 0 w h bytes) + (make-object image-snip% bm)) + +; map-image : (int int color -> broad-color) image -> image +(define (map-image f img) + (unless (procedure-arity-includes? f 3) + (error 'map-image "Expected function with contract num(x) num(y) color -> color as first argument")) + (unless (image? img) + (error 'map-image "Expected image as second argument")) + (map-image-internal (colorize-func f) img)) + +; The version for use before students have seen structs: +; map3-image : +; (int(x) int(y) int(r) int(g) int(b) -> int(r)) +; (int(x) int(y) int(r) int(g) int(b) -> int(g)) +; (int(x) int(y) int(r) int(g) int(b) -> int(b)) +; image -> image +; Note: by default, preserves alpha values from old image. +(define (map3-image rfunc gfunc bfunc pic) + (unless (procedure-arity-includes? rfunc 5) + (error 'map3-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) -> num(r) as first argument")) + (unless (procedure-arity-includes? gfunc 5) + (error 'map3-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) -> num(g) as second argument")) + (unless (procedure-arity-includes? bfunc 5) + (error 'map3-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) -> num(b) as third argument")) + (unless (image? pic) + (error 'map3-image "Expected image as fourth argument")) + (map-image-internal + (lambda (x y c) + (make-color (rfunc x y (color-red c) (color-green c) (color-blue c)) + (gfunc x y (color-red c) (color-green c) (color-blue c)) + (bfunc x y (color-red c) (color-green c) (color-blue c)) + (color-alpha c))) + pic)) + +; map4-image : +; (int(x) int(y) int(r) int(g) int(b) int(a) -> int(r)) +; (int(x) int(y) int(r) int(g) int(b) int(a) -> int(g)) +; (int(x) int(y) int(r) int(g) int(b) int(a) -> int(b)) +; (int(x) int(y) int(r) int(g) int(b) int(a) -> int(a)) +; image -> image +(define (map4-image rfunc gfunc bfunc afunc pic) + (unless (procedure-arity-includes? rfunc 6) + (error 'map4-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) num(alpha) -> num(r) as first argument")) + (unless (procedure-arity-includes? gfunc 6) + (error 'map4-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) num(alpha) -> num(g) as second argument")) + (unless (procedure-arity-includes? rfunc 6) + (error 'map4-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) num(alpha) -> num(b) as third argument")) + (unless (procedure-arity-includes? gfunc 6) + (error 'map4-image "Expected function with contract num(x) num(y) num(r) num(g) num(b) num(alpha) -> num(alpha) as fourth argument")) + (unless (image? pic) + (error 'map4-image "Expected image as fifth argument")) + (map-image-internal + (lambda (x y c) + (make-color (rfunc x y (color-red c) (color-green c) (color-blue c) (color-alpha c)) + (gfunc x y (color-red c) (color-green c) (color-blue c) (color-alpha c)) + (bfunc x y (color-red c) (color-green c) (color-blue c) (color-alpha c)) + (afunc x y (color-red c) (color-green c) (color-blue c) (color-alpha c)))) + pic)) + + +;; map-masked-image : (int int maybe-color -> maybe-color) image -> image +;(define (map-masked-image f pic) +; (unless (procedure-arity-includes? f 3) +; (error 'map-masked-image "Expected function with contract number number maybe-color -> maybe-color as first argument")) +; (unless (image? pic) +; (error 'map-masked-image "Expected image as second argument")) +; (let* [[width (image-width pic)] +; [height (image-height pic)] +; [bm (make-object bitmap% width height)] +; [bmdc (make-object bitmap-dc% bm)] +; [mask (get-mask pic)] +; ] +; (render-image pic bmdc 0 0) +; (build-masked-image +; width height +; (lambda (x y) +; (f x y +; (if (pixel-visible? x y pic) +; (get-pixel-color x y pic) +; #f)))))) diff --git a/collects/picturing-programs/pictures/bloch.jpg b/collects/picturing-programs/pictures/bloch.jpg new file mode 100644 index 0000000000000000000000000000000000000000..938bebf7c1cb4688a5dfb4e5554ee74a5d266c5a GIT binary patch literal 10927 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 literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/calendar.png b/collects/picturing-programs/pictures/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..c4b586345dbc08233e60e60caa3f72a9e9cdb918 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^ia;#S!3HEVr!3h7q*&4&eH|GXZnE6jbc+edS4j2< z@?~JCQe$9fXklRZ1r%y{!N5>zz`*b-fq}tl1_Oh5!JJ)zHb4o^0*}aI1_o|n5N2eU zHAey{c+%6wF(l&f+v&Yr4GKIhwI%ayels4tW>)@c&5B0BOK)z!HQ{>6DA?!Cp~u|r zar(x_wUWtu;yERh+-Ke>{$JOT*!TbT$L)`U-+r(stQHDmFjo~|5M5*%z#zEjdpkR0g5s9F fecP6DCzY+SeSctyMj@*-&{GVau6{1-oD!M<%D#4K literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/mad_hacker.png b/collects/picturing-programs/pictures/mad_hacker.png new file mode 100644 index 0000000000000000000000000000000000000000..bca2e7670ed7390141fd82170ffd338342cc8e32 GIT binary patch literal 2475 zcmd5;`#%#3AKu)SJ7caR%M@W8wuR)lY}kfom}_h^_q*o0wHOC;d1-A4;mkxsDN;wB zB)XkflsZDnB}Eina0;2@{V(3<^Ld`<*XM`t_xU_rqK}8Nf}R2Z08qwxVn};#{Xg!L z-c!nJ`5pj3YMtoikKNtf)ix*jyW17U5IacjT|4uU6l!l6IVwFjoE9c0CEr|3!`RzU z(FTo;jc}N8Lu13AZzh`>&Lcg%%geZkfcoSN)^mwKW1no_#&qxRCkp~e0)c>@$U1cl zl}f>dhJ`^On!mzyAu0;jqo^%p_jk;K5J&3+dU|gDL3n3m$+a8#7#lbQ>`lO!qA*7> zL@Q^ElbK;_ON$3Nv#CjFprK+D+IGZP8-+xh;<(AdZUZ7Fj}=){lK*S$RkU|X2+7;l znc(M3gqV2R`S=}Fms2yeKi_*>$jf%X5%8&P3d&$gjGdPoDkPKrwTP!GEA2^(bF{ZN zG_!cc$fgI*=gGFj{J6jvB41Ws z1#^hk2LXd~3u>yXB`>RyjxOcglQVbDk_Z?yfyhn{I&NcRpe#p^jixdSYszzePBxuA z%U9FXla-bVNXw4Q=YBX{LM8_Z8boLt8|y&P;_MZ5^%xZ$tJ9IBGmnRH;h9NzTd2BX zLPFeNBt=bCgAf=JRbJQD*5*nKJ)#aoTB9$nzT^=sbaY{?Y?>!MMpg>QJjF4^REGqH zHcBKUsEi#HTvAe^q@)Nl(6zQS4@La~wV@RA8eR%H0S+)DB$LkMm|NRAK$M3Q6JPdur6gxYr8A<^Q71fC0RY)99LB{z`vQNAX~z$Sg1&?`g+;$a zlfY#pzsaPM@rz1FL-B~nOZ=sS-k<*z_9R~xUOzC}z)NZuWFmRE=K8Q#$jeQIH^OM} zbKLXzUT?(q(*|u(+!x2G?=`&SJl)(Gsj;=~kBKgNoi+4ST03ELx4g(J(>`q= zD*0YX6r$w3q35PoDaf|0;H~_|1OjdkdFAe<>iT%w*i3hA=V8}$afhRS^6QW9P|8)j z_Gd1P5!l_DwZ+z!2KF2Yx=x)cF3h>#x#pS30toLeX`~(iWAFIliyEif19Mxq?ZR#@ z^JU7AAB*oa9}iD4lO7+n;B!c;bF+f*ctPk25gXzfLMYR!$Yivch=o~cd0WGO-_B^S zTsqh5zCB8e#$FpH|MNHMlJHFG52NMk(!~d#GW~YHEj~mqwYbQ>$a`j?@?cPZEMHV@ zHO@@?qh80rKXE#gAf313T&uL;p6+O>^!eFFYuwf`&PH1IguBbj)s-+Svr8TK4qrZa zQ*duRi21xuq%kh4jGHb|{GizRbqx6p4-!aICx#Ky*#17YQCE*(U^Mtj<$;0BDBgB;nbbMU3Uco@ZI=AvFFPX>JR8BxDe!!FL4_vbJs!B#QT)eMce{S zcZeR?=?kbJEh|%)5xO?DaJ8?-A%6$L=~p+G{hfRWx3x3t5*XN7t1zB>vrlrfzMhf0 zSTJ;~I>qp&_+jn=O_wnsx4AD|#MX_D`0UqfTIY0TByy`y>eInc6_)NZcQ@aKdR$t|*uS@4($7!3P6815JF~ra_2c^Y8^39)Z;?p%<*y|Cu#n-7 zVy91iB83KTO>ixz7IS`}Y#J&yEqr}^I!I1G8?3rM_E~|FD}kx&H!M@HyQ!Vw8Mqo` z{qjY`A9T%5-+p!@1v=}8gArdXZH@07(*OFkgLNPAPc2w6*dCHy-kBsoAey-2Pv#Z|-+Qx8kxr+2%&q>gX}Ja~>j!RpNZk;$2{&V$+n`OT`Ybb+zhqdOM-;j#W3)pG{v;e6l_Zeef;;+gZ<@X-w-@*=bR>nO~lwK~69B@R;;rB6XEKsKuPCz?Jf2J|XrRp-6leW-o5*as*%F4>!1ySvhW$aic4h^I2USMdNG)(3ONmBRTKx_+OK literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/qbook.png b/collects/picturing-programs/pictures/qbook.png new file mode 100644 index 0000000000000000000000000000000000000000..93e674c849dba1632d0a53d2b76f6716f00736d7 GIT binary patch literal 748 zcmeAS@N?(olHy`uVBq!ia0vp^&Oofr!VDyrHNM~hQjEnx?oJHr&dIz4ats1|LR|m< z|IYw|3>yp*_V3@ndGqG~{~ui1(gT#o3f`0y90E$jl(zh6_@Cx6;UX-=A--ypgoEpdxG=RO3D+9QW@Nf5(_dilb!SP%2JC;Qi~Kc zJo8FYb2Q7_e@Oy8ch%FyF{ENn&y>A=%?1K3f}*;yr%s60&O5q?aoX$bJ*u50-|W7f zUBlaGt#nsR@ZkLPw7<^R=XwP`H^2L#TOx3^ZLI^F(Bod0xb=dKU|AldwC z^5F@bD}IOv@?La1_*9@K!rvoiH{<&9C%1q9Y~hi5Ag8tIj7y&%@5)k>sAoIm1Pl+H zzZj*ssY3pcwB(O@Esark-+b(yGRgMyLhc!XDa$U3v2}QzOq{;5(x!Ko@Wh}kLOueL z+h!i)owb!ocN(MvjamdQk4 z51f2uN38xNpET*Dyf+!1Gk)%pHu7Y;(jlXi(X;%>{4N8YY5K)Q7oyc#9Ssj%ZN4e) ztNOH7eCpa2PHZmDJJ>xX1l$wPOib^7dZ(^`gAu1R>(lhTZZpnV#h9{BR1#aD_^!Zp zw-lS-BG0#rY~}d({&$p_+a*@{@-6G5tAE|zIB?u@U|;P#={Kv66}hyoqOH zx%McgJW%?QzrwrlBfoz?+Gi(_zhu9OrQ-b8_9ys((f|KHGs90#71qU#imO1$(bLt> JWt~$(698P_F~$G@ literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/schemelogo.png b/collects/picturing-programs/pictures/schemelogo.png new file mode 100644 index 0000000000000000000000000000000000000000..1374f7fbd386974684ed2f2ad312c9ddabee34db GIT binary patch literal 4107 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 JPDHLkV1mm2&9VRh literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/small_hieroglyphics.png b/collects/picturing-programs/pictures/small_hieroglyphics.png new file mode 100644 index 0000000000000000000000000000000000000000..634a11fdbf4852ae1aedd19ec54940b3b0a62061 GIT binary patch literal 1474 zcmV;z1wHzSP)P)t-s|NsB~ zp+)}w{`;Oo{;Wy#NI)kP%!50fWHEkFDg2o>Tsk2m6%4(3HrJ9){hs%g)la?!l0Me1cSU$~Iv_JJ zGc_zAG&M9d4OeMyWN&v*a%VaqFf1T24MT5kbY*UIIv_1EEFd^IEFdyDGBqq9G&D3d z4M}HiZ*pa1AWv{(Z)9b2It?T-Ff~hkhmZgO02y>eSaefwW^{L9a%BKVa$#_2X=6ig zZgypIbY*fiT}bW#00g2*L_t(|oUB&SZsa%&tC0uGvTIqHn{EF8OOKSDOxkU+d%y)~ zXC`52iK1k`z5OrOV?Un9{+H0S)r9N#3-B?axa#xq2kd@A<9hxV@Xv58`uOMg0{$j; z;*QN^OYXivcB1P(5%c;uw#~L}OQ}C^#BzPB&zF*ir#8H&(t0ici~_V3ELDVPWva@QByB_^WUFclVgMBA zs%}zn2S6r52B3}T8iCF9bSM~sv#!RJdlu0)bBRdo9`|Sn(!s47-25_g77sLoN|xJ; zJLTRLk+4pFR;#D_SlnQX;L6Aa0FiD!G=y_ElO#|m&@n`e=*^%k)95lIUz8i z>QZ=VfkGohiOPEy!kV`hcpyX#>GDFF=G5#$hZ#nO7+BIrh6Qp2;t@{~pf`xJhoBl} zZ6c@-f+(QH+D=6}&{zp1kFYncceA5%eEFr;y`yO zWzw*eC|082`&D0X4~W2mD8gx@m^jn|^PsgT_?|@P1yA86Pa`sef(mZQpv4Or_kezQ zbQb@6LqXxttl|Tah#SlY%7!7=J0#^`U4P z(0dvNA0?_&IaZKe0w1DHAShukIFfpwJyp#?lxW$l&Lmp|hjU{cpnJi1O| zx1etdn{rJE^!%(>E!MalE9Xc#xf{E)ZH%M_H_+iJb#Qd<69ZG#LK6%gT2aW&S@ocS z@T6!49il+RxxnN`g$vWTCd6|!_6SW-D-1)(Z%XCKY^>4B^4jPfm;e9( literal 0 HcmV?d00001 diff --git a/collects/picturing-programs/pictures/stick-figure.png b/collects/picturing-programs/pictures/stick-figure.png new file mode 100644 index 0000000000000000000000000000000000000000..5cce89c381fba89eee767614a6fba3e7b7e8a33c GIT binary patch literal 2920 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 Sr{pmJ0000= 0) && RegExp.$1; + +var page_args = + ((function(){ + if (!page_query_string) return []; + var args = page_query_string.split(/[&;]/); + for (var i=0; i= 0) args[i] = [a.substring(0,p), a.substring(p+1)]; + else args[i] = [a, false]; + } + return args; + })()); + +function GetPageArg(key, def) { + for (var i=0; i= 0 && cur.substring(0,eql) == key) + return unescape(cur.substring(eql+1)); + } + return def; +} + +function SetCookie(key, val) { + var d = new Date(); + d.setTime(d.getTime()+(365*24*60*60*1000)); + try { + document.cookie = + key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/"; + } catch (e) {} +} + +// note that this always stores a directory name, ending with a "/" +function SetPLTRoot(ver, relative) { + var root = location.protocol + "//" + location.host + + NormalizePath(location.pathname.replace(/[^\/]*$/, relative)); + SetCookie("PLT_Root."+ver, root); +} + +// adding index.html works because of the above +function GotoPLTRoot(ver, relative) { + var u = GetCookie("PLT_Root."+ver, null); + if (u == null) return true; // no cookie: use plain up link + // the relative path is optional, default goes to the toplevel start page + if (!relative) relative = "index.html"; + location = u + relative; + return false; +} + +// Utilities ------------------------------------------------------------------ + +normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/]; +function NormalizePath(path) { + var tmp, i; + for (i = 0; i < normalize_rxs.length; i++) + while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp; + return path; +} + +// `noscript' is problematic in some browsers (always renders as a +// block), use this hack instead (does not always work!) +// document.write(""); + +// Interactions --------------------------------------------------------------- + +function DoSearchKey(event, field, ver, top_path) { + var val = field.value; + if (event && event.keyCode == 13) { + var u = GetCookie("PLT_Root."+ver, null); + if (u == null) u = top_path; // default: go to the top path + u += "search/index.html?q=" + escape(val); + if (page_query_string) u += "&" + page_query_string; + location = u; + return false; + } + return true; +} + +function TocviewToggle(glyph, id) { + var s = document.getElementById(id).style; + var expand = s.display == "none"; + s.display = expand ? "block" : "none"; + glyph.innerHTML = expand ? "▼" : "►"; +} + +// Page Init ------------------------------------------------------------------ + +// Note: could make a function that inspects and uses window.onload to chain to +// a previous one, but this file needs to be required first anyway, since it +// contains utilities for all other files. +var on_load_funcs = []; +function AddOnLoad(fun) { on_load_funcs.push(fun); } +window.onload = function() { + for (var i=0; i + .techinside doesn't work with IE, so use both (and IE doesn't + work with inherit in the second one, so use blue directly) */ +.techinside { color: black; } +.techinside:hover { color: blue; } +.techoutside:hover>.techinside { color: inherit; } + +.SCentered { + text-align: center; +} + +.imageleft { + float: left; + margin-right: 0.3em; +} + +.Smaller{ + font-size: 82%; +} + +.Larger{ + font-size: 122%; +} + +/* A hack, inserted to break some Scheme ids: */ +.mywbr { + width: 0; + font-size: 1px; +} + +.compact li p { + margin: 0em; + padding: 0em; +} + +.noborder img { + border: 0; +} + +.SAuthorListBox { + position: relative; + float: right; + left: 2em; + top: -2.5em; + height: 0em; + width: 13em; + margin: 0em -13em 0em 0em; +} +.SAuthorList { + font-size: 82%; +} +.SAuthorList:before { + content: "by "; +} +.author { + display: inline; + white-space: nowrap; +} diff --git a/collects/picturing-programs/tests/README b/collects/picturing-programs/tests/README new file mode 100644 index 0000000000..186b0113a4 --- /dev/null +++ b/collects/picturing-programs/tests/README @@ -0,0 +1,11 @@ + +to test: $ ./xrun +to add a player: $ ./player Foo + +shared.ss : player infrastructure +carl.ss : one specific player derived from shared.ss +sam.ss : another one + -- add more with player plus string + +balls.ss : the server + diff --git a/collects/picturing-programs/tests/bad-draw.ss b/collects/picturing-programs/tests/bad-draw.ss new file mode 100644 index 0000000000..6a9edb64b6 --- /dev/null +++ b/collects/picturing-programs/tests/bad-draw.ss @@ -0,0 +1,12 @@ +#lang scheme + +(require picturing-programs) + +(define s "") +(define x 0) + +(with-handlers ((exn? void)) + (big-bang 0 + (on-tick (lambda (w) (begin (set! x (+ x 1)) w))) + (on-draw (lambda (w) (set! s (number->string w)))))) + diff --git a/collects/picturing-programs/tests/balls.ss b/collects/picturing-programs/tests/balls.ss new file mode 100644 index 0000000000..ea26770659 --- /dev/null +++ b/collects/picturing-programs/tests/balls.ss @@ -0,0 +1,87 @@ +#lang scheme + +(require picturing-programs htdp/testing) + +;; rotate through a bunch of players with the ball until nobody is left + +;; ----------------------------------------------------------------------------- +;; Universe = [Listof IWorld] +;; BallMail = (make-mail IWorld 'go) +;; Result = (make-bundle [Listof IWorld] [Listof BallMail] '()) + +(define Result0 (make-bundle '() '() '())) + +;; ----------------------------------------------------------------------------- +;; [Listof IWorld] -> Result +;; create bundle with a singleton list of mails to the first world on the list +(define (mail2 lw) + (make-bundle lw (list (make-mail (first lw) 'go)) '())) + +;; ----------------------------------------------------------------------------- +;; Universe IWorld -> Result +;; add w to the list of worlds; get the first one to play + +(check-expect (add-world '() iworld1) (mail2 (list iworld1))) + +(define (add-world univ wrld) + (mail2 (append univ (list wrld)))) + +;; ----------------------------------------------------------------------------- +;; Universe IWorld Sexp -> Result +;; w sent message m in universe u + +(check-expect + (switch (list iworld1 iworld2) iworld1 'go) (mail2 (list iworld2 iworld1))) + +(check-error + (switch (list iworld1 iworld2) iworld2 'go) "switch: wrong world sent message") + +(check-error + (switch (list iworld2 iworld1) iworld2 'stop) "switch: bad message: stop") + +(define (switch u w m) + (local ((define fst (first u)) + (define nxt (append (rest u) (list fst)))) + (cond + [(and (iworld=? fst w) (symbol=? m 'go)) (mail2 nxt)] + [(iworld=? fst w) (error 'switch "bad message: ~s" m)] + [else (error 'switch "wrong world sent message")]))) + +;; ----------------------------------------------------------------------------- +;; [Listof IWorld] Universe IWorld -> Result +;; w disconnected from the universe + +(check-expect (disconnect (list iworld1 iworld2 iworld3) iworld2) + (mail2 (list iworld1 iworld3))) +(check-expect (disconnect '() iworld2) Result0) + +(define (disconnect u w) + (local ((define nxt (remq w u))) + (if (empty? nxt) Result0 (mail2 nxt)))) + +;; IWorld [Listof IWorld] -> [Listof IWorld] +;; remove w from low + +(check-expect (remq 'a '(a b c)) '(b c)) +(check-expect (remq 'a '(a b a c)) '(b c)) +(check-expect (remq 'b '(a b a c)) '(a a c)) + +(define (remq w low) + (cond + [(empty? low) '()] + [else (local ((define fst (first low)) + (define rst (remq w (rest low)))) + (if (eq? fst w) rst (cons fst rst)))])) + +;; -- run program run + +(test) + +(define (run _) + (universe '() + (on-new add-world) + (check-with list?) + (on-msg switch) + (on-disconnect disconnect))) + +(run 'go) diff --git a/collects/picturing-programs/tests/design.txt b/collects/picturing-programs/tests/design.txt new file mode 100644 index 0000000000..b163e5fb71 --- /dev/null +++ b/collects/picturing-programs/tests/design.txt @@ -0,0 +1,34 @@ + + Two collaboration worlds display a moving ball, one of them should rest. + +Pass Through (Distributed) Version +---------------------------------- + + Two screens pop up and a ball moves from the bottom to the top, on each of + them. When one reaches the top, it rests and sends a signal to the other + to 'go. This means only one of the worlds will have a moving ball, the + other one rests. + + use ../pass-through.ss + + World and Messages: + ;; World = Number | 'resting + ;; Message = 'go + +Arbitrated Version +---------------------------------- + + Two screen pop up. The server sends one of them a go signal and the other + one a rest signal. Until then both move so I can use the same shared + code. + + use ball-universe.ss + + World and Messages: + ;; World = Number | 'resting + ;; ReceivedMessage = 'go + ;; SendMessages = ... any token will do ... + + Server: + ;; ReceivedMessages = ... any token will do ... + ;; SendMessages = 'go diff --git a/collects/picturing-programs/tests/full-scene-visible.ss b/collects/picturing-programs/tests/full-scene-visible.ss new file mode 100644 index 0000000000..b8bf9dc167 --- /dev/null +++ b/collects/picturing-programs/tests/full-scene-visible.ss @@ -0,0 +1,15 @@ +#lang scheme/base + +(require picturing-programs + (prefix-in 2: 2htdp/image) + (prefix-in 1: htdp/image)) + +(define (see-full-rectangle x f) + (big-bang x + (on-tick sub1) + (stop-when zero?) + (on-draw (λ (x) (f 100 100 'outline 'black))))) + +(see-full-rectangle 3 2:rectangle) + +(see-full-rectangle 3 1:rectangle) diff --git a/collects/picturing-programs/tests/image-equality-performance.ss b/collects/picturing-programs/tests/image-equality-performance.ss new file mode 100644 index 0000000000..f398705024 --- /dev/null +++ b/collects/picturing-programs/tests/image-equality-performance.ss @@ -0,0 +1,908 @@ +#lang scheme + +#| + +This is a file from Guillaume that ran very slowly with the +htdp/image library; here it is used as a performance test. +Porting to #lang scheme +2htdp/image consisted of adding requires, +changing overlay/xy to underlay/xy, defining empty-scene, and +adding the check-expect macro (and related code). +Also added the timing code at the end. + +|# + + +(require picturing-programs + (only-in mrlib/image-core + skip-image-equality-fast-path)) + +(define-syntax (check-expect stx) + (syntax-case stx () + [(_ a b) + (with-syntax ([line (syntax-line stx)]) + #'(set! tests (cons (list (λ () a) (λ () b) line) + tests)))])) +(define tests '()) +(define (run-tests) + (for-each + (λ (l) + (let ([a-res ((list-ref l 0))] + [b-res ((list-ref l 1))] + [line (list-ref l 2)]) + (unless (equal? a-res b-res) + (error 'test "test failed; expected ~s and ~s to be equal, but they weren't, line ~a" + a-res + b-res + line)))) + tests)) + +(define (empty-scene w h) + (overlay + (rectangle w h 'solid 'white) + (rectangle w h 'outline 'black))) + +;;Program for creating game of croos-circle game +;;contract :image->image + +;;defining a union square +;;A square is either +;;A square is blank +;;A square is cross +;;A square is Circle + +;;defining width of square +(define square-width 150) + +;;defining th height and width of scene +(define width (* square-width 3)) +(define height (* square-width 3)) + + +;;defining the image circle +(define Circle (underlay/xy (circle 20 'solid 'orange) 0 0 (circle 10 'solid 'white))) +;;defining the image cross +(define cross (underlay/xy (rectangle 10 30 'solid 'green) 0 0 (rectangle 30 10 'solid 'green))) +;;defining the blank image +(define blank (underlay/xy (rectangle square-width square-width 'solid 'red) 0 0 + (rectangle (- square-width 8) (- square-width 8) 'solid 'white))) + +;;Given a square returns +;;the image of square +;;draw-square :square ->image +(define (draw-square square) + (cond[(equal? 'Circle square)(underlay/xy blank 0 0 Circle)] + [(equal? 'cross square)(underlay/xy blank 0 0 cross)] + [(equal? 'blank square)blank] + )) + + +;;test +(check-expect(draw-square 'Circle)(underlay/xy blank 0 0 Circle)) +(check-expect(draw-square 'cross)(underlay/xy blank 0 0 cross)) +(check-expect(draw-square 'blank)blank) + +;;== Cross and circles, part #3 == + + +;;define a structure for ROW +;;ROW structure used for creating a ROW in the board +;;contract ROW:image image image->image +(define-struct ROW (left middle right) #:transparent) + + +;; defining a blank row + +(define blank-ROW (make-ROW 'blank 'blank 'blank)) +;;defining the cross row +(define cross-ROW (make-ROW 'blank 'cross 'blank)) + +;;defineing the cross-row-blank secoend combination +(define cross-ROW-blank (make-ROW 'cross 'cross 'blank )) +;;defining a row cross-row +(define cross-row (make-ROW 'cross 'cross 'cross )) +;;defining a row blank-circle +(define blank-circle (make-ROW 'Circle 'blank 'blank)) +;;defining a row cross-circle +(define cross-circle (make-ROW 'cross 'cross 'Circle )) +;;defining a row circle-cross +(define circle-cross (make-ROW 'cross 'Circle 'Circle )) +;;defining a row cross-blank +(define cross-blank (make-ROW 'cross 'blank 'blank )) +;;function for creating ROW with the square +;;contract:square square square->ROW +;template: for draw-row +;template for ROW +;(define (a-row-function a-row) +; ... (row-left a-row) ;; is a square +; ... (row-mid a-row) ;; is a square +; ... (row-right a-row)) ;; is a square + + + +(define (draw-row row) + (underlay/xy (draw-square(ROW-left row)) (image-width blank) 0 + (underlay/xy (draw-square(ROW-middle row)) (image-width blank) 0 (draw-square(ROW-right row)) ))) + +;;test + +(check-expect (draw-row (make-ROW 'Circle 'cross 'blank)) + (underlay/xy (draw-square 'Circle) (image-width blank) 0 + (underlay/xy (draw-square 'cross ) (image-width blank) 0 (draw-square 'blank) ))) + +(check-expect (draw-row (make-ROW 'Circle 'cross 'blank)) + (underlay/xy (draw-square 'Circle) (image-width blank) 0 + (underlay/xy (draw-square 'cross ) (image-width blank) 0 (draw-square 'blank) ))) + +(check-expect (draw-row (make-ROW 'Circle 'blank 'cross)) + (underlay/xy (draw-square 'Circle) (image-width blank) 0 + (underlay/xy (draw-square 'blank ) (image-width blank) 0 (draw-square 'cross) ))) + +(check-expect (draw-row cross-ROW-blank) + (underlay/xy (draw-square 'cross) (image-width blank) 0 + (underlay/xy (draw-square 'cross ) (image-width blank) 0 (draw-square 'blank) ))) + +(check-expect (draw-row cross-row ) + (underlay/xy (draw-square 'cross) (image-width blank) 0 + (underlay/xy (draw-square 'cross ) (image-width blank) 0 (draw-square 'cross) ))) + +;;define a structure for BOARD +;;contract make-BOARD :image image image->image +(define-struct BOARD (top-row center-row bottom-row) #:transparent) + +;; purpose : defining an empty board +(define empty-board (make-BOARD blank-ROW + blank-ROW + blank-ROW)) + +;;function for creating board with the row + +;template: for draw-board +;(define (a-board-function a-row) +; ... (top-row a-row) ;; is a square +; ... (center-row a-row) ;; is a square +; ... (bottom-row a-row)) ;; is a square + +;;defining the background +(define background (empty-scene width height)) + + +;;this function will reusing the fuction draw-row for creating row +;;contract:row row row->board + +;;test +(check-expect (draw-board (make-BOARD cross-ROW-blank + cross-ROW + cross-row )) + (underlay/xy (draw-row cross-ROW-blank) + 0 (image-height (draw-row cross-ROW)) + (underlay/xy (draw-row cross-ROW) + 0 (image-height (draw-row cross-ROW)) + (draw-row cross-row )))) + +(check-expect (draw-board (make-BOARD cross-circle + (make-ROW 'Circle 'cross 'blank) + circle-cross)) + (underlay/xy (draw-row cross-circle) + 0 (image-height (draw-row cross-circle)) + (underlay/xy (draw-row (make-ROW 'Circle 'cross 'blank)) + 0 (image-height (draw-row(make-ROW 'Circle 'cross 'blank))) + (draw-row circle-cross)))) + +(check-expect(draw-board (make-BOARD cross-circle + (make-ROW 'Circle 'cross 'Circle) + circle-cross)) + (underlay/xy (draw-row cross-circle) + 0 (image-height (draw-row cross-circle)) + (underlay/xy (draw-row (make-ROW 'Circle 'cross 'Circle)) + 0 (image-height (draw-row (make-ROW 'Circle 'cross 'Circle))) + (draw-row circle-cross)))) + +(check-expect (draw-board (make-BOARD (make-ROW 'blank 'cross 'Circle) + (make-ROW 'Circle 'cross 'cross) + circle-cross)) + (underlay/xy (draw-row (make-ROW 'blank 'cross 'Circle)) + 0 (image-height (draw-row (make-ROW 'blank 'cross 'Circle))) + (underlay/xy (draw-row (make-ROW 'Circle 'cross 'cross)) + 0 (image-height (draw-row (make-ROW 'Circle 'cross 'cross))) + (draw-row circle-cross))) ) + +(check-expect (draw-board (make-BOARD (make-ROW 'blank 'cross 'Circle) + (make-ROW 'Circle 'blank 'cross) + (make-ROW 'cross 'blank 'Circle))) + (underlay/xy (draw-row (make-ROW 'blank 'cross 'Circle)) + 0 (image-height (draw-row (make-ROW 'blank 'cross 'Circle))) + (underlay/xy (draw-row (make-ROW 'Circle 'blank 'cross)) + 0 (image-height (draw-row (make-ROW 'Circle 'blank 'cross))) + (draw-row (make-ROW 'cross 'blank 'Circle))))) + + + + +(define (draw-board board) + (underlay/xy (draw-row (BOARD-top-row board)) + 0 (image-height (draw-row (BOARD-top-row board))) + (underlay/xy (draw-row (BOARD-center-row board)) + 0 (image-height (draw-row(BOARD-center-row board))) + (draw-row (BOARD-bottom-row board))))) + +;;purpose: given the x coordinate of the mouse click and returns +;;the symbol 'L, the symbol 'M, or the symbol 'R, +;;depending on whether that X position falls on the right, the middle or the left of the board. +;;contract: which-column:: number -> symbol + +;;test + +(check-expect (which-column (* square-width .5)) 'L) +(check-expect (which-column (* square-width 1.5)) 'M) +(check-expect (which-column (* square-width 2.3)) 'R) + +(define (which-column x-pos) + (cond[(and (>= x-pos 0)(<= x-pos square-width))'L] + [(and (>= x-pos (+ square-width 1))(<= x-pos (* 2 square-width)))'M] + [(and (>= x-pos (+ (* 2 square-width) 1))(<= x-pos (* 3 square-width)))'R] + [else "play in the board,you played outside the square"])) + + + +;;purpose: given the y coordinate of the mouse click and returns +;;the symbol 'T, the symbol 'C, or the symbol 'B, +;;depending on whether that Y position falls on the top, the center or the bottom of the board. +;;contract: which-row:: number -> symbol + +;;test + +(check-expect (which-row (* square-width .6)) 'T) +(check-expect (which-row (* square-width 1.3)) 'C) +(check-expect (which-row (* square-width 2.7)) 'B) + +(define (which-row y-pos) + (cond[(and (>= y-pos 0)(<= y-pos square-width))'T] + [(and (>= y-pos (+ square-width 1))(<= y-pos (* 2 square-width)))'C] + [(and (>= y-pos (+ (* 2 square-width) 1))(<= y-pos (* 3 square-width)))'B] + [else "play in the board,you played outside the square"])) + + + +;;purpose: give the row and the square to be played and returns a new row replacing the left square +;; play-on-left : row square ->row + +;;test +(check-expect (play-on-left (make-ROW 'blank 'cross 'Circle) 'Circle) + (make-ROW 'Circle 'cross 'Circle)) + +(check-expect (play-on-left (make-ROW 'blank 'cross 'Circle) 'cross) + cross-circle) + +(check-expect (play-on-left cross-ROW 'Circle) + (make-ROW 'Circle 'cross 'blank)) +(define (play-on-left row play) + (make-ROW play (ROW-middle row) (ROW-right row))) + + +;;purpose: give the row and the square to be played and returns a new row replacing the middle square +;; play-on-middle : row square ->row + +;;test +(check-expect (play-on-middle (make-ROW 'blank 'blank 'Circle) 'Circle) + (make-ROW 'blank 'Circle 'Circle)) + +(check-expect (play-on-middle (make-ROW 'blank 'blank 'Circle) 'cross) + (make-ROW 'blank 'cross 'Circle)) + +(check-expect (play-on-middle blank-ROW 'Circle) + (make-ROW 'blank 'Circle 'blank)) + +(define (play-on-middle row play) + (make-ROW (ROW-left row) play (ROW-right row))) + + +;;purpose: give the row and the square to be played and returns a new row replacing the right square +;; play-on-right : row square ->row + +;;test +(check-expect (play-on-right blank-ROW 'Circle) + (make-ROW 'blank 'blank 'Circle)) + +(check-expect (play-on-right (make-ROW 'blank 'Circle 'blank) 'cross) + (make-ROW 'blank 'Circle 'cross)) + +(check-expect (play-on-right blank-ROW 'Circle) + (make-ROW 'blank 'blank 'Circle)) + +(define (play-on-right row play) + (make-ROW (ROW-left row) (ROW-middle row) play )) + +;;purpose : given the row, which column ,square to be played returns new row replacing the column +;; play-on-row : row square symbol -> row + +(check-expect (play-on-row blank-ROW 'L 'Circle) + (make-ROW 'Circle 'blank 'blank)) +(check-expect (play-on-row blank-ROW 'M 'Circle) + (make-ROW 'blank 'Circle 'blank)) +(check-expect (play-on-row blank-ROW 'R 'Circle) + (make-ROW 'blank 'blank 'Circle)) + +(define (play-on-row row column-label play) + (cond [(equal? column-label 'L) (make-ROW play (ROW-middle row) (ROW-right row))] + [(equal? column-label 'M) (make-ROW (ROW-left row) play (ROW-right row))] + [(equal? column-label 'R) (make-ROW (ROW-left row) (ROW-middle row) play)] + [else row])) + +;;purpose given a board, a square to be played and the label of the position to be played +;;returns a new board with the square to be played at the labeled position on the top row + +;; play-on-board-at-top : board square symbol -> board +;;test +(check-expect (play-on-board-at-top empty-board 'Circle 'L) + (make-BOARD (make-ROW 'Circle 'blank 'blank) + blank-ROW + blank-ROW)) + + +(check-expect (play-on-board-at-top empty-board 'Circle 'M) + (make-BOARD (make-ROW 'blank 'Circle 'blank) + blank-ROW + blank-ROW)) + + +(check-expect (play-on-board-at-top empty-board 'cross 'R) + (make-BOARD (make-ROW 'blank 'blank 'cross) + blank-ROW + blank-ROW)) + + +(define (play-on-board-at-top board play column-label) + (make-BOARD(play-on-row (BOARD-top-row board) column-label play) + (BOARD-center-row board)(BOARD-bottom-row board)) + ) + + + +;;purpose given a board, a square to be played and the label of the position to be played +;;returns a new board with the square to be played at the labeled position on the middle row + +;; play-on-board-at-top : board square symbol -> board +;;test +(check-expect (play-on-board-at-middle empty-board 'Circle 'L) + (make-BOARD blank-ROW + (make-ROW 'Circle 'blank 'blank) + blank-ROW)) + + +(check-expect (play-on-board-at-middle empty-board 'Circle 'M) + (make-BOARD blank-ROW + (make-ROW 'blank 'Circle 'blank) + blank-ROW)) + + +(check-expect (play-on-board-at-middle empty-board 'cross 'R) + (make-BOARD blank-ROW + (make-ROW 'blank 'blank 'cross) + blank-ROW)) + + +(define (play-on-board-at-middle board play column-label) + (make-BOARD (BOARD-top-row board) (play-on-row (BOARD-center-row board) column-label play) + (BOARD-bottom-row board)) + ) +;;purpose given a board, a square to be played and the label of the position to be played +;;returns a new board with the square to be played at the labeled position on the bottom row + +;; play-on-board-at-top : board square symbol -> board +;;test +(check-expect (play-on-board-at-bottom empty-board 'Circle 'L) + (make-BOARD blank-ROW + blank-ROW + (make-ROW 'Circle 'blank 'blank))) + + +(check-expect (play-on-board-at-bottom empty-board 'Circle 'M) + (make-BOARD blank-ROW + blank-ROW + (make-ROW 'blank 'Circle 'blank))) + + +(check-expect (play-on-board-at-bottom empty-board 'cross 'R) + (make-BOARD blank-ROW + blank-ROW + (make-ROW 'blank 'blank 'cross))) + + +(define (play-on-board-at-bottom board play column-label) + (make-BOARD (BOARD-top-row board) (BOARD-center-row board) + (play-on-row (BOARD-bottom-row board) column-label play) + ) + ) + + +;;purpose :given the board ,square to be played,column and row label and returns a new board +;;with the square to be played at the position reffered +;; play-on-board : board square symbol symbol -> board + +;;test +(check-expect (play-on-board empty-board 'cross 'R 'T) + (make-BOARD (make-ROW 'blank 'blank 'cross ) + blank-ROW + blank-ROW)) + + +(check-expect (play-on-board empty-board 'cross 'L 'C) + (make-BOARD blank-ROW + cross-blank + blank-ROW)) + + +(check-expect (play-on-board empty-board 'cross 'M 'B) + (make-BOARD blank-ROW + blank-ROW + cross-ROW)) + + +(define (play-on-board board play column-label row-label) + (cond [(equal? row-label 'T) (play-on-board-at-top board play column-label)] + [(equal? row-label 'C) (play-on-board-at-middle board play column-label)] + [(equal? row-label 'B) (play-on-board-at-bottom board play column-label)] + [else board])) + + +;;purpose : Given a board structure, a return the image of that board centered on the scene. +;;create-board:board->scene + +;;test +(check-expect (create-board (make-BOARD blank-ROW + blank-ROW + cross-ROW)) + (place-image (draw-board (make-BOARD blank-ROW + blank-ROW + cross-ROW)) + (/ square-width 2)(/ square-width 2) background)) + +(check-expect (create-board (make-BOARD (make-ROW 'Circle 'cross 'Circle) + blank-ROW + cross-ROW)) + (place-image (draw-board (make-BOARD (make-ROW 'Circle 'cross 'Circle) + blank-ROW + cross-ROW)) + (/ square-width 2)(/ square-width 2) background)) + +(check-expect (create-board (make-BOARD (make-ROW 'Circle 'cross 'blank) + blank-ROW + cross-ROW)) + (place-image (draw-board (make-BOARD (make-ROW 'Circle 'cross 'blank) + blank-ROW + cross-ROW)) + (/ square-width 2)(/ square-width 2) background)) + +(define (create-board board) + (place-image (draw-board board)(/ square-width 2)(/ square-width 2) background) + ) + +;; clack1 : Mouse handler. Plays a cross (always a cross) where the mouse is clicked, on button-up. +;; clack1 : board number number symbol -> board + +(define (clack1 board x y event) + (cond [(symbol=? event 'button-up) + (play-on-board board 'cross (which-column x) (which-row y))] + [else board])) + +(check-expect (clack1 (make-BOARD blank-ROW + blank-ROW + cross-ROW) 40 68 'button-up) + (make-BOARD cross-blank + blank-ROW + cross-ROW)) + +(check-expect (clack1 (make-BOARD blank-ROW + blank-ROW + cross-ROW) 160 168 'button-up) + (make-BOARD blank-ROW + (make-ROW 'blank 'cross 'blank) + cross-ROW)) + +(check-expect (clack1 (make-BOARD blank-ROW + blank-ROW + blank-ROW) 310 365 'button-up) + (make-BOARD blank-ROW + blank-ROW + (make-ROW 'blank 'blank 'cross) + )) +;; purpose : Given the current player, return which player goes next. +;; other-player : square -> square + +(define (other-player play) + (cond [(equal? play 'Circle) 'cross] + [(equal? play 'cross) 'Circle])) + +(check-expect (other-player 'cross) 'Circle) +(check-expect (other-player 'Circle) 'cross) + +;; purpose : Given a horz. pos (either 'L, 'M or 'R), finds the content of that square. +;; lookup-square : row symbol -> square + +(define (lookup-square column-label row) + (cond [(equal? column-label 'L)(ROW-left row)] + [(equal? column-label 'M)(ROW-middle row)] + [(equal? column-label 'R)(ROW-right row)])) + +(check-expect(lookup-square 'L (make-ROW 'blank 'Circle 'cross)) 'blank) +(check-expect(lookup-square 'M (make-ROW 'blank 'Circle 'cross)) 'Circle) +(check-expect(lookup-square 'R (make-ROW 'blank 'Circle 'cross)) 'cross) + +;; lookup-row : Given a vert. pos (either 'T, 'C or 'B), finds that row. +;; lookup-row : board symbol -> row + +(define(lookup-row row-label board) + (cond [(equal? row-label 'T)(BOARD-top-row board)] + [(equal? row-label 'C)(BOARD-center-row board)] + [(equal? row-label 'B)(BOARD-bottom-row board)])) + + +(check-expect(lookup-row 'T (make-BOARD (make-ROW 'cross 'blank 'Circle) + blank-ROW + blank-ROW)) (make-ROW 'cross 'blank 'Circle)) + +(check-expect(lookup-row 'C (make-BOARD blank-ROW + (make-ROW 'cross 'blank 'Circle) + blank-ROW)) (make-ROW 'cross 'blank 'Circle)) + +(check-expect(lookup-row 'B (make-BOARD blank-ROW + blank-ROW + (make-ROW 'cross 'blank 'Circle) + )) (make-ROW 'cross 'blank 'Circle)) + +;; lookup : Given a horz. and a vert. pos, finds that square. +;; lookup : board symbol symbol -> square + +(define (lookup board column-label row-label) + (lookup-square column-label (lookup-row row-label board))) + +(check-expect(lookup(make-BOARD (make-ROW 'cross 'blank 'Circle) + blank-ROW + blank-ROW) 'L 'T) 'cross) + +(check-expect(lookup(make-BOARD blank-ROW + (make-ROW 'cross 'blank 'Circle) + blank-ROW) 'M 'C) 'blank) + +(check-expect(lookup(make-BOARD blank-ROW + blank-ROW + (make-ROW 'cross 'blank 'Circle) + ) 'R 'B) 'Circle) + + +;; move-legal? : Return true if the square at horizondal and vertical position is blank. +;; move-legal? : board symbol symbol -> boolean + +(define(move-legal? board column-label row-label) + (equal? (lookup board column-label row-label) 'blank)) + +(check-expect (move-legal? empty-board 'L 'C) true) +(check-expect (move-legal? (make-BOARD blank-ROW + (make-ROW 'Circle 'cross cross) + blank-ROW) + 'M 'C) false) +;;define a structure for game +;;contract make-game :square board number->game +(define-struct GAME (next-player board move-count) #:transparent) + +;;defining the initial-game +(define initial-game (make-GAME 'cross empty-board 0)) + +;;purpose: Given a game and a horz. and vert. position, the next player plays in that square, if legal. The move-count goes up by 1,and the next-player switches hand. +;; play-on-game : game symbol symbol -> game + +(check-expect(play-on-game initial-game 'L 'T) + (make-GAME 'Circle + (make-BOARD cross-blank blank-ROW blank-ROW) 1)) + +(check-expect(play-on-game (make-GAME 'Circle + (make-BOARD cross-blank blank-ROW blank-ROW) 1) + 'M 'C ) + (make-GAME 'cross + (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + blank-ROW) 2)) +(check-expect(play-on-game(make-GAME 'cross + (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + blank-ROW) 2) + 'R 'B) + (make-GAME 'Circle + (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + (make-ROW 'blank 'blank 'cross)) 3)) + +(define (play-on-game game column-label row-label) + (cond [ (move-legal? (GAME-board game) column-label row-label) + (make-GAME (other-player (GAME-next-player game)) + (play-on-board (GAME-board game) (GAME-next-player game) column-label row-label) + (+ (GAME-move-count game) 1))] + [else game])) + +;; game-over? : Returns true when the game is over. +;; game-over? : game -> boolean +(check-expect (game-over? (make-GAME 'Circle (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + (make-ROW 'blank 'blank 'cross))3)) false) +(check-expect (game-over? (make-GAME 'Circle (make-BOARD cross-ROW-blank + (make-ROW 'blank 'Circle 'blank) + (make-ROW 'blank 'blank 'cross))3)) false) +(check-expect (game-over? (make-GAME 'Circle (make-BOARD cross-circle + (make-ROW 'cross 'Circle 'cross) + (make-ROW 'Circle 'cross 'Circle))9))true) +(define (game-over? game) + (>= (GAME-move-count game) 9)) + + + +;; clack2 : Mouse handler. Plays the game on button-up. +;; clack2 : game number number symbol -> game + +(check-expect (clack2 initial-game 90 90 'button-up) + (make-GAME 'Circle + (make-BOARD cross-blank blank-ROW blank-ROW) 1)) + +(check-expect (clack2 (make-GAME 'Circle + (make-BOARD cross-blank blank-ROW blank-ROW) 1) + 160 160 'button-up) + (make-GAME 'cross + (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + blank-ROW) 2)) + +(check-expect (clack2 (make-GAME 'cross + (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + blank-ROW) 2)310 310 'button-up) + (make-GAME 'Circle (make-BOARD cross-blank + (make-ROW 'blank 'Circle 'blank) + (make-ROW 'blank 'blank 'cross)) 3)) + + +(define (clack2 game x y event) + (cond [(symbol=? event 'button-up) + (play-on-game game (which-column x) (which-row y))] + [else game])) + +;; game->scene : Draws a game +;; game->scene : game -> scene + +(check-expect (game->scene (make-GAME 'Circle + (make-BOARD cross-blank blank-ROW blank-ROW) 1)) + (place-image (draw-board (make-BOARD cross-blank blank-ROW blank-ROW)) + (/ square-width 2)(/ square-width 2) background)) + + +(check-expect (game->scene (make-GAME 'cross + (make-BOARD (make-ROW 'cross 'blank 'Circle) blank-ROW blank-ROW) 1)) + (place-image (draw-board (make-BOARD (make-ROW 'cross 'blank 'Circle) blank-ROW blank-ROW)) + (/ square-width 2)(/ square-width 2) background)) + +(define (game->scene game) + (place-image (draw-board (GAME-board game)) (/ square-width 2)(/ square-width 2) background) + ) + + +;; winning-triple? : Return true if a, b, and c are all the same symbol as player. +;; winning-triple? : symbol symbol symbol symbol -> boolean + +(check-expect (winning-triple? 'cross 'cross 'cross 'cross)true) +(check-expect (winning-triple? 'Circle 'Circle 'blank 'cross)false) +(check-expect (winning-triple? 'Circle 'Circle 'Circle 'Circle)true) +(check-expect (winning-triple? 'cross 'blank 'cross 'cross)false) + + +(define (winning-triple? player a b c) + (and(and (equal? player a)(equal? player b))(equal? player c))) + + +;; winning-row? : Returns true if the indicated row is a win for the given player. +;; winning-row? : board square symbol -> boolean + +(check-expect (winning-row? (make-BOARD cross-row + circle-cross + (make-ROW 'Circle 'blank 'blank)) + 'cross 'T)true) + + + +(check-expect (winning-row? (make-BOARD (make-ROW 'cross 'blank 'Circle) + circle-cross + (make-ROW 'blank 'cross 'blank)) + 'Circle 'C)false) + + + +(check-expect (winning-row? (make-BOARD (make-ROW 'cross 'Circle 'blank ) + (make-ROW 'cross 'Circle 'cross) + (make-ROW 'Circle 'Circle 'Circle)) + 'Circle 'B)true) + +(define (winning-row? board player vertical-pos) + (cond[(equal? vertical-pos 'T)(winning-triple? player (ROW-left (BOARD-top-row board)) + (ROW-middle (BOARD-top-row board)) + (ROW-right (BOARD-top-row board)))] + [(equal? vertical-pos 'C)(winning-triple? player (ROW-left (BOARD-center-row board)) + (ROW-middle (BOARD-center-row board)) + (ROW-right (BOARD-center-row board)))] + [(equal? vertical-pos 'B)(winning-triple? player (ROW-left (BOARD-bottom-row board)) + (ROW-middle (BOARD-bottom-row board)) + (ROW-right (BOARD-bottom-row board)))] + [else false] + )) + + +;; winning-column? : Return true if the indicated column is a win for the given player. +;; winnnig-column? : board square symbol -> boolean + + +(check-expect (winning-column? (make-BOARD cross-ROW-blank + circle-cross + cross-blank) + 'cross 'L)true) + + + +(check-expect (winning-column? (make-BOARD circle-cross + circle-cross + (make-ROW 'blank 'Circle 'blank)) + 'Circle 'M)true) + + + +(check-expect (winning-column? (make-BOARD circle-cross + (make-ROW 'cross 'blank 'Circle) + (make-ROW 'Circle 'Circle 'Circle)) + 'Circle 'R)true) + +(check-expect (winning-column? (make-BOARD circle-cross + cross-blank + (make-ROW 'Circle 'Circle 'Circle)) + 'Circle 'R)false) + + +(define (winning-column? board player horizontal-pos) + (cond[(equal? horizontal-pos 'L)(winning-triple? player (ROW-left (BOARD-top-row board)) + (ROW-left (BOARD-center-row board)) + (ROW-left (BOARD-bottom-row board)))] + [(equal? horizontal-pos 'M)(winning-triple? player (ROW-middle (BOARD-top-row board)) + (ROW-middle (BOARD-center-row board)) + (ROW-middle (BOARD-bottom-row board)))] + [(equal? horizontal-pos 'R)(winning-triple? player (ROW-right (BOARD-top-row board)) + (ROW-right (BOARD-center-row board)) + (ROW-right (BOARD-bottom-row board)))] + [else false] + )) + + + +;; winning-down-diagonal? : Return true if the top-left to bottom-right diagonal is a win. +;; winning-down-diagonal? : board square -> boolean + + + + +(check-expect (winning-down-diagonal?(make-BOARD (make-ROW 'Circle 'Circle 'Circle) + (make-ROW 'cross 'Circle 'blank) + (make-ROW 'cross 'blank 'Circle)) + 'Circle)true) + +(check-expect (winning-down-diagonal?(make-BOARD circle-cross + cross-blank + (make-ROW 'Circle 'blank 'Circle)) + 'Circle)false) +(check-expect (winning-down-diagonal?(make-BOARD (make-ROW 'cross 'blank 'cross ) + (make-ROW 'Circle 'cross 'blank) + (make-ROW 'blank 'Circle 'cross)) + 'cross)true) + + +(define (winning-down-diagonal? board player) + (and (equal? player (ROW-right (BOARD-bottom-row board))) (and (equal? player(ROW-middle (BOARD-center-row board))) + (equal? player (ROW-left (BOARD-top-row board)))))) + + +;; winning-up-diagonal? : Return true if the bottom-left to top-right diagonal is a win. +;; winning-up-diagonal? : board square -> boolean + +(check-expect (winning-up-diagonal?(make-BOARD circle-cross + (make-ROW 'cross 'Circle 'blank) + (make-ROW 'Circle 'blank 'Circle)) + 'Circle)true) + +(check-expect (winning-up-diagonal?(make-BOARD circle-cross + cross-blank + (make-ROW 'Circle 'blank 'Circle)) + 'Circle)false) +(check-expect (winning-up-diagonal?(make-BOARD (make-ROW 'cross 'blank 'cross ) + (make-ROW 'Circle 'cross 'blank) + (make-ROW 'cross 'blank 'Circle)) + 'cross)true) + + +(define (winning-up-diagonal? board player) + (and (equal? player (ROW-left (BOARD-bottom-row board))) (and (equal? player(ROW-middle (BOARD-center-row board))) + (equal? player (ROW-right (BOARD-top-row board)))))) + +;; winning-board? : Returns true if the given board is a win for the given player. +;; winning-board? : board square -> boolean + +(check-expect (winning-board? (make-BOARD cross-row + circle-cross + blank-circle) + 'cross)true) + +(check-expect (winning-board? (make-BOARD circle-cross + cross-row + blank-circle) + 'cross)true) +(check-expect (winning-board? (make-BOARD circle-cross + blank-circle + cross-row ) + 'cross)true) + +(check-expect (winning-board? (make-BOARD (make-ROW 'Circle 'cross 'cross) + (make-ROW 'Circle 'cross 'Circle) + blank-circle) + 'Circle)true) +(check-expect (winning-board? (make-BOARD (make-ROW 'cross 'Circle 'cross) + circle-cross + (make-ROW 'Circle 'Circle 'blank)) + 'Circle)true) +(check-expect (winning-board? (make-BOARD cross-circle + circle-cross + (make-ROW 'Circle 'blank 'Circle)) + 'Circle)true) + +(check-expect (winning-board? (make-BOARD cross-circle + circle-cross + blank-circle) + 'Circle)true) +(check-expect (winning-board? (make-BOARD (make-ROW 'cross 'Circle 'cross) + cross-circle + (make-ROW 'Circle 'blank 'cross)) + 'cross)true) + +(define (winning-board? board player) + (or (winning-up-diagonal? board player) + (or (winning-down-diagonal? board player) + (or (winning-row? board player 'T) + (or (winning-row? board player 'C) + (or (winning-row? board player 'B) + (or (winning-column? board player 'L) + (or (winning-column? board player 'M) + (winning-column? board player 'R))))))))) + + + +;; game-over-or-win? : Returns true when the game is over either because the board is full, +;; or because someone won. +;; game-over-or-win? : game -> boolean + +(check-expect (game-over-or-win? (make-GAME 'Circle + (make-BOARD (make-ROW 'cross 'blank 'Circle) blank-ROW blank-ROW) 3))false) + + +(check-expect (game-over-or-win? (make-GAME 'Circle + (make-BOARD (make-ROW 'cross 'blank 'Circle) + (make-ROW 'blank 'cross 'Circle) + (make-ROW 'cross 'blank 'Circle))7))true) + + +(check-expect (game-over-or-win? (make-GAME 'cross + (make-BOARD cross-circle + (make-ROW 'Circle 'cross 'Circle) + (make-ROW 'cross 'Circle 'cross))9)) + true) + +(define (game-over-or-win? game) + (or (winning-board? (GAME-board game) (GAME-next-player game)) + (game-over? game))) + + +(collect-garbage) (collect-garbage) (collect-garbage) +(printf "running tests with fast path optimization in place\n") +(time (run-tests)) +(printf "running tests without fast path optimization in place\n") +(parameterize ([skip-image-equality-fast-path #t]) + (time (run-tests))) diff --git a/collects/picturing-programs/tests/install-teachpack.ss b/collects/picturing-programs/tests/install-teachpack.ss new file mode 100644 index 0000000000..faff902bb4 --- /dev/null +++ b/collects/picturing-programs/tests/install-teachpack.ss @@ -0,0 +1,2 @@ +#lang scheme/base +(require (planet sbloch/picturing-programs:2)) \ No newline at end of file diff --git a/collects/picturing-programs/tests/map-image-bsl-tests.rkt b/collects/picturing-programs/tests/map-image-bsl-tests.rkt new file mode 100755 index 0000000000..606b7c94f9 --- /dev/null +++ b/collects/picturing-programs/tests/map-image-bsl-tests.rkt @@ -0,0 +1,196 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-beginner-reader.ss" "lang")((modname map-image-bsl-tests) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) +(require picturing-programs/book-pictures) +(require picturing-programs/map-image) +(require 2htdp/image) + +;(define (always-red x y) (name->color "red")) +;"(build-image 50 35 (lambda (x y) red)):" +;(build-image 50 35 always-red) +;"should be a 50x35 red rectangle" +;(define (a-gradient x y) (make-color (real->int (* x 2.5)) +; (real->int (* y 2.5)) +; 0)) +;"(build-image 100 100 (lambda (x y) (make-color (* x 2.5) (* y 2.5) 0))):" +;(build-image 100 100 a-gradient) +;"should be a 100x100 square with a color gradient increasing in red from left to right, and in green from top to bottom" + +; Test cases for primitives: +(check-expect (real->int 3.2) 3) +(check-expect (real->int 3.7) 4) +(check-expect (real->int 3.5) 4) +(check-expect (real->int 2.5) 2) +(check-expect (real->int #i3.2) 3) +(check-expect (real->int #i3.7) 4) +(check-expect (real->int #i3.5) 4) +(check-expect (real->int #i2.5) 2) + +;(check-expect (maybe-color? (make-color 3 4 5)) true) +;(check-expect (maybe-color? (make-color 3 4 5 6)) true) +;(check-expect (maybe-color? false) true) +;(check-expect (maybe-color? true) false) +;(check-expect (maybe-color? (make-posn 3 4)) false) +;(check-expect (maybe-color? "red") false) + +(check-expect (name->color "white") (make-color 255 255 255)) +(check-expect (name->color "black") (make-color 0 0 0)) +(check-expect (name->color "blue") (make-color 0 0 255)) +(check-expect (name->color "plaid") false) + +(check-expect (color=? (make-color 5 10 15) (make-color 5 10 15)) true) +(check-expect (color=? (make-color 5 10 15) (make-color 5 15 10)) false) +(check-expect (color=? (make-color 255 255 255) "white") true) +(check-expect (color=? (make-color 255 255 255) "blue") false) +(check-expect (color=? "forest green" 'forestgreen) true) +(check-expect (color=? "forest green" 'lightblue) false) +(check-expect (color=? (make-color 5 10 15 20) (make-color 5 10 15)) false) +(check-expect (color=? (make-color 5 10 15 255) (make-color 5 10 15)) true) +(check-expect (color=? (make-color 5 10 15 0) false) true) +(check-expect (color=? (make-color 5 10 15 20) false) false) + +; Test cases for map3-image: + +; red-id : x y r g b -> num +(define (red-id x y r g b) r) +; green-id : x y r g b -> num +(define (green-id x y r g b) g) +; blue-id : x y r g b -> num +(define (blue-id x y r g b) b) +; zero-5-args : x y r g b -> num +(define (zero-5-args x y r g b) 0) + +(define tri (triangle 60 "solid" "orange")) +; (define hieroglyphics pic:hieroglyphics) +; (define scheme-logo pic:scheme-logo) +; (define bloch pic:bloch) + +"tri:" tri +"(map3-image red-id green-id blue-id tri) should be tri:" +(map3-image red-id green-id blue-id tri) +"(map3-image zero-5-args green-id blue-id tri) should be a green triangle:" +(map3-image zero-5-args green-id blue-id tri) + +"(map3-image zero-5-args green-id blue-id bloch) should be a de-redded Steve Bloch:" +(map3-image zero-5-args green-id blue-id bloch) + +; gradient-g : x y r g b -> num +(define (gradient-g x y r g b) (min 255 (* 4 x))) +; gradient-b : x y r g b -> num +(define (gradient-b x y r g b) (min 255 (* 4 y))) +"(map3-image zero-5-args gradient-g gradient-b tri) should be a triangular window on a 2-dimensional color gradient:" +(map3-image zero-5-args gradient-g gradient-b tri) +"The same thing with some red:" +(map3-image red-id gradient-g gradient-b tri) +"And now let's try it on bloch. Should get a rectangular 2-dimensional color gradient:" +(map3-image zero-5-args gradient-g gradient-b bloch) +"The same thing preserving the red:" +(map3-image red-id gradient-g gradient-b bloch) + +; color-id : x y color -> color +(define (color-id x y c) + c) + +; kill-red : x y color -> color +(define (kill-red x y c) + (make-color 0 (color-green c) (color-blue c))) +(define (kill-red-preserving-alpha x y c) + (make-color 0 (color-green c) (color-blue c) (color-alpha c))) + +; make-gradient : x y color -> color +(define (make-gradient x y c) + (make-color 0 (min (* 4 x) 255) (min (* 4 y) 255))) + +(define (id x) x) + +"tri:" tri +"(map-image color-id tri):" +(define ex1 (map-image color-id tri)) ex1 +"(map-image kill-red tri):" +(define ex2 (map-image kill-red tri)) ex2 +"(map-image kill-red-preserving-alpha tri):" +(define ex2prime (map-image kill-red-preserving-alpha tri)) ex2prime +"(map-image make-gradient tri):" +(define ex3 (map-image make-gradient tri)) ex3 +"(map-image kill-red hieroglyphics):" +(define ex4 (map-image kill-red hieroglyphics)) ex4 +"(map-image kill-red scheme-logo):" +(define ex5 (map-image kill-red scheme-logo)) ex5 +"(map-image kill-red bloch):" +(define ex6 (map-image kill-red bloch)) ex6 + +;(define (other-bloch-pixel x y) +; (get-pixel-color x (- (image-height bloch) y) bloch)) +;(define flipped-bloch (build-image (image-width bloch) (image-height bloch) other-bloch-pixel)) +;flipped-bloch +; +; +;(define RADIUS 3) +; +;(define (clip-to n low high) +; (min (max n low) high)) +;(check-expect (clip-to 10 5 15) 10) +;(check-expect (clip-to 10 15 20) 15) +;(check-expect (clip-to 10 -20 7) 7) +; +;(define (near-bloch-pixel x y) +; (get-pixel-color +; (clip-to (+ x (- RADIUS) (random (+ 1 RADIUS RADIUS))) 0 (image-width bloch)) +; (clip-to (+ y (- RADIUS) (random (+ 1 RADIUS RADIUS))) 0 (image-height bloch)) +; bloch)) +; +;(define fuzzy-bloch +; (build-image (image-width bloch) (image-height bloch) near-bloch-pixel)) +;fuzzy-bloch +; +;(define (near-tri-mpixel x y) +; (if (pixel-visible? x y tri) +; (get-pixel-color +; (clip-to (+ x (- RADIUS) (random (+ 1 RADIUS RADIUS))) 0 (image-width tri)) +; (clip-to (+ y (- RADIUS) (random (+ 1 RADIUS RADIUS))) 0 (image-height tri)) +; tri) +; false)) +;(define fuzzy-tri +; (build-masked-image (image-width tri) (image-height tri) near-tri-mpixel)) +;fuzzy-tri + +; Convert all white pixels to transparent +(define (white-pixel->trans x y old-color) + (if (color=? old-color "white") + false + old-color)) +(define (white->trans pic) + (map-image + white-pixel->trans + pic)) + +(define (white-pixel->red x y old-color) + (if (color=? old-color 'white) + "red" + old-color)) +(define (white->red pic) + (map-image white-pixel->red pic)) + +"(overlay (white->trans hieroglyphics) (rectangle 100 100 'solid 'blue)):" +(define hier (white->trans hieroglyphics)) +(overlay hier (rectangle 100 100 "solid" "blue")) + +; pixel->gray : x y color -> color +(check-expect (pixel->gray 3 17 (make-color 0 0 0)) (make-color 0 0 0)) +(check-expect (pixel->gray 92 4 (make-color 50 100 150)) (make-color 100 100 100)) +(define (pixel->gray x y c) + (make-gray (quotient (+ (color-red c) + (color-green c) + (color-blue c)) + 3))) + +; make-gray : natural -> color +(define (make-gray n) + (make-color n n n)) + +; color->gray : image -> image +(define (color->gray pic) + (map-image pixel->gray pic)) + +(color->gray bloch) +(color->gray hieroglyphics) \ No newline at end of file diff --git a/collects/picturing-programs/tests/map-image-isl-tests.rkt b/collects/picturing-programs/tests/map-image-isl-tests.rkt new file mode 100755 index 0000000000..51367ce32c --- /dev/null +++ b/collects/picturing-programs/tests/map-image-isl-tests.rkt @@ -0,0 +1,3128 @@ +#reader(lib"read.ss""wxme")WXME0108 ## +#| + This file uses the GRacket editor format. + Open this file in DrRacket version 5.0.0.3 or later to read it. + + Most likely, it was created by saving a program in DrRacket, + and it probably contains a program with non-text elements + (such as images or comment boxes). + + http://racket-lang.org/ +|# + 28 7 #"wxtext\0" +3 1 6 #"wxtab\0" +1 1 8 #"wxmedia\0" +4 1 8 #"wximage\0" +2 0 34 #"(lib \"syntax-browser.ss\" \"mrlib\")\0" +1 0 16 #"drscheme:number\0" +3 0 44 #"(lib \"number-snip.ss\" \"drscheme\" \"private\")\0" +1 0 36 #"(lib \"comment-snip.ss\" \"framework\")\0" +1 0 43 #"(lib \"collapsed-snipclass.ss\" \"framework\")\0" +0 0 19 #"drscheme:sexp-snip\0" +0 0 36 #"(lib \"cache-image-snip.ss\" \"mrlib\")\0" +1 0 40 #"(lib \"image-core.ss\" \"2htdp\" \"private\")\0" +1 0 33 #"(lib \"bullet-snip.ss\" \"browser\")\0" +0 0 29 #"drscheme:bindings-snipclass%\0" +1 0 25 #"(lib \"matrix.ss\" \"htdp\")\0" +1 0 22 #"drscheme:lambda-snip%\0" +1 0 56 +#"(lib \"hrule-snip.ss\" \"macro-debugger\" \"syntax-browser\")\0" +1 0 45 #"(lib \"image-snipr.ss\" \"slideshow\" \"private\")\0" +1 0 26 #"drscheme:pict-value-snip%\0" +0 0 38 #"(lib \"pict-snipclass.ss\" \"slideshow\")\0" +2 0 55 #"(lib \"vertical-separator-snip.ss\" \"stepper\" \"private\")\0" +1 0 18 #"drscheme:xml-snip\0" +1 0 31 #"(lib \"xml-snipclass.ss\" \"xml\")\0" +1 0 21 #"drscheme:scheme-snip\0" +2 0 34 #"(lib \"scheme-snipclass.ss\" \"xml\")\0" +1 0 10 #"text-box%\0" +1 0 32 #"(lib \"text-snipclass.ss\" \"xml\")\0" +1 0 15 #"test-case-box%\0" +2 0 1 6 #"wxloc\0" + 0 0 81 0 1 #"\0" +0 75 1 #"\0" +0 12 90 -1 90 -1 3 -1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 255 255 255 1 -1 0 9 +#"Standard\0" +0 75 12 #"Courier New\0" +0 12 90 -1 90 -1 3 -1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 255 255 255 1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 -1 -1 2 24 +#"framework:default-color\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 150 0 150 0 0 0 -1 -1 2 15 +#"text:ports out\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 150 0 150 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 93 -1 -1 -1 0 0 0 0 0 0 0 0 0 1.0 1.0 1.0 255 0 0 0 0 0 -1 +-1 2 15 #"text:ports err\0" +0 -1 1 #"\0" +1.0 0 -1 -1 93 -1 -1 -1 0 0 0 0 0 0 0 0 0 1.0 1.0 1.0 255 0 0 0 0 0 -1 +-1 2 1 #"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 175 0 0 0 -1 -1 2 17 +#"text:ports value\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 175 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1.0 0 92 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1.0 1.0 1.0 34 139 34 0 0 0 -1 +-1 2 27 #"Matching Parenthesis Style\0" +0 -1 1 #"\0" +1.0 0 92 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1.0 1.0 1.0 34 139 34 0 0 0 -1 +-1 2 1 #"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 38 38 128 0 0 0 -1 -1 2 37 +#"framework:syntax-color:scheme:symbol\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 38 38 128 0 0 0 -1 -1 2 38 +#"framework:syntax-color:scheme:keyword\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 38 38 128 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 194 116 31 0 0 0 -1 -1 2 +38 #"framework:syntax-color:scheme:comment\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 194 116 31 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 41 128 38 0 0 0 -1 -1 2 37 +#"framework:syntax-color:scheme:string\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 41 128 38 0 0 0 -1 -1 2 39 +#"framework:syntax-color:scheme:constant\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 41 128 38 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 132 60 36 0 0 0 -1 -1 2 42 +#"framework:syntax-color:scheme:parenthesis\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 132 60 36 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 255 0 0 0 0 0 -1 -1 2 36 +#"framework:syntax-color:scheme:error\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 255 0 0 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 -1 -1 2 36 +#"framework:syntax-color:scheme:other\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 81 112 203 0 0 0 -1 -1 2 +38 #"drracket:check-syntax:lexically-bound\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 81 112 203 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 178 34 34 0 0 0 -1 -1 2 28 +#"drracket:check-syntax:set!d\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 178 34 34 0 0 0 -1 -1 2 1 +#"\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 68 0 203 0 0 0 -1 -1 2 31 +#"drracket:check-syntax:imported\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 68 0 203 0 0 0 -1 -1 4 1 +#"\0" +0 70 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 4 4 #"XML\0" +0 70 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 4 1 #"\0" +0 71 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 4 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 1 0 0 0 0 0 0 0 0 1.0 1.0 1.0 0 0 255 0 0 0 -1 +-1 4 1 #"\0" +0 71 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 1 0 0 0 0 0 0 0 0 1.0 1.0 1.0 0 0 255 0 0 0 -1 +-1 4 1 #"\0" +0 71 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1.0 1.0 1.0 0 100 0 0 0 0 -1 +-1 0 1 #"\0" +0 75 12 #"Courier New\0" +0.0 12 90 -1 90 -1 3 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 8 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0.0 0.0 0.0 1.0 1.0 1.0 255 0 0 0 0 +0 -1 -1 8 24 #"drscheme:text:ports err\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0.0 0.0 0.0 1.0 1.0 1.0 255 0 0 0 0 +0 -1 -1 0 1 #"\0" +0 -1 1 #"\0" +0.0 13 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 2 1 #"\0" +0 -1 1 #"\0" +0.0 13 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 22 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 15 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 4 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 14 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 20 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 19 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 22 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 14 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 4 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 20 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 22 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 14 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 4 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 15 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 20 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 19 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 2 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 1 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 2 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 1 0 0 0 0 0 0.0 0.0 0.0 1.0 1.0 1.0 65 105 225 0 +0 0 -1 -1 17 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 2 1 #"\0" +0 71 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1.0 1.0 1.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 2 1 #"\0" +0 71 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0.0 0.0 0.0 1.0 1.0 1.0 0 100 0 0 0 +0 -1 -1 0 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0.0 0.0 0.0 1.0 1.0 1.0 200 0 0 0 0 +0 -1 -1 24 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 -1 -1 0 1 #"\0" +0 75 12 #"Courier New\0" +0.0 14 90 -1 90 -1 3 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 19 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 2 38 #"drscheme:check-syntax:lexically-bound\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 81 112 203 0 0 0 -1 -1 2 +28 #"drscheme:check-syntax:set!d\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 178 34 34 0 0 0 -1 -1 2 31 +#"drscheme:check-syntax:imported\0" +0 -1 1 #"\0" +1 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 0 0 0 0 1 1 1 68 0 203 0 0 0 -1 -1 17 1 +#"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 24 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 1 0 0.0 0.0 0.0 1.0 1.0 1.0 0 0 0 0 0 0 +-1 -1 24 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 4 1 #"\0" +0 -1 1 #"\0" +1.0 0 92 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 0 -1 -1 0 1 #"\0" +0 75 23 #"Lucida Sans Typewriter\0" +0.0 12 90 -1 90 -1 1 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 15 1 #"\0" +0 -1 1 #"\0" +1.0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 1 0.0 0.0 0.0 0.0 0.0 0.0 255 165 0 0 +0 0 -1 -1 0 1 #"\0" +0 75 7 #"Monaco\0" +0.0 14 90 -1 90 -1 3 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 0 1 #"\0" +0 75 1 #"\0" +0.0 10 90 -1 90 -1 3 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 0 1 #"\0" +0 75 12 #"Courier New\0" +0.0 10 90 -1 90 -1 3 -1 0 1 0 1 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 255 +255 255 1 -1 0 1072 0 4 3 85 +( + #";; The first three lines of this file were inserted by DrRacket. The" + #"y record metadata" +) 0 0 4 29 1 #"\n" +0 0 4 3 85 +( + #";; about the language level of this file in a form that our tools ca" + #"n easily process." +) 0 0 4 29 1 #"\n" +0 0 4 3 190 +( + #"#reader(lib \"htdp-intermediate-reader.ss\" \"lang\")((modname map-i" + #"mage-isl-tests) (read-case-sensitive #t) (teachpacks ()) (htdp-setti" + #"ngs #(#t constructor repeating-decimal #f #t none #f ())))" +) 0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 7 #"require" +0 0 4 3 1 #" " +0 0 14 3 39 #"installed-teachpacks/picturing-programs" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"always-red" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"name->color" +0 0 4 3 1 #" " +0 0 19 3 5 #"\"red\"" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 19 3 1 #"\"" +0 0 19 3 1 #"(" +0 0 19 3 11 #"build-image" +0 0 19 3 1 #" " +0 0 19 3 2 #"50" +0 0 19 3 1 #" " +0 0 19 3 2 #"35" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 6 #"lambda" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 1 #"x" +0 0 19 3 11 #" y) red)):\"" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 11 #"build-image" +0 0 4 3 1 #" " +0 0 20 3 2 #"50" +0 0 4 3 1 #" " +0 0 20 3 2 #"35" +0 0 4 3 1 #" " +0 0 14 3 10 #"always-red" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 19 3 1 #"\"" +0 0 19 3 6 #"should" +0 0 19 3 1 #" " +0 0 19 3 2 #"be" +0 0 19 3 1 #" " +0 0 19 3 22 #"a 50x35 red rectangle\"" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"a-gradient" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"make-color" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 9 #"real->int" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 20 3 3 #"2.5" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 37 #" " +0 0 22 3 1 #"(" +0 0 14 3 9 #"real->int" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 20 3 3 #"2.5" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 37 #" " +0 0 20 3 1 #"0" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 19 3 1 #"\"" +0 0 19 3 1 #"(" +0 0 19 3 11 #"build-image" +0 0 19 3 1 #" " +0 0 19 3 3 #"100" +0 0 19 3 1 #" " +0 0 19 3 3 #"100" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 6 #"lambda" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 1 #"x" +0 0 19 3 1 #" " +0 0 19 3 1 #"y" +0 0 19 3 1 #")" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 10 #"make-color" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 1 #"*" +0 0 19 3 1 #" " +0 0 19 3 1 #"x" +0 0 19 3 1 #" " +0 0 19 3 3 #"2.5" +0 0 19 3 1 #")" +0 0 19 3 1 #" " +0 0 19 3 1 #"(" +0 0 19 3 1 #"*" +0 0 19 3 1 #" " +0 0 19 3 1 #"y" +0 0 19 3 12 #" 2.5) 0))):\"" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 11 #"build-image" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 14 3 10 #"a-gradient" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 19 3 7 #"\"should" +0 0 19 3 1 #" " +0 0 19 3 2 #"be" +0 0 19 3 1 #" " +0 0 19 3 1 #"a" +0 0 19 3 1 #" " +0 0 19 3 7 #"100x100" +0 0 19 3 1 #" " +0 0 19 3 6 #"square" +0 0 19 3 1 #" " +0 0 19 3 4 #"with" +0 0 19 3 1 #" " +0 0 19 3 1 #"a" +0 0 19 3 86 +( + #" color gradient increasing in red from left to right, and in green f" + #"rom top to bottom\"" +) 0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 17 3 7 #"; Test:" +0 0 4 29 1 #"\n" +0 0 17 3 31 #"; color-id : x y color -> color" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 8 #"color-id" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 14 3 1 #"c" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 14 3 1 #"c" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 17 3 31 #"; kill-red : x y color -> color" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 8 #"kill-red" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 14 3 1 #"c" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"make-color" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"color-green" +0 0 4 3 1 #" " +0 0 14 3 1 #"c" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"color-blue" +0 0 4 3 1 #" " +0 0 14 3 1 #"c" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 17 3 36 #"; make-gradient : x y color -> color" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 13 #"make-gradient" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 14 3 1 #"c" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"make-color" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"min" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 20 3 1 #"3" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 20 3 3 #"255" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"min" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 20 3 1 #"3" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 20 3 3 #"255" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 3 #"tri" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 8 #"triangle" +0 0 4 3 1 #" " +0 0 20 3 2 #"60" +0 0 4 3 1 #" " +0 0 19 3 7 #"\"solid\"" +0 0 4 3 1 #" " +0 0 19 3 8 #"\"orange\"" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 13 #"hieroglyphics" +0 0 4 3 1 #" " +0 3 27 4 1 #"\0" +2 -1.0 -1.0 0.0 0.0 0 8 500 +( + #"\211PNG\r\n\32\n\0\0\0\rIHDR\0\0\0-\0\0\0D\b" + #"\2\0\0\0\232\203+_\0\0\16\263IDATx\234\315Zmh\ei~" + #"\377Y\2625\243Qt\243\235\221\214\343\310Rl\354\e;t#G\336\353\36\1" + #"'\265S\16\226\202\203\367\270\227\300n" + #"\16\221\17\313\366>\264\320\300r9\266" + #"\210+\267\307B\312}\332+--\246" + #"\331\224]Z\272a\375\341\26\272\304\256#0tY\353\354\334\21Eg\343X/" + #"\261}\36\315DS\331\362\214t\222\373" + #"\341?3\32\331N\262\335\273+\375c" + #"\304h\364\274\374\237\337\377\355\367<\217" + #";\16\16\16\360\377@:\177_\3)\212R-,wl}\356\331\315\325ND" + #"\17N\276\3247z\351\213w\357\370\35" + #"\361\240\351\303\367\337m4\232\35\365\212" + #"\213\345\355\237\36\207.\205_y\353\377" + #"B\217\342'\357\366l\177zhz[\232\272\246\2740\346\236\374\eQ\24\377P" + #"z\24\226\357\366~v\343\330\351\17\211" + #"\354\35\354\376\326\317\236\333\314\365\aU" + #"\2@h\177m\347\337\376\374\271\315\236" + #"\217\207\242(\4\254\242(\225'j\347\352G'\v\37}A%ly\256\257\34" + #"\326\3039\353\376g\377\330\263\375\351\332" + #"\256oOSb\247X\267\333\5\30VC\346\350XY\315+\361\373\307N\323\324" + #"\265\315?~\307\216 {\226\303z\334" + #"\277\373\257B\355Q\317\366\247\0\326v" + #"}\203'\366\350g\267\333\5`\376\241" + #"\366G\347\306\304'K\317\206!\235\257\306#\334\323~%\2675\206\276yl<" + #"w\34\34\34\24?y\367\224\374s\200" + #"\241\246\241\375\265C\215fR\245\304\270" + #"\377X\f\2342\377P\233\30~\216\275" + #"\32\215&\200\255s?\340\372F\235\220\270\n\313wO\26>\2429\\," + #"/>Y:\332\371t\250\353\250\22\351|\365\331S:'\266\305\355v\271\335" +) 500 +( + #"\256\336\317n\360\263\337),\337\265\337wvl}\356D\373X\3447\344:\206" + #"1\377P\343\271.\e\371\353\267\263\27" + #"FB\353;:\200\242R\371\273\357\237\337\220K\30nSt%W=\35\352Z" + #"\310T.\216\370m\250\32\215&\272\374n\267\213Y\375wX6r\377\3557:" + #"\354\236\311;\305\257\370:\337\3720\27" + #"8\341\276\366\17\231&\272\376\352_\262" + #"_?;P\370\315\177\237;\27\370\317" + #"\264\326\23\350:\311w\1\310j^\201" + #"\305_\\\364\276\372\365\336\351\227\204&" + #"\272\4\366\267\277\321\352\347\242\234=T" + #"|$\374\247_\365\364\a\331?\31\371\312?\247J\343_=qpp\340ru" + #"\270\\\35\313\305\375\223|\27k\224\\" + #"\347\256\232\353\227\275\203\364\224\325\274\177" + #"\375\212\177vI\375\341w_\\\310T" + #"\346n\234\0030w\343\334\236\246\0\200Z\313\225t[\343!f;W\322]," + #"\233\325\274d \37/:\e\0\220\370\262\375\34\r\262+\217u\362z[\326v" + #"}-;\210O\226\310\204\22\277\357b" + #"\371\344tX\342\313\311\3510\200\304x" + #"\20@<\302\345J:\4\17\200\225\234\351\23\253F\17\0r\32\255Z'\r\242" + #"A\326\16\354\213#\376\311w\36\244\363" + #"\325t\276\232\274S\234\177P>\32J" + #"B\317)\373\271s\325\350\221\330CA" + #"\177\330%\243A\26\300\372\216~q\304\337\276V\3\360.d*\3642W\322\201" + #" =O\f\263\275\337?\377\301\334*\200\2511\341\270x6\234_:\aO\354" + #"5\32\260\21\313j\3367\337[\f\213\376[o\f\332\215h\271\3\335,9," + #"\351z/#\317\217\370\201m[Q\307\350\f\300H|99\35:2=\0h" + #"\325:\300\211O\226\354\204\346Z\333\3659\314f|0\267:w\343\314" + #"\304\231\2003,i\232{\31\3311\231q\3635\211\347\272\0\\\231\34J" +) 500 +( + #"\214\373\245\376\206\255\0015j\352\272\265" + #"\266\200\355F\351|5\253y7\344\372!\315:\3333\361q\231J\360\344J:" + #"\324\332\205\221P\256\244\317?\324.\f\371\335nW\32\200" + #"Z\3\0\265FIbjL\320\252\365\205LeC\256\223\v;#b\325\350Y" + #"\337\221\263Z 9\215\254\26\240_\263" + #"Z\300\331&q\371e\250\225\211\363\241" + #"\231\2177-\\-<\204\335_\303\266\213ZK\\\356\245F\331Gn\2117\b" + #"\241\201n\26\0\371\232#s3\316\201" + #"\bW\251\277\1\265\245\237\304\227-\214" + #"\r\32\37`\240V\254\bg\354T\326\371+W,\206_R\267t\276\252=\324" + #"\314F\367\v\322x\320i\235\354#\267c\334\226*3\251J,\312\1\325\201n" + #"\26j%\253\5(\345XA\336\212\246" + #"h\220\315\225\364+\223C\200\f\301\3" + #"\265\322\302#\330\335\r\313\377\342\21\216" + #"\24\347\271\256x\304m7Z\337\321\241" + #"V~\374a\1\300\17\277\373\242S\233\231T\5\300\354\222:5&\0 C\244" + #"5\0\210E[\261\352\343\305\363\300\236" + #"\246\234?\333'\361\345\365\35\235\260\261" + #"]\342\30\276N\345\0\260F\21\230[" + #"\245,\a\30\20\374\357\247\ns7_&S\336\313\310\24\250\3165@\360C\255" + #"\220/\203w\317\244\n{\16\375\32\215" + #"\246\246(\242(v\36\234|\t\362\317" + #"-\220\315\317\r\271\216a\3239\240\326" + #"\302\242\237@\222\372\e\353;:\25<\0\263w\326_\37\357\203Jv" + #"\301\205\221\2205+(j\0\254\357\24\22\27C\23\303\254m\235X\224#" +) 500 +( + #"\207\3\340v\233\1\354\352\330\372\334\241" + #"\4\354\326-\377\22<6\266\315M\371\326\e}\0VrU\262E\302\341Cd" + #"\276\254\26\200\340\a\220\234\16%\247\303" + #"\324\376\352\337\27\0\244\363\215\2511a" + #"%Wu\244\"<^\276\v\200\360h\361\0\0W&\207\34\301\306@\255\25\225" + #"\212\217\27%\276\f\260\0&\206Y\f\263\20z-Gc\200V\322\333\334\332^" + #"\274_\217\6Y\212\336=\255:\263 " + #"\377\345+\275\311;r4\310\306\242\\" + #"\256\244_\30\tY~\312\274 \212\260" + #"\374\303pF\227\304;3\277\1\301\37" + #"\26\375R\177#\275\334\240\20\260\242\316" + #"\\\323\305\21?\231\t\0\4\377\206\\9\177\266oOS$\276<\377P_\310" + #"T\310\n\204D|40\273\244\332~jG>\351\301\244\363\325\331%\25G$" + #"\32d\23\227\375\0\240V\342\21w<\22\4\f h\256\306\362\6\302\234\3426" + #"W\322q\277\0\300\307\367\361\234r/#_\30\t\315.\251\311k\3\263Kj" + #"z\271<5&\\\277\235=\34\267\\\337(\356\e\224\243\34U\321 \345\342\21" + #"\316l-\370)\275\246\363\215\331\245\342\372\216^T*\27FBScB<\342" + #"\206\340G\276l\247\335x\304\235\325\2" + #"\213\367\v\0^\37\357\213E\271\370h" + #"\200\306!\205p\e\207\361\250\26\226\5" + #"\240\321h\332\334\202d%W\312\225t\37/J\375\36\302\2034[\311U\257L" + #"\16QUkn\312?\372D\5\2048*h\245]7\0\211/K\343~\333X" + #"\244\4\371\207\365\322\3\265f\327B\27" + #"\261\370\265]\2373\355\254\344\252\261(" + #"75&\354i\n\371\251\35P\211\361" + #"\240\304\227\241V\240\326\2107\255\344\252" + #"\24 V\24\34)\226j\253\273\217\27\241V\302\242\211.\0R\240S" + #"Q\24\1\214\304\227\321\37\200Z\313j^\251\277\21\37\r\230\375-s\220" +) 500 +( + #"\372+\271\352J\256\232\270\334k\2172" + #"\223*\305\242\34}u\344\17\333\353\333" + #"\212\300\367\276\246\257\32\0PTL\317p\261\32\260\362" + #"\a|\274\270\222\253\22G\231]R\255" + #"\262u\264\350\324\232\272\326\313\355\267\360" + #"h4\232\264\265l\352\272\213e\0\314\244J\357\247\no\277:\300s]\16\273" + #"0\22_\226x\26([\313\262\352\210Z\331\323\32T_$\224%rs\265\2" + #"\370\17O\357\20\27\313\v\273\2776\365P\24Ep\273hb\0a\321O\360\276" + #">\336g&\2116\237=\326\343L\32A\376ai\360\214\366\307H'\200\246\256" + #"\305\242\334\371\263\347\3674\205 \215\6" + #"\331D\213=\264\334*\235\257ZD\225" + #"A\333\1!c\356\243\216\233\373h\262" + #"\261\v\305\332\256/D\365\226\360\211G" + #"\0\354\203\347\342\0217\20l+\331\216\374\263\222*\1Ui^,*Y\242\1\0\244\376\306\342}s}\261(\27\213r\266\227" + #"\20Ov\b\263\220\221\247\306\4\3225>\32\270~;K\\\2166\210NqY" + #"x0mg4j\r\255\243\25X\335\230h\320\332\31\b~\20\331t\0n\347" + #"1{\255\353;z<\342N\214\a\23\343~\242\245\rY\247\r3\265h\361d" + #"\347\27\240\315x.\226\317\225t\211/\27\225\n\275o\35,[\330\370x1\26" + #"\345\262\232\227tr:G:\337\2308C{L\362zf\240\233]y\254;\361" + #"\260\217\215;\255/\69\335\354\222\232" + #"\234\16\1\314L\252\224+\351\3672r" + #"zL\2700\22\"\272\260!\327\323\234\271zb4\211q\177rNM^\v\244" + #"\227\315\202\340\4d\376A\231\262@,\332\0\20\r\262Dh\314\205\2515;D" + #":EQ\334\361\16\206\366\327\342\21#\36iE]b\2346m!\b\376\353\267" + #"\263\230\16\3Lb\234\231I\225\356e\344\354\344P]" + #",\333\262K\355D\364\350R,\360\31\250\25\a\1\6Q\23\263\34\n\376+\223" + #"C\316cd\251\277\341H<\255\332d)\307\264Lo:\0\323\322#\374\312[" + #"\366\351v\2730\316\246\326\350\265\327\307" + #"\373\250\324A\255\230\207;\202\177\210\331" + #"\216\6\331\346\246\374\224\273\"\3069\202" + #"eh\0\6\355\243L\376\321\375\255\237" + #"\251\177\366A\361\354[\26\35\177\216\f" + #"1\333\326\342\374\23g\2P+\253F\17\235\270\3\310j^\213!{\35K?" + #"V\30EQ\340\344c\242(\212\342%\214^R\24\345\361\362\335\27" + #"\367o\311\373\221\366;(3\331;\316^\30\250\225\357}\315\233\356\364{?\273A\5\301zm\337" + #"4<_\262\232W\3509\345\274\347\376" + #"\362\367\373\212\2424\346\336~\356e\352" + #"\323\244\343\352\177\264}u\352q\364z" + #"\367\vjs\364\252\365\31\"{\a\217" + #"\376\363\301\377\16\217g(ZX\276\333" + #"\261\365\371)\371\356S\fd\306|\361\354[O\275G\376\22\263>[\327ja" + #"\371\211\242\274 \212tH|p\362\245'\212rj\364\3223F\373]\377\17" + #"\345\367%\377\3\375'}}\352Gu\327\0\0\0\0IEND\256B`\202" +) 0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 10 #"schemelogo" +0 0 4 3 1 #" " +0 3 21 4 1 #"\0" +2 -1.0 -1.0 0.0 0.0 0 5 500 +( + #"\211PNG\r\n\32\n\0\0\0\rIHDR\0\0\0#\0\0\0!\b" + #"\6\0\0\0S\21\22R\0\0\t\37IDATx\234\215\230\355\217U\305\35" + #"\307?3s\316\271\367\356\335\275\273\v" + #"\253\b,\312\302\212\201U\360\241\21\305" + #"\207\264\325h\32 \230\22\215iL\214" + #"&j4\276h\323\244\370\302\27\375\17" + #"\372\316DSM\225\264\232\232J\211F\32\324H\224\224\4\253R\352BQ@)" + #"\320]\330e\357>\334\207\3634\363\353" + #"\213s\356\303\"&\235dr\346\356\335" + #";\277\317\371\376\276\363\2339G\375\362" + #"7\277\23ZM)\20A\20\24\352\212Wk5\270\"F\227\231\2366$q\211" + #"b\1\2344\350\355kR.\247`B\322\324\2*\2336\377mk|y\34\224" + #"B\304\341)S\4\4\245\24\2277\311" + #"1\25`J\203\364\226\207\270\252\177\220" + #"B\241D\217\257\251/X\16\34\260\354" + #"\371KB\24\305\24\213\21\245R\215\25+#\206\257\255\263zMHO_B\222" + #"\350\305\363\251\356\30\222!*\360\264)" + #"\0\322\276\213\356\261B(\307u6\272yF\3725+\276\371\214\312\344i\274M" + #"c\360\353_\221\6\36;w\326\331\264" + #"\251\311\213/6h4\f\365\272\342\342" + #"\305\2\343_\25\251T\32\254\37\253s" + #"\323-\t\345\212AD\345\301\311\5\320" + #"\355\210\210\340i\343ga\363\177\312\25" + #"\4\5k/\234\344\247\37\274\305\365S\23(\233@\243\231}\361\327=P\352%" + #"\330\265\213\300+\361\364\323\v\34:\344" + #"\261g\217!\b\f\3064\20\21\252\325\200\277\37T\34\37op\317O\"\326\215" + #"\371X\347ub\344\361T\256\232\271\353" + #"\307\17\377\26\245QJ\347\3713(\317\343G\307\16\262s\357\357Y13\215r" + #".\303\17\2\360\375l\206\317?\207\a\37D/_A" + #"\261\35038\b{\3668\254u(%(%h\355P" +) 500 +( + #"\312\321h\b\247Oj\302F\235\325k\3\224\th\305$\357Z\e\264\322&\3" + #"\321\6ez\177\2164" + #"\211;1\333W\203\316\b\r\n\215B\263\376\304a\266\376\355M\nI\2\236\a" + #"Zw \272\273\347\301\241CP\257\3P*\5<\372h\17P\4\n9\210\1" + #"4\240Q\312\a\204\243G\2\16\35\230F)\227{S\203(\4\320*7\253 " + #"\364W\317\363\263\17\377D\311\246\231\22" + #"\335 \227Cy\36\234>\rSS\355\225\261}{\201\221\221\"iZ\310\325\361" + #"Q\312\344P\6\245\3638~\364bf]\2251)\24\272=\223" + #"\265\334\371\351^\256\231\257~\37\244\265" + #"\26\273\307Zg\252\324j\355)\206\2075;w\3728\347\347J\264@Za\262" + #",$\211\346\320'5\32\v\v\371\252\315\352P\e\346\252\211S\334|\342\37?" + #"\f\320]\34Z\313\241\247'\353\235/x\3541\217e\3134i\252sUt\373" + #"\273VZ\264\206\352L\221\361\177N\243" + #"\273\212\241\26\21\34\302\372\243\2370\220" + #"\304\35EZA/\277\266\306i\n\e6\300\312\225t\267\2611\315\266m\6k" + #"U\333/\235\32F^\\5\"p\374_u\302fGY\215\202\240Ve\315\231" + #"\177\177\337\244W\2\352Vg\307\16\bCx\371eh6\363\354)\36y\4*" + #"\25\205s\335\0\212\274\274\265\341f\253" + #"\232\363\337\235\a\322\34\6\350\235\271\300" + #"\322\331)\376\357\226\24602\2\17?\f\257\274\2\317>\vo\277\r@\222\n" + #"\e7\n[\266\bI\"]?\222\256\236\335K\222\30\316\237] " + #"lLw\301,\\\242\344\354\367\357\376\207Z\222\300\223Of\343\327" +) 500 +( + #"^\313\256/\275\4\325*V\24A l\333&\370\276\344\225\375J=\263\335\314" + #"\214\320\250M\223\304\215\314?\305\352E" + #"\364\17\201\264\352v\353\32\30706\6O=\225\25\275\223'\241T\202/\277D" + #"\366\355\303\32C\263i\271\343\16\313\330" + #"\230#M\35\320\352\262h,\342\b\233\t6\265D\315\331L\31\325l\222\212," + #"\16|\371g\0\3472\365v\355\312\0\336x\243\343\2574\305\275\371&I\265J" + #"l\35\275\275)[\267\246(e\21\261m\b\221\305Pij\21\21\242h>3" + #"pT\352\241\336\255\304\225\300 3\351" + #"\326\255\231W\366\355\203\361\361l\277\22" + #"\1\337'=x\220\370\360aR\21\302\320r\367\335\226u\353,I\322\201\351t" + #"\vX\264\1\248\233f\312\324\372\227" + #"2\3\304\335\201\273\25\201\314\264K\226\300\v/dJ\354\336\235\245,oVk" + #"\302\2719\242\275{\211\223\2040L\350" + #"\353Ky\340\201\4\245\322v\360L\25" + #"K\266\202,\205\202Ck\335\332\30\240" + #"\321\1775S\332\260p\2712\335=\f\341\211'\340\326[\341\360a8p\240\255" + #"\212\0\21\3204\206h\377~\342o\277%\26\241\321H\330\2749et\324\222$" + #"\335@)\"\26\245R\6\6\25ZkD\362\n\34\r-grp\31S\316\321" + #"\274\22H\34\303\2325\360\374\363\231\f" + #"\257\276\n\263\263\331q1W\264.B" + #"\323\30\302\263g\211\16\34 \266\2260" + #"\214)\225\22\356\273/Ek\213s\255\364$@\202\361\32,\35R\210d\213G" + #"\3\270\236\n\27Vo`Z\204I\21\"\347: \316e0\317<\3\303\303p" + #"\364(\274\367\36\4A\246\210\b5\21\352@C)\232\316\21~\360\1\321\314\f" + #"q\222\320l&l\332\2240:\232bm\n\304\210$8\227P\251" + #"\204,\31\352\3019\207\322\232\366\271\357\322\206;9\347\27\230\20aB" +) 500 +( + #"$S\b \212\340\346\233\341\361\307\263\317\257\277\216LN\22kMM\2049`" + #"\36\250\213\320\20\241\351y4\217\35#" + #"\372j\234\3309\3428\241PH\271\367" + #"^\213\347%\210\304@\204RM\326\214\32\312\345\"\3169\214\361;\ee\264r" + #"\224\263\3537sI\204s\"\234u\216" + #"\31k\t\201\370\271\347\210\206\206\b\277" + #"\376\232\332;\3570\353yTE\230\21aN\204y\21\26\240\255NX\257\23\36" + #"\374\224(\212r3\247\254[\227\260jU\204\265\21\"1\225\376yFF+8" + #"\311N\230~P\312\353\214Rh\343Q" + #"\335\262\235\263}\203L\345@g\242\210" + #"\377\336~;\323\367\337\317\314\334\34\323" + #"\273ws\351\314\31f<\217*,\2\251\265|\3\204J\21\379Bz\361\"" + #"i\356\35\245B6n\fsUf\271qS@_%K\2216\206Bi \253" + #"\300BV\266\355\320J&\356\377\5\27" + #"\214\307\224s\234\367}\376\263c\a\347" + #"\353u\246\307\307\231\335\263\207Y\245\230m)\2,\344\236i@\6\"Bl\f" + #"\361\205\vD\307\216\21\245)\315f\223" + #"Z\255\311\360\252\210\201\201\32k\257O" + #"\30\275\341*D\f\210P(V\360\2032^{3\315O[\361\330\26\316U'" + #"\211?\3723\225[n\24162Bib\202\302\307\37\23\2348\201\366\274\254R" + #"\210\220\266\327\5$\"\355q\254\24q" + #"\232\22}\361\5\341\310\bQ\30\22\305\21iTe\375\372\32\327^\277\nc\2" + #"\254M\t\202\"=\275C\b\n\257\275\253\347\n\241\24\315;\267s^)\232\253" + #"\373\351;w\216`|\234\340\335w\361" + #"\322\24\343\373\350\274\266H\273t-\206" + #"\212\201H)\222S\247\210&&\b\v\5\346O\235bv>f\355\3721\n\305" + #"\36\254u\370^@_\377\n\264WD\221\35\341\351" + #"V\a\300\363\2\354\335\01719\365\r\v\177\370#" +) 392 +( + #"}_\217SH\22\214\347\241E\350>\235t\n;m\245R\21b\255\211\347\347" + #"\t\367\357gf`\220\270\260\204\342\350M\4\2052\316Z|\277@o\377r\214" + #"_\316\n\247Ry\232Z\255\253\372\e420\302\354]?g\241w\210\322\211" + #"#\24\347.\21H\366(\254\0Q*\333iD\26\3\211\20\2\363\2452!%" + #"\314\360Fz\227\255\314B\211\243P\352" + #"\245\\\271\6\343\225\262Z\226\317\347e" + #"\351\311\36e\263\263mN\2432\205\314" + #"\362uDC\303To\334\214\376\3568\376w'P\323\223x\315:\244\t\210\303" + #"\265\24\361|\242\240H<\260\24\273\342" + #":\364u7\320\263\344j\214\3268\233\342\a=\24{\6\bJ\3he\350n" + #"\322J\223\312\326\367e\362\250\266\251\213" + #"~\31\177\370F\222kF\211\306\356 " + #"\235\233\306-T\241\276\200\213\233\210\b" + #"\342\371H\261\214\352\353\307\357\351\303\317" + #"\275\245\225\306\363K\4}\275\24\n\25" + #"\264\27,\202\350>\320y\213\361\272^" + #"S\344\362u\247\315x=\24\6\256\305\366-'\265\0216\rq\316bm\214\270" + #"\354\25\210\"\3\320\332\307\363\vx~" + #"\t\343\27\263G\331\326\363|~\313\"\16\205B\345{\\\3073B\236\273\305 " + #"\355\3673\252\363\236\306\363\2\367\244?\356\264" + #"R\225\37\366\271\207-o\234\207\203?" + #"\354\275V\255\n_U}\365\343\177\366\267\376\246\326ZDb\214Z\353<\317c" + #"\214u]\267mk\2555\306 \"\21)\245\20Q8v\365\226\20\4\220\231\231" + #"\31\0P\e\245TL\302\314Q@D\0\25\21!\"\0z\27\1@D\4\"" + #"3'v\34\223HJ\34DD\1*\245\24\31\"\2 \221\4\22\215U\332\32" + #"D\364.z\357}\212\"\222ey\21411\23\221\b\246\224\20Qk\355\373\240" + #"\224B\224\224\222\367>\245D\n\264\326e\226\305\30Y\"\"2Gf6J\e" + #"c|L\"2,^D\264\326yVfY\346\234\323Z[\233!\242\210\350," + #"\313\224R\303\207\206\227\206\347eY\246" + #"\265F\304\233\267\20Q\230SJBD" + #"\204\214\300\f\tD\245\204\210\"\240\265" + #"V\244B\b}\337\207\30\25je\264\241,\t\203$\26\1I\nI\31\0\304" + #"z\335\2\0\20!\242R\214\250\20\1@\25y\316\22C\2141\306\24\5\21\213" + #"\242\320Zo\267u\214Q\0\224RD\372\271\334\301Z\313\314\314ID\2141\306" + #"\30$\271>\t\271\376g\220B\224\210" + #"\210)\361p\322\303\327\211h\320\211\20" + #"\2\0\20)\245\224\210h\276>\1\341a\317\"\303\377Y\226\rB" + #"\31\3442\334\202Y|bC\n\220\6\5H\"\2\202\4)%f" +) 500 +( + #"F\214(b\25)e\24(!$I\f,)%\366\220\"\0#\t\"X\255" + #"\207{j\255\2551\306X\"\2\200\355v\2434*\245\2546I\261\367\276\253]" + #"\2141\257J\21f\26ED\n\207E1\263B\22I\203\346j3\234\330\247\366" + #"\2\327\242I)1\262 \210\340\240\373\303\343\6U\2101\306\30\a9\\\257*" + #"\2040\250\3\0000\363 \266O\v\353FR\327\17\3bR\232,J\20\214\302" + #"\2\0\303\263\235s)%ku\231W\332\220\367\336\365AH\220\31$hH\214" + #"\2 \b\200(\263\311(JD\306\4\202\222\274w(\222D\214U\303\343\206{" + #"j\255\25\231a\351\314,\2\210\250\210\0 \306am\327\352L4(\1\212p" + #"J\t@\230\31\360Z\323\207k\20\304" + #"p\347O\2778\274>\270\213\301u\350\301P\225R\327\36DDD\210(\306x" + #"\243\215\303\367SJ1F\324\6P1\20#\t)\200\353\273\247\350\21X\21 " + #"\260\244\20\22\a\357\243\367EQ\21\t" + #"\201$\226$\234R\210)\b\244\305\3716\244\30}\362!\244\30c\222\24b\22" + #"\316\363\334Z]\24UV\26y\236\17rAB\357=\247Dt-5N\211S" + #"\24\21dQJi\243\a\375O)\245\24\231\323s\2370lX\17\2333\3060" + #"\303\315y+\245\210H\221\32\366\253\265" + #"\326Z\17r\320\203\276\r\322\271\221\345\24027r\271>\bDF\"\322\0\30" + #"\a=\345ka3s\337\367ef\213\262D\220\20|\b\201\0\313,C\341\224" + #"b\364\276wm\323l\333\266\356\373>D\277\\.S\n\314\300\2\4\b\244P" + #"@\20\236l\267\332\230" +) 500 +( + #"\v\0\2641&\306\350\275\277\t:\327oh\315\3141\306\e\a6|\200\201b" + #"J1\306\304\21\5\b%%\36\354\16\08EBA`\220\20C\f\"\365\246" + #"\211\311;\347\272\256i\272\246\353\32\357}L^)E \bH\n\2552\244\215" + #"&\22TUUu]\267\331l\316\317\237i\255o\337\276]\330l\276;\253\353" + #"Z)e\255\"\302\224\4\231\25\340\240\a\34\243Oi8mMJ\220\5\243\326" + #"*%\341\3476\16\0\210\nQ1\207\e#\240\347\27\"\32cnD#\"\272" + #",\313\276\357\235s7;\277\321\232\30" + #"\343\340M\207=\17G\302\f\201S\f\201SDD\255\20A@\322\316d\334\265" + #"\315v\263\322\b\231\265\22\374\372j\261" + #"\\-\326\253\r3\v\247$q8\264\322\32P\246i\32N)\204\20\22\327\t" + #"DPD\230\5\210l^\224e\231eY\337\367ggg\313\345:\377\243?\272" + #"s\347\304\346\371x<\256\252j\210\230" + #"\326f\271\265m]\207\340R\222hU\201\225\322\210$\22eP\37\21\276\tI" + #"7\36\363\32^<\227\313\240\a\203\\\6\335af\r\0CH\16!\334\204\253" + #"!\22\r\2177\306\f\212\23c\f,\2\24\235\17\336+E\231\325\n\304\365\255" + #"k\233\320nr\2435\244\365j\265^.\353z\3235m\337\367\207\207\207D\244" + #"\25\242\202\20B\327\265\316\271\224x\\\225!\4\257Td\30\300K\2141DF" + #"\245\275\367\233U'\bJ)B\354\332z\275^\2@Y\226]3+\252*\313" + #"2c\214R*8\327l\327\243\252\250\212\212!E\337\373\236SJ!\204\353\340" + #"B\370\263\250L$\237\322\221A\")\245\e\17<\4\226ksi\232\346&\30" + #"\335\204\267\e\27=H\347\306Q\1p\337: 4\32\231S" + #"\3378E\220\e=\336\235\317'\325\343G\37=\376\370\243f\273" +) 500 +( + #"\321Z\217\212\374h>\317s{~~\351|[;\347\203\23\21\255\251\310s\223" + #"Y\347\0343\22!q\212\221\2319F\216)\205\266K\"\"HD\300\2\204\3" + #"*Y\\^5E\263\331\324\303\36\262" + #"\242\330\335\335\335\231\216GU\321\266m" + #"]\327eY\226e\311B\336\203\210L" + #"\247\323\276\357\333\276\2131*\245\254\265" + #"\2028\4\223\e\333\31v\215$\203\216\334\354\24\21u\baP\236\e\17:\370" + #"\24\2555|\352\272Fw\"\343*\353" + #"\373>\4\247\211\212\302\32\2558\205\3307?9}\264Y-\255V\267\36\336/" + #"\254Y,\257.\317\317\272\256+\212\322" + #"h]Mg\2440\306\330\272\266m\333\345zaL\26B\350z\337\367\256\355\275" + #"s\22\"0\303xl\a[N)y?`\"\205\212\332\266\355]\253\310\240\"" + #"\"\312\363\334\367\375z\231\357\316\246)" + #"\5kmJ\341\352\352\242\357\373\361dvtt\224\347V$\265}\27B\30`" + #"\22\0y\337\251\347\301\367gQ\211`" + #"x\334\215\36\0\200\316\262l\20\336\215" + #"\227\276\t\3577\342\270\201v I+\310\24h\243\224RZA\f]\263\336\324" + #"\365\206@\200S\360\375\371\351')\206" + #"\340:\255\365\341\376\2562\231snS" + #"o\266\333\265\367\36\21\205D\0206\233+$BT\332\332Y^*\243\215\316\224" + #"2\27\27\27\210\327\353A\2210\34\240\310tm5D4\374\177c+\332Z\3733u@$\"c\314M<\32,\360\306" + #"u!\360fu5*\362\252\314\373\276_\234_\256\327+\210I)\\\254\26;" + #"\223\361\341\321\201\325\24B\b\256\17!$\1\322" + #"\266,\313\235\235\235\224B\344\24\243o\372\256n\233" +) 500 +( + #"\375\315\301-\r/\216\252\242^-\26\213E" + #"\357Z\243\364lT\20\221p:z\370" + #" \270\256\353\272\24|\b\272\357{\255" + #"\260(\212$\220\227\243<\267DD\32\23\310f\263Y\254\226J\333\224R`I" + #",\314\320\373\30|\360\336\347\312\0\0" + #"\21\212\b\260 \241\266J)\305\t\24)P\244Tf\255\r!\304\224\272\256\233" + #"\214\n@\346\230V\253U\333\266\27\213" + #"\313\303\243[\273\273\2731-\333\266\r!\355\310\274\32Ool\344\32g1\17" + #"xu\200&\237\226\321\265\35!0\0 \374\314\e\337`\301O\333\e\242 \n" + #"\202tM\35\203C``\t\241C\266eYfe\321u\335ry\325l\2671" + #"\372\20BJa6\235\336:>i{\37B\252\353M]\3276\317\366\366\366\216" + #"\217_\270}|\262Z\255\6\235\0\322J)f\30`\324\307\37|" + #"h\214\261\326\16\253\264\326\216F\223\254(\332\266].WW\313E" +) 500 +( + #"J)+\252,3\340\261k\373\0204\0\214\306\245\321\231sn\273Z\17\325\222" + #"\351d\364\354\354bS7\326\352\252(\225\321\2?\253\31\b\243\0#( \205" + #"\210\3n\277\21\212\210\350L+\0\b\201\223\\\eQ`\31\n\31y\236\e\243" + #"X8F/\220\214\326Y\226\257N/\257\316N\253\252\"\1\321\246\17~V\314" + #"\235\357\227\313e]o\234sYf\246;{E\231\221@\343[m\362\266w\312" + #"\330\375\303\243\20\302\351\351\0313\347U" + #"\271\\.\255\311\210\310\373\350\234\273I;vgc\347\234w53k$-\5" + #"\3456WY>\316}\247V\222\252q\331v}U\25>\6\255\311\32\245Q\205" + #"\20\"\342h\\~\374\361\343\361\270z" + #"\366\344\311t:\275u\260\37c\374\301" + #"\17\337\235\224UUU}]\37\237\234" + #"\364\236\233\266A\244\262,\204\b\20\31" + #"1\3054\304mE8\304&\35\274\263yV\24\5\305\324\2730x\31\21!\245" + #"Hc\214\321\265\215@\312\214\2111\324" + #"\313\325\362\362\274*\313\363\363s\255\365" + #"\255\343;\0\274\\.\17\217\16\272\256" + #"\v\301\345y\276\273\2733\231\216\272\256" + #"[\\\234o6\365v\325\326u\335\266=\242\30\223\r\231\224s\260\273;j\21" + #"!\311\200$\207Z\217\210\244h\b\271\2626/la3\21\251\327\227\247\237<" + #"~\345\225W z\220\200\234\b\5\205" + #"\201\0233\257\327\353\371t\222\347y\323" + #"4\a\a\aE\221\365]\227Y\273^" + #"\257\263,+\313\362\341\335\273\347\317N" + #"\253\252\322Z\327\333-\250Lk#\"!D2\32\211\342\20\241EX$\245$" + #"$\304\242cb\203D\306\22\273\224\222" + #"\213\201\231\211@\204%1\a\2378\24Y6\256\212\355v\3334[c\314\266m" + #"@\301\321\235\243\272\336Xk\233\246\371\360\247\357+" + #"\245f\343\311|\266\2434\236?\375\344\343\217?\366" +) 500 +( + #"\241\257\312q\225\331\223\243\207e1\352" + #"]\333\324\335\215;{\374\370qb\226" + #"\224\20\261,\313\361x\234e\31\3l\353\365d2)\313rp\371Z\353\235\331" + #"\204\23h\205\nA\223\22f\22\340\230" + #"\24\"\201\324u\34\25~\360\265V\321l\270\213\213\213\272\256" + #"\263\242\30\215\306J\333\325v\263\331l\252,s))$`6JG\2453\355" + #"\235s!\204\242(\26\213\305l6[m\353\246i\246\323i\327u]\357\307\343" + #"\361d2\21\21c\314\266i\1\325T" + #"\333\233\242\324\247\262J\374\31\262\a\322" + #",\350\23Cb\237\230H#\221\"\0" + #"\200\302\232\276\3575\2005\332\367\335\371" + #"\263O\316NO\233v\353\273\366\341\203" + #"\a\273\273;\227\227\227\325\250\374\350\375" + #"g\34\323\v\307\267]\327We\236i\303)\220@\n~\261X<=\377\350\326" + #"\255[\2208W\224\372xuz\212\210" + #"G\207\a/\177\356\315\321\250\264\326\26" + #"6\313rS\225\343\351l\\\226\245R" + #"\312\346\271\367~\265Z\355\217G\244U" + #"\226eu\333_\\-\216\217\16\233\315" + #"\266\3364\213M\215\244\200%\267\31p*s]o7\336\373\275\275\275\17?\374" + #"\360\2157\336\230L&\253\325j>\237\23Q\323\366O" + #"\236<9::Z,\26\321;\205\3205\2552YU" +) 500 +( + #"U\332h\200\233:$\17\350\204@1\263\240\350\300\211\242\0\200RJ\233\fI" + #"R\210\316u&\313A\222B \24\327\324\313\213\213f\275R\32wvv\214\265" + #"\325x\264^\257R\343Q\370\336\v\307\207{\273\365zSZ\23}X,7}" + #"\323\26Eq4\337;>8z\364\321G}\333*\245N\216\216\216\337\371\302\356" + #"|6\32\225e\226\37\34\356Yk\215\321\nI)e\254\"\"\6\251\267-+" + #"*ig>\256\210H\0007\266!\200\254\250.\236\235-F\343\272n\25P\2" + #"\261F\v\333\274\320m\263\5\200\311d" + #"\342\34\307\30g\343\311j\265\362\336\217" + #"\307\343\262\244\365z\275\263\263\263\335n" + #"Edgw\257\353c\275\331\344\326\226e\351cH\b\326f1\245A\2(\224" + #"RJ\234\264 \b\16\365z!H\b4\24\301bp\n\1\205}\337\267\365:" + #"\371.\327h\213|4\235v\336\265m" + #"\233e\331\371\325\342\356\311\311\253/\277" + #"\224\\O!\370\256%\346\343\303[\4" + #"\260Y\255\317\317\3167\253\365\361\355[" + #"'\257\277\376\342\213/\336\272}8\233\315&U9\32W\271\315R\n\210\b\310" + #"\300i\370\307{\337\367}I\25\3z\357\267u\275^o\233\256M\211gen" + #"\212\242\312\3632\3174\241V\312G0J\ar]\327)\245\254Q)\372\3314" + #"\277\274:\237\214g\32!\204\220R*\213,\6wuy\216\300u]\317\346\273" + #"ya\257\26\253\311d\244\315N\323\5F(\313*\306\b\"C\356\r\0001\260" + #"\36\232$C\223\1\0\264&\2\324\206\24\0i%!m\267\333\315b\345\273\226" + #"SL\301\337\275w\262\177xx\372\364i\baT\26\243\262x\377\307?*\214" + #"\336\333\231\247\256u}\277m\332f\3338\347^8>y\375\353" + #"_\177\371\301\375\375\375\335\331l6\300\274\254,!\371z\265\234\224" +) 500 +( + #"%\247\20c\22\5V)D\352bH\234RJ\256m;\347\25\300tT\24\271" + #"\355]p\211#\200&\260\204\232\0\225N)(\24\24X/\27C\335\274m\333" + #"\331lvz\372\254\310+\"\"\1\347" + #"\234\265\266\252\252\305b\261\277\277\277\331" + #"6\321\273\361t\36\234O!j\244\350\3\20j\244\2334\32\1E$rR?" + #"\377\365\2579\327{\357\264V\271\265\b" + #"\200,\210\320\326un5\1\177\357\273" + #"\337\336.\27mS[\245\347\273\273\236" + #"\323\223\247Og\343\t\241@\f\213\313" + #"\363\351\250\332\254\226\311\371\313g\247W" + #"\227\27\222\322\341\321\321\347?\367\271\257" + #"\374\311\257\274\375\366\347O\356\34\215G" + #"\245\265&3F+%\311\263w\212@k$\205\nA8\22\202R\250\21\t@" + #"\30\254\326Fk\340\24\274\363C=\210" + #"h\265^\367\316\231,\377\301\217~\270\177pk2\235\234\235\235=xp_\e" + #"]\327\e\37\302\311\311\311x<\366\336" + #"{\327Of\23\357\274\"\234\314f\314\\U\325\345\345\345d2VJ\eem" + #"fb\f\275\353\212\242\260\231\361!\20" + #"`\357\34\202R\312 \22\2i\205d\214R\230\223\2a`\211 \254\0w\246" + #"\23N\341\374\374|y\265\300\24\247\223Qi\255R\252o;TT\26\371\273\177" + #"\370\335\355rQf\252^\\\276\372\342" + #"\213\355fk\215\232\336\276}\357\205\273" + #"\257\275\366\332\275{\17v\347{e\236i\225\bD!\21]cp %\21\340" + #"y\316\246\206R\210<\307\326,(@\0JQn-*\212L\t\320\271\263\266" + #"\256\243\v\17\357\335_7\315\254\332'`\357\272\334\32k-\vt]W\226\345" + #"\336\336^\337\367]\327\r\317rm\307" + #"\b\314\254\224\352\272.E\26163\312\2@\327\264 4\236N\200\250" + #"\17\2352\371\220$_\367\333Rp\204\2405!BH\21R\2\26\324\332" +) 500 +( + #"\30s\265\270z\364\341G\315\266.23\235N%\4\16q\3334\367\36\334\377" + #"g\377\364\377\356\266\253\243\375=\327\324" + #"o\276\371\31\203`'\243\275\371\311\311" + #"\311\335\a\17\36\334\273\367`o\367@\20}\337+\f q\220\1\20\202\0#" + #"\b\241\322\n\204\1\24\211\32\3407\3\2) \4!\"\245\265\21\1&\204\204" + #"\bh\225f\216H\362\231\327_\373\316\367\376xg:)\212\234\b\1`@+" + #"\336\365F\253\252,\224R1FD$M]\327\224e\231b\250\362\254\363\301\261" + #"\333\254\326;\273\363\314\26.\6\"*" + #"\212\2H\273\340\255\265\317K\237BD" + #"\332\365\r\20\352\353\5%\2\24\4\340Xo\273'O\37}\362\311'Y\221\27" + #"\231\325Z/\226+\335;[V?\370\303?Z\\^\31\344\375\371\356\375\267\336" + #",3]Zc\225~\345\245\227_~\371\345\361t\2\244\35{\2453\225k\205" + #"\0L8\24t\256\5\1\242\30H\303\265\332 \2444\224v\1\2252F\200\221" + #"\201(\1i\22\0a`\30\215F\323\361$\325\355t6\331\333\237\217\306eY" + #"dY\226u\256\37\312q\0000\364\216c\342\262,\273\256\323Z\367.\fa\270" + #",\313(\240\224Z\257Wy\236g&/\263\274(\nc\f\0\31\245scA" + #"\321\200c\24)M\302\3140\24W\24 )\2121E\37\353\355\372\364\364\264m" + #"\333\303\203}%\274\\\254\317\317\317G" + #"\243\221\356\375\305\331\351l:99>" + #"\32UEU\344;\343\262*\213\375\371" + #"\356\375\207\367\357\234\334a\304\266sL" + #"\230\345\23129\260\3\t\220\30D\0\360\271\245\bD\6\1\0\6R\200)\205" + #"\300\300\250\2204\242\4`\1`%\212" + #"I\31\212\302\222\225\305tg\266\351\373\345r9\235N\231YkR" + #"\n\347\363\331j\265\270\301f)\245\276w\3\3527\306\204\310CH" +) 500 +( + #"1\306 '\245\264Q\252\256\267D4\231Mc\364\253\325\nQ\r\3111\262\0" + #"\b\t!*\255\25\0\241\b\0\263\b\1$I\34ctmWo\333!mi" + #"\273\376\262\256\233\272-\212\242]\255\252" + #"\242,\262\374\345\373\0175\244\314\330\373" + #"\367\356\245\344_y\345\245\203\203}\3143\5X\331\214\262\f\310\2{H$\t" + #"\0A\0\b\257\335\n\0\202\b\260\2 \0\4aN\314\4\204\203\224\4\211A" + #"XYA\320\2123-\3348?\235N\227\333\372\321'\247d\262\310q2\231(" + #"\224\303[w>\374\360\303A;\6\304\\7\355\320\366\31 I\337\367!\204\246" + #"i\206n\352\356\356a\327um\333fE\16\244c\333(\235\227\243\221\367^)" + #"\205h\0\4$\321u\237\20\21\230cp18\201\204$\353\365:\204PU\225" + #"sn\2500eY\246\265\35\225U\327" + #"\266\257\277\374\322f\265 \204_\370\371" + #"\257\306\30>\367\331\317\336{\370\260\334" + #"\335\205<\203\334\322\250\204\"\aB\317" + #"\311s\f\222\34G\307\321\245\350Sd\1\26\0R\214\4J\203\326\2404\240B" + #"\322\240\ri\213\3120\320`V\204\232" + #"\210\206\232\256\265v2\231\24E\261\331l\210\340\340pOD\212\242PJ)\20" + #"\211\1\0\262,C\220\241\207\303\314\3\256\311\262l(J9\347\206^y\bC" + #"\32H7\275\221\241\204\220@\30AD" + #"\250\353\232\241\365;|z\310\353\264\326" + #"\253\325*\204`\213\334\307\20#\3@5\36\31\243|[\277\361\342}\r)\272" + #"\336(\344\230\366\367\17\366\17o\301d\6\325\b\254\5m\0PBbd\223Y" + #"$BPCO\v\361\232\212@J]\327\323\205\0005\247\265\316\213\261" + #"\331=\2&\360\f^@\b\224F\253\205\220E\214\316MVe\37187\225E" + #"\203\21$0\4\6\1\22\0\357\270\251" + #"\271k%\206\344\372f\275\362}\253\t" + #"\252\"+\213\314\32e\254\32\22\227<\317\1`ggg<\0363\363\243G\217" + #"\272\316\205$\37|\364x<\235\353," + #"\23\"\227\222g\236\357\355m\233\246\355" + #";\322\252\256\333\252\32o\326u\225\217\220i:\236Yk\2652}\357W\313M" + #"\327u)\245\224\222R\252(\nD\344" + #"pM\272\320\306\346Z\333\341\275\201\25" + #"\221RJ!\326u\235Y\233R\252\252" + #"j\273^\221\202\275\235\371\343G\37\374" + #"\2117^\335\31\345\357\237=}\370\322" + #"+\363\331\364\344\316\235 \0006\207\315" + #"&\21\b\"!\222\202\353\352\254h\b" + #"\f\f\220\4\30\204\t9\245\310\230\222\322\6\22sL\302\f)\32$\235\333<" + #"3q\310\364Q\n\310\254\265I\270\353" + #"\373\276o\233f\233R\34\345\371\336\336" + #"\336\376\376~\323\366\353\365z\261X9\201r25Y\221\4{\357\334\325B!" + #"\331<\207\4\bj\320;`\t!$\237\2048\261$\20f\361)\2\200\3152" + #"D\205C\364\1FP\314\21Q\310\332L)M\244\224\322J\31D\205\2\"R" + #"\327uQ\24\311\aM\212}\34\345\331" + #"\301|\247Yw_\375\312\237\352\333\246\331\326\367N^\30U\325\316t6*+" + #"\330l%1\n\350\301F\224\6e\310\0304F@$\t'\201\241W\366\\\303" + #"]\333F\37A\4Y@\4\22#\v\t\210H\340\24" + #"\205\205p\21081\306\256i\255\326\326\30\205\224\333l" +) 500 +( + #"R\215D\244\2567)\270\325b\351\273\336\373\30B\222\4\333u}\265X%\1" + #"e3P\332\330\\+\233e\5>\247p\335\364\211\6e\311\363\274(\212\233:" + #"\377\315E\302(\214 Dx\355\201\224R\271\261\301{C\b\302\256\251A\340`" + #">\347\20N\216v~\351\353\277\260\272" + #"\274x\351\301\375/\177\351\v\267\17\17a2*\247c\210\16AH\0\20A\0" + #"X\200\31b\2fad\6f` P\6\264U\332*\245\243\v\300B\332P" + #"\226+\245%\261\357]\327u\203\377\223" + #"\347T\247\201S\340\234#\"\255\t\220" + #"\255\246\331t\242\25\272\256\221\24\215Q" + #"!\204\305\305\345z\275\36|S]\327" + #"\253\345\306\365\301\365\1\200\200\224\3153" + #"\0\240\347\254\224\241[\3244M\337_" + #"c\237\377_\253d\350\223\260\b\212\0\242B\0E*\313\20G\202,\321\207q" + #"\231\365u3\262xr\353\350'?\372" + #"\341\317}\351\235\335\203\203gO\36\377" + #"\302\327~\356\341\303{\22\1B\0e\304\367C\344\25\20T)\5`\20\21A" + #"\1\3\b\202\"\300\f4|\"^\233\364\220\32\300\200<\4\206?\1D\245\210" + #"\6\213\16\"\2\310D\320t\r\n(\200\252\314o\35\36\\]]m\327\253\340" + #"\373I\265#H\256\353#\247TM@(Fn\333>\306\245\265vTV\271\261" + #"\232T\210\211\31\22'\245\224\20\245\224" + #"z\27\272\256\273\351\347\313\365:\256\365" + #"E\3078p\333\bQ\t\263\bj\255MU)\205mS\317\307\205\2\230V\345" + #"\275\333\267\277\377\255\357\274\371\372k~" + #"\275\34\217\252\227\37\276\b\332@\350a[CYHLd\324P\240H\34#\310" + #"\0\332\b\20\224\5 aN\229E\340\304!@LJ\31\216IB\0171\244" + #"\20\201\223FM\32\273\320\2030$\20\216C<" + #"bf\2\320\244PC\f.1\214\253b>\233^" +) 500 +( + #"]\225!A\317\232\265\251\212\262\351\332" + #"\266\256{\37\224\322\204\246k]\360\311" + #"\352L\4\307\245\215\221\25\22\240B\5" + #"\360\274.ws\377\e\363\271!\265h\204kx\220\"GN\314\234Ym\214\231" + #"\214\306\276\2539\372\334\220%\274{\347" + #"\350\336\311\341\e\257\275$\211\177\355\327" + #"~\355\245\207/\2\0f\31\220\2\1\3122\361\21\24\260\340\200iq\340d\221" + #"b\227\206\346K\342\304q0ZRd\24JJ1\372(a\340\321\20\242B@" + #"\26\364>\206\20$\5\"\30hQ\301'k-\20\326m\337\371\220gfo>" + #"[/w\214-\236\\n4\341\270\252b\214M\3271`\236\225\t\0205D\221" + #"\304 .\246L|L\271\325JA\344 \200C\347\343\206b\205\210D\n\0\20" + #"\324s\36\315\247\232l\314\234D\f\23" + #"j5\36\217\317\353\265\353z\255\220c" + #"\330\235\357\274\361\312\313\17N^\220\224" + #"~\351\227\377\r\0\224\355\26u.\310\251\363\240M\24\4\"QZ\20\22\1)" + #"\205H\244\320\207\0,\"BB\2L\244\214R\244\bR$$\215\32\254E\1" + #"`\221\230\"$\320:\370\350BH)fV\3)FH }\333\26U\251\224" + #"*r\314\362\252\357\373\247\2173\204\316" + #"\22F\21\205\240\20%\261\311s\245\363" + #"MS\23\352\30\203\vIR\262\326\367}\257I!JL\214\32\211\310j5p" + #"\23\256\25d\340A\242\36\312\333\224\231" + #"\34\205\206\366\310\240K!\204\336\265\240" + #"\2009\216\306U\327\245\331d\264?\337" + #"\375\267\376\322\257E\357\263,\203\20!\t*\v\240@\20A\221\20\nh\324\n" + #"13v\234\227\304\222\234\aR\231\261y^\24Ue\265)\367\16\262\375\375\30" + #"# \372\336\203\315\" \216f`r\250\252\236\331\24\245(K:o" + #"}\270Z\257Wu[7]\323\365!1*]\327\355\340\32\327\313\325" +) 500 +( + #"\250(_z\351\245\331d\252\220\26\27" + #"\347\n\261(\212\242(\352\272\326Z[k#'\322\332\205\0D\333\3556$\251" + #"\333\246\367\356\206\340CD\257\274\362\312" + #"\316\316\316\rM\350\246!\313\314z " + #"\200\340s\254\t\300\232\224\321\240\265N" + #" \333\355V)\360\336\357\316g\323\262" + #",\212b\275\332\26\271\315\362\34\320\0" + #"\342`\24\200d\225\302\262\200\24}\b" + #"\210\230\333,\204\20\267M\364^\223\"" + #"\201\24\243\252\e\320\332\26\5hms\6c\321\304~\333\364}\27c\334n6" + #"\260\331>[-@\323\325\345\371\371\371" + #"\271%\234N\307e\221\347\345h\275\274" + #"\212\314\202\b@\3\355\247*\212\343[" + #"\267\27\253f\263m\226W\227\266\254\bp2\231x\337\263\b \r^\224A@" + #"\20492*f\354\373\26\24\210\210\2656\317sk\255s\201\323ug\366\206#" + #"\244\275\353P!\">w\310\210\212\200\240\232TD\320\367m5\322Z\353j4" + #"\312\362\314\205`ma\313\22L\301>z\37\0\25j\20\240|:\1[\200w" + #"\340#\31\v\343\221\355\373\264\335\346\244" + #"\301\32@\264\230C\327\261w\224\227\251" + #"\355\352\272\316\363\\\0\267\336kSt\256n\205\232Msz\265Xm\326\347g" + #"\247!\204\371d\342\22\e\265)2;\260/\2252H8\244,\250\364\376\336\374" + #"\301\375\273Q\370\17\377\370\207\202\340}" + #"\32Mw.\267[\300\353\356*\0033cJ,\234\6\230\177\r\\\237\e\307\215" + #"\21!ifFx\336\267w\256\37\22" + #"\263!\262\n\211H\2\241\331\316\216\217" + #"\302 Y\236\217g\323\266\355\r\341v" + #"\275\234\317v\215\27\315\321\273\230\0\312" + #"2\323y\t\250\240\34\203\261\20\243U" + #"\32HAb\350\372\276\336\352\4\326h$\2R\233\325*\201\354(\263m" + #"jAj\372\320{\377\311\263\363\311d" + #"\266\332l\372\276_\254V\277\365\215\337" +) 500 +( + #"\273Z-!\305{wO\320\230\365\246" + #"\366\256\333\231\216S\360D\224X\252\252RJ9\3478D \375\302\311\35A8" + #"\273\270|zv\36\223\204\350\a\35a\24\0\24\221$,\22%\5\4N\211\213" + #"\242\20\302\276\367a`t\366*\245\244\254\31R6y\36\2324pd$H8" + #"\204\r!\21\321\28\232N\352\36<" + #"\v\241\354\355\37^\255\226\243\252pA" + #"\234g\21O\24\207\0\237\270\227&\244" + #"\224\362\365\326\30\303 \326j-\2\316" + #"C\364\271\266\353\345\231\3\262y\6\250" + #"\274s\306Z\357\\\323\366m\357O/" + #".\337\377\360\203\357\376\341\367\22\340\351" + #"\331\263\315\272\276\\^\2\362t:\335" + #"\237\317\257\326u\323\366\333\315J\202\233" + #"\357L\203\353\262,\233\315f\207\207\207" + #"\343\361\230\264\361\235G\235\262<\273u" + #"\264\377\331\317\274\272\334n\330\205\276o" + #"\255\315\352\316\3*Aa@z\36}S\n\201\240\322:\n\3035\237\236\206x" + #"\244\340\232C8\30\24\21ic\24\"\16)\3##\b\242\b\321x:\2619" + #"0B\210q6\337a\1\1\212IZ\37}\"\255\255\326\6Q\325\255\367\336\207" + #"\20\326\353\365x<.\252\274,\363\221s\211C\327\324\4\22\233.\0WE\321" + #"{\207\314u]\177\353\17\276\373\341\243" + #"\307?\371\340\343M\333^\256\226\313m" + #"\235\227U\335\273\316y1Y\3275\373E\31\1\36}rZevT\344I\344" + #"\311\323\323\340\373\"3C\226\177rr" + #"2\360\16\2251\333\315\312\226\305\313\17" + #"\37<:}\366\344\354\352rSk\255\0037H\210\200\200\300\310H\22!\1\0" + #"sr\316%\270\36;\250\252*\201\08xN/\24\271\256:kk\224 \0" + #"sB\270f\243je\214\321 \373\373S\210)\t'\220(\374\361\223\307" + #"?\375\361{\231\255\20U\221W\343" + #"\361X)\35\375u\325\343\350\350\350\344" +) 500 +( + #"\205\343b6\5I \2\241\267\2101\364g\317N\273\355&8\377\354\374\"\2" + #"v!\374\306o\376\346\207\217\2370\232H\3308\257\263|\261m\266m\263\\m" + #"\262,\333\31O\31\310\205\230g\371\355" + #";w\366\367\346\276\335\256W\213\315r\211\300u\333?~zjM>\233\315@" + #"\351\212hp\26eY\276\370\360\376\325\272VM3T\5BdP\244\210\2114" + #"\360\320ce\21\t!\304\201!?4^\257\305q\303}\302!\376h$\315 " + #"\202\0B\0B\327\3543\325u<\231" + #"\314V\347\347\224d\261\331n\333\356\321" + #"\207\37|\363w\277Y\225\323\266\367\"@Dm\333o6\eCj6\233\275\366" + #"\352\313_z\347\235\a\367\357j\302*" + #"\327\323\321\b\221\25\247*\263W\247M" + #"\3234\337\373\301\273\243\331t\272\273\347" + #"\373n6\36]\2557\"\272o\353\21\r\337\310\0\0 \0IDATBQ" + #"\263i\1aR\26'''\223\311\304" + #"\32=.\213\303\203\275\235\361\250\336\256" + #"\372\336\217F\243\335\331\216w\375'\217" + #"\0375\233\355\325\325\25\"\26EUX" + #"S\24\231\0\307\340\17w\347\222\234\2q\301\0276s\276CBA\r\250\0\31" + #"Q!3\212(\245BH.\270\276o;\327\6a\237\274\305\302{\27cBP" + #"Z)RZ{\226\20B\34\350H\306\2@\n\3408\226\3058$\24\320\223\351" + #"t\273u\337\370\375o\255..\300\330\36\31K\275Z\254}J\231-F\a\273" + #"\301\271Mr\177\374\336\217\2576W\372" + #"\377I_z\353\315*7\257\334\277\373\342+/\272\246\233\214F\207\207\aOO" + #"?9<\330\275Z\257\236\376\361\223\335" + #"yY\364\332\371\372r\261<9\330\373" + #"\370\361\223B\27o\274\361\231\243[w^\377\354g\2422Gwn\317" + #"\306\243\365\342J\202\267\32]\333\254\26\347\261w?\371\311\2173kw" +) 500 +( + #"\347\363\361xl\264\3163\203\0\271\265" + #"\235s\212\342(\267o\275\361\3527\276" + #"\375\a\333\325\246\230\355[k\203\240\261" + #"e\333\264\263\242\210\255\317(s]\273" + #"\335\270;\367n\345\34}\352G\363r" + #"\271\335\224&\367\311\231\262\260\202Z\224" + #"\26\244\310\352\355/\276\35bJ\2D" + #"\212H\201 \n\22\200&\375\243\37\276" + #"\353\232^k=*\313\262(\234\217\244" + #"\350rqU\267\355\376\321\221\v\341\354" + #"\352\352j\265,GU5\32\365\256C" + #"\224\235\351\270*\363\330\265;\223Q\352" + #"\232\276m\2652\212\250(\212rTh" + #"\255{\327o\353m\353:\245\224\326\352" + #"\316\355;\17\357\335\377\313\377\336\277\277" + #"3\233\335;>f\206\373/\275|p" + #"t\v\222\314\246\343\303\375\275\375\371<" + #"\263\306*\22N\273\363\331\336|\267\310" + #"s\327\367\353\325\312;\247\225\3122\313" + #"\234\214\"cL\210aS7\333\246\353" + #"\372\200:\v\221\265\316&\345\310\22u" + #"\365\26\274\313\214\272{\357\205\325jy" + #"q\272z\345\225\27\0\371\344\344Nd\16!\245\310\222\b\22\2\3p\322\203}" + #"\312\363I\222\347\271\23\204\20\344\371H" + #"E\3234WWW\355\266\326\n\353\272v!\2546\333\37\376\364rwG\357\354" + #"\354|\374\370ip\335\275\223\343p\326M\362\374\311\323O\16&cc3A\232" + #"\357\3546Mg\264\235\317\313\321d\254" + #"t\346R\22\245f]\17\244\366\366\17" + #"\313\321t\276\273\377\215o\374\376\263\363" + #"\213\343[\307\257\277\365\326?\376\307\377" + #"\344\366\v'\247\217\37O\306\225\353\266" + #"\243\334\36\354\316\357\3369\312\363|>" + #"\237\325\223\355\325\325EQd\253\325\252" + #"\353\272\276o\307\251\2\226\350\23h\30" + #"\225\325\341\376\301\351\345\372\342\223\205." + #"I\241\352\353mV\tI:\230O\245kA\322{?\374\b\1" + #"\216f\264==\337\214\306t\357\301n9v\365\225ga\2248(" +) 500 +( + #"\306\300m\273\221\b\260\b\3020\202\341C/\"J\323P.^\257\327\315zc" + #"\255\356\333\256\355\334\253o\274\361\332\253" + #"\237AE\213\325\346\342\342\342`\367\245" + #"G\37~0\251r\237x\265Y\203\17\37\334\337" + #"\277<\273\314l\5@\201\200I\263\246" + #"\204\244\a\322RB!\304a\212\17\204\243\0\n(\245\2@\b\316\332\311\303" + #"{\367\217\16\367o\35\34\336\271u\374" + #"\326\333\237_o\333\237~\360~U\214N" +) 500 +( + #"OOOOOEp\273m\200\364\356" + #"\376\236\346\331\336l\274\330l\317\257\26" + #"\267\16nY]\0\0\220\321\312\22\250" + #"\224\244\357}\302\320\371\364\225\267\277t" + #"\373\265\317\274\373\255o\377\37\277\376\17" + #"\377\306\177\362\237\376\342\327\377\325\363\253" + #"\313\377\362\277\377o\316\316N\327\3535" + #"'\177\373`\367\227~\351\227R\354\337" + #"\373\361\273\343\3618F\357<\21QY" + #"\0266S\314\261\255\273\230bn\264\322" + #"f\350\332\345\231\35\27\345l42\345Dksqq\365\344\243\367_z\341\366" + #"/\376+\277\362\2457?s\377\316\235\247?}\3577\377\341o|\347\17\276u" + #"p\373\20\214z\353\313_~\373\325\327~\347{\337/\217\3560`\300\4\21#" + #"\245\3531\22\21F$$\210!@\342\4\301\20Zm\34\242\353\35\0\354\357\357" + #"\277\370\342\213\307\207\267r[|\347\233" + #"\337z\357\203\217\372\340\217\216\357\376\375" + #"\177\360\17\26\253U\214!\372pr|" + #"\373/\376\271_\271w\347\326\356\250|" + #"\374\321\207\235\v6/\323\325R\t\262" + #"@\337\373\276\367\321\aC\272\310\213\27" + #"_:\271\375\316\27\177\374[\337\370\357" + #"\376\333\377\341\27\276\366\247_\177\375u" + #"U\24\267\336x\343\357\375\235\277\3737" + #"\377\326\177\36}\370\345\177\355\317~\346" + #"\215W\306E\266Z^\274\375\326_*,!\16\215!\31\217\307Z\23i<}" + #"|\252\243\36\354\210S\22\20\r2)" + #"\213\375\235\371\243\3233@=\316l\256" + #"\351\vo~\366O}\351\35\35\303?" + #"\372\207\277.\216_\270}\370\345/\374" + #"\345\313\313\313\323\213\363\313\247O\337\376" + #"\342\227\276\311\337\327\200Q\200\4\230\205" + #"\5\324\347?\377\331\224\22\b\220\"\4" + #"\210)\245\20S\364F\253\323\247O}" + #"\337\371\276\233\216F\257\275\372\322\321\336nU\25\37\375\364\375" + #"\337\376\255\3376\231\375\375\337\373" + #"\375\277\373\367\376\336\17~\372\344" +) 500 +( + #"?\372\17\377\203\37\274\373\356\27\336y" + #"\347\367\177\357wO\237>i\267\233\257" + #"}\365\347^\177\353\315\355j\245\204(" + #"\2Eq\316-W\253\313\253\313\272\353" + #"\262\274\234\315\347\373\207G#\241\263\363" + #"\213_\375\v\1771\313\362\367?\370\360" + #"\335?\372\376\17\277\363\235\242\314\347\363" + #"\235\177\363/\374j\221\233\313\263\263[" + #"\267\367\37\334}\341\336\335\223[G\a" + #"\363\235\351|>\253\252j\230\373EB\24,L\241Q\371\340\275\367\tD\210b" + #"\2\26\330\266\375j\271\324\212N\216\16" + #"\276\364\326\3472\224zu\265\2748;" + #"\276\375\302\203\a\367\257\316\317&\223\322" + #"\0323\231L\357=x\240\263b\323z" + #"\320\206\265\31\230\362\352\235\267?cs\253H\373\20b\214V\ek5!Z\243" + #"\317\237=\2738}6\31\25\363\351\364" + #"O\376\211/?\270{\267\335\326\277\361" + #"\353\377'\2\376\217\377\313\377\376\325?" + #"\371\305\277\366\37\377\365\177\361\333\377\374" + #"w\177\357\367\\\357\236>y<\237N" + #"\377\335\177\373\337\321\244~\374\356\17\336" + #"y\353\315\365rY\332|RN(q\323uu\333v}\17\bY^\330,\213" + #"\211'\263\311\255\373\17\312\376\370\311\257" + #"\374\353_\337\237M~\370\275\357\36\37" + #"\337>~\341n5\36\315f\23\337\267" + #"F\351\274\310#\303\235{\367\177\357\333" + #"\1770?\272\275X\327\243jL\2z\bC\244(3\226A\256g\341\252j\263" + #"\270\32\332\275\303\300\311\316t\266\\." + #"?y\374\244i\232o~\363\233?\377\305\327?\377\366\347>" + #"\373\331\317\376\365\277\372\327\376" + #"\306\177\361_\357M\344\366\255\243" +) 500 +( + #"\235\311x\177w\357\253\177\342K\253\313" + #"\263\355z\235\231\314\220\202\220R\22d" + #"\221x\335=\314$\31\245\372\266\376\340" + #"\247\357U\343\263\235\331\336h2K." + #"\224\231~x\367\344\316\361\21* \220" + #"\304^B\217\300V\243\"h\352\306{\347\373>J\324\0\211\31\30\t\0\265F" + #"!c\fE\315\314\336\373\266\353\266\333" + #"-\"\36\36\36\206\256\335\235\215\236}" + #"\362tj\324\301\356^\364\241\16\35Y\265i\266\314l\24Zc\210\323N9\232" + #"\215\306\276\3572E\34=$\320\0\20cT\bJ)\20`\216 \306\30\223\347" + #"yfL\323\364U\256\2151\263\331\254" + #"^\257R\nU\221\375\352\237\373s\343" + #"\351\364\223'O\376\305o\375\363_\374" + #"\205\257\375W\314\"2\231L^y\371" + #"\301\376tz|\353\360\336\255\243\247\37" + #"\277\2778\2738x\3700t~\300A\314\34\202O)\220\210&\324\306\372\276Y" + #"\371^\211X\205\bT\31\255v\306\5\2H\220\208*\t\310)\b\a\214\254" + #"\0!q\364\301\307\220T\22Dd4:[m6\nT\344\4$Q\22#\17" + #"\211r\b\241n\267\333\345\352hon" + #"\224\252\267\333\373\367\356\265]\27\201\313" + #"\235\211\257\333\324\266\233\325fw\257J" + #",\256o\367v\347O\266M6\329\337+&]\24\205\367\236c\"\"\4\360" + #"!pJ(<\233M\255\3256\303\315\246\36\206\210\367vww&\343\317\275\372" + #"z]\267?y\377\247o\274\364\362\305" + #"\345\362\177\373\273\377\353\335\373\17\337~" + #"\373\355\243\243#%\314\336mV\253z" + #"\261\340\276\277}\353h\273Z\317\262\311" + #"\317\346\21X$&\226\210\2202m\252\242r!\271v\323n\325x4U\212\240" + #"o\300\32H^B\204\344\b\205\24\211\200\bOF#bvM\335\307\224" + #"B\24\4Il\214qC\277\tR\2\361)\n\202\3153\235\331\335\335\335\305" +) 500 +( + #"\352C\233g''/\334\276u\374\321O\336-@\216n\37>Y\257Q\231\335" + #"\335\335\234\345\351O>\330\237\357k\322" + #"\355z;\35\215\337?\277\30\315f\261" + #"\353Pi]\346\2269\206\220\6\236\220" + #"\"b\216\336C\312\354\361\361\361\327\276" + #"\372s\377\357\357\376\16$v\316\335}" + #"\360P\203\234?yr\373\326\376\347?" + #"\3779\317\202*\373\323\277\370\213\223\311" + #"\214\231\233m=?>iOO?\370\321\273\17\216\357\270V?\376\360\303W\37" + #"\276d\222\212\237\"\16\243p\n>\270.\304.\317s $2\30{\361\6 " + #"\202\22\330\331\203\0\244\0\22\3'\340\bB\0\b\200\n\301(\233\351\24ct" + #"!$\2378rV\26m\3332\247$\251\363\316\263\4N]\337o\333f\370\225" + #"\203\375\303[\217?9\375\336\37}\377" + #"\267\376\351?}\347\235\317\37\275\364\260" + #"\260\331\311l~\347\360\350GJ\327\253" + #"\315$\37\25yN \214\314\304L\202" + #"\6\325\227\276\370\271\30BL,\314\2" + #"\303\230\232\200\200\353\273\273''o\276" + #"\361\306{?\376Qn\365W\276\374\345" + #"\223\223;\365f5*\212\242(\246\267" + #"\16\25a\271\263SV#\265\277\257\31\212[\267`\2610\a\a\23\224f\275\351" + #"6kJiZ\215\25\16\277\330\340\232\276v}\e\330\23\201\0\e\245B\350\201" + #"\323d\\\216\313*\270.\5\247\213\f\0 x\b\16\202\a\216\20\3\244\3101" + #"u\365\306\365='!\"\4\364.t]\337\365\236\1\32\327\304\24bJM\337" + #"'\200\326\207\263\253\225s\\T\225\367" + #"\361\317\377\231?;\316\362\awO\316" + #"\237\236z\357G\263\235\355f\235\v\276" + #"px\313\257\266g\317\316\372\220\216\357" + #"?\374\341\343\307\215pP:i4F\353a.\231\b\206y2c\2141" + #"\232\0%\305a\354n2\231(\204\361x\234RZ.\227\205\322\17\36~\264" + #"SU}\323\272\256\263\343Q\\\265\3\203f\370\1\4\205\24\234k \216JK" + #"J!0\247\0\3545I\n>\255\227\355z\31\1\25\240\"\3208\220\317\5\5" + #"\242\363\311\207\201\225\b\f\34%\372\304" + #"\314>\206\272k\221yh\247\0\241 \272\20\266M\35\22\6\37'\263\251r\375" + #"\255\223\333\273\177\241\372\335\337\375\235\315" + #"j\2757\233^=;?\e\315\357\35\277\360\344\321\323\323\307\217_\vn\263]" + #"\215\246\343\263\336\251I\5J\21s\322\231\251F\3450;@D\306\346yYL" + #"w\346\217\237\236\376\301\367\3760\245d" + #"\214\232M+\360\36b,\312,D\327ump\335f\273\30\217\n\350j \200" + #"\314\20\247\350{\2\214>\30\245\17v" + #"\367\226\237<\213\336\371\336\365};T" + #"\260\0 \205\344\32Wo\32\3\244\30\326\227\227\315vcsS\344z\273\276\30" + #"(\322\304I\361\320<\a\rJimm\256\224a\346\24B\350]\360=\2\30" + #"B\204\4\34\4\3220\315\36\5|L" + #"u\333\331\274D\304\373\17\356\215\312\312" + #"{\377\356\273\357~\376\v\357\34\334:" + #"\272\274:/\313\274m\333\367?\374`" + #"\262\2677\333?\350b\364\211\333\246/" + #"\3132\306h\224F\4\235\320\371\b\250\n\233[\fQ\0\2\v\202*\313r\262" + #"7\277<}\202\32\367v\247\241\255CrV\374|g\34\202SZ\272v\225\345" + #"%\200\207\330\202\315\200\245Y_.\316" + #"\257\24A\273\255%\t\241)\212\22#\207\340&\223\2111&\\\5J\252Y\365" + #"\f)7Yh\375\335\aw\17O\356\304\350\201=\214\212\"\270,\317B\202\224" + #"\22\2070T\233\1@ \211H\364\1X\230\331\aG (~\263Y" + #"\264\335f\224\21\32\273n\235\17\311\tl[\357Bl\233VR\362}" +) 500 +( + #"\275\331.\3122\213]\361\335\37|\377" + #"\325\317\276\246+j\\\35\272\346\356\335" + #"\273\247\3556\224\371\355W_\177\377\364" + #"\324\224\345\342r9\253J\24\320\312\20" + #"\20\vp\b\316\207\376\232H \4\204\237<;\353\234\3BmMn,pT" + #"\222\366wf\256m9\205\334\232\311\250\312\253\0224BpPo\340\374\34Ar" + #"k\242\363\316\271<\317\255\315\333\266\255" + #"\333fgw~pt\224@\372\246\323\332 \322\371\263\313\263O.O\237\236}" + #"\360\336\a\333\325\266\230\355\200@wy" + #"\256\6\16vH\224\304\0Y\245\v\233\0256\313\263\22\0D~6o\351\223\17" + #"!\244\340\211\20\340z\220Lg9\220r.0\263@\352\232zo\276c\225\252" + #"\233\315\301\301\374\356\335\27\210`g>" + #"\t\301\235\236\235N\16vO\27\213\17" + #"\317\236\275\374\2717\337{\3748\340\300" + #"\30P\32\220\222h$\35SJ\221\1\230\320h5D\r\260\326j\344!{\32" + #"\2065\373\336WE\36BTJ\e$ \5\200\20\"\204\4!nW[d)" + #"\362,\3656vN)5\236\216\301\356" + #"\202\367\354\23d\305\356\336A\333\364\333" + #"\246\236Lw\306\223\311\316|\326\367\355" + #"by\376\343\37\275\367\316tdG\245VA\217\306\320\213 \244a|\rRL" + #"1\n3\263s\256wNDB\342\310\22\223D\6\26E:\343\330o\353\266\366" + #",\332:\347\232\246\321H\263\361\244[" + #"m\356\337\273;\255\312'\357\3750\207" + #"\3750\235\370\266\361m\2678\277\370\312" + #"W\276BDO\237\235\356\35\35>z\372d\333\267\261(Q+\324\32\20SJ" + #"\303\20#\f-\375\201\374\242PRJ\363\371\214\210.//\257\256\256\206F\\" + #"\333\273\276\367\2312Z\220]\340m#\313uZob\335F\347\25`" + #"\f\1Y\6B\326f\263\341\30a\177\37\356?\244\351\30\362b\272\273?" +) 500 +( + #"\336\231\273\220\226\353m\37b\236\25\a" + #"\aG\343\321\364\364\364\374\203\367\37\1" + #"ef\357\20z\17\306\340\363\237\220\30" + #"\370/\316\271\266\353\232\266m\372\256u" + #"}\344\224\30XHH\223\315\5\t\320" + #"\364\236\333\316\365.l\326u]\327\326" + #"\30\220\24\\\234\215\252\344\273\345\305\331" + #"\217\337\375\376\367\277\373\355v\263I\275" + #"?\332?x\353\255\317\177\374\350Q\2" + #"\271\373\342\203\357\374\361\37\3512g\4" + #"\324\206\264\1\300\30Y\377\254\b\256\354" + #"\320|\20\221\24c\337v\303\325\367>D\26AD\205\202\222\308r\302\36\343" + #"\320\345U\332j\255\2255\354\372\30B" + #"\350\35\247\230RZ\254\227\363'\4h" + #".//\273\316={\366\354\352\352\312" + #"\0303\236\316\20EH\25\325\350\366\361" + #"\275\305z\365\235o\377aY\216^\370\314\353 \32\230A\4PH\1\1\"\202" + #"\b\263\244>\370\336;@\5\212\\b" + #"\379\2\212\322m\307@\332\330\302\260" + #"\352\3\267m\ezG\210\302|\2647" + #"\333\235N\344\377+\354L\243,\273\252" + #"\373~\246;\337\373\346\251^\325\253\271" + #"'uK\352A\255\201\226\2050\266\301\306$1&N\b\20\260\23\17\313I\234" + #"a\31b\3!^N\274\22\343E\260\35\307\304\361\212\rF@p\f6\211\215" + #"\22$@ !\206\226\324j\365\334\325C\r\257\352\325\e\357<\237!\37nw" + #"GI>\344~\253\367\241\206S\367\234" + #"\275\317\336\377\377o\347\331\302\\\213p" + #"\252b8\327\254\351\232\322l6/]\272\344x~\255\331\351\217FJ\331\n\31" + #"c\n\301\22\206\b\25\220\nRh\204$,\21,a\214!\0\2141*h\20" + #"P\214q\273\335\246a\220e4\214\222" + #"\22\301\210\340,\212!\221\210\214%\211@\0\21@\b@ \0\4@W\265" + #"\224\247~\342\2\0\312\3452\204\360\366" + #"\326f\271\322p\303\b\0\300\21L\31\365" +) 500 +( + #"\2420\t#!\304\245+\227\27\27\346" + #"\27\227\26d\305\330\336\331=\377\332\245j\245fUJ@@ 8\340\234r\226" + #"f4J\2230\216\3424\25\20f9\23\20@.\242<\217\363\234q\301\0N" + #"3N4E\263*\fE\341\314\245\224C\b9c\30\242\305\336\234\251ky\32" + #"\255\364\26\252\226A\343@\225d\f\t" + #"\243\302u\374\366|7f\374\322\365\e" + #"\330\262\322,\203\30\n\2148\204\214\n" + #"\316\1\21\b\21\204\357\250\227\270` " + #"g\34\0!8\0\232&\327\252\215\231\266g{\356\314u\225j%MrD\271" + #"\f%\b\0\1\20\2(\270\0y\16\30\23\214!I\222e\222\347\351x:r" + #"<\3332\314,\347\243\351M\"k\226e9\236\377\332\305\v\e\e\e;[\333" + #"A&t\2\356?z\360\304\211\23\245" + #"\222\331h\265\271\300\333;\203.\27\325" + #"z\345N#\225s\312\262$\211\202(" + #"\212\323\204Hr\234\245\34a\310H\222" + #"\347I\236\v\210\5\304D\325\31\0\0\3024\27\266\353g\31\225e9M\222(" + #"\f\312\246\34'\241\4\b&\304\27\271" + #"\f\330\304\365$\305\230N\355\205\305^,\340`w7\303\310u\35\255\326H\n" + #"\371\215\270#\363\"\b\241BV,\0\343\frP|\16\30\315\342\230EQ\344" + #"z>C(\214\22V\6Q\222\326\24\215 \214\0\24\2143p\307\266\2031\26" + #"\0`J\205`i\32_\277~}<\36.../\256\254\216\35\177\241\267\344" + #"x\336\263\317}\355\362\245K\307\217?" + #"\360\203?\374C\30\3038\b\313\345\262\343\316nno7\353\265\252$\247L " + #",\t\306\1\344\20BD0\21\262\242\251\252\20\200 /\b\2234\345\30c\2" + #"2\312s\2160F\20c\325,\207Q\224\244\211\27\204\343\351,I" + #"SYV\n(R\236\347\222D\32\215F\352\272\243\311\270]-cY" +) 500 +( + #"\202\20\227+\265\\\240\e\333\233^N\365ze6u\270\204xa\370\24\242\260" + #"2\20\0001c\f\2(\21\202\20.\32o\\\210B\t\220\344\231a\30\356\376" + #"\376h<}\340\360}\271\353\306Yn" + #"\351F\226e\204\20\333\266\253\325\252@" + #"\0\21\0024m\274\265\325\354v\211\204" + #"\256\335\270\266\273\2673\236M\307\316L" + #"R\255\315\235mS\267\314\222\361\2467?i\232\272\242\311\b\201Jen6\233" + #"9\236\267~\360 !D/\225\25\303\2244=Nc}\256\3\3428\363\2754" + #"\317R\232g4\335\35\fT]Oi\316\31\253Z\225\\\2008\247DQ\375 " + #"\220\24\271T\255y{\273\266\353c\214}?\350\365z\30#\300\250\241[[\333" + #";U\313\344\234\325\352\315\341x$I" + #"\312\241\203\253[{\303[\333\233\323(\f\21J)\225M\223\2 N\222\4" + #"\241\\\206X\226%\202\20\2B@\1\205\20\2p\4 \300\b\1@ b\214" + #"\2\0004\335\214e\325\rB?\210PN1\0203\307f\214\325j\265R\245," + #"W\312<\212\2624\25I\"\0ciTm\324\337\374Co\n\243\250\\.c" + #"Y\271ys\347\371o\277\340y\336\322" + #"\322\222\347\243S\v\247\262<\336\331\331\231\315f\325ju~~~w8 \204" + #"\264\347\3474\313\210\262L\2250\b\2\1\0@\320v\3758\215$]\265*&" + #"@D\370\334\r\302\214\213$cy\316\20\226\3028\221\1\317B?\214\323\361t" + #"\302\270Ptmo\270O)5Tu{o\320l\325\211\252U\353Ug:\221" + #"\215\322\372\372\201\3537\372c\327\267\343" + #"4\0060C\200\"\222\v\1(\307\222\4\0$\2\"\4%\214\360\251G\357\a" + #"\36764\23\20\202B\351\6!dy\236\347\31\1 \16\303f" + #"\265\276\270\320#\b\22\b\323,K\263\24K\4A$c\314x\16" +) 500 +( + #"\t\202\30j\272\236\321<\311\2228K" + #"\243,\211\222x{g\273\331\352\334\177" + #"\377\375\215v\243\336\2547\2325\333\265" + #"oo\336z\370\321\207\271`\262\"Y" + #"\225\362v\177\347\332\3065\253\\\231\270" + #"v\234\246Q\24\205aL\24\331\254U" + #"\262<\365\302\210\3\356\372\376p<\16" + #"\242\210q\240\250\32e\234\t\301(\37" + #"\216F\214\2134\315)\3437n\334\304\262Jdy<\236\b\301\21\306a\30a" + #"L\342$V5CV\264\224\363\251\27" + #"\334\336\31\314\3028\22\234J\22\223d\212\b\aH\0(a\31\n\201\271 \0" + #"\312\4\27b\30 \270`\224\26\205/\211 \ba\316h\301<\21X\202\0;" + #"\276\237SN\1\n\362D\301H\325U\216\241\237D^\34\3122)\227\313\bB" + #"IU\247\366\324\361\32O\335 \324\bh\224" + #"\264(\t\323\311\b\t\320\250W5E\251\324\252\212\242 \202'\243\341p\373" + #"\354\263\267\267o\307Y\2723\350\357\354" + #"\354Fq0\263\355(\16\254\222\325\356" + #"t\16\34>\20$Q\243\331\210\3234\210\342$\315j\315\326d\352\f\207\223j" + #"\243,k\32\304\344\373/\365{K\365F\255\t\21\2265\325\213\243K\327nd" + #"4\253\267\232\343\231\3\211\234\346\24\21" + #"\t\21y8\32\217FcI\226\25U\273\265y{f\273\345J\315\17\2030\216" + #"\323,\247\0346\232-\327\v\262<\3172jU*\234s?\360\3750Z]_" + #"\323t\3`I \4 \"D\222\b\6\224\261$\205\214\27\326\206\214\345a\232" + #"\340\323'\36\304\210`P\3543\0\220" + #"\20\200\n\301\262,\311\363\24#\244\353" + #"j\226\323\233\267nUj\325n\267M" + #"xj\231\262\254\20\317\263\1\2\275\245" + #"\36\222\360\237|\356\323\333\375\255\235\275" + #"~\222\247\227._\253\327\253\365f\215" + #"\321\274\325i\237\273r\221\21\241\30\246" + #"\244i\236\37\345\24x^\274y\273\277" + #"\272z\270R\251_\277\271\211e\305\rC\263\\\"\6\315\31\v\303H\321\265z" + #"w.Lc@p\1774\2112nV\352^\224\251\246\25\305\31\"r\316\270\355" + #"\332\222$[\225\322\346v_Q\365\333\2677\227W\327\303 v\334\300\264J@" + #"\300\235~\237qF0\312\2634\317\342" + #"\273\244\27\324\353-I\262\302r\312)S%B dY\"\30c\234\2,R" + #"F\303$\311r\206\37:\361 \6E\271\207q\300\1\20\2\26\210\23\2061\222" + #"$\2 \240\31\333\333\37\350\206\2650" + #"?g\2518\16\2750\214\315\2229\277" + #"\260\270\271u\373;g\277\367\312\253" + #"\257\366w\367\272\363s\266\343T+\345Z\265\246*\252" + #"\242\250{\273\3\3230\e\315\266;qgC\273jVY" +) 500 +( + #"\314&\203iY\257\210LHX)\233" + #"\245\351h:\327\232\203\0\255\254\254\30" + #"\252\261\267\277o\226JI\226\224\2525" + #"\200p\224\344i\306\242\214\n\16dE\247\fDI\22'\311\316\366\266\0BQ" + #"u\312a\20FX\222\303(*\225jX\"\206n@\204\201\20\276\357\307Q," + #"\0SU\2251\32\307\31!hyy\ra\31\0\168#\b\v\236\347Y." + #"\4C\30\1\49\20Lp\210d\202\361]\250\237\340\20C\204 \23\274\250\0" + #"\25\315\2158\216M\323\254T*E2" + #"\206T\324\254\230I\222\315\246~\226n" + #"\237{\355\\\277\337\217#Z\253\266gS\37r\"K\332p0\255\226\312\276\353" + #"\369t\210g\302\2F\310\242\216\325" + #"Xj.\332\23\233\341\224 \331\333\17" + #"\324\204\324\24\263L\265*S\267\a\273a\4\372\303\335\212e\210<;w\3765" + #"\3154\24Y\253\327*Q\234z\266\235\204Qaq\314\263\244\325h\2Ll\307" + #"\323\366GHR\323\234\226\313\345\3537n\34=\326\315\4C\230\204I\34F>" + #"\0\3340\2644M%L\204\254\206 " + #"\331\336\336\213\343\30\21\25\223;n\e" + #"\3122J)\306\260\340\e\27F\27\211\310D\226e\16\1\340T\b\1\1D\b" + #"\336\341\200\302;\6\2528J\233U\253^\257_\271xe<\231\31\315:\3432" + #"\27b2\363wvG\267o\3651\306\235FW\226\244[\e7\f]\25\f\225" + #"\364\212\241Z\263\301$\262\343\325\271\345" + #"\275\255\335\310\217\"\340\357_\356\v\16" + #"\21@\263\300\276\265\2655\337\233\2275" + #"\265.\2317\316]\335\363|S\31\224\3325{<\6H\314u\32a\224\330\323" + #"\311x<\311(X[_\206\20\5A\310\271\37E\341\342\342\262nXq\30M" + #"]\217H\t*pJ\222\f\t\4\0(\262\344" + #"\373\376h\177\266\260\330i4\32\257\274z\221\220P" +) 500 +( + #"\323\264J\331\332\37\371i\232*\32\305D*\374\20YV\254\213D\bI\323T" + #"\334\305U\23$\21\4\0c\2023\16\0(\232\245y\236\313\262\f\4\244\371\35" + #"Rq\1\240\233\315f\367-\257\214\306" + #".\347\234\20\203\261<\315\270\251k\234\341\327._z\340\3501CUtE\25" + #"y\276?\30\334w\340\350\366\315\315+\337\273J\30\252\226*\226QR%u~" + #"~\241\323jS\316\336\376VK\325\265\251\353,\256-\rg\243R\245\204$\242" + #"U\365\227n\234\177\345\312k\272iy~`\226j\243\311\364\312\306\r\31345" + #"\335\360\274\300\365\375\361d8\231\316\222" + #"\224Fq\246\350y\220\346\345j\335\v\242\271\371y\3354\222,5\f}o\177" + #"\240\312\240Y\257\327\252\265,\1\270\2" + #"\5c\246\256\267\32\b\0t\227\350w\247$Z(1\v\317\315\235\367E\222\310" + #"\35MT1+B\210\371\316<\3018\362\3\3352\353\365:\345\271\343yHF" + #"\275\365E,\343\214\246W67\346:\255\307J\247\227V\326._\275\206\211r" + #"\350\310\341\225\265\265 L6\267w\222" + #",#\204h\272\31%\224\t\30\347\324\340\"\241L\312\2224M\17\256\37(H" + #"\232\0\200\320\367*%\313\3204CSK&<\270~`k\273\37G\251\256\231" + #"\2053\237R\n\300\377\206;\2\0\n\350\20\6\361\27\216\0\0\31{IDA" + #"T\347\\\226eR\270_\vR\"\306\230r\3129g@p\200h\316\5\207\4" + #"cU\325\363<\327\r\243\331i\273\276w" + #"\376\342\2453\217>F\223\364\362\325k\236c" +) 500 +( + #"\3474C\16\362\\\333\322\324o\277z" + #"\263\206\301\3\367->\371\310\e\16\254" + #"\257\265k\215\271\271nN\301\312\241\243" + #" \243\236m\227\2542@\250\226e\260^\237n\\\267*Vc~a:\36l" + #"n\336\272\335\337\262,c\1772vbO1\364\3337oj\212\332h\317-," + #".\337\336\351\177\346\251\317\23\"Q\312" + #"\v\32^\232QU7\330\314\216\22\312" + #"\21\230\332n\257\327\253\326k\366t6" + #"\263'\30\242,\215%\202j\245R\265\\1T\255\323\351\364w\aI\222\325\312" + #"%M\3238\200y\236A(\n&Cq\\\24:Cx\27PG\204\20\0A" + #"B0\a\2s\3149AH`\314\n\3174FH\326\24\32\247\262,\227\313\345" + #"]{\333fb0\36\314&\323 \211\27V\226\6\375\376h2D\202o\215\374" + #"\307\36\354\35^]\373\205\277\377\367\312" + #"\206)\262\314\254\327\275\361T)W\22" + #"\346\253\232\2029\271\261{3MS\310" + #"\205w\311\231\330\223\301`\317\v\\\253" + #"l\6i\20&\241\256\353~\0304[\235$\2156\267\267\36;\363\3068\16\a" + #"\203\301\334\334\334\e\36?3\30N\235 \34\357\355g4GDRU5c " + #"\3162\331\320\3428^]_\267\312\345" + #"\376\316\326p\260\247\20I!\30\b\321" + #"\355\264dU\267g\221\353\372y\316\f" + #"\253\274\270\270$\313r\2323\306\330\35" + #"\266\310\353\30\315\340u\30t\202\b\304" + #"\30\346y\236\345\31!\22\23\200%)cB\226d\204 \4\230\346\\\222\244\341" + #"p\30EA\222\305y\34\2454\265\335Y\265^\16\343\2603\337Y[]\364\355" + #"I\247\321|\340\276\303U\3038\177\341" + #"\225\345\371y\221g\303\263\337\26\30\371" + #"\214\1\tO\247S\300\270\357\205\216" + #"\343`\204\366\367\367*\265\n\343\371h\272oX:\204" + #"\0b\240X\35N\262\235\301\326\312\362\301\a\36\230\213\222" +) 500 +( + #"\260\263\260x\345\352\215\25,\t!8" + #"\20\262\252K\262\2\t\261\35W\226\343z\263E\24\231A`*j\236\347q\34" + #";\216\323j\265f\243\21\301\350\2113" + #"\217\227,ci\365\340\273\337\375\216?" + #"\372\314\227*\25\355\360\362\352\211\223\0171\1\2077o6[uY&I\222\24" + #"0\301Vk\301\266m\3030\20B\205\323\24?\372\330I\0@\316\250\20\2\24" + #"\241\213R\214\211,\313D\222\205\20I\34s\3011Bq\349\266=\337\353\356" + #"\r\6\0\201 \b\34\317>~\342\201R\331@\b\236y\303\243\22\342Q\24$" + #"\241\3578\323\311x\177\270\337\337\334\276" + #"\225r:\232\215.^\363\304\351\202\353\n\21\202\20%Y\316\250P\24\31@\230g)gT" + #"\222$\231H\214Q\316\250\242(\20\342\351\324N3\252\353\352l:[Z^:" + #"x\340@\30\4\343\321piiQp~\363\306\365q\334\205\336\322`<\302\22iw\347\31\347\273\203=Ji\265Z\355" + #"\365\26\20\202\223\311\2041\326\351t\35\307\303\20G\201W-WVWVh\226" + #"\267\233M\202\241\347y\315fs4\31?\372\3g\226\217\34\335\277}\e`\324" + #"Y\230\177\361[\337\336\334\334,\200\223" + #"\b\241B\305r\317\374\n!\304\307O\336G\b\1\20\t!\n\340D\341\241\341" + #"\254\200\347\b\0\5\202\220\20\214 `\214g\24\0H\346:s\343\321xo0" + #"\234\237\357\226+\345\207O\237\256\224," + #" \4\306\260\323\354\264\32\r @\316r\201\225\221\2370I\223t+\312\31R" + #"t(\253N\234\23\335\340X*7[\313\353\207U\253\334\356.4\273=\275T" + #"s\343\364\320\261\373\241$\351\226\211e" + #"\2312\261\260\274\354\270n\247;?\263" + #"\335\214\346\252\246\312\212\34\6\201\353\272" + #"\b\241j\265\"\270\244\251\2527\235\316" + #"w\3334\215\236|\362q\232%\245\222" + #"\225\345\331\265\215\e\a\16\335\367#?" + #"\366\266\317\375\331\227Z\235n\245\325~" + #"\371\345\227\5\347\220\363R\305\332\330\270" + #"\376\320C\17\365\373\333\313\313\313Q\24" + #"\336\241\245\336\301\361\"\304\30\27\260\300" + #"\303H\5\254\340^\266#K*$\22\3159\27@QuI\321\250\0\206e\n" + #"\0\0F\253\a\17\304i\342\205\321\351" + #"G\37Ut\243\275\260t\364\304\311\207" + #"\37\177ckq\211I\312\352\221\243\17>|\206\230e?\347\367\237:}\370\376" + #"\343~\222O\303H(*\303\210\21I\262J\233\373" + #"cR*\247H.u{\201 \1\3f\243=\234" +) 500 +( + #"\332DV\222\214\23I\353\316\367\366v" + #"\a\355f\307\263\275\222e)\222\302rf\232V\271Z\355t\273\345j\245T*" + #"-\316wT!b\317\3064\377\3017\276\221\347\224R\36\206\221nZ\27/]" + #"\231\233_(U\e\2677\267\27zK\253\253\253 \3154\325P\24-K)g" + #"\350\363\237\377\302\352\312\1\317\r\270w \337=\207" + #"0\226$\200PNEN\205\0\244\\\255\2464\237\357-\250\272Vo6N\235" + #"~x8\236f\234\357\16\307PR\5T\30\222\357?\371p\2515\0272\200\215" + #"\322\261\a\216SJw\267w\r\303\322u]\226\345\365\365uI\221UU\335\356" + #"\357(\232\246\232\326f\177\267\325\231K" + #"\31\37N\355\3\a\2174\232\355\2342U3+\225\32\3012!\204\3454p\3" + #"UQ\312\345\262\3538\263\231\23\206!g\300\231\314\246\373;Y" + #"\340\236\363\343" + #"g\277\365\302o\374\346\307\315j\353\353" + #"\337\370\326\215\215[\357y\317\337\275t" + #"\341\342\346\215\r\5cY&E\364I\323\\\226e\313,EA\364\3143\317\334" + #"\276\275\265\330[\206\0\337\201\350\24/\302\35H\316" + #"]\327\347=\271m\221\355\334\3\306\20B\f\303\332" +) 500 +( + #"\335\35\310\262\206\220T\262\252\325J\343" + #"\312\345\r\307\rm7\324\315J\255\336Z?pX3Ji\16\306So2u" + #"9@\265Z\243\333]\b\3038K\251,\251\236\27t:\335\373\216\34k4Z" + #"I\222\215F\23{\346\214\6\243\300\r" + #"\334\231g\225\252\266\eyA\274\265;" + #"\30\333.\303\260?\332\37N\3073\327&2n7\353U\313\4Y\2\343\250S" + #"2N\334wpi~\316um\307\265\21\306\271\0\222a\375\267\247\377\347_\373" + #"\311\277\365\304\233\337\22\245\374_\377\333" + #"\217\277\353=\357\323%\345\353_}\306PT\2D\226\244El\251\325j\5q" + #"gn~>\216\343\317~\366\263\266m\367z=EQl\333.\306\233\341{\177" + #"\377\275{w\21\233\360]pX\1\377\0\0\224J%YR\2676w\30c\355" + #"\366\234,\253KK\313\214q\307\366Z" + #"\315\216\256\233\234\241\356|\17\"\342\272" + #">\302$\315\250\254h\2\240\321x\232" + #"\344T\267J\262\242\265\332]\16\341l" + #"fW*\325r\251\362\374\363\337\316\31" + #"\17\242\30\21\3310\312A\30;n\310" + #"\5t\303\350\312\306\215\333\333\233\0242" + #"\263d\224+\226\340\224&!fl}\261wxy\245\327nC\301\25M\36O" + #"\247\272U\2524\233\317~\363\371\230\241" + #"\17|\350\243F\251\361\361\337\371=\327" + #"\217>\362\341\177\361\335\357\235\275~\365" + #"Z\243V\365m\307\262\254$I\242(\3224-\317s\337\367u]\327u\323\236" + #"9\177\365WOO\247\266\246\32\235v" + #"\27\25C\367\320\335\ec\261\247\212\242" + #"La\333\340w\347\326\25\3\231\366\367" + #"\367\273\363\35E\2254M\213\242\350\322" + #"\245\v\a\17\35j\265\333\31\315]\337" + #"Ki\336\37\354\251\206\311\0l\265" + #"\333\222\252q\b9\302#\327\231\370\376\324u3\316\17\34" + #"9r\344\376\a\0\304\275\345\225\336\362J\275\323A\262b" +) 500 +( + #"\225\253\232aQ.\6\303\t\301\212\0xqy\255\321j\16F\3038M\246\323" + #"\251,\223\321\376\340\334+g'\303=\t\360\205fS\203(\v\2.(\"\270" + #"\325i\217\246\263 \311_\374\376\313\277" + #"\374\241\17w\227\326^\272p\371\343\277" + #"\375{\377\356w~\227q\360\324SO" + #"\235:u\352\374\313\257\224\313\226\246iQ\22\347\214&YJdI\321T\317\17" + #"\0\204\213\313\313\216\347\376\325\323_A" + #"D\342\0\242{v\374<\317\3234-" + #"\314\363\205~\344\236\254L\334\35\271\305\0303M}:\35K\22\236LF\0\262" + #"\271n\307vf\327\256_\315\262\354\362" + #"\345\213i\226%Y\f\0`\202.\255\256\330\276\2675\330M8\263*\345c'" + #"O\254\254\257\31\325\352\312\301\203F\245" + #"d\224+\17\234<\345\307\311\356\336\376" + #"\352\241\3a\232M]\357\253\317~\355" + #"\300\301\303\a\17\37\261m{2\231\24" + #"\234\364\305\345eU\223!\24\2663\233\215Ge\253\324\250V\fUA\234UJ" + #"\246\357\2059\340~\234\316\365\26\177\363" + #"\343\237\370\311w\275\353\235?\365\356\\" + #"\200_\370\207\377\370\255?\376\366\37\371" + #"\341\37|\376\371o\237=\373R\1qn\324\352\266ms\316k\265\32c\214\20" + #"R\255V\223$1\f\323\367\3\4\311\376`\364\231\317|f<\232\242{\23L" + #"\nF\234a\30\232\246\335\eZR\300\35\n\366qQ\216O\222\230\20\f \303" + #"\4\214\246#\200\201j\250\232\251P\236" + #"\6\221\317\4\365C\217\3108g\231\254J+k\313'\37}4\244\24\353zo" + #"m\255\267\276\356\204\321#\217\377@\224" + #"\323\326\302\2\220\345\34\302\265#G\316" + #"\276rn\355\340\301W/\\(\327\252a\30\16\207C\307ql{\26F\376|" + #"\247\315\362\0240\376\362Kg}\307>\260\266~\374" + #"\301\373+\3452g\2547\277\340\330^\275\335\206D\255" +) 500 +( + #"\267\272\177\360G\237:\375\330\e>\366" + #"[\277\35e\371\a~\365#\343\321\344" + #"?\375\301\357g\f|\364\243\277\366\276\367\275oww\27\0P\350L\25E)" + #"\246\370$I\346\373\241\256\233q\34\253" + #"\252\252(\252$\311\223\361\354\251\247>" + #"\213\356-\201,\313\246i\352\272^L\216\n\303\260\270:\25!\251xw \4" + #"\365F\225\262\314\363\34Y&\246\251;" + #"\316l4\332\227$\211C\356\6\356h\274?\236N\373{;f\251\2243:\277" + #"\264X\256TdS_^[\205\22\271\265\265}\377\311\343a\34\331\201g\224K" + #"[;;\257\276\366\332\324\266\37\371\344\27\277\370\347\275^/\214\223\377\253:w\367KT" + #"\314/T\24\315\262J\265Z\3\277\341\211\307\212\220TL! \204\24R\251\2" + #"'\302\271(\242\225t\347!q\32\23\tk\272\216\tv\\\347\326\355[3\333" + #"V5meu\355\342\245K\215FkemMQ\344\214\346\263\231mX\346x" + #"2\225Ue~a\341\322\225\313\b\341\251=\213\223\244\325i\333\216{}c\243" + #"\267\330s=\257\267\330;\373\322Y\0\341\325+W\6\375\335j\305j5\32\375" + #"\235\255\311h\337P${\367\205/}\356\v_\202D\335\37M~\354m?\376\253\37\376" + #"\310O\276\363'v\372\373?\371\226\267\376\317\257" + #"=\373\374\v\337\374\312\227\277\334\231\233\363\375\20I" +) 500 +( + #"\n\345\0a\2\21\246\214\3\210\20&" + #"\214\213\2342\312\30\343\200\25\327\350_" + #"\372\340?H\222\4\0`\232\246\242(\224\3224\2713\231\215R\232ey\261d" + #"\5\260\23B\220f1cl<\36\247iZ\257\327\25E)(\256\222$u\273" + #"\335\245\245\245\215\215\rMS\346\347\347" + #"\1\0\206a\270\266S\251T\3428~\371\345\227\3438\35\f\6kkk\275^" + #"\357\312\345k\245R)I\22\327uo\334\270\321\355v\31\343\316t\2668?\317" + #"\362\324\324\215\375a\237\3234\317\222\351" + #"dx\342\201\373\21\24\235f\313q<\4\260\241\233YFM\263\324]\\\212\0" + #"\370\307\277\374\201\337\375\275\377\3607\336" + #"\36175\325:x\354\330\342\322\362\377" + #"\370\253\277\344\0\274\371G\336\266\262\264" + #"\364\307\177\370\373\315V\207e9g\264\336h2&2z\207\212_`W\213\342" + #"\377\275\354\244\330=\370\324#'\v\250" + #"P\321p\213\343\230R\6!,\332F\367PLB\210$I|?\340\214+\262" + #"\n\0$X*\227+\234\211\315\315\355" + #"\313\227\257>\367\334\267\216\37?\2311" + #"~\355\372\306\322\362\232\0\230Hj\267" + #"3\257\313\222e\352\343\321P\"\370\354" + #"\367\276\377\336w\277\3334\364g\277\372" + #"U\300\270e\30\333\233\233\b\210,\311" + #"B?8\177\356\234\251\351\373{\375\245" + #"\305\356\225\213\27n]\277\n\31\255\31" + #"\372\211cG1\20\vs\335$\311\232\215v\234\244\363\313k7\266vz\253k" + #"\vk\a\337\3653?\367\261\337\376\17\357}\357\317xa\364S\177\373\357Dq" + #"\374\374s\3171\1>\361\211O<\365'\237:\373\335o\377\347?\372\324_\374" + #"\351\237Z\325j\271ZMS\212\260T\244\365Ei\16\337\0354'\356\316\354+" + #"P\321\2448Y\212\251\247\305\371\n\0\202\20\32\206" + #"\301\30\313\262\2748\242\2127B\b!8d\24p\6" +) 500 +( + #"]'\270t\361\352\315\2337g3\247\210\342\237\376\324gW\17\254\37?~\\" + #"\221\r\337\vt\255\344\330\376#'\217" + #"\177\362\367\177\327u\335G\36y\344M" + #"O\274\261\277\265\375\364\323O\327\353\365" + #"\252Uz\361[\317\207a\30\4A\255\3268\177\376\274eY\356t\302Ev\366" + #"{\337\315\242h\2717\267\276\274,\362" + #"\214\305\361\312\362r\222$Y\24\aX" + #"\"\252ve\343\306\251\307\36\275\377\304" + #"CO\274\371-\37\372\227\277\361\326\267" + #"\377\4\a\340\327~\375\337|\355\e\337" + #"\370\3467\237\203\0\274\370\255\347>\361" + #"[\277\371\37\377\375\357A\0\276\374\345" + #"/\253\245\22\"XV\2648\311\356\235" + #"/\367\222\265\342\223\202Y\5\341\235a" + #"\225\244\310\331\212\334\244\250q\"H " + #"\204A\20@\b\1\200\205\327\261\200H" + #"2*r\316\316\237\277p\375\332\r\337\367\213\rX\251\265J\245\22\245lkg" + #"o2\363'c\367\353\337x\341\340\301" + #"\203\353\353\353K\363s\316h\257bZ" + #"\272\254|\343\231gW\26\227\256_\275" + #"\272{k\323\237\314\316\276\360\342\336\336" + #"\236\241\231\367\335w\337\355[\267\26;\35J\351p\267_*\e\232\f\217?p" + #"\37\317\262\222\256\365\346\226\2667\267\"" + #"\317\265mw\355\320\341W.\\\232E" + #"\311\233\177\364\307\316<\371\346\345\225C" + #"?\373\217~\351\227\376\331?\345\0\374" + #"\247O\177\376\217>\365'_\374\322_" + #"\234x\360\270\353\330\357|\307O|\340" + #"\3\37\370{?\375\276\347\236\377\3263" + #"\177\371\337\201,k\246q\373\366\315\205" + #"\305\25\232\345\257_\232\"\253\a\0\231" + #"f\351\336y,8\200?\377K?\247\231\206B\2448KY\226C\202\t\304T" + #"pA\231\242\31\272\242r\b\2220\331" + #"\37\217\372[\333\373\373\373{\273\243 \b-\313*\227\313y" + #"\316 \24\212\2561\306\262\224\32\206\261\277\277_*\225rF\213" +) 500 +( + #"\366\335\323\377\375\313\27_\375nI\227ol\\C@\2604=w\356\234\3478" + #"y\306\2424QU\215R\232g\254\220\330K\222dY\246@\242Q+\21\0\226" + #"\227z\25\323p\235Y\255T3\313\225" + #"r\275\261qk\323\215\263\367\377\334\317" + #"\273Q\372\246\37\376\341\277\375\236\367\376" + #"\307?\370c\n\300\347\276\360\27\277\370" + #"\236w\177\351\177<\375\344\23\217\17\372" + #"\333?\372#o9r\337\241?\375/" + #"\237\3275\343\221\307\316\274\362\375\357-" + #"\35>\\\370,\34\307\251\225\312Y\222\0267\236\2738JR4\3\356-\26\0" + #"\2000P )eE%\fS\1\1\340\20r6\236\215\247\263\376x8\2329" + #"v\350\207q\232\24\336PC\267\f\253\2!\244\34\0D\4\340Q\230\24? " + #"M\323z\243\n!\344\t\rg\223\371" + #"\225\225\303G\357\273r\365\302\3513\217" + #"\332\266\215X:\32l\3130;\260\334\335\333\333kTkQ\232\246\31\321U\t" + #"\0 \30\325U\311\320\211U\256b(Z\315\206\204I\222gZ\251jS\32F" + #"\331\rg\247\277?\373\205\177\360Of" + #"\t\374\261\277\376\316\267\377\265w~\374" + #"c\237\300\202\177\345+\317\374\342\273\377" + #"\326'?\365\251\37|\362\2110\360\336" + #"\375\336\367\266\346\346\376\353\27\377\"\212" + #"\242?\375\322\347_\371\376\313\365\371\305" + #"\300\217\204\200\232\241\e\232F)\305\22\1\0\b\b\20\301\\\b\316sD^\37" + #"\276\5\0\200H\262\252(\232f\230\214" + #"1/\367F\303\321\336\356\376t:\335\332\352\347y.8,.\n\246Q*\n" + #"zy\232\1\0\357\216\321*HCw\6\3PJ\1\2733w\v\20R\344A" + #"\262\246\eVI3\215\232Q\2014\232\264j\25\323p\35Y\222\25H\260,S" + #"\210\b\20\f0\246\251\252a\30eC\227U\245d" + #"Z\20\n\315P\25\303\2348\201\227en\302~\371\243" +) 488 +( + #"\277\326ht\337\360\3O\274\355\307\377" + #"\372\257|\360\237\327\312\225\257<\375\364" + #"O\277\377\375\377\354C\277\362\376\367\274" + #"\213\n\360\301\17~0\216\343g\237\371z\234d9\345?\373w\337\17T]\226" + #"\325\242B2\36\216\352\365z\1\244\376" + #"\377>\344\300\201\3\266m\337\270q\343" + #"\326\255[\203\301\300q\2340\210\3238" + #"n\266\273\222$A\200\213\333S!r" + #"\310\363\\\302\344\365\244\230{\27\361\242aNYv\347\363 image" +0 0 4 29 1 #"\n" +0 0 17 3 50 #"; vertical reflection defined by bitmap operations" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"myflip" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 15 3 5 #"local" +0 0 4 3 1 #" " +0 0 22 3 2 #"[(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"other-pixel" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 15 #"get-pixel-color" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 3 #"))]" +0 0 4 29 1 #"\n" +0 0 4 3 4 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"build-image" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"image-width" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 17 #" " +0 0 14 3 11 #"other-pixel" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 14 3 1 #"n" +0 0 4 3 1 #" " +0 0 14 3 3 #"low" +0 0 4 3 1 #" " +0 0 14 3 4 #"high" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"min" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"max" +0 0 4 3 1 #" " +0 0 14 3 1 #"n" +0 0 4 3 1 #" " +0 0 14 3 3 #"low" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 14 3 4 #"high" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 12 #"check-expect" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 20 3 2 #"10" +0 0 4 3 1 #" " +0 0 20 3 1 #"5" +0 0 4 3 1 #" " +0 0 20 3 2 #"15" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 20 3 2 #"10" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 12 #"check-expect" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 20 3 2 #"10" +0 0 4 3 1 #" " +0 0 20 3 2 #"15" +0 0 4 3 1 #" " +0 0 20 3 2 #"20" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 20 3 2 #"15" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 12 #"check-expect" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 20 3 2 #"10" +0 0 4 3 1 #" " +0 0 20 3 3 #"-20" +0 0 4 3 1 #" " +0 0 20 3 1 #"7" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 20 3 1 #"7" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"myfuzz" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 15 3 5 #"local" +0 0 4 3 1 #" " +0 0 22 3 2 #"[(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"near-pixel" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 12 #" " +0 0 22 3 1 #"(" +0 0 14 3 15 #"get-pixel-color" +0 0 4 29 1 #"\n" +0 0 4 3 13 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"random" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 3 #")))" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"image-width" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 13 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"random" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 3 #")))" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 13 #" " +0 0 14 3 3 #"pic" +0 0 22 3 3 #"))]" +0 0 4 29 1 #"\n" +0 0 4 3 4 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"build-image" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"image-width" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 17 #" " +0 0 14 3 10 #"near-pixel" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 6 #"myfuzz" +0 0 4 3 1 #" " +0 0 14 3 5 #"bloch" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 6 #"myfuzz" +0 0 4 3 1 #" " +0 0 14 3 3 #"tri" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"masked-fuzz" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 17 3 41 #"; Like myfuzz, but preserves the old mask" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 15 3 5 #"local" +0 0 4 3 1 #" " +0 0 22 3 2 #"[(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"near-pixel" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 12 #" " +0 0 22 3 1 #"(" +0 0 14 3 2 #"if" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 14 #"pixel-visible?" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 16 #" " +0 0 22 3 1 #"(" +0 0 14 3 15 #"get-pixel-color" +0 0 4 29 1 #"\n" +0 0 4 3 17 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"random" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 3 #")))" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"image-width" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 17 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"clip-to" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"random" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"+" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 4 3 1 #" " +0 0 14 3 6 #"RADIUS" +0 0 22 3 3 #")))" +0 0 4 3 1 #" " +0 0 20 3 1 #"0" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 17 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 16 #" " +0 0 20 3 2 #"#f" +0 0 22 3 3 #"))]" +0 0 4 29 1 #"\n" +0 0 4 3 4 #" " +0 0 22 3 1 #"(" +0 0 14 3 18 #"build-masked-image" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"image-width" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"image-height" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 24 #" " +0 0 14 3 10 #"near-pixel" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 11 #"masked-fuzz" +0 0 4 3 1 #" " +0 0 14 3 5 #"bloch" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 11 #"masked-fuzz" +0 0 4 3 1 #" " +0 0 14 3 3 #"tri" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 17 3 41 #"; Convert all white pixels to transparent" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"white->trans" +0 0 4 3 1 #" " +0 0 14 3 3 #"pic" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 15 3 5 #"local" +0 0 4 3 1 #" " +0 0 22 3 2 #"[(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 5 #"white" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 11 #"name->color" +0 0 4 3 1 #" " +0 0 19 3 7 #"\"white\"" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 3 10 #" " +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 9 #"new-color" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 14 3 9 #"old-color" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 12 #" " +0 0 22 3 1 #"(" +0 0 14 3 2 #"if" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 6 #"equal?" +0 0 4 3 1 #" " +0 0 14 3 9 #"old-color" +0 0 4 3 1 #" " +0 0 14 3 5 #"white" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 16 #" " +0 0 14 3 5 #"false" +0 0 4 29 1 #"\n" +0 0 4 3 16 #" " +0 0 14 3 9 #"old-color" +0 0 22 3 3 #"))]" +0 0 4 29 1 #"\n" +0 0 4 3 4 #" " +0 0 22 3 1 #"(" +0 0 14 3 16 #"map-masked-image" +0 0 4 29 1 #"\n" +0 0 4 3 5 #" " +0 0 14 3 9 #"new-color" +0 0 4 29 1 #"\n" +0 0 4 3 5 #" " +0 0 14 3 3 #"pic" +0 0 4 29 1 #"\n" +0 0 4 3 4 #" " +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 14 3 4 #"hier" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 12 #"white->trans" +0 0 4 3 1 #" " +0 0 14 3 13 #"hieroglyphics" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 7 #"overlay" +0 0 4 3 1 #" " +0 0 14 3 4 #"hier" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 9 #"rectangle" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 19 3 7 #"\"solid\"" +0 0 4 3 1 #" " +0 0 19 3 6 #"\"blue\"" +0 0 22 3 2 #"))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 15 3 6 #"define" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 13 #"diamond-color" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 3 2 #" " +0 0 22 3 1 #"(" +0 0 14 3 10 #"make-color" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 20 3 1 #"5" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"max" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"abs" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 1 #"x" +0 0 4 3 1 #" " +0 0 20 3 2 #"50" +0 0 22 3 2 #"))" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 3 #"abs" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"-" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 4 3 1 #" " +0 0 20 3 2 #"50" +0 0 22 3 4 #"))))" +0 0 4 29 1 #"\n" +0 0 4 3 14 #" " +0 0 20 3 1 #"0" +0 0 4 29 1 #"\n" +0 0 4 3 14 #" " +0 0 22 3 1 #"(" +0 0 14 3 1 #"*" +0 0 4 3 1 #" " +0 0 20 3 1 #"2" +0 0 4 3 1 #" " +0 0 14 3 1 #"y" +0 0 22 3 3 #")))" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 11 #"build-image" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 20 3 3 #"100" +0 0 4 3 1 #" " +0 0 14 3 13 #"diamond-color" +0 0 22 3 1 #")" +0 0 4 29 1 #"\n" +0 0 4 29 1 #"\n" +0 0 22 3 1 #"(" +0 0 14 3 8 #"big-bang" +0 0 4 3 1 #" " +0 0 14 3 5 #"bloch" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"on-draw" +0 0 4 3 1 #" " +0 0 14 3 7 #"show-it" +0 0 22 3 1 #")" +0 0 4 3 1 #" " +0 0 22 3 1 #"(" +0 0 14 3 7 #"on-tick" +0 0 4 3 1 #" " +0 0 14 3 6 #"myfuzz" +0 0 4 3 1 #" " +0 0 20 3 1 #"1" +0 0 22 3 2 #"))" +0 0 diff --git a/collects/picturing-programs/tests/perform-robby.ss b/collects/picturing-programs/tests/perform-robby.ss new file mode 100644 index 0000000000..15f9503631 --- /dev/null +++ b/collects/picturing-programs/tests/perform-robby.ss @@ -0,0 +1,21 @@ +#lang scheme +(require 2htdp/universe 2htdp/image) + +(define (slow) + (let sloop ([n (expt 2 22)]) + (unless (zero? n) + (sloop (- n 1))))) + +(define (update-world w) + (slow) + (- w 1)) + +(define (render w) + (circle 30 'solid (if (odd? w) 'red 'green))) + +(big-bang 10 + (on-tick update-world) + (on-draw render) + (stop-when zero?)) + +(printf "done\n") diff --git a/collects/picturing-programs/tests/player b/collects/picturing-programs/tests/player new file mode 100644 index 0000000000..38d9e9e9e9 --- /dev/null +++ b/collects/picturing-programs/tests/player @@ -0,0 +1,15 @@ +#! /bin/sh +#| -*- scheme -*- +exec mred -qu "$0" ${1+"$@"} +|# + +#lang scheme + +(require "shared.ss") + +(define argv (current-command-line-arguments)) + +(unless (= (vector-length argv) 1) + (error 'player "name of one player expected: $ ./player name")) + +(make-player 200 (vector-ref argv 0)) diff --git a/collects/picturing-programs/tests/profile-robby.ss b/collects/picturing-programs/tests/profile-robby.ss new file mode 100644 index 0000000000..ce1da9d02c --- /dev/null +++ b/collects/picturing-programs/tests/profile-robby.ss @@ -0,0 +1,18 @@ +#lang scheme/gui +(require profile + scheme/runtime-path) + +(define-runtime-path perform-robby "perform-robby.ss") + +(profile-thunk + (λ () + (parameterize ([current-eventspace (make-eventspace)]) + (let ([s (make-semaphore 0)]) + (queue-callback + (λ () + (dynamic-require perform-robby #f) + (semaphore-post s))) + (semaphore-wait s)))) + #:threads #t) + + diff --git a/collects/picturing-programs/tests/robby-optimization-gone.ss b/collects/picturing-programs/tests/robby-optimization-gone.ss new file mode 100644 index 0000000000..528df04b92 --- /dev/null +++ b/collects/picturing-programs/tests/robby-optimization-gone.ss @@ -0,0 +1,20 @@ +#lang scheme/gui + +(require 2htdp/universe) +(require 2htdp/image) + +(define s "") +(define x 1) + +(big-bang 1 + (on-tick (lambda (w) + (begin + (set! x (+ x 1)) + (if (= x 3) 0 1)))) + (stop-when zero?) + (on-draw (lambda (w) + (begin + (set! s (string-append "-" s)) + (rectangle 1 1 'solid 'green))))) + +(unless (string=? s "---") (error 'world-update-test "failed! ~s" s)) diff --git a/collects/picturing-programs/tests/rotating-triangle.ss b/collects/picturing-programs/tests/rotating-triangle.ss new file mode 100644 index 0000000000..344c6f1fd3 --- /dev/null +++ b/collects/picturing-programs/tests/rotating-triangle.ss @@ -0,0 +1,24 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-beginner-reader.ss" "lang")((modname rotating-triangle) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) +(require picturing-programs) + +(define R 60) +(define SIDE (* R (sqrt 3))) +(define TRI (triangle SIDE "solid" "blue")) +(define CIRC (circle R "solid" "white")) +(define tricirc (overlay/xy TRI + (- (/ SIDE 2) R) 0 + CIRC)) +(define badtricirc + (overlay/align "middle" "middle" + TRI + CIRC)) + +(define (rotate-1 pic) + (rotate 1 pic)) + +(big-bang badtricirc + (on-tick rotate-1 .05) + (check-with image?) + (on-draw show-it)) diff --git a/collects/picturing-programs/tests/sam.ss b/collects/picturing-programs/tests/sam.ss new file mode 100644 index 0000000000..6ed9176f14 --- /dev/null +++ b/collects/picturing-programs/tests/sam.ss @@ -0,0 +1,7 @@ +;; The first three lines of this file were inserted by DrScheme. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname sam) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) +(require "shared.ss") +(require picturing-programs) + +(launch-many-worlds (make-player 200 "sam") (make-player 100 "carl")) diff --git a/collects/picturing-programs/tests/shared.ss b/collects/picturing-programs/tests/shared.ss new file mode 100644 index 0000000000..fff1a9093d --- /dev/null +++ b/collects/picturing-programs/tests/shared.ss @@ -0,0 +1,74 @@ +#lang scheme + +(require picturing-programs htdp/testing) +;(require "../2htdp/universe.ss" htdp/testing) + +;; World = Number | 'resting +(define WORLD0 'resting) + +;; constants +(define HEIGHT 100) +(define DefWidth 50) + +;; visual constants +(define BALL (circle 3 'solid 'red)) + +(define mt (nw:rectangle DefWidth HEIGHT 'solid 'gray)) + +;; ----------------------------------------------------------------------------- +;; Number (U String Symbol) -> true +;; create and hook up a player with the localhost server +(define (make-player width t) + (local ((define mt (place-image (text (format "~a" t) 11 'black) + 5 85 + (empty-scene width HEIGHT))) + + ;; ---------------------------------------------------------------- + ;; World Number -> Message + ;; on receiving a message from server, place the ball at lower end or stop + #| + (check-expect (receive 'resting 'go) HEIGHT) + (check-expect (receive HEIGHT 'go) HEIGHT) + (check-expect (receive (- HEIGHT 1) 'go) (- HEIGHT 1)) + (check-expect (receive 0 'go) 0) + |# + (define (receive w n) + (cond + [(number? w) w] + [else HEIGHT])) + ;; World -> World + #| + (check-expect (move 'resting) 'resting) + (check-expect (move HEIGHT) (- HEIGHT 1)) + (check-expect (move 0) (make-package 'resting 'go)) + |# + (define (move x) + (cond + [(symbol? x) x] + [(number? x) (if (<= x 0) (make-package 'resting 'go) (sub1 x))])) + + ;; World -> Scene + ;; render the world + + ; (check-expect (draw 100) (place-image BALL 50 100 mt)) + + (define (draw w) + (cond + [(symbol? w) (place-image (text "resting" 11 'red) 10 10 mt)] + [(number? w) (place-image BALL 50 w mt)]))) + (big-bang WORLD0 + (on-draw draw) + (on-receive receive) + (on-tick move .01) + (name t) + (check-with (lambda (w) (or (symbol? w) (number? w)))) + (register LOCALHOST)))) + +; (generate-report) + +;; --- + +(require scheme/contract) + +(provide/contract + [make-player (-> (and/c number? (>=/c 100)) (or/c string? symbol?) any/c)]) diff --git a/collects/picturing-programs/tests/stop.ss b/collects/picturing-programs/tests/stop.ss new file mode 100644 index 0000000000..ad0b47216c --- /dev/null +++ b/collects/picturing-programs/tests/stop.ss @@ -0,0 +1,21 @@ +;; The first three lines of this file were inserted by DrScheme. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname stop) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) +(require picturing-programs) + +;; on RETURN stop + +(define (main debug?) + (big-bang "" + (on-key (lambda (w ke) + (cond + [(key=? ke "\r") (stop-with w)] + [(= (string-length ke) 1) + (string-append w ke)] + [else w]))) + (state debug?) + (on-draw (lambda (w) + (place-image + (text w 22 'black) + 3 3 + (empty-scene 100 100)))))) diff --git a/collects/picturing-programs/tests/stripes.rkt b/collects/picturing-programs/tests/stripes.rkt new file mode 100644 index 0000000000..2d7daab906 --- /dev/null +++ b/collects/picturing-programs/tests/stripes.rkt @@ -0,0 +1,99 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname stripes) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) + +(require "../package/picturing-programs.rkt") + +; choose-color : num(x) num(y) -> color +(check-expect (choose-color 57 0) (name->color "red")) +(check-expect (choose-color 57 1) (name->color "blue")) +(check-expect (choose-color 72 2) (name->color "red")) +(check-expect (choose-color 14 9) (name->color "blue")) +(define (choose-color x y) + ; x number + ; y number + (cond [(even? y) (name->color "red")] + [(odd? y) (name->color "blue")])) + +; red-blue-stripes : num(width) num(height) -> image +(check-expect (red-blue-stripes 10 0) + (rectangle 10 0 "solid" "purple")) +(check-expect (red-blue-stripes 10 1) + (rectangle 10 1 "solid" "red")) ; fails +(check-expect (red-blue-stripes 10 2) + (above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue"))) +(check-expect (red-blue-stripes 10 3) + (above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red"))) ; fails +(check-expect (red-blue-stripes 10 4) + (above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue"))) +(check-expect (red-blue-stripes 10 5) + (above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red"))) ; fails +(define (red-blue-stripes width height) + ; width number + ; height number + (build-image width height choose-color) + ) + +(red-blue-stripes 10 3) +"should be" +(above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red")) + +(red-blue-stripes 10 5) +"should be" +(above (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red") + (rectangle 10 1 "solid" "blue") + (rectangle 10 1 "solid" "red")) + +(define s0 (red-blue-stripes 10 0)) +(define s1 (red-blue-stripes 10 1)) +(define s2 (red-blue-stripes 10 2)) +(define s3 (red-blue-stripes 10 3)) +(define s4 (red-blue-stripes 10 4)) +(define s5 (red-blue-stripes 10 5)) + +(define grad (build-image 10 10 + (lambda (x y) (make-color (* 25 x) (* 25 y) 0)))) + +(define (dump img) + (map (lambda (y) + (map (lambda (x) + (get-pixel-color x y img)) + (list 0 1 2 (- (image-width img) 2) (- (image-width img) 1))) + ) + (list 0 1 2 (- (image-height img) 2) (- (image-height img) 1)))) + + +(define (red-purple-helper x y c) + (cond [(color=? c (name->color "red")) + (name->color "purple")] + [else c])) + +(define (red->purple pic) + (map red-purple-helper pic)) + +(check-expect (red->purple (rectangle 50 30 "solid" "blue")) + (rectangle 50 30 "solid" "blue")) ; does nothing +(check-expect (red->purple (rectangle 50 30 "solid" "red")) + (rectangle 50 30 "solid" "purple")) ; replaces everything +(check-expect (red->purple (overlay (triangle 30 "solid" "red") + (rectangle 60 60 "solid" "green"))) + (overlay (triangle 30 "solid" "purple") + (rectangle 60 60 "solid" "green"))) +(check-expect (red->purple (overlay (text "hello" 18 "red") + (ellipse 100 50 "solid" "yellow"))) + (overlay (text "hello" 18 "purple") + (ellipse 100 50 "solid" "yellow"))) diff --git a/collects/picturing-programs/tests/test-image.ss b/collects/picturing-programs/tests/test-image.ss new file mode 100644 index 0000000000..2372d1a0ec --- /dev/null +++ b/collects/picturing-programs/tests/test-image.ss @@ -0,0 +1,1561 @@ +#lang scheme/base +#| +;; snippet of code for experimentation +#lang scheme/gui +(require 2htdp/image + lang/posn + (only-in lang/htdp-advanced equal~?)) + +(define images + (list (rhombus 10 90 'solid 'black) + (rotate 45 (square 10 'solid 'black)))) + +(define t (new text%)) +(define f (new frame% [label ""] [width 600] [height 400])) +(define ec (new editor-canvas% [parent f] [editor t])) +(for ((i (in-list images))) (send t insert i) (send t insert " ")) +(send f show #t) +|# + +(require "../image.ss" + (only-in "../../mrlib/image-core.ss" + image% + make-image + image-shape + image-bb + image-normalized? + skip-image-equality-fast-path + make-overlay + make-translate + make-bb + normalize-shape + make-ellipse + make-polygon + make-point + make-crop + crop? + normalized-shape?) + (only-in "../private/image-more.ss" + bring-between + swizzle) + "../private/img-err.ss" + "../../mrlib/private/image-core-bitmap.ss" + lang/posn + scheme/math + scheme/class + scheme/gui/base + schemeunit + (only-in lang/htdp-advanced equal~?)) + +(require (for-syntax scheme/base)) +(define-syntax (test stx) + (syntax-case stx () + [(test a => b) + (with-syntax ([check-equal? (datum->syntax #'here 'check-equal? stx)]) + #`(begin + ;(printf "running line ~a\n" #,(syntax-line stx)) + #,(quasisyntax/loc stx (check-equal? a b)) + (parameterize ([skip-image-equality-fast-path #t]) + #,(quasisyntax/loc stx (check-equal? a b)))))])) + +(define-syntax (test/exn stx) + (syntax-case stx () + [(test/exn a => b) + (with-syntax ([check-equal? (datum->syntax #'here 'check-equal? stx)]) + #`(let ([reg b]) + (unless (regexp? reg) + (error 'test/exn "expected a regular expression, got ~e" reg)) + ;(printf "running line ~a\n" #,(syntax-line stx)) + #,(quasisyntax/loc stx (check-regexp-match + reg + (with-handlers ((exn:fail? exn-message)) a "NO EXN!")))))])) + +;; test case: (beside (text "a"...) (text "b" ...)) vs (text "ab") + +;(show-image (frame (rotate 30 (ellipse 200 400 'solid 'purple)))) + +(define-simple-check (check-close a b) + (and (number? a) + (number? b) + (< (abs (- a b)) 0.001))) + +(define-syntax-rule + (round-numbers e) + (call-with-values (λ () e) round-numbers/values)) + +(define (round-numbers/values . args) (apply values (round-numbers/proc args))) + +(define (round-numbers/proc x) + (let loop ([x x]) + (cond + [(number? x) (let ([n (exact->inexact (/ (round (* 100. x)) 100))]) + (if (equal? n -0.0) + 0.0 + n))] + [(pair? x) (cons (loop (car x)) (loop (cdr x)))] + [(vector? x) (apply vector (map loop (vector->list x)))] + [(is-a? x image%) + (make-image + (loop (image-shape x)) + (loop (image-bb x)) + (loop (image-normalized? x)))] + [(object? x) + ;; add a random number here to hack around the way Eli's tester treats two errors as a passing test + (error 'round-numbers/proc "cannot handle objects ~a" (random))] + [(let-values ([(a b) (struct-info x)]) a) + => + (λ (struct-type) + (apply + (struct-type-make-constructor struct-type) + (map loop (cdr (vector->list (struct->vector x))))))] + [else x]))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; circle vs ellipse +;; + +(test (ellipse 40 40 'outline 'black) + => + (circle 20 'outline 'black)) +(test (ellipse 60 60 'solid 'red) + => + (circle 30 'solid 'red)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; width and height +;; + +(test (image-width (rectangle 10 20 'solid 'blue)) + => + 10) +(test (image-height (rectangle 10 20 'solid 'blue)) + => + 20) +(test (image-width (rectangle 0 100 'solid 'blue)) + => + 0) +(test (image-height (rectangle 0 100 'solid 'blue)) + => + 100) +(test (image-width (rectangle 100 0 'solid 'blue)) + => + 100) +(test (image-height (rectangle 100 0 'solid 'blue)) + => + 0) + +(check-close (image-width (rotate 45 (rectangle 100 0 'solid 'blue))) + (inexact->exact (ceiling (* (sin (* pi 1/4)) 100)))) +(check-close (image-height (rotate 45 (rectangle 100 0 'solid 'blue))) + (inexact->exact (ceiling (* (sin (* pi 1/4)) 100)))) +(check-close (image-width (rotate 45 (rectangle 0 100 'solid 'blue))) + (inexact->exact (ceiling (* (sin (* pi 1/4)) 100)))) +(check-close (image-height (rotate 45 (rectangle 0 100 'solid 'blue))) + (inexact->exact (ceiling (* (sin (* pi 1/4)) 100)))) + +(test (image-width (scale 4 (rectangle 10 10 'outline 'black))) + => + 40) +(test (image-width (rotate 90 (scale 4 (rectangle 10 10 'outline 'black)))) + => + 40) + +(test (image-width (scale 4 (rectangle 10 10 'solid 'black))) + => + 40) +(test (image-width (rotate 90 (scale 4 (rectangle 10 10 'solid 'black)))) + => + 40) + + +(test (image-width (ellipse 10 20 'solid 'blue)) + => + 10) +(test (image-height (ellipse 10 20 'solid 'blue)) + => + 20) +(test (image-width (ellipse 0 100 'solid 'blue)) + => + 0) +(test (image-height (ellipse 0 100 'solid 'blue)) + => + 100) +(test (image-width (ellipse 100 0 'solid 'blue)) + => + 100) +(test (image-height (ellipse 100 0 'solid 'blue)) + => + 0) + +(test (image-width (rotate 30 (ellipse 100 0 'solid 'blue))) + => + (inexact->exact (ceiling (* (cos (* pi 1/6)) 100)))) +(test (image-height (rotate 30 (ellipse 100 0 'solid 'blue))) + => + (inexact->exact (ceiling (* (sin (* pi 1/6)) 100)))) +(check-close (image-width (rotate 30 (ellipse 0 100 'solid 'blue))) + (* (sin (* pi 1/6)) 100)) +(check-close (image-height (rotate 30 (ellipse 0 100 'solid 'blue))) + (ceiling (* (cos (* pi 1/6)) 100))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; polygon equality +;; + +(test (polygon (list (make-posn 0 0) + (make-posn 10 10) + (make-posn 10 0)) + "solid" "plum") + => + (polygon (list (make-posn 10 10) + (make-posn 10 0) + (make-posn 0 0)) + "solid" "plum")) + +(test (polygon (list (make-posn 0 0) + (make-posn 0 10) + (make-posn 10 10) + (make-posn 10 0)) + "solid" "plum") + => + (rectangle 10 10 "solid" "plum")) + +(test (polygon (list (make-posn 0 0) + (make-posn 0 10) + (make-posn 10 10) + (make-posn 10 0)) + "solid" "plum") + => + (polygon (list (make-posn 0 0) + (make-posn 0 10) + (make-posn 10 10) + (make-posn 10 0) + (make-posn 0 0)) + "solid" "plum")) + +(test (polygon (list (make-posn 0 0) + (make-posn 0 10) + (make-posn 10 10) + (make-posn 10 0)) + "outline" + (make-pen "plum" 8 "solid" "round" "round")) + => + (polygon (list (make-posn 0 0) + (make-posn 0 10) + (make-posn 10 10) + (make-posn 10 0) + (make-posn 0 0)) + "outline" + (make-pen "plum" 8 "solid" "round" "round"))) + +;; make sure equality isn't equating everything +(test (equal? (rectangle 10 10 'solid 'blue) + (rectangle 10 10 'solid 'red)) + => + #f) + +;; make sure 'white and black match up with color structs +(test (rectangle 10 10 'solid (make-color 255 255 255)) + => + (rectangle 10 10 'solid 'white)) +(test (rectangle 10 10 'solid (make-color 0 0 0)) + => + (rectangle 10 10 'solid 'black)) + +;; test zero sized image equalities + +(test (rectangle 0 100 'solid 'white) + => + (rectangle 0 100 'solid 'white)) + +(test (rectangle 0 100 'solid 'white) + => + (rectangle 0 100 'solid 'black)) + +(test (rectangle 100 0 'solid 'white) + => + (rectangle 100 0 'solid 'black)) + +(test (rectangle 0 0 'solid 'black) + => + (rectangle 0 0 'solid 'orange)) + +(test (equal~? (rectangle 0 100 'solid 'white) + (rotate 90 (rectangle 100 0 'solid 'black)) + .1) + => + #t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; testing overlays +;; + +(test (overlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 10 10 (image-shape (ellipse 100 100 'solid 'blue))) + (make-translate 0 0 (image-shape (ellipse 120 120 'solid 'red)))) + (make-bb 120 + 120 + 120) + #f)) + +(test (overlay/xy (ellipse 100 100 'solid 'blue) + -10 -10 + (ellipse 120 120 'solid 'red)) + => + (overlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red))) + + +(test (overlay/xy (ellipse 50 100 'solid 'red) + -25 25 + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate + 25 0 + (image-shape (ellipse 50 100 'solid 'red))) + (make-translate + 0 25 + (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 + 100 + 100) + #f)) + +(test (overlay/xy (ellipse 100 50 'solid 'green) + 10 10 + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 10 10 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 + 110 + 110) + #f)) + +(test (overlay (ellipse 100 50 'solid 'green) + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 + 100 + 100) + #f)) + +(test (overlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red) + (ellipse 140 140 'solid 'green)) + => + (make-image + (make-overlay + (make-translate + 10 10 + (make-overlay + (make-translate 10 10 (image-shape (ellipse 100 100 'solid 'blue))) + (make-translate 0 0 (image-shape (ellipse 120 120 'solid 'red))))) + (make-translate 0 0 (image-shape (ellipse 140 140 'solid 'green)))) + (make-bb 140 140 140) + #f)) + +(test (overlay/align 'middle + 'middle + (ellipse 100 50 'solid 'green) + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 100 100) + #f)) + +(test (overlay/align 'middle + 'middle + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 100 100) + #f)) + + +(test (overlay/align 'right + 'bottom + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 100 100) + #f)) + +(test (overlay/align 'right + 'baseline + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 100 100) + #f)) + +(test (beside/align 'top + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 50 0 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 150 100 100) + #f)) + +(test (beside/align 'center + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 50 25 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 150 100 100) + #f)) + +(test (beside/align 'baseline + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 50 50 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 150 100 100) + #f)) + +(test (beside (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + => + (beside/align 'center + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue))) + +(test (above/align 'left + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 100 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 100 150 150) + #f)) + +(test (above/align 'center + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 100 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 100 150 150) + #f)) + +(test (above/align 'right + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + + => + (make-image + (make-overlay + (make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 100 (image-shape (ellipse 100 50 'solid 'blue)))) + (make-bb 100 150 150) + #f)) + +(test (above (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue)) + => + (above/align 'center + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'blue))) + + + +(test (underlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 0 0 (image-shape (ellipse 120 120 'solid 'red))) + (make-translate 10 10 (image-shape (ellipse 100 100 'solid 'blue)))) + (make-bb 120 + 120 + 120) + #f)) + +(test (underlay/xy (ellipse 100 100 'solid 'blue) + -10 -10 + (ellipse 120 120 'solid 'red)) + => + (underlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red))) + + +(test (underlay/xy (ellipse 50 100 'solid 'red) + -25 25 + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 + 100 + 100) + #f)) + +(test (underlay/xy (ellipse 100 50 'solid 'green) + 10 10 + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 10 10 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 0 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 + 110 + 110) + #f)) + +(test (underlay (ellipse 100 50 'solid 'green) + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 + 100 + 100) + #f)) + +(test (underlay (ellipse 100 100 'solid 'blue) + (ellipse 120 120 'solid 'red) + (ellipse 140 140 'solid 'green)) + => + (make-image + (make-overlay + (make-translate + 0 0 + (make-overlay + (make-translate 0 0 (image-shape (ellipse 140 140 'solid 'green))) + (make-translate 10 10 (image-shape (ellipse 120 120 'solid 'red))))) + (make-translate 10 10 (image-shape (ellipse 100 100 'solid 'blue)))) + (make-bb 140 140 140) + #f)) + +(test (underlay/align 'middle + 'middle + (ellipse 100 50 'solid 'green) + (ellipse 50 100 'solid 'red)) + => + (make-image + (make-overlay + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red))) + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green)))) + (make-bb 100 100 100) + #f)) + +(test (underlay/align 'middle + 'middle + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 0 25 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 25 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 100 100) + #f)) + +(test (underlay/align 'right + 'bottom + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 100 100) + #f)) + +(test (underlay/align "right" + "baseline" + (ellipse 50 100 'solid 'red) + (ellipse 100 50 'solid 'green)) + => + (make-image + (make-overlay + (make-translate 0 50 (image-shape (ellipse 100 50 'solid 'green))) + (make-translate 50 0 (image-shape (ellipse 50 100 'solid 'red)))) + (make-bb 100 100 100) + #f)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; testing normalization +;; + +(test (normalize-shape (image-shape (ellipse 50 100 'solid 'red)) + values) + => + (make-translate 25 50 (make-ellipse 50 100 0 'solid "red"))) + +(test (normalize-shape (make-overlay (image-shape (ellipse 50 100 'solid 'red)) + (image-shape (ellipse 50 100 'solid 'blue))) + values) + => + (make-overlay (image-shape (ellipse 50 100 'solid 'red)) + (image-shape (ellipse 50 100 'solid 'blue)))) + +(test (normalize-shape (make-overlay + (make-overlay (image-shape (ellipse 50 100 'solid 'red)) + (image-shape (ellipse 50 100 'solid 'blue))) + (image-shape (ellipse 50 100 'solid 'green))) + values) + => + (make-overlay + (make-overlay (make-translate 25 50 (make-ellipse 50 100 0 'solid "red")) + (make-translate 25 50 (make-ellipse 50 100 0 'solid "blue"))) + (make-translate 25 50 (make-ellipse 50 100 0 'solid "green")))) + +(test (normalize-shape (make-overlay + (image-shape (ellipse 50 100 'solid 'green)) + (make-overlay (image-shape (ellipse 50 100 'solid 'red)) + (image-shape (ellipse 50 100 'solid 'blue)))) + values) + => + (make-overlay + (make-overlay (make-translate 25 50 (make-ellipse 50 100 0 'solid "green")) + (make-translate 25 50 (make-ellipse 50 100 0 'solid "red"))) + (make-translate 25 50 (make-ellipse 50 100 0 'solid "blue")))) + +(test (normalize-shape (make-translate 100 100 (image-shape (ellipse 50 100 'solid 'blue))) + values) + => + (make-translate 125 150 (make-ellipse 50 100 0 'solid "blue"))) + +(test (normalize-shape (make-translate 10 20 (make-translate 100 100 (image-shape (ellipse 50 100 'solid 'blue)))) + values) + => + (make-translate 135 170 (make-ellipse 50 100 0 'solid "blue"))) + +(test (normalize-shape (image-shape + (beside/align 'top + (rectangle 10 10 'solid 'black) + (crop 0 0 5 5 (rectangle 10 10 'solid 'green))))) + => + (make-overlay + (make-polygon + (list (make-point 0 0) + (make-point 10 0) + (make-point 10 10) + (make-point 0 10)) + 'solid + "black") + (make-crop + (list (make-point 10 0) + (make-point 15 0) + (make-point 15 5) + (make-point 10 5)) + (make-polygon + (list (make-point 10 0) + (make-point 20 0) + (make-point 20 10) + (make-point 10 10)) + 'solid + "green")))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; testing rotating +;; + +(test (bring-between 123 360) => 123) +(test (bring-between 365 360) => 5) +(test (bring-between -5 360) => 355) +(test (bring-between 720 360) => 0) +(test (bring-between 720.5 360) => .5) + +(test (equal~? (rotate 90 (rectangle 100 100 'solid 'blue)) + (rectangle 100 100 'solid 'blue) + .1) + => + #t) + +(test (round-numbers + (normalize-shape (image-shape (rotate 90 (rotate 90 (rectangle 50 100 'solid 'purple)))) + values)) + => + (round-numbers + (normalize-shape (image-shape (rotate 180 (rectangle 50 100 'solid 'purple))) + values))) + +(test (round-numbers (normalize-shape (image-shape (rotate 90 (ellipse 10 10 'solid 'red))))) + => + (round-numbers (normalize-shape (image-shape (ellipse 10 10 'solid 'red))))) + +(test (round-numbers (normalize-shape (image-shape (rotate 90 (ellipse 10 12 'solid 'red))))) + => + (round-numbers (normalize-shape (image-shape (ellipse 12 10 'solid 'red))))) + +(test (round-numbers (normalize-shape (image-shape (rotate 135 (ellipse 10 12 'solid 'red))))) + => + (round-numbers (normalize-shape (image-shape (rotate 45 (ellipse 12 10 'solid 'red)))))) + +(test (round-numbers (rotate -90 (ellipse 200 400 'solid 'purple))) + => + (round-numbers (rotate 90 (ellipse 200 400 'solid 'purple)))) + +(test (equal~? (rectangle 100 10 'solid 'red) + (rotate 90 (rectangle 10 100 'solid 'red)) + 0.1) + => + #t) + +(test (equal~? (rectangle 100 10 'solid 'red) + (rotate 90 (rectangle 10.001 100.0001 'solid 'red)) + 0.1) + => + #t) + +(test (equal~? (rotate + 90 + (overlay/xy (rectangle 20 100 'solid 'purple) + 20 0 + (ellipse 40 40 'solid 'orange))) + (overlay/xy (rectangle 100 20 'solid 'purple) + 0 -40 + (ellipse 40 40 'solid 'orange)) + .1) + => + #t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; scaling tests +;; + +(test (scale 2 (rectangle 100 10 'solid 'blue)) + => + (rectangle 200 20 'solid 'blue)) + +(test (scale 3 + (overlay/xy (rectangle 100 10 'solid 'blue) + 0 + 20 + (rectangle 100 10 'solid 'red))) + => + (overlay/xy (rectangle 300 30 'solid 'blue) + 0 + 60 + (rectangle 300 30 'solid 'red))) + +(test (scale 3 + (overlay/xy (rectangle 100 10 'solid 'blue) + 0 + 20 + (overlay/xy (rectangle 100 10 'solid 'blue) + 0 + 20 + (rectangle 100 10 'solid 'purple)))) + => + (overlay/xy (rectangle 300 30 'solid 'blue) + 0 + 60 + (overlay/xy (rectangle 300 30 'solid 'blue) + 0 + 60 + (rectangle 300 30 'solid 'purple)))) + +(test (scale/xy 3 4 (ellipse 30 60 'outline 'purple)) + => + (ellipse (* 30 3) (* 60 4) 'outline 'purple)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; misc tests +;; + +(test (rectangle 100 10 'solid 'blue) + => + (rectangle 100 10 "solid" "blue")) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; regular polygon +;; + +;; note: the regular-polygon and the rectangle generate the points in reverse directions. +(test (round-numbers (regular-polygon 100 4 'outline 'green)) + => + (round-numbers (rectangle 100 100 'outline 'green))) + +(test (swizzle (list 0 1 2 3 4) 2) + => + (list 0 2 4 1 3)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; text +;; + +(test (beside/align "baseline" + (text "a" 18 "black") + (text "b" 18 "black")) + => + (text "ab" 18 "black")) + +(test (round-numbers + (image-width (rotate 45 (text "One" 18 'black)))) + => + (round-numbers + (let ([t (text "One" 18 'black)]) + (image-width (rotate 45 (rectangle (image-width t) + (image-height t) + 'solid 'black)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; triangle +;; + +(test (round-numbers (rotate 180 (isosceles-triangle 60 330 "solid" "lightseagreen"))) + => + (round-numbers (isosceles-triangle 60 30 "solid" "lightseagreen"))) + +(test (triangle 40 'outline 'black) + => + (regular-polygon 40 3 'outline 'black)) + +(test (equal~? (rotate (+ 180 45) (right-triangle 50 50 'solid 'black)) + (isosceles-triangle 50 90 'solid 'black) + 0.001) + => + #t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; square +;; + +(test (square 10 'solid 'black) + => + (rectangle 10 10 'solid 'black)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; rhombus +;; + +(test (equal~? (rhombus 10 90 'solid 'black) + (rotate 45 (square 10 'solid 'black)) + 0.01) + => + #t) + +(test (equal~? (rhombus 50 150 'solid 'black) + (rotate 90 (rhombus 50 30 'solid 'black)) + 0.01) + => + #t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; lines +;; + +(test (image-width (line 10 20 'black)) + => + 11) +(test (image-height (line 10 20 'black)) + => + 21) + +(test (round-numbers (rotate 90 (line 10 20 'black))) + => + (round-numbers (line 20 -10 'black))) + +(test (round-numbers (line 20 30 "red")) + => + (round-numbers (rotate 180 (line 20 30 "red")))) + +(test (round-numbers (line -30 20 "red")) + => + (round-numbers (line 30 -20 "red"))) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 10 10 90 190 "red")) + => + 100) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 10 10 90 190 "red")) + => + 200) +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 10 10 200 200 "red")) + => + 200) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 10 10 200 200 "red")) + => + 200) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 10 10 300 300 "red")) + => + 300) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 10 10 300 300 "red")) + => + 300) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + -10 10 100 200 "red")) + => + 110) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + -10 10 100 200 "red")) + => + 200) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 10 -10 100 200 "red")) + => + 100) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 10 -10 100 200 "red")) + => + 210) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 100 200 10 -10 "red")) + => + 100) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 100 200 10 -10 "red")) + => + 210) + +(test (image-width (add-line (rectangle 100 200 'solid 'black) + 100 200 -10 10 "red")) + => + 110) +(test (image-height (add-line (rectangle 100 200 'solid 'black) + 100 200 -10 10 "red")) + => + 200) + +(let* ([txt (text "H" 24 'black)] + [bl (image-baseline txt)]) + (test (image-baseline (add-line txt 0 0 100 100 'red)) + => + bl)) + +(let* ([txt (text "H" 24 'black)] + [bl (image-baseline txt)]) + (test (image-baseline (add-line txt 0 -10 100 100 'red)) + => + (+ bl 10))) + +(test (scene+line (rectangle 100 100 'solid 'black) + 10 10 + 90 50 + "red") + => + (add-line (rectangle 100 100 'solid 'black) + 10 10 + 90 50 + "red")) + +(test (image-width (scene+line (rectangle 100 100 'solid 'black) + -10 -20 + 110 120 + "green")) + => + 100) +(test (image-height (scene+line (rectangle 100 100 'solid 'black) + -10 -20 + 110 120 + 'purple)) + => + 100) +(test (image-baseline (scene+line (rectangle 100 100 'solid 'black) + -10 -20 + 110 120 + 'olive)) + => + 100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; curves +;; + +;; make sure a curve stays roughly in the middle pixels by +;; covering up a white curve with a thin black bar +(test (overlay/align 'middle + 'middle + (rectangle 82 2 'solid 'black) + (add-curve (rectangle 100 20 'solid 'black) + 10 10 0 1/4 + 90 10 0 1/4 + 'white)) + + => + (rectangle 100 20 'solid 'black)) + +;; and then make sure the curve actually draws something ... +(test (not (equal? (add-curve (rectangle 100 20 'solid 'black) + 10 10 0 1/4 + 90 10 0 1/4 + 'white) + (rectangle 100 20 'solid 'black))) + => + #t) + +(test (scale 2 + (add-curve + (rectangle 100 100 'solid 'black) + 20 20 0 1/3 80 80 0 1/3 'white)) + => + (add-curve + (rectangle 200 200 'solid 'black) + 40 40 0 1/3 160 160 0 1/3 'white)) + +(test (rotate + 90 + (add-curve + (rectangle 100 100 'solid 'black) + 20 20 0 1/3 80 80 0 1/3 'white)) + => + (add-curve + (rectangle 100 100 'solid 'black) + 20 80 90 1/3 80 20 90 1/3 'white)) + +(test (add-curve (rectangle 100 100 'solid 'black) + 10 10 0 1/4 + 90 90 0 1/4 + 'white) + => + (scene+curve (rectangle 100 100 'solid 'black) + 10 10 0 1/4 + 90 90 0 1/4 + 'white)) +(test (scene+curve (rectangle 100 100 'solid 'black) + 10 10 0 1/4 + 110 110 0 1/4 + 'red) + + => + (crop 0 0 100 100 + (add-curve (rectangle 100 100 'solid 'black) + 10 10 0 1/4 + 110 110 0 1/4 + 'red))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; bitmap tests +;; + +(test (clamp-1 0 3 5) + => 3) +(test (clamp-1 0 0 5) + => 0) +(test (clamp-1 0 -2 5) + => 0) +(test (clamp-1 0 4 5) + => 4) +(test (clamp-1 0 7 5) + => 4) + +(test (build-bytes 5 sqr) + => (list->bytes '(0 1 4 9 16))) + + +(define onePixel (list->bytes '(255 0 0 255))) +;(call-with-values (λ () (scale onePixel 1 1 100)) show-bitmap) + +(define blue2x1 (list->bytes '(255 0 0 255 255 0 255 0))) +;(call-with-values (λ () (scale blue2x1 2 1 20)) show-bitmap) + +(define blue2x2 (list->bytes '(255 0 0 255 255 0 0 255 255 0 0 255 255 0 0 255))) +(define gray2x2 (list->bytes '(255 100 100 100 255 100 100 100 255 100 100 100 255 100 100 100))) +;; Some blue x green checkerboards: +(define checker2x2 (list->bytes '(255 0 0 255 255 0 255 0 + 255 0 255 0 255 0 0 255))) +(define checker3x3 (list->bytes '(255 0 0 255 255 0 255 0 255 0 0 255 + 255 0 255 0 255 0 0 255 255 0 255 0 + 255 0 0 255 255 0 255 0 255 0 0 255 ))) + + +(test (bmbytes-ref/safe checker3x3 3 3 0 0) => (list->bytes '(255 0 0 255))) +(test (bmbytes-ref/safe checker3x3 3 3 1 1) => (list->bytes '(255 0 0 255))) +(test (bmbytes-ref/safe checker3x3 3 3 2 2) => (list->bytes '(255 0 0 255))) +(test (bmbytes-ref/safe checker3x3 3 3 1 2) => (list->bytes '(255 0 255 0))) +(test (bmbytes-ref/safe checker3x3 3 3 0 3) => (list->bytes '( 0 0 0 255))) +(test (bmbytes-ref/safe checker3x3 3 3 -1 -1) => (list->bytes '( 0 0 0 255))) +(test (bmbytes-ref/safe checker3x3 3 3 -1 1) => (list->bytes '( 0 0 255 0))) +(test (bmbytes-ref/safe checker3x3 3 3 1 19) => (list->bytes '( 0 0 255 0))) + +#; +(test (bytes->list (interpolate checker2x2 2 2 1 0)) + => + '(255 0 255 0)) + +#; +(test (bytes->list (interpolate checker3x3 3 3 0 0)) + => + '(255 0 0 255)) + +#; +(test (bytes->list (interpolate checker3x3 3 3 0 1)) + => + '(255 0 255 0)) + +#; +(test (bytes->list (interpolate checker3x3 3 3 0 2)) + => + '(255 0 0 255)) + +#; +(test (bytes->list (interpolate checker3x3 3 3 0.5 0)) + => + '(255 0 128 128)) + +(test (image-width (bitmap icons/stop-16x16.png)) + => + 16) +(test (image-height (bitmap icons/stop-16x16.png)) + => + 16) + +(test (let () + (define bmp (make-object bitmap% 4 4)) + (define mask (make-object bitmap% 4 4)) + (define bdc (make-object bitmap-dc% bmp)) + (send bdc set-brush "black" 'solid) + (send bdc draw-rectangle 0 0 4 4) + (send bdc set-bitmap mask) + (send bdc set-brush "black" 'solid) + (send bdc clear) + (send bdc draw-rectangle 1 1 1 1) + (send bdc set-bitmap #f) + (let-values ([(bytes w h) (bitmap->bytes bmp mask)]) + bytes)) + => + (bytes-append #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" + #"\0\0\0\0" #"\377\0\0\0" #"\0\0\0\0" #"\0\0\0\0" + #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" + #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0" #"\0\0\0\0")) + +;; ensure no error +(test (begin (scale 2 (make-object bitmap% 10 10)) + (void)) + => + (void)) + + +(define (fill-bitmap b color) + (let ([bdc (make-object bitmap-dc% b)]) + (send bdc set-brush color 'solid) + (send bdc set-pen color 1 'transparent) + (send bdc draw-rectangle 0 0 (send b get-width) (send b get-height)) + (send bdc set-bitmap #f))) + +(define blue-10x20-bitmap (make-object bitmap% 10 20)) +(fill-bitmap blue-10x20-bitmap "blue") +(define blue-20x10-bitmap (make-object bitmap% 20 10)) +(fill-bitmap blue-20x10-bitmap "blue") +(define blue-20x40-bitmap (make-object bitmap% 20 40)) +(fill-bitmap blue-20x40-bitmap "blue") + +(test (image-width (image-snip->image (make-object image-snip% blue-10x20-bitmap))) + => + 10) +(test (image-height (image-snip->image (make-object image-snip% blue-10x20-bitmap))) + => + 20) +(test (image-baseline (image-snip->image (make-object image-snip% blue-10x20-bitmap))) + => + 20) +(test (scale 2 (make-object image-snip% blue-10x20-bitmap)) + => + (image-snip->image (make-object image-snip% blue-20x40-bitmap))) + +(test (rotate 90 (make-object image-snip% blue-10x20-bitmap)) + => + (image-snip->image (make-object image-snip% blue-20x10-bitmap))) + +;; there was a bug in the bounding box computation for scaled bitmaps that this test exposes +(test (image-width (frame (rotate 90 (scale 1/2 (bitmap icons/plt-logo-red-diffuse.png))))) + => + 128) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; cropping (and place-image) +;; + +(test (crop 0 0 10 10 (rectangle 20 20 'solid 'black)) + => + (rectangle 10 10 'solid 'black)) + +(test (equal~? (crop 0 0 40 40 (circle 40 'solid 'red)) + (rotate 180 (crop 40 40 40 40 (circle 40 'solid 'red))) + 0.1) + => + #t) + +(test (beside/align 'middle + (rectangle 10 10 'solid 'black) + (crop 0 0 10 10 (rectangle 10 10 'solid 'green))) + => + (beside/align 'middle + (rectangle 10 10 'solid 'black) + (rectangle 10 10 'solid 'green))) + +(test (place-image/align (circle 4 'solid 'black) + 10 10 + 'left 'top + (rectangle 40 40 'solid 'orange)) + => + (underlay/xy (rectangle 40 40 'solid 'orange) + 10 10 + (circle 4 'solid 'black))) + +(test (place-image/align (circle 4 'solid 'black) + 50 50 + 'left 'top + (rectangle 40 40 'solid 'orange)) + => + (rectangle 40 40 'solid 'orange)) + +(test (place-image/align (circle 4 'solid 'black) + 36 36 + 'left 'top + (rectangle 40 40 'solid 'orange)) + => + (underlay/xy (rectangle 40 40 'solid 'orange) + 36 36 + (crop 0 0 4 4 (circle 4 'solid 'black)))) + +(test (place-image/align (circle 8 'solid 'black) + -4 -4 + 'left 'top + (rectangle 40 40 'solid 'orange)) + => + (overlay/xy (crop 4 4 16 16 (circle 8 'solid 'black)) + 0 0 + (rectangle 40 40 'solid 'orange))) + +(test (place-image/align (circle 4 'solid 'black) + -4 0 + 'left 'top + (rectangle 40 40 'solid 'orange)) + => + (overlay/xy (crop 4 0 4 8 (circle 4 'solid 'black)) + 0 0 + (rectangle 40 40 'solid 'orange))) + +(test (place-image/align (circle 4 'solid 'black) + 5 10 'center 'center + (rectangle 40 40 'solid 'orange)) + => + (underlay/xy (rectangle 40 40 'solid 'orange) + 1 6 + (circle 4 'solid 'black))) + + +(test (place-image/align (circle 4 'solid 'black) + 10 15 'right 'bottom + (rectangle 40 40 'solid 'orange)) + => + (underlay/xy (rectangle 40 40 'solid 'orange) + 2 7 + (circle 4 'solid 'black))) + +;; this test case checks to make sure the number of crops doesn't +;; grow when normalizing shapes. +(let* ([an-image + (crop + 0 0 50 50 + (crop + 0 10 60 60 + (crop + 10 0 60 60 + (overlay + (overlay + (ellipse 20 50 'solid 'red) + (ellipse 30 40 'solid 'black)) + (overlay + (ellipse 20 50 'solid 'red) + (ellipse 30 40 'solid 'black))))))] + [an-image+crop + (crop 40 40 10 10 an-image)]) + + (define (count-crops s) + (define crops 0) + (let loop ([s s]) + (when (crop? s) + (set! crops (+ crops 1))) + (when (struct? s) + (for-each loop (vector->list (struct->vector s))))) + crops) + + (test (+ (count-crops (normalize-shape (image-shape an-image))) 1) + => + (count-crops (normalize-shape (image-shape an-image+crop))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; pen arguments +;; + +;; just make sure no errors. +(test (image? (polygon (list (make-posn 0 0) + (make-posn 100 100) + (make-posn 100 0) + (make-posn 0 100)) + "outline" + (make-pen "darkslategray" 6 "solid" "round" "round"))) + => + #t) + +(test (image? (line 10 + 10 + (make-pen "darkslategray" 6 "solid" "round" "round"))) + => + #t) + +(test (scale 2 + (polygon (list (make-posn 0 0) + (make-posn 100 0) + (make-posn 100 100)) + "outline" + (make-pen "black" 6 "solid" "round" "round"))) + => + (polygon (list (make-posn 0 0) + (make-posn 200 0) + (make-posn 200 200)) + "outline" + (make-pen "black" 12 "solid" "round" "round"))) + +(test (scale 2 + (ellipse 30 40 "outline" + (make-pen "black" 2 "solid" "round" "round"))) + => + (ellipse 60 80 "outline" + (make-pen "black" 4 "solid" "round" "round"))) + +(test (scale 2 + (polygon (list (make-posn 0 0) + (make-posn 100 0) + (make-posn 100 100)) + "outline" + (make-pen "black" 0 "solid" "round" "round"))) + => + (polygon (list (make-posn 0 0) + (make-posn 200 0) + (make-posn 200 200)) + "outline" + (make-pen "black" 0 "solid" "round" "round"))) + +(test (scale 2 + (add-line + (rectangle 100 100 'solid 'black) + 20 20 80 80 + (make-pen "black" 6 "solid" "round" "round"))) + => + (add-line + (rectangle 200 200 'solid 'black) + 40 40 160 160 + (make-pen "black" 12 "solid" "round" "round"))) + +(test (scale 2 + (add-curve + (rectangle 100 100 'solid 'black) + 20 20 0 1/2 + 80 80 0 1/2 + (make-pen "black" 6 "solid" "round" "round"))) + => + (add-curve + (rectangle 200 200 'solid 'black) + 40 40 0 1/2 + 160 160 0 1/2 + (make-pen "black" 12 "solid" "round" "round"))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; test that the extra mode check is there +;; + +(test/exn (rectangle 10 10 "solid" (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^rectangle: expected ") + +(test/exn (rectangle 10 10 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^rectangle: expected ") + +(test/exn (circle 10 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^circle: expected ") + +(test/exn (ellipse 10 10 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^ellipse: expected ") + +(test/exn (triangle 10 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^triangle: expected ") + +(test/exn (right-triangle 10 12 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^right-triangle: expected ") + +(test/exn (isosceles-triangle 10 120 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^isosceles-triangle: expected ") + +(test/exn (square 10 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^square: expected ") + +(test/exn (rhombus 40 45 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^rhombus: expected ") + +(test/exn (regular-polygon 40 6 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^regular-polygon: expected ") + +(test/exn (star 40 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^star: expected ") + +(test/exn (star-polygon 40 7 3 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^star-polygon: expected ") + +(test/exn (polygon (list (make-posn 0 0) (make-posn 100 0) (make-posn 100 100)) + 'solid (make-pen "black" 12 "solid" "round" "round")) + => + #rx"^polygon: expected ") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; random testing of normalization +;; make sure normalization actually normalizes +;; and that normalization doesn't introduce new structs +;; + +(require redex/reduction-semantics) + +(define-language 2htdp/image + (image (rectangle size size mode color) + (line coord coord color) + (add-curve (rectangle size size mode color) + coord coord pull angle + coord coord pull angle + color) + (overlay image image) + (overlay/xy image coord coord image) + (underlay image image) + (underlay/xy image coord coord image) + (crop coord coord size size image) + (scale/xy size size image) + (scale size image) + (rotate angle image)) + + (size big-nat) + (mode 'outline 'solid "outline" "solid") + (color "red" 'red "blue" "orange" "green" "black") + (coord big-int) + (pull 0 1/2 1/3 2 (/ big-nat (+ 1 big-nat))) + (angle 0 90 45 30 180 natural (* 4 natural)) + + ; Redex tends to choose small numbers. + (big-nat (+ (* 10 natural) natural)) + (big-int (+ (* 10 integer) integer))) + +(define-namespace-anchor anchor) + +(define (image-struct-count obj) + (let ([counts (make-hash)]) + (let loop ([obj obj]) + (when (struct? obj) + (let ([stuff (vector->list (struct->vector obj))]) + (unless (member (car stuff) '(struct:translate struct:scale)) ;; skip these becuase normalization eliminates them + (hash-set! counts (car stuff) (+ 1 (hash-ref counts (car stuff) 0)))) + (for-each loop (cdr stuff))))) + (sort (hash-map counts list) string<=? #:key (λ (x) (symbol->string (car x)))))) + +(define (check-image-properties img-sexp img) + (let* ([raw-size (image-struct-count (image-shape img))] + [normalized (normalize-shape (image-shape img) values)] + [norm-size (image-struct-count normalized)]) + (unless (normalized-shape? normalized) + (error 'test-image.ss "found a non-normalized shape after normalization:\n~s" + img-sexp)) + (unless (equal? norm-size raw-size) + (error 'test-image.ss "found differing sizes for ~s:\n ~s\n ~s" + img-sexp raw-size norm-size)))) + +(time + (redex-check + 2htdp/image + image + (check-image-properties + (term image) + (eval (term image) (namespace-anchor->namespace anchor))) + #:attempts 1000)) + diff --git a/collects/picturing-programs/tests/ufo-rename.ss b/collects/picturing-programs/tests/ufo-rename.ss new file mode 100644 index 0000000000..f9d074b4be --- /dev/null +++ b/collects/picturing-programs/tests/ufo-rename.ss @@ -0,0 +1,15 @@ +#lang scheme +(require (prefix-in uni: picturing-programs) + ) + +(define (create-UFO-scene height) + (uni:place-image UFO 50 height (uni:empty-scene 100 100))) + +(define UFO + (uni:overlay (uni:circle 10 'solid 'green) + (uni:rectangle 40 4 'solid 'green))) + +(uni:big-bang 0 + (uni:on-tick add1) + (uni:stop-when (lambda (y) (>= y 100))) + (uni:on-draw create-UFO-scene)) diff --git a/collects/picturing-programs/tests/world0-stops.ss b/collects/picturing-programs/tests/world0-stops.ss new file mode 100644 index 0000000000..828a602cf5 --- /dev/null +++ b/collects/picturing-programs/tests/world0-stops.ss @@ -0,0 +1,13 @@ +;; The first three lines of this file were inserted by DrScheme. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname world0-stops) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) + +(require 2htdp/universe) + +"does big-bang stop when the initial world is already a final world?" +(big-bang 0 (stop-when zero?) (on-tick add1)) + +"does big bang stop when the initial world is a stop world?" +(big-bang (stop-with 0) (on-tick add1)) + +(define-struct stop (x)) diff --git a/collects/picturing-programs/tests/xrun b/collects/picturing-programs/tests/xrun new file mode 100644 index 0000000000..f72756086f --- /dev/null +++ b/collects/picturing-programs/tests/xrun @@ -0,0 +1,3 @@ +mred balls.ss & +./player carl & +./player sam & diff --git a/collects/picturing-programs/tiles.rkt b/collects/picturing-programs/tiles.rkt new file mode 100644 index 0000000000..d18e3745ac --- /dev/null +++ b/collects/picturing-programs/tiles.rkt @@ -0,0 +1,143 @@ +#lang racket/base +; Modified 1/19/2005 to be compatible with new image.ss contracts. +; Modified 2/16/2005 to include stuff from world.ss as well as image.ss +; Modified 2/17/2005 to provide on-update-event (which requires overriding a few +; functions from world.ss) +; Modified 5/20/2005 to rename on-update-event as on-redraw-event, and +; handle pinholes more consistently in image-beside and image-above. +; Modified 1/26/2006 to remove the functions I was replacing in image.ss +; (since image.ss now does things the way I wanted) and +; to remove my tweaked copy of world.ss (since world.ss now does things the +; way I wanted). +; Modified 7/12/2006 to allow image-beside and image-above to take variable numbers of arguments. +; Modified 7/26/2006 to add image-beside-align-top, image-beside-align-bottom, image-above-align-left, and image-above-align-right. +; Modified 12/17/2007 to add crop-top, crop-bottom, crop-left, crop-right. Also utility functions slice-pic and unslice-pic. +; Modified 12/26/2007 to provide all-from image.ss, so we never have to mention image.ss at all. +; Modified 8/15/2008 to add image-above-align-center and image-beside-align-center. +; Modified 10/28/2008 to use provide/contract (and 4.x-style module specs, rather than (lib blah blah)) +; Modified again 10/28/2008 to do more user-friendly "check-arg"-style checking instead. +; Modified 1/3/2009 to fix bugs in crop-* and unslice-pic related to zero-sized images. +; Modified 7/9/2009 for compatibility with DrScheme 4.2 +; Modified 10/19/2009 for compatibility with DrScheme 4.2.2: image? is now in htdp/image, so it doesn't need to be required from htdp/advanced. +; Modified 1/12/2010: renamed image-above et al to above et al, image-beside et al to beside et al. +; place-image and scene+line are now defined in sb-universe, so they don't need to be here. +; Modified 1/30/2010 for compatibility with 4.2.4: require 2htdp/private/universe-image, which +; has a bunch of functions that accept both htdp-style images and 2htdp-style images. +; Modified 2/10/2010: replaced color-list with alpha-color-list to fix transparency bug. +; Modified 5/24/2010: eliminated all reference to pinholes, scenes, and htdp/image. +; Now using purely 2htdp/image, 2htdp/universe. Downside: no reflection primitives. +; Modified 6/23/2010: had rotate-cw and rotate-ccw reversed. And now we DO have reflection, +; so I'm putting it back in -- at least for vertical and horizontal axes. +; Modified 6/26/2010 to rename .ss to .rkt, lang scheme to lang racket, etc. +; Modified 7/2/2010: I did NOT have rotate-cw and rotate-ccw reversed; there's a bug in +; rotate that causes them to work incorrectly on bitmaps. Reversing them back. +; Modified 12/13/2010: Added flip-main and flip-other (formerly known as +; reflect-main-diag and reflect-other-diag, which had been disabled for +; a while). + + (require + 2htdp/image + lang/error ; check-arg, check-image, etc. + ) + + (provide + (all-from-out 2htdp/image) + ; above above-align-right above-align-left above-align-center ; included in 2htdp/image + ; beside beside-align-top beside-align-bottom beside-align-center ; include in 2htdp/image + reflect-vert reflect-horiz ; synonyms for flip-vertical and flip-horizontal, respectively + reflect-main-diag reflect-other-diag ; temporarily disabled + rotate-cw rotate-ccw rotate-180 ; will simply call rotate + ; show-pinhole ; what's a pinhole? + crop-top crop-bottom crop-left crop-right) ; will simply call crop + + + ;; Symbol Any String String *-> Void +(define (check-image tag i rank . other-message) + (if (and (pair? other-message) (string? (car other-message))) + (check-arg tag (image? i) (car other-message) rank i) + (check-arg tag (image? i) "image" rank i))) + + + ; reflect-horiz : image => image + (define (reflect-horiz picture) + (check-image 'reflect-horiz picture "first") + (flip-horizontal picture)) + + ; reflect-vert : image => image + (define (reflect-vert picture) + (check-image 'reflect-vert picture "first") + (flip-vertical picture)) + + ; reflect-main-diag : image => image + (define (reflect-main-diag picture) + (check-image 'reflect-main-diag picture "first") + (rotate -45 (flip-vertical (rotate 45 picture)))) + ; there ought to be a more efficient way than this.... + + ; reflect-other-diag : image => image + (define (reflect-other-diag picture) + (check-image 'reflect-other-diag picture "first") + (rotate 45 (flip-vertical (rotate -45 picture)))) + + ; synonyms + (define (flip-main picture) (reflect-main-diag picture)) + (define (flip-other picture) (reflect-other-diag picture)) + + ; natural-number? anything -> boolean + (define (natural-number? x) + (and (integer? x) (>= x 0))) + + ; crop-left : image natural-number -> image + ; deletes that many pixels from left edge of image + (define (crop-left picture pixels) + (check-image 'crop-left picture "first") + (check-arg 'crop-left (natural-number? pixels) "natural number" "second" pixels) + (crop pixels 0 + (- (image-width picture) pixels) (image-height picture) + picture)) + + ; crop-top : image number -> image + ; deletes that many pixels from top edge of image + (define (crop-top picture pixels) + (check-image 'crop-top picture "first") + (check-arg 'crop-top (natural-number? pixels) "natural number" "second" pixels) + (crop 0 pixels + (image-width picture) (- (image-height picture) pixels) + picture)) + + ; crop-right : image number -> image + ; deletes that many pixels from right edge of image + (define (crop-right picture pixels) + (check-image 'crop-right picture "first") + (check-arg 'crop-right (natural-number? pixels) "natural number" "second" pixels) + (crop 0 0 + (- (image-width picture) pixels) + (image-height picture) + picture)) + + ; crop-bottom : image number -> image + ; deletes that many pixels from bottom edge of image + (define (crop-bottom picture pixels) + (check-image 'crop-bottom picture "first") + (check-arg 'crop-bottom (natural-number? pixels) "natural number" "second" pixels) + (crop 0 0 + (image-width picture) + (- (image-height picture) pixels) + picture)) + + + ; rotate-cw : image => image + (define (rotate-cw picture) + (check-image 'rotate-cw picture "first") + (rotate -90 picture)) + + ; rotate-ccw : image => image + ; Ditto. + (define (rotate-ccw picture) + (check-image 'rotate-ccw picture "first") + (rotate 90 picture)) + + ; rotate-180 : image => image + (define (rotate-180 picture) + (check-image 'rotate-180 picture "first") + (rotate 180 picture))