This review session assumes that the final covers the material starting from
the MVC lectures.

The exam will be multiple choice/multiple answer/fill in the blank/short answer
with a Python programming question

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
	      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
	 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
		 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
		 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
	    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.

            When to call repaint
                If not using the MVC model: from the event listener
                If using the MVC model: from the notification method the
                   view uses to handle the change from the model

    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
	    hash tables (associative arrays)

    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 and while
	        else: on loops
		use range() fct to do counting loops
	    def fct(...):
	    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
	    .popleft: remove a value from the front of a list
	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.
	    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,
            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


	    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
	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

    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
        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

        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
		Can communicate with server via Socket's input and output
		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
		--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
		   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
	     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
	     --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)
	       ((= n 0) 1)
	       ((= n 1) 1)
	       (#t (* n (fact (-n 1)))))))

	   Tail recursive construction
	    (define fact (lambda (n)
	        (letrec ((factHelper (lambda (n productThusFar)
		    ((= 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
          Scheme code--you won't have to write a scheme program but you may
	  have to execute a scheme function and tell me what it outputs

      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
	      Map: breaks a computation into a computation over identical
	      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
	    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