A1: Currency
Image from www.postoffice.co.uk

Thinking about that trip overseas? Whenever possible, it is best to go when the exchange rate is in your favor. When your dollars buy more in the foreign currency, you can do more on your vacation. This is why it would be nice to have a tool that could tell you how much your cash is worth in another currency.

However, there is no set mathematical formula to compute this conversion. The value of a currency (with respect to another) is constantly changing. In fact, in the time that it takes you to read this paragraph, the exchange rate between the dollar and the Euro has probably changed several times. So how do we write a program to handle something like that?

One solution is to make use of a web service. A web service is a program that, when you send it a request, automatically generates a web page with the information that you asked for. In our case, the web service will tell us the current exchange rate for most of the major international currencies. Your job will be to use string-manipulation methods to read the web page and extract the extract information we need. Full instructions are included below.

Authors: W. White, D. Yoon, Q. Jia, L. Lee, and S. Marschner

Learning Objectives

This assignment is designed to give you practice with the following skills:

  • How to write a self-contained module in Python
  • How to write a script that uses a self-contained module
  • How to use string methods in Python
  • How to connect Python to a web service
  • How to read specifications and understand preconditions
  • How to use docstrings appropriately for specifications
  • How to follow the coding conventions for this course
  • How to thoroughly test a program

The functions we ask you to write in this assignment are relatively short and straightforward. The emphasis is testing and “good practices”, not complicated computations. You will find that the most recent lab is very helpful in understanding this assignment.

Table of Contents


Academic Integrity and Collaboration

This assignment is a slightly modified version of an assignment given in previous semesters. Please do this assignment without consulting (or seeking) previous solutions. Since you are allowed to revise and resubmit, with help from us, until you have mastered this assignment, there is no reason for you to look at previous solutions. The same goes for using generative AI. Please do not use it on this assignment.

We also ask that you do not enable violations of academic policy. Do not post your code to Pastebin, GitHub, or any other publicly accessible site.

Collaboration Policy

You may do this assignment with one other person. If you are going to work together, form your group on CMS as soon as possible. This must be completed before you submit the assignment. Both people must do something to form the group. The first person proposes, and then the other accepts. You have to do this early because CMS does not allow you to form groups once grades are released. Once you have grouped on CMS, only one person submits the files.

If you do this assignment with another person, you must work together. It is against the rules for one person to do some programming on this assignment without the other person sitting nearby and helping. Furthermore, this assignment is not designed for you to split the work cleanly between partners. Sit together and take turns “driving”; alternate using the keyboard and mouse.

With the exception of your CMS-registered partner, we ask that you do not look at anyone else’s code or show your code to anyone else (except a CS1110 staff member) in any form whatsoever. This includes posting your code on Ed Discussions to ask for help. It is okay to post error messages on Piazza, but not code. If we need to see your code, we will ask for it.

Before You Get Started

These instructions may seem long, but that is because we have tried to give you all the information you need in one document. The meat of the instructions are Parts I, II, and III. Those cover exactly what code we want you to write. However, we expect you to read all of these instructions, since the other parts give you a better understanding of exactly why and how we are asking you to do these things.

We recommend that, before you write any code at all, you read the instructions in their entirety. This will greatly increase your chances of completing the assignment quickly. Many requests for resubmission are caused not by issues with programming but simply by not following instructions.

Assignment Scope

Everything that you need to complete this assignment should have been covered by Lessons 7 and 8 (Specifications and Testing) in class. In particular, you may not use if-statements anywhere in this assignment, as they are not necessary. Submissions containing if-statements will be returned for you to revise. Similarly, students with prior programming experience should not try to use loops or recursion, nor should they use f-strings (which are not covered in class).

We also recommend that you start early. If 600 students try to contact a web service at once this will slow everybody down. Connecting to, and reading from, a web page is not instantaneous. It will take several seconds for some of the functions you will write to complete their calculations. Furthermore, if you wait until the last minute to test this assignment, you will be connecting to the same web page as everyone else in the class, so things could slow down even more.

Grading Policy (Revise-and-Resubmit Cycle)

To ensure that everyone masters this assignment, we will use an iterative feedback process. If one of the objectives below is not properly met, we will give you feedback and expect you to revise and resubmit. This process will continue until you are done. This process should be done by Friday, September 26. Once you finish you will receive a perfect score of 10. In our experience, almost everyone is able to achieve a perfect score within two submissions.

In grading your code, we will focus on the following issues in order:

  • Correct function specifications and/or formatting
  • Adequate test cases
  • Correct implementations (does it pass our test cases?)

Formatting is graded according to the course style guidelines.

If your code fails one of the three criteria above, we will notify you and ask you to resubmit. We stop checking once we find the first few errors, so you should not assume that the errors we point out are the only errors present.

Until we have decided that you have mastered (e.g. 10/10) the assignment, your “grade” on CMS will be the number of revisions so far. This allows us to keep track of your progress. Do not be alarmed if you see a “1” for the assignment at first! The assignment will be considered completed when it passes all three steps outlined above.

Development Environment

To do this assignment, Python must be set up properly. If you have not already done this, follow the installation instructions to set it up on your computer.

You should also create a folder on your hard drive that is dedicated to this assignment and this assignment only. Every time that you work on a new assignment, we want you to make a new folder, to keep things organized and avoid problems with naming collisions. Make sure that the command shell and Pulsar are both open in the current folder before you start.

Assignment Help

If you do not know where to start, if you do not understand testing, or if you are completely lost, please see someone immediately. This can be the course instructor, a TA, or a consultant. Do not wait until the last minute. A little in-person help can do wonders. See the office hours page for more information.


The Currency Exchange Web Service

Before you do anything at all, you should play around with the currency exchange web service. You do not need any Python to do this; just a web browser.

USD to EURO

For this assignment, you will use a simulated currency exchange service that never changes values. This is important for testing in Part C. If the answer is always changing, it is hard to test that you are getting the right answers. We explain how you can make a few minor changes to get real-time currency-exchange results in an appendix. However, we do not want you to submit such code for your assignment. Stick with the fixed, unchanging server.

To use the service, you connect your web browser to the following address:

http://cs1110.cs.cornell.edu/2025fa/a1?    

This prefix is followed by a currency query. A currency query has three pieces of information in the following format (without spaces; we have included spaces here solely for readability):

old=currency1 & new=currency2 & amt=value

where currency1 is a three-letter code for the original currency, currency2 is a three-letter code for the new currency and value is a float value for the amount of money in currency1. For example, if you want to know the value of 2.5 dollars (USD) in Cuban Pesos (CUP), the query is

old=USD&new=CUP&amt=2.5

The query is not enough by itself. To use it, you have to make it part of a web page URL. The full URL for this query combines the prefix and the query together, like this

http://cs1110.cs.cornell.edu/2025fa/a1?old=USD&new=CUP&amt=2.5

Click on the link to see it in action.

You will note that the “web page” in your browser is just a single line in the following format:

{ "old":"2.5 United States Dollars", "new":"64.375 Cuban Pesos", "status":"Success" }

This is what is known as a JSON representation of the answer. JSON is a way of encoding complex data so that it can be sent over the Internet. You will use what you know about string operations and methods to pull out the relevant data out of the JSON string.

You should try a few more currency queries to familiarize yourself with the service. Note that if you enter an invalid query (for example, using a non-existent currency code like AAA), you will get the following response in error:

{ "old":"N/A", "new":"N/A", "status":"Source currency code is invalid." }

Similarly, if you enter a query with two valid currency codes, but with an invalid quantity value, you will get the following error:

{ "old":"N/A", "new":"N/A", "status":"Currency amount is invalid." }

For all error responses, the old and new will be "N/A". The value status is a specific error message describing the problem (and is "Success" if there is no error). This will be important for error handling in this assignment.

Currency Application

Your primary goal in this assignment is to write an interactive application that queries the user for input and responds as follows:

[user@machine]:a1 > python a1app.py 
Enter old currency: USD
Enter new currency: EUR
Enter currency amount: 2.5
You can exchange 2.5 USD for 2.1337425 EUR.

To create this application, you will create three files:

  • a1.py : a module with a collection of functions to perform the calculation.
  • a1test.py : a unit test script verifying that a1.py is working correctly.
  • a1app.py : a script to receive user input and provide an answer.

Of the three files, a1app.py will be the easiest. It will be no more complex that than scripts you wrote for lab. The vast majority of the work will be in the file a1.py. This file will contain a definition for following function:

def exchange(src, dst, amt):
    """
    Returns the amount of currency received in the given exchange.

    In this exchange, the user is changing amt money in currency src to the 
    currency dst. The value returned represents the amount in currency dst.

    The value returned has type float.

    Parameter src: the currency on hand (the old value)
    Precondition: src is a string for a valid currency code

    Parameter dst: the currency to convert to (the new value)
    Precondition: dst is a string for a valid currency code

    Parameter amt: amount of currency to convert
    Precondition: amt is a float
    """

This function will involve several steps. You will get the JSON string from the web service, break up the string to pull out the numeric value (as a substring), and then convert that substring to a float. As this is the very first assignment, we are going to take you through this process step-by-step. However, not every function that we ask you to implement will be used by exchange.

This assignment might feel like you are working in reverse. You will write the functions to break up the string first, and the functions to interact with the web service last. This is because we want you to develop the following programming habit: always complete and test the helper functions before finishing the functions that use them.

Currency Tests

In addition to the application, you will also create a test script. As we said, we have fixed the exchange rates on the server so that they never change, making it possible for you to design test cases. If you would like to see these fixed rates, they (and the supported currencies) are included in an appendix.

Note however, that you should not use this table in any of the functions that you write in a1.py. The table is for testing your functions, not for writing them. There is no reason for you to waste your time hard-coding in all of the currencies listed in the table into your program, since the web service you will contact already knows them all anyway.


Part I: The Assignment Files

One of the most important outcomes of this assignment is that you understand the importance of testing. This assignment will follow an iterative development cycle. That means you will write a few functions, then fully test them before you write any more. This process makes it easier to find bugs; you know that any bugs must have been part of the work you did since the last test.

Iterative development requires that you work on each of the files simultaneously. In particular, you will write some code in a1test.py, move to a1.py and then back to a1test.py. Therefore, to get you started we want you to first create all three files. You are not going to put (much) code in the files right now. We just want you to have the files created so that you have a starting point to work from.

The very first thing you should do is specifically create a directory for this assignment. This folder should contain the three assignment files and nothing else.

The Module a1

In your newly created directory, you should create the module a1 (with file name a1.py). This will be the main module for this assignment. Following the style guidelines your file should start with a descriptive docstring, and the last two lines should be (1) the name and netid of the authors and (2) the date the file was last editted. This is the docstring that we would like you to use:

"""
Module for currency exchange

This module provides several string parsing functions to implement a 
simple currency exchange routine using an online currency service. 
The primary function in this module is exchange.

Author: YOUR NAME(S) AND NETID(S) HERE
Date:   THE DATE COMPLETED HERE
"""

Cut-and-paste this docstring into a1, making sure to insert your name and date as appropriate.

The Script a1test

Iterative development hinges on proper testing, which was covered in both lesson 8 and lab 6. In the same folder as a1.py, create the file a1test.py. This will be the test script for the a1 module.

As with a1.py, this file should start with a docstring specification that includes (1) your name and netid and (2) the date the file was last editted. This is the docstring that we would like you to use:

"""
Test script for module a1

When run as a script, this module invokes several procedures that 
test the various functions in the module a1.

Author: YOUR NAME(S) AND NETID(S) HERE
Date:   THE DATE COMPLETED HERE
"""

After this docstring, add the following two lines.

import introcs
import a1

Normally a test script has a test procedure for each function being tested. However, to simplify this activity, you are only going to write four test procedures: testA, testB, testC, and testD. Note that this is different than what you did in lab. In lab, each function got its own test procedure. This time, each test procedure will test a group of several functions, and these groups correspond to the sections in Part II.

To get this test script started, you should add a procedure stubs for each of the four test procedures. Remember that a procedure stub should have the keyword pass (indented) after the header, but nothing else. For example, here is the code for the first one.

def testA():
    """
    Test procedure for Part A
    """
    pass

These procedures will eventually contain your test cases, which we talked about in Lesson 8. If you are curious about how they are supposed to work, look at the example code from that set of videos.

Finally at the end of a1test, you will need to add code to call the test procedures. Remember that any function – even a test procedure – does nothing until you call it. Add these lines:

testA()
testB()
testC()
testD()
print('Module a1 passed all tests.')

Again, see the relevant lesson for an explanation of why you are doing this. The script code will call your four test procedures, which are (currently) empty. If everything is working, then the module will print out the message

Module a1 passed all tests

Try this out.

The Script a1app

You will write the script a1app.py last. We do not want you to put any code in this file until a1.py is complete and fully tested. However, it is a good idea to have all three files in your directory, so you should create a file called a1app.py right now. When you create this file, add the following docstring:

"""
User interface for module currency

When run as a script, this module prompts the user for two currencies and 
an amount. It prints out the result of converting the first currency to 
the second.

Author: YOUR NAME(S) AND NETID(S) HERE
Date:   THE DATE COMPLETED HERE
"""

You can now ignore this file until Part III of the instructions.


Part II: The Core Functions

Iterative Development

In this part of the assignment, you will work on the files a1.py and a1test.py. It is is broken into four parts (listed as Parts A, B, C, and D). In each part, you will do the following:

Add a function stub to a1

We will give you the function header to write. We will also give you a detailed docstring specification for the function. You should copy-and-paste the specification into the function body, indented.

Add test cases to a1test

Yes, this means you are writing tests before writing the function bodies. We talked about this in the lesson on testing.

Unless otherwise instructed, each test case should be a call to an assert function in the introcs module. Furthermore, your tests should be representative. While we talked about this in class, you might be a little unsure of what we are asking for here. If so, you should review lab 6 with a consultant before going any further.

Write the function bodies

Make sure that the function satisifies the specifications exactly. If the specification says to return something, you need a return statement. Make sure that the value returned is of the correct type.

Run the test script a1test

If errors are found, fix them and re-test. Keep doing this until no more errors are found.

Function Specifications

The descriptions that we provide in each part below represent the level of completeness and precision we are looking for in your docstring comments. In fact, it is best to copy-and-paste these descriptions to create the first draft of your docstring comments. If you do not cut and paste, please adhere to the conventions we use, such as using a single line, followed by a blank line and a more descriptive paragraph, or by using “Returns …” for fruitful-functions. While we have provided the contents of the specification, we have not always formatted them properly for you.

If you want to see if your specifications are written correctly, start an interactive Python shell and type

>>> import a1
>>> help(a1)

This should list all the functions with their specifications.

Part A: Breaking Up Strings

A large part of this assignment is breaking up a JSON string. Conceptually, you want to separate the currency amount from the currency name. For example, if we are given the string "4.502 Euros", then we want to break it up into "4.502" and "Euros" .

This is the motivation for the two functions below. The implementation of these functions should be relatively simple. We were able to implement them both in one or two lines.

before_space(s)
Returns a copy of s up to, but not including, the first space

Parameter s: the string to slice
Precondition: s is a string with at least one space
after_space(s)
Returns a copy of s after the first space

Parameter s: the string to slice
Precondition: s is a string with at least one space

Implement these functions according to their specification, as described in Iterative Development. In other words,

  • Write the header and specification in a1.py.
  • Place test cases in the procedure testA of a1test.py.
  • Implement the functions in a1.py.
  • Test for and correct errors until no errors remain.

To test the functions, you should make use of assert_equals in the module introcs to compare the result of each functions with the string that you expect to get back. Our solution has four test cases for each of the two f unctions above. When you think about what test cases you want to include, consider the following:

  • Does the specification allow for strings with more than one space?
  • Does the specification allow for strings that start with a space?
  • Does the specification allow for strings that don’t have any spaces?

Keep in mind that the answer to any of the above questions might be No. In addition, do not forget to add a specification to testA. Just because it is used for testing does not mean that it should not be properly specified.

When you write your test cases write a single-line comment (#) just above the test case explaining what it is testing. If you make it clear what you are testing, this can help us provide better feedback when we return the graded assignment.

Part B: Processing a JSON String

All of the responses to a currency query, whether valid or invalid, contain the keywords "old" and "new". If it is a valid currency query, then the answer is in quotes after the keyword "new". If it is invalid, then the quotes after "new" are the string "N/A". Hence the next step is to extract the information in quotes after these keywords.

While working on each of the functions below, remember to write the test cases in at1test.py before implementing the body. All test cases in this section go in the procedure testB, which you should remember to specify. You should thoroughly test each function before implementing the next one.

first_inside_quotes(s)
Returns the first substring of s between two (double) quotes

A quote character is one that is inside a string, not one that 
delimits it.  We typically use single quotes (') to delimit a 
string if want to use a double quote character (") inside of it.

Examples:
first_inside_quotes('A "B C" D') returns 'B C'
first_inside_quotes('A "B C" D "E F" G') returns 'B C', 
because it only picks the first such substring

Parameter s: a string to search
Precondition: s is a string containing at least two double quotes

You should have completed the function above in lab 6. Because this function is technically part of the lab, and not the assignment, you may talk to students other than your partner about it (collaboration is always allowed on labs). This is the only function for which this is allowed. The rest of the functions are part of the assignment, so you may only collaborate with your partner.

Once you have this function completed, you should move on to the following functions.

get_old(json)
Returns the old value in the response to a currency query

Given a JSON response to a currency query, this returns the string inside 
double quotes (") immediately following the keyword "old". For example, if 
the JSON is

'{ "old":"1 Bitcoin", "new":"9916.0137 Euros", "status":"Succes" }'

then this function returns '1 Bitcoin' (not '"1 Bitcoin"').

This function returns 'N/A' if the JSON response contains an error message.

Parameter json: a json string to parse
Precondition: json is the response to a currency query
get_new(json)
Returns the new value in the response to a currency query

Given a JSON response to a currency query, this returns the string inside 
double quotes (") immediately following the keyword "new". For example, if 
the JSON is

'{ "old":"1 Bitcoin", "new":"9916.0137 Euros", "status":"Succes" }'

then this function returns '9916.0137 Euros' (not '"9916.0137 Euros"').

This function returns 'N/A' if the JSON response contains an error message.

Parameter json: a json string to parse
Precondition: json is the response to a currency query
has_error(json)
Returns True if the query has an error; False otherwise.

Given a JSON response to a currency query, this returns true if the status
is anything other than 'Success'. For example, if the JSON is

'{ "old":"N/A", "new":"N/A", "status":"Currency amount is invalid." }'

then the query is not valid, so this function returns True (It 
does NOT return the message 'Currency amount is invalid').

Parameter json: a json string to parse
Precondition: json is the response to a currency query

Note that three of the functions above have json is the response to a currency query in the precondition. This just means that your test cases should only consider strings that can be returned by the server. So the string

'{ "old":"2 Namibian Dollars", "new":"2 Lesotho Maloti", "status":"Success" }

is okay to test, but the string

' "old":"2 Namibian Dollars", "new":"2 Lesotho Maloti" '

is not. Again, write a single-line comment (#) just above each test case explaining what it is testing. This will help us give you better feedback.

You should not use a conditional statement to implement these functions. Simply find the position of the appropriate keyword and extract the value in quotes immediately after it. Your implementation must make use of the find or index string methods.

Part C: Contacting the Server

Now it is time to interact with the web service. In this part, you will implement a single function. The test cases for this function should go in procedure testC in a1test.py. Do not forget to specify testC properly.

currency_response(src, dst, amt)
Returns a JSON string that is a response to a currency query.

A currency query converts amt money in currency old to the 
currency new. The response should be a string of the form    

    '{ "old":"<old-amt>", "new":"<new-amt≫", "status":"Success" }' 

where the values old-amount and new-amount contain the value 
and name for the original and new currencies. If the query is 
invalid, both old-amount and new-amount will be 'N/A', while 
"status" will have an error message.

Parameter src: the currency on hand (the old value)
Precondition: src is a string with no spaces or non-letters

Parameter dst: the currency to convert to (the new value)
Precondition: dst is a string with no spaces or non-letters
    
Parameter amt: amount of currency to convert
Precondition: amt is a float

While this function sounds complicated, it is not as bad as you think it is. There is a function inside of the introcs module called urlread. This function takes a single web address as an argument, and returns the contents of the web page. Try this now in the interactive shell by typing

>>> import introcs
>>> introcs.urlread('http://www.cornell.edu')

You will notice that this function does exactly what you want. So what is the challenge? The challenge is coming up with the correct web address (URL). Once you do that, you just return the result of urlread. Revisit our explanation of how the currency service works to see why finding the correct URL is a potential challenge.

When you test this function, you need to ensure that it returns exactly the right JSON string for the value given. The best way to test this is to use a web browser to manually get the right JSON answer. For example, one test case can be constructed by seeing the result of going to the URL

http://cs1110.cs.cornell.edu/2025fa/a1?old=USD&new=CUP&amt=2.5

You can copy the value from this web page into a test case in testC (but do not forget to add quotes). Then check that the function returns the same JSON string. Remember to be thorough with your choice of test cases. One is not enough.

Important: Fetching a web page takes time, especially if too many people are trying to do so simultaneously. You should give each call to this function at least 5-10 seconds to complete before restarting any tests.

Part D: Computing the Exchange

We are now ready for the final part of the assignment. Implement the following specifications, again using our test-case-before-function-body approach. The test cases should go in procedure testD in a1test. When making your test cases, reread the introcs documentation. There is a case in which you will want to use assert_floats_equal instead of assert_equals.

is_currency(code)
Returns: True if code is a valid (3 letter code for a) currency
It returns False otherwise.

Parameter code: the currency code to verify
Precondition: code is a string with no spaces or non-letters.

In implementing is_currency, you should not use the table of currencies. That would make a very large function with a lot of if-statements; you are not allowed if-statements in this assignment. Instead, you must use currency_response and has_error as helper functions. However, you will find the table of currencies useful in determining correct answers for your test cases.

exchange(src, dst, amt)
 Returns the amount of currency received in the given exchange.

In this exchange, the user is changing amt money in currency src to the 
currency dst. The value returned represents the amount in currency dst.

The value returned has type float.

Parameter src: the currency on hand (the old value)
Precondition: src is a string for a valid currency code

Parameter dst: the currency to convert to (the new value)
Precondition: dst is a string for a valid currency code

Parameter amt: amount of currency to convert
Precondition: amt is a float

You may also use the table of currencies to craft some test cases for the function exchange. However, you might find it easier to use a currency query URL to look up the correct answer, and then paste the answer into your test case.

A bigger issue with testing exchange is that problem that we saw in class: real numbers cannot be represented exactly. This creates problems when you try to test equality between floats. To solve this problem, introcs provides a function called assert_floats_equal. You should use this function to test exchange instead of assert_equals. There is an example of this issue in the exercises of lab 6.

Finally, bear in mind that, like currency_response, these functions connect to the web service, and so are not instantaneous. In our solution, with complete test procedures for everything, it can take up to 2 seconds to run the unit test on campus. This will be a bit slower if you are working closer to the deadline.


Part III: The Application Script

You are essentially done. The last part of the assignment is to complete the file a1app.py. This file will be no more complicated than the script dice.py that you made for lab 3. In fact, it will have a similar number of lines.

At the top of the file a1app.py remember to add the line

import a1

This will allow you to access the exchange function in this script. This is the only function of a1.py that you will need to use. Everything else will be either an input function, a print function, or some other built-in function, just as you did in the lab.

We are not going to give you much more guidance than that. Use your file dice.py as a guide if you are unsure what to do. In this end, the script should prompt the user and provide an answer, as shown below.

[user@machine]:a1 > python a1app.py 
Enter old currency: USD
Enter new currency: CUP
Enter currency amount: 2.5
You can exchange 2.5 USD for 64.375 CUP.

Obviously you will get different answers for different currencies and amounts. But otherwise, the output displayed must look exactly like it does above. You must use those exact words for your final print statement and end with a period.


Finishing Touches

Once you have everything working you should go back and make sure that your program meets the course and assignment coding conventions, including the following:

  • You have indented with spaces, not tabs (Pulsar handles this automatically).
  • Functions are each separated by two blank lines.
  • Lines are short enough (~80 characters) that horizontal scrolling is not necessary.
  • The specifications for all of the functions are complete.
  • Function specifications are immediately after the function header and indented.
  • Docstrings are only used for specifications, not general comments.
  • Each test cases has a single-line comment before it, explaining what is being tested.
  • Your name(s) and netid(s) are in the comments at the top of the modules.

One of the things that you may have the biggest difficulty with is breaking up long lines. First, you may not be aware when your lines are too long. If you are using Pulsar, you should see a vertical line on the right side of the window. This is the wrap guide. If you go past this, you have gone too far; it is time to break up your lines.

As for breaking up long lines, there are two solutions. First, Python allows you to “hit Return” within any expression inside of parentheses. So if you are adding together several expressions together, like

a = 'Hello ' + name + ', it is good to meet you'

you can break it up over several lines, using parentheses, as follows:

a = ('Hello ' + name + 
     ', it is good to meet you')

Turning it In

Upload the files a1.py, a1test.py, and a1app.py to CMS by the due date: Friday, September 19. Do not submit any files with the extension/suffix .pyc. It will help to set the preferences in your operating system so that extensions always appear.

Check CMS daily until you get feedback from a grader. Make sure your CMS notifications for CS 1110 are set so that you are sent an email when one of your grades is changed. To find the feedback, click on the Assignment 1 link in CMS. On the page you are brought to, click on the red word “show” in the line Grading Comments & Requests (show). You can contact your grader if you have questions about their feedback; you can see their netid in the place you can see their feedback.

Within 24 hours, do RRRRR: Read the feedback, Revise your program accordingly, Resubmit, and Request a Regrade using the CMS. If you do not request a regrade, we have no simple way of knowing that you have resubmitted.

This whole process – starting from first submission on September 19 – continues until you submit a solution that demonstrates complete mastery. In some cases this may require multiple additional resubmits by you. You need to complete this process within one week. You need to have submitted a final, correct version by Friday, September 26, which means you will probably want to have re-submitted at least once before then.

Completing the Survey

In addition to turning in the assignment, we ask that you complete the new survey posted in CMS. With the change in demographics each year, and we would like some understanding of how long you spent on the assignment and your impression of the difficulty.

Please try to complete the survey within a day of turning in this assignment. Remember that participation in surveys compromise 1% of your final grade. We also ask that you be honest in your answers.


Appendix: Live Exchange Service

This section is not part of the assignment. It is optional. Furthermore, do not make the changes in this section to the file that you submit for grading. It will be sent back to you to fix.

This assignment was first designed back in 2012, to take advantage of a service called iGoogle. iGoogle was a JSON service provided by Google (hence the name) which supported simple Python programs. It was intended for any data that might be changing often, such as currency exchange rates, weather data, or similar types of things. Unfortunately, Google discontinued the service in November 2013, two months after we ran the assignment for a second time.

This meant that we could still simulate a fake currency exchange service, but we no longer had a real-world example to show off the power of this assignment. Most replacements to iGoogle typically charge for their service (because they are used by currency traders), and we could not justify the subscription cost for a single assignment.

Fortunately, there is now a great service called Open Exchange Rates. This service still charges, but it is free if you only need a new currency value once an hour. This is a pretty good compromise, because that is frequent enough for anyone who is not a currency trader.

The data from Open Exchange Rates is not in a format usable by this assignment. However, it does allow your instructor to turn the fake currency service into a real currency service. We are actually running two currency servers in this class. In the web service instructions we told you to use the URL prefix

http://cs1110.cs.cornell.edu/2025fa/a1?    

If you change that prefix to

http://cs1110.cs.cornell.edu/2025fa/xchg?    

you will get our real server instead.

The server updates once an hour at 40 minutes after the hour. To see this in action, run a query just before this time, at say 8:38. Wait 5 minutes and run the same query again. See how it changes? This is one of the reasons we did not use the real service in development. It is too hard to test against. In fact, even professional software engineers would do what we did: write a program against an unchanging exchange service before deploying it against the real thing.

We promise to keep the real server running for at least the next year, should you wish to show this off to other people.


Appendix: Supported Currencies

Code Name 1 USD =
AED United Arab Emirates Dirham 3.6725
AFN Afghan Afghani 68.219237
ALL Albanian Lek 82.857761
AMD Armenian Dram 380.976748
ANG Netherlands Antillean Guilder 1.79
AOA Angolan Kwanza 917
ARS Argentine Peso 1363.781945
AUD Australian Dollar 1.52532
AWG Aruban Florin 1.8025
AZN Azerbaijani Manat 1.7
BAM Bosnia-Herzegovina Convertible Mark 1.668415
BBD Barbadian Dollar 2
BDT Bangladeshi Taka 121.38196
BGN Bulgarian Lev 1.67037
BHD Bahraini Dinar 0.376029
BIF Burundian Franc 2975.724025
BMD Bermudan Dollar 1
BND Brunei Dollar 1.283259
BOB Bolivian Boliviano 6.891875
BRL Brazilian Real 5.41405
BSD Bahamian Dollar 1
BTC Bitcoin 9.011918e-06
BTN Bhutanese Ngultrum 88.031559
BWP Botswanan Pula 13.409255
BYN Belarusian Ruble 3.370185
BZD Belize Dollar 2.005886
CAD Canadian Dollar 1.38375
CDF Congolese Franc 2901.356578
CHF Swiss Franc 0.79812
CLF Chilean Unit of Account (UF) 0.024592
CLP Chilean Peso 969.613995
CNH Chinese Yuan (Offshore) 7.13
CNY Chinese Yuan 7.13285
COP Colombian Peso 3977.4792
CRC Costa Rican Colón 505.353049
CUC Cuban Convertible Peso 1
CUP Cuban Peso 25.75
CVE Cape Verdean Escudo 94.062685
CZK Czech Republic Koruna 20.8095
DJF Djiboutian Franc 177.607167
DKK Danish Krone 6.3711
DOP Dominican Peso 63.075287
DZD Algerian Dinar 129.863
EGP Egyptian Pound 48.536572
ERN Eritrean Nakfa 15
ETB Ethiopian Birr 142.670161
EUR Euro 0.853497
FJD Fijian Dollar 2.2528
FKP Falkland Islands Pound 0.740302
GBP British Pound Sterling 0.740302
GEL Georgian Lari 2.7
GGP Guernsey Pound 0.740302
GHS Ghanaian Cedi 10.5
GIP Gibraltar Pound 0.740302
GMD Gambian Dalasi 71.500005
GNF Guinean Franc 8644.877668
GTQ Guatemalan Quetzal 7.649392
GYD Guyanaese Dollar 208.6671
HKD Hong Kong Dollar 7.7961
HNL Honduran Lempira 26.130946
HRK Croatian Kuna 6.42982
HTG Haitian Gourde 130.356149
HUF Hungarian Forint 334.936585
IDR Indonesian Rupiah 16378.7
ILS Israeli New Sheqel 3.329324
IMP Manx pound 0.740302
INR Indian Rupee 88.1865
IQD Iraqi Dinar 1306.632532
IRR Iranian Rial 42075
ISK Icelandic Króna 122.158246
JEP Jersey Pound 0.740302
JMD Jamaican Dollar 159.590544
JOD Jordanian Dinar 0.709
JPY Japanese Yen 147.40196681
KES Kenyan Shilling 129.059466
KGS Kyrgystani Som 87.45
KHR Cambodian Riel 3999.163749
KMF Comorian Franc 420.499968
KPW North Korean Won 900
KRW South Korean Won 1386.5
KWD Kuwaiti Dinar 0.304884
KYD Cayman Islands Dollar 0.831137
KZT Kazakhstani Tenge 536.003744
LAK Laotian Kip 21639.411445
LBP Lebanese Pound 89319.87455
LKR Sri Lankan Rupee 301.155933
LRD Liberian Dollar 199.97441
LSL Lesotho Loti 17.631478
LYD Libyan Dinar 5.414374
MAD Moroccan Dirham 9.064278
MDL Moldovan Leu 16.740455
MGA Malagasy Ariary 4435.898914
MKD Macedonian Denar 52.497338
MMK Myanma Kyat 2099
MNT Mongolian Tugrik 3592.646
MOP Macanese Pataca 8.015782
MRU Mauritanian Ouguiya 39.984645
MUR Mauritian Rupee 46.070001
MVR Maldivian Rufiyaa 15.41
MWK Malawian Kwacha 1729.408354
MXN Mexican Peso 18.7152
MYR Malaysian Ringgit 4.2245
MZN Mozambican Metical 63.899993
NAD Namibian Dollar 17.631478
NGN Nigerian Naira 1521.856076
NIO Nicaraguan Córdoba 36.707187
NOK Norwegian Krone 10.04675
NPR Nepalese Rupee 140.850491
NZD New Zealand Dollar 1.696929
OMR Omani Rial 0.384159
PAB Panamanian Balboa 1
PEN Peruvian Nuevo Sol 3.513158
PGK Papua New Guinean Kina 4.162934
PHP Philippine Peso 56.7
PKR Pakistani Rupee 283.017661
PLN Polish Zloty 3.626762
PYG Paraguayan Guarani 7188.730959
QAR Qatari Rial 3.645383
RON Romanian Leu 4.3322
RSD Serbian Dinar 99.96161
RUB Russian Ruble 81.180388
RWF Rwandan Franc 1444.657468
SAR Saudi Riyal 3.750234
SBD Solomon Islands Dollar 8.223823
SCR Seychellois Rupee 14.768574
SDG Sudanese Pound 600.5
SEK Swedish Krona 9.3953
SGD Singapore Dollar 1.2852
SHP Saint Helena Pound 0.740302
SLE Sierra Leonean Leone 23.25
SLL Sierra Leonean Leone (Old) 20969.5
SOS Somali Shilling 570.01488
SRD Surinamese Dollar 38.8775
SSP South Sudanese Pound 130.26
STD São Tomé and Príncipe Dobra (pre-2018) 22281.8
STN São Tomé and Príncipe Dobra 20.899979
SVC Salvadoran Colón 8.726808
SYP Syrian Pound 13002
SZL Swazi Lilangeni 17.625933
THB Thai Baht 32.051184
TJS Tajikistani Somoni 9.425123
TMT Turkmenistani Manat 3.51
TND Tunisian Dinar 2.916784
TOP Tongan Pa'anga 2.40776
TRY Turkish Lira 41.202502
TTD Trinidad and Tobago Dollar 6.769034
TWD New Taiwan Dollar 30.495
TZS Tanzanian Shilling 2498.446077
UAH Ukrainian Hryvnia 41.11265
UGX Ugandan Shilling 3508.637132
USD United States Dollar 1
UYU Uruguayan Peso 40.150739
UZS Uzbekistan Som 12404.531258
VES Venezuelan Bolívar Soberano 152.630543
VND Vietnamese Dong 26402.66281
VUV Vanuatu Vatu 119.1167
WST Samoan Tala 2.7716
XAF CFA Franc BEAC 559.857475
XAG Silver Ounce 0.02438519
XAU Gold Ounce 0.0002788
XCD East Caribbean Dollar 2.70255
XCG Caribbean Guilder 1.797483
XDR Special Drawing Rights 0.695927
XOF CFA Franc BCEAO 559.857475
XPD Palladium Ounce 0.00090026
XPF CFP Franc 101.84931
XPT Platinum Ounce 0.00072638
YER Yemeni Rial 240.100004
ZAR South African Rand 17.58868
ZMW Zambian Kwacha 23.812327
ZWG Zimbabwean ZiG 26.78
ZWL Zimbabwean Dollar 322