This review session assumes that the final covers the material starting from
the GUI Layout lecture.

The exam will be multiple choice/multiple answer/code reading/fill in the blank/short answer
with a Python programming question and possibly a Scheme question. You need to
be able to read code for all for topics that we covered in the second half of
the course: GUIs, Python, Java Concurrency, and Scheme.

Layout Managers

    Goal: Assign space, size, and a position to each set of objects in a container
    Issues

        How to assign a position to an object
        How to assign a size to an object
        How to assign space to an object
        How to align an object when the space it is assigned exceeds its size
        How to assign a new position/space/size to an object when it's window or container is re-sized 

    Overview of Java Layout

        Java has containers and components. Containers are objects that can
            contain other objects and components are either containers or
            primitive objects.
        Each container has a layout algorithm associated with it
        Each component specifies three quantities to assist the layout manager
            preferredSize: it's preferred width/height
            minimumSize: the minimum size it wants to be displayed at
            maximumSize: the maximum size it wants to be displayed at 
        All layout managers take components' preferredSize into account when
            computing the initial size of a window. However, when a window is
	    re-sized, then these three quantities may be ignored by the layout
	    manager. 

    Java's layout managers

        Border Layout: Useful for the top-level of an application and putting
	    pallettes around a canvas object

	    1) Divides a container into 5 regions and when you add an object
	       to a container, you specify which region it should be placed in.
                center
                page_start (north)
                page_end (south)
                line_start (west)
                line_end (east 
            2) Respects preferredWidth for East/West regions and preferredHeight
	       for North/South regions
            3) Center region gets all of the extra space 

        Flow Layout: Horizontally lays out objects at their natural size. Useful
	     for simple one-line tool pallettes or organizing a group of related
	     widgets on one-line. Although it can handle multi-line groups,
	     other layout managers are probably better equipped to deal with
	     multi-line groups.

            When the container is re-sized

                If the container is not wide enough to accommodate all the
		   objects, then the flow layout uses multiple rows
                If the container is wider than the combined width of the
		   objects, then the row of objects is left-aligned, centered,
		   or right-aligned depending on the alignment that is
		   specified when the instance of the FlowLayout algorithm
		   is created. 

    Grid Layout: Lays out objects in a table with each object having the
        same width/height

        1) Typically used for tool pallettes
        2) Sets width to the max width component and the height to the max height
	     component: Hence only the preferred width of the max width
	     component and the preferred height of the max height component
	     are respected

        3) Can specify number of rows and/or columns: can set either to 0 but
	   not both. For example, if you set rows to 0 and columns to 3, then
	   there can be an infinite number of rows and each row will have up
	   to three objects. 

        4) When you resize the container, the space is divided evenly among the
	   objects.
        5) The order in which you add objects to the container determines the
	   order in which they are laid out. If you specify the number of
	   columns, then objects are laid out left-to-right, top-to-bottom.
           If you set the number of columns to 0, then objects are laid out
	   top-to-bottom, left-to-right. 

    Box Layout: Lays out objects in either vertical/horizontal stacks (rows)
        and it provides a variety of layout controls. A much more sophisticated
	version of flow layout that is good for laying out a single row or
	column of elements.

        1) Parameters: Can choose axis for layout

            horizontal: BoxLayout.LINE_AXIS
            vertical: BoxLayout.PAGE_AXIS 

        2) When resizing the container

            For horizontal layout, it tries to respect preferredHeight.

                as you increase the width, BoxLayout increases the width of
		    each object up to its maximum preferred width
                as you decrease the width, BoxLayout decreases the width of
		    each object down to its minimum preferred width 

            For vertical layout, it tries to respect preferredWidth

                as you increase the height, BoxLayout increases the height
		    of each object up to its maximum preferred height
                as you decrease the height, BoxLayout decrease the height
		    of each object down to its minimum preferred height 

          3) Fillers: fillers are invisible objects that allow you to control
	     the spacing between objects. Filler objects are added to
	     containers like other visible objects

                a) Rigid Area: invisible object that gives you fixed space
		   between two objects (use rigid areas rather than
		   horizontal/vertical struts for fixed space because
		   horizontal/vertical struts have infinite height/width
		   that can mess up layout calculations)

                   Examples

                    Box.createRigidArea(new Dimension(10, 0)): creates a
		       horizontal box 10 pixels wide and 0 pixels high--would
		       be added to a horizontal layout to put 10 pixels
		       between two objects
                    Box.createRigidArea(new Dimension(0, 10)): creates a
		       vertical box 10 pixels high and 0 pixels wide--would
		       be added to a vertical layout to put 10 pixels between
		       two objects 

                b) Glue objects: invisible objects that expand/shrink as
		   space is allocated to or removed from a container

                   i) each glue object is made the same size as all other
		        glue objects
                   ii) common uses
                        --keep objects "squashed" against sides of the container
                        --center objects in the middle of the container
                        --evenly space objects in the container 
                   iii) types of glue
                        --horizontal glue: has 0 minimum width and infinite
			    maximum width (essentially has 0 height)
                        --vertical glue: has 0 minimum height and infinite
			    maximum height (essentially has 0 width) 

           4) Ways to Create a BoxLayout manager

               a) JPanel foo = new JPanel(new BoxLayout(BoxLayout.LINE_AXIS));
               b) Box foo = Box.createHorizontalBox(); -- Box is a container
	             object that uses the box layout manager 

    Gridbag Layout: Good for dialog boxes and general layouts.
        1) Roughly lays out objects in a grid but with different sized rows and
	    columns.
        2) Objects can span multiple rows/columns
        3) Can control how objects are aligned/anchored in their assigned space

    Important methods associated with layout managers

        1) JFrame methods

            pack(): invokes layout manager on the JFrame's content pane.
                The layout manager will size the window so that it's just big
		enough to accommodate the objects at their preferred width and
		height.

		-- You should always call the pack method right before you
		     make the JFrame visible
                -- If you want a window to resize itself after adding or
		     removing a component from a JPanel, you will need to call
		     the pack method 

            getContentPane(): gets container object for the JFrame--you should
	        downcast this object to a JPanel 

        2) JPanel methods

             setLayout(instance of layout manager): sets layout manager
             add(component, parameters): adds components to a container and
	         the parameters provide layout hints. For example, with a
		 BorderLayout manager you would provide a parameter specifying
		 the region where the object should be placed
             revalidate(): indicates that the layout manager for this panel
	         must be called to re-layout the panel's components. You
		 should call this method any time you add or remove components
		 from a panel.
             repaint(): indicates that the panel should be repainted. You
	         should call this method after calling revalidate() since
		 you want the panel redrawn after it's been laid out 

MVC Model

    Know what each of the three components--model, view, and controller--is
    responsible for in a graphical user interface

    Know how to design/implement the MVC model for a particular application
    	 Model class: Need the following methods
             query methods so views can access state information
             registration/de-registration methods for views
             change methods for the controller. These methods will:
             notification methods for the views. Specifically, for each method
	         M in the listener interface, implement a notifyM() method in
		 the model that notifies listeners with the old value

	 Listener interface for views (observers): The model uses the
	    listener interface to notify the views of changes to the model.
	    
         View Classes: For each view there is a class that
              registers the view with the model at view creation time
	      		(typically in the constructor)
              implements the listener interface and repaints affected screen
	      		 regions
	      in practice, implements the controller by providing methods that
	      	 translate events into change method calls on the model

		 the controller is typically bundled with the view, because
		 each view is so idiosyncratic that it's tough to write
		 independent controllers

Custom Painting and Event Handling in Java
    custom painting refers to the drawing of custom application graphics
    	   that cannot be drawn via pre-defined widgets
    paintComponent method handles repainting: you never call this method
    	    directly but instead call repaint to schedule a paint event
	typically erase "damaged" areas of the screen and repaint these
		  damaged areas with updated graphics
	paintComponent is passed an instance of a Graphics object: the
		  Graphics object contains methods for drawing objects,
		  setting fonts, fill styles, line styles, etc.
        if you erase the entire screen before repainting, then you must
	   call super.paintComponent or you will get ghosting
    repaint schedules a paint event that ultimately calls the paintComponent
    	    method
	 repaint may be passed a bounding box indicating the portion of the
	 screen that's been damaged

	 these bounding boxes are combined into a single bounding box and
	 passed to paintComponent via the clip region in the Graphics object


    event handling: Java uses what is called an event listener model
    	description of model
	      certain objects are "event sources" and generate events. These
	        event sources may be input devices or widgets
	      other objects are "event listeners". They register with event
	      	    sources via addXXXListener methods where XXX represents
		    the event. For example, mouse listeners use the
		    addMouseListener method.
		 Every event listener implements an XXXListener interface
		    where XXX is the name of the event. For example, event
		    listeners for Mouse events implement a MouseListener
		    interface.
		 When an event occurs, every event listener is called via
		    a method in its implemented interface. For example, if
		    you express an interest in MouseEvents, then you implement a
		    MouseListener interface that supports mousePressed,
		    mouseReleased, mouseEntered, mouseExited, and mouseClicked
		    method
		 Java provides XXXAdapter classes that provide empty method
		    bodies for each method in the associated XXXListener
		    interface. This way you can extend the XXXAdapter class
		    and only override those methods you care about.
        two types of events:
	    input events: generated by input devices, such as mouse and
	        keyboard
	    action events: generated by widgets, such as menus or sliders,
	    	   often in response to input events
 	    input events are considered "low-level" events and action events
	    are considered "high-level" events since they are synthesized
	    from "low-level" events

        when an event occurs, an event listener processes the event and if
	    you are implementing an MVC model, then the event listener calls
	    change methods in the model.

	    Regardless of whether or not you are using the MVC model, the
	        event listener must call repaint to schedule a paint event.

Python
    Goal of scripting languages
        --Accomplish specific tasks quickly without concern for machine efficiency
        --Emphasis is on programmer efficiency

    Characteristics of scripting languages
        Economy of expression
	Lack of variable declarations
	Flexible dynamic typing
	Easy access to system facilities
	Sophisticated pattern-matching and string manipulation
	Built-in high-level data types
	    lists
	    hash tables (associative arrays)
	Interpreted

    Syntax you must memorize: This list is exhaustive for the features but
        not for all the syntax for these features. See the appropriate parts
	of the Python notes for all the syntax

	Values: Numbers, strings, boolean values, None

	Arithmetic, relational, and boolean operators
	
        Control structures: functions, conditionals, loops
	    for...in and while
	        else: on loops
		use range() fct to do counting loops
	    def fct(...):
	    if/elif/else
	Lists:
	    use array slices when appropriate
	    .pop: remove a value from the back of a list
	    .insert(0, val): insert val at beginning of the list
	    .append
	    .popleft: remove a value from the front of a list
	Dictionaries
	Tuples
	Iteration over sequences
            dict.keys(): returns list of keys
	    dict.iteritems(): returns list of key/value pairs
	    enumerate(list): returns index/value pairs
	    for v1, v2 in zip(list1, list2): Allows you to loop over two or
	        more sequences at the same time--pairs corresponding entries
		from each sequence.
	Sorting
	    use either list.sort or sorted(list)
	    sorted([5, 2, 3, 1, 4], reverse=True): sorts in reverse
	    sorting using lambda functions
	        tuples: sorted(student_tuples, key=lambda student: student[2])
		objects: sorted(student_objects, key=lambda student: student.age)
	    primary and secondary sorting: return tuple of values
	        sorted(student_objects, key=lambda student: (student.age, student.name))
            attribute accessor functions: simplify accesses to attributes
	        imported from operator module
		itemgetter(index): returns element at index position in a tuple
		attrgetter(attribute): returns value of attribute in an object

	Functional Operations on Lists
	    filter
	    map
	    reduce

	I/O

	    opening/closing files
	    reading from a file/stdin
	    writing formatted output to stdout/file
	    .split: splits a string into fields
	    .strip: strips leading and trailing spaces
	    for x in file: files can be read like lines in a list

        Other things to know for multiple choice/multiple answer

	1) Parameters in functions: how declared, how passed, etc
	2) Generator functions: yield statement
	3) Modules
	   a) how to create modules
	   b) how to import modules
	   c) how to create packages using __init__.py
	4) Exception handling
	   a) basic try/except/else/finally syntax
	   b) how to raise an exception
	   c) how to create user exceptions
	5) Classes
	   a) use prototype-instance model rather than class-instance model
	       i) all prototypes are objects
	       ii) can dynamically add/delete instance variables from any
	       	   object, including methods
	   b) know difference between a function in a prototype and a method
	      in an instance
	   c) One constructor per prototype and its name is __init__
	   d) First argument to methods is a pointer to self
	   e) Know how to create objects and call methods
	   f) Know why it's important to create instance variables in
	      constructor rather than in the prototype--problem with
	      variables that store mutable types

Concurrency
    Know definitions: Concurrency, process, thread, deadlock, starvation, livelock

    Java's Thread mechanism
    	Runnable Interface
	Thread Class
    Handling Interrupts
    	Interrupted Exception thrown by some methods (e.g., sleep())
	Thread.interrupted() can be used to check if thread is interrupted
		if exception doesn't exist
    Synchronization
        Why we need it--race conditions
	   Thread interference
	   Memory inconsistency: thread A depends on thread B to perform a
	      write before it performs read (happens-before relationship)
    Synchronization to avoid Thread Interference--typically need to keep
        synchronized objects that are shared among threads (e.g., the
	timekeeper and random number generator objects in the race problem)
        Synchronized Methods
	Synchronized Statements: help avoid starvation
    Synchronization to Enforce happens-before relationships (i.e., avoid
    		    memory inconsistency)
        .join(): forces a thread to completely finish
	.wait(): relinquishes a lock and waits on another process to perform
		 some action before resuming
	    .notify(), .notifyall(): indicates that you're about to release
	        a lock--generally return after doing this, which releases
		the lock. You can also call wait() after this to release
		the lock
	    .wait() is often called from within a synchronized method
	Volatile Methods: Do not explicitly prevent thread interference but
		 do force threads to write values to memory rather than
		 holding them in registers

    Sockets
        What are sockets
	How to write a client/server interaction in Java
	    Server listens using SocketServer class
	        When it accepts a connection it gets a Socket and can
		   communicate with the client via the Socket's input and
		   output streams
		Frequently forks a client thread if it's dealing with
		   multiple clients
	    Client gets a Socket instance when the server accepts a
	        connection
		Can communicate with server via Socket's input and output
		   streams
		If client must also listen to stdin, then it forks a
		   separate thread so it can monitor stdin on one thread
		   and server input on the other thread
	    Typically the server maintains one or more synchronized data
	        objects that helps it keep info on the clients
	Detecting shutdown
	    Can't use .close()
	    shutdown has occurred when the Socket's input stream returns
	    	     a null line

    High level Concurrency Mechanisms in Java
        Mutex Locks
	    Lock is the interface that specifies the Mutex Lock API
	    Advantage over old-style Java locks: Can try to acquire a lock
	    	but back out if lock can't be acquired--helps avoid deadlock
	    ReentrantLock is the class that typically implements a mutex
	        lock
		--a thread that holds the lock can execute any method that
		  attempts to acquire the lock

    	Thread Pools
	    Task: computation you want repeated one or more times--handed
	       to a thread pool
	    Thread pool: Pool of one or more threads to which a task may
	    	   be assigned
	       Java manages the threads and assigns them to cores
	       Executors manage the thread pool
	           Executor
		   ExecutorService: provides control over tasks
		       Allows you to terminate a task
		       Allows you to retrieve a value from a task
		       Allows you to shut down the pool
		       Provides Fork/Join pools so work can be recursively
		          decomposed into subtasks for parallelism
		   ScheduledExecutorService: allows scheduling of tasks
		       Supports future execution of a task
		       Supports periodic execution of a task

         Concurrent Collections
	     Unsynchronized collections fail "fast" if concurrent execution
	        is attempted but only guarantee "best effort"
	     Synchronized classes
	         BlockingQueue: Fifo queue for producer/consumer
		 ConcurrentMap: Hash table
		 ConcurrentNavigableMap: Sorted map
		 Vector
	     Why not to use synchronized class for single-threaded apps
	         Overhead of obtaining/releasing locks
		 Must dump registers to memory when methods complete thus
		    disrupting pipelined processors

	  ThreadLocalRandom: A random number generator isolated to the current
	     thread
	     --Avoids sharing/contention with Math.random()
	     --Faster than generating your own random number objects

	  Atomic Variables: Increment variables that need to perform simple
	     atomic operations such as counting or setting and retrieving
	     a value

Functional Programming

    Derived from Church's lambda calculus
        emphasizes computing by composing functions and using parameters to
	communicate state information between functions

    Conceptual features
        Defines outputs of a program as a mathematical function
	No side effects
	Emphasizes recursion rather than iteration

    Characteristics that differentiate it from imperative languages
        1st class functions
	higher order functions
	implicit polymorphism
	built-in lists
	structured function returns
	constructors for aggregates
	garbage collection

    Improving efficiency of functional programs: use tail recursion
        tail recursion: function in which additional computation never
	   follows a recursive call.
	compiler can replace recursion with iteration and re-using the
	   stack frame
	can re-write a non-tail recursive function into a tail recursive
	   function using continuations
	   continuation "continues" a computation by making modifications
	      to the arguments in the next recursive call: so it holds
	      results of computations in the arguments

    Program construction methods
        Inductive construction: Follows natural recursive definition
	   akin to post-processing a list
	Tail recursion
	   uses continuation arguments
	   akin to pre-processing a list

   	   Example factorial

	   Inductive construction

	   (define fact (lambda (n)
	     (cond
	       ((= n 0) 1)
	       ((= n 1) 1)
	       (#t (* n (fact (-n 1)))))))

	   Tail recursive construction
	   
	    (define fact (lambda (n)
	        (letrec ((factHelper (lambda (n productThusFar)
	           (cond
		    ((= n 0) productThusFar)
		    ((= n 1) productThusFar)
		    (#t (factHelper (- n 1) (* n productThusFar)))))))
	          (factHelper n 1))))

      Scheme: Go over the scheme notes and make sure you know how to read
          and write Scheme code

      Evaluation Order
          Applicative Evaluation
	  Normal Form Evaluation
	  Scheme uses applicative evaluation for functions and normal form
	     evaluation for special "forms" such as if, cond, boolean operators
	  Memoization to speed up normal form evaluation
	  Strict vs non-strict languages
	      strict: all arguments must be well-defined so applicative
	         evaluation can be used
	      non-strict: not all arguments must be well-defined so normal
	         form evaluation must be used
	  Scheme: can use delay and force to obtain generator functions

      Higher Order Functions
          The Big 4
	      Filter
	      Map: breaks a computation into a computation over identical
	      	   subtasks
	      Reduce: summarizes a computation by combining the results of
	      	      subtasks or a list
	      Currying: makes an argument to a function constant--used for
	          syntactic sugar

    Advantages of functional languages
        lack of side effects makes programs easier to understand
	lack of explicit evaluation order (in some languages) offers
	    possibility of parallel evaluation (e.g. MultiLisp)
	lack of side effects and explicit evaluation order simplifies
	         some things for a compiler (provided you don't blow it in
		 other ways)
	programs are often surprisingly short
        language can be extremely small and yet powerful

     Problems with functional languages
        Performance
	    trivial update problem
	        initialization of complex structures
		summarization problem
		in-place mutation
	    heavy use of pointers (locality problem)
	    frequent procedure calls
	    heavy space use for recursion
	    requires garbage collection
	requires a different mode of thinking by the programmer
	difficult to integrate I/O into purely functional model