Problem Set 8 : CS50 Shuttle

Hello everyone! Welcome back! This is cs50! How’s the C$50 Finance? It was fun, right? Hehe..
Umm.. well, today I’m going to write about Problem Set 8. OMG, the last!!! OK, so what it is all about? It is all about JavaScript and third-party APIs.

As always, take your time to read :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide


Getting Started

Per the instruction http://cdn.cs50.net/2014/x/psets/8/pset8/pset8.html, if you don’t have Chrome installed on your computer (not inside of the appliance), download and install the latest version of Chrome from http://www.google.com/chrome.
Then using Chrome, download and install the Google Earth Plug-in from http://www.google.com/earth/explore/products/plugin.html. Note that the plug-in requires Mac OS or Windows unfortunately. Once the plug-in installed, you may need to reload that page or restart your browser, but you should see a 3D Earth embedded the page. If unable to get Google-Earth plug-in, you may skip this problem set.
Best to minimize the number of programs and windows you have open while working on this problem set. The Google Earth Plug-in likes to consume CPU cycles and RAM. In fact, if you ever feel your computer slowing down, you might want to quit some programs or even reboot (after saving your work).
Next, start up your appliance, open a terminal window and execute :

update50

To ensure that your appliance is up-to-date!
Like Problem Set 7, this problem set comes with some distribution code that you’ll need to download before getting started. Go ahead and execute :

cd ~/vhosts/localhost/public

Then execute :

wget http://cdn.cs50.net/2013/fall/psets/8/pset8/pset8.zip

In order to download zip file of this problem set’s distro. Then execute :

ls

You should see that you now have a file called pset8.zip in your ~/vhosts/localhost/public directory. Unzip it by execute :

unzip pset8.zip

Then :

ls

You should see that you now also have a directory called pset8. You’re now welcome to delete the ZIP file with the below :

rm –f pset8.zip

If you next execute :

cd pset8

Followed by

ls

You should see that pset8 contains index.html and four directories (css, fonts, and img, and js). Ensure that all files inside of the pset8 (and its descendants) are world readable by executing :

find . – type f | xargs chmod 644

So that the appliance’s web server will be able to access your work. Then ensure that all directories inside pset8 are world-executable by executing the below :

find . – type d | xargs chmod 711

Finally, ensure that few other directories are still world-executable by executing the below :

chmod 711 ~
chmod 711 ~/vhosts
chmod 711 ~/vhosts/localhost
chmod 711 ~/vhosts/localhost/public 

If you opt to create files or any other directories for this problem set, keep in mind that :
• any files should probably be readable and writable by you but only readable by anyone else (i.e 644).
• and any directories should world-executable (i.e 711).

Unlike Problem Set 7, your code for Problem Set 8 will indeed live in a virtual host (aka vhosts) called localhost rather than one called, e.g., pset8. Using localhost will make it easier to access your code from Chrome on your own computer (outside of the appliance).

Now head to the URL below using a browser on your own computer (outside of the CS50 Appliance), where w.x.y.z is your appliance’s IP address (which should be displayed in the appliance’s bottom-right corner), and each of w, x, y, and z is thus a number between 0 and 255:

http://w.x.y.z/pset8/

You should see University Hall! If not, do double-check that you’ve not missed or mistyped a step.

Incidentally, anytime you’d like to print some debugging information to the Console tab of Chrome’s Debugging Tools during this problem set, a la printf in C, know that you can include a line like

console.log("hello, world");

in your JavaScript code. So long as Chrome’s Console is open, you’ll see that text. Just be sure to remove any such lines before submitting your work. Do keep an eye on that Console during development, too, as syntax errors and more tend to appear there in red. Alternatively, you can include a line like

alert("hello, world");

in your JavaScript code to display messages to yourself, but the pop-up that results tends to be more annoying, especially if you accidentally call alert in a loop!


Your mission of this problem set is to implement your own shuttle service that picks up passengers all over campus and drops them off at their houses. Your shuttle equipped with an engine, a steering wheel, and some seats. Assuming that you’re still at http://w.x.y.z/pset8 looking at University Hall, here’s how to drive the keyboard:

Move Forward  W
Move Backward S
Turn Left     
Turn Right    
Side Left     A
Side Right    D
Look Downward 
Look Upward  

Oops! Where did I go? I think I’ve lost my way… 😉

cs50 shuttle

OK, now open up index.html first and read over the HTML code inside :

index.html

Look at the div announcement :

announcements

Then, let’s take a peek at css/service.css :

/**
 * service.css
 *
 * Computer Science 50
 * Problem Set 8
 *
 * Global stylesheet.
 */
 
html
{
 height: 100%;
}

body
{
 font-family: sans-serif;
 height: 100%;
 margin: 0;
}

#announcements
{
 font-size: smaller;
 margin: 5px;
 text-align: center;
}

Then, open up building.js, you should see the below :

/**
 * buildings.js
 *
 * Computer Science 50
 * Problem Set 8
 *
 * Buildings on campus.
 */

var BUILDINGS = [
 {
 root: "04558",
 name: "1 Bow Street",
 address: "1238 Massachusetts Ave",
 lat: 42.372341075,
 lng: -71.116148412
 },
……………etc
];

Now, turn to passengers.js sneak peek :

var PASSENGERS = [
 {
 username: "abuchholtzau",
 name: "Allison Buchholtz-Au",
 house: "Adams House"
 },
………….etc
];

Then you’ll want to check houses.js. You can see the coordinates which are the official coordinates for the passengers destinations.

var HOUSES = 
{
 "Adams House": {lat: 42.37189, lng: -71.11639},
 …..etc
};

If you’d like to look up where some building is on campus, feel free to search for it at http://maps.cs50.net/

Ok, let’s take a peek at js/shuttle.js. You don’t need to understand this file entirely, but know that inside of a Shuttle there are two properties : position, which encapsulates a shuttle’s position(including latitude and longitude)

// shuttle's position
 this.position = {
 altitude: 0,
 heading: config.heading,
 latitude: config.latitude,
 longitude: config.longitude
 };

and states which encapsulates a shuttle’s various states.

// shuttle's states
 this.states = {
 flyingUpward: false,
 flyingDownward: false,
 movingBackward: false,
 movingForward: false,
 slidingLeftward: false,
…etc
};

OK, now pay your attention at js/service.js when you’ll most do your work here. You may modify any of this problem set’s files except for js/math3d.jd, js/building.js, js/houses.js, and js/passengers.js.

Anyway, inside of js/service.js you should do the below:

  1. Pickup chart
  2. Dropoff
  3. Extra features

PICKUP CHART

It’s time start picking the passengers up. Recall from index.html that when the button labeled Pick Up clicked, the function called pickup is js/service.js is called. How to do it? Well, it’s part of challenge. Implement pickup as follows :

  • If the button is clicked when and the shuttle is within 15.0 meters of a passenger and at least one seat is empty, the passenger should be given a seat on a shuttle and removed from both 2D and 3D earth.
  • If the shuttle is not within 15.0 meters of any passenger, make an announcement to the effect.
  • If the shuttle is within range of some passengers but no seats are free, make an announcmement to that effect (and don’t pick up the passenger).
    By the way you’ll want to read :
    Google Maps JavaScript API v3 https://developers.google.com/maps/documentation/javascript/tutorial
    Google Earth API https://developers.google.com/earth/documentation/

Hints to get you started on picks-up :
1. To calculate the shuttle’s distance, “d“, from some point (lat, lng), you’ll probably  want something like :

var d = shuttle.distance(lat, lng);

2. To remove a placemark, “p“, from 3D earth, you’ll probably want something like

var features = earth.getFeatures();
features.removeChild(p);

3. To remove marker, m, from the 2D map, you’ll probably want something like :

m.setMap(null);

4. Then, you’ll want to update shuttle.seats to give the passenger a seat, be sure not to add extra seats.

Incidentally, be sure not to pick up any freshmen (i.e anyone whose home isn’t in js/houses.js).
Take a look at the pseudocode below to get you done the pickup function.

Pseudocode :

1. detect passenger(s) in range –> loop through all passengers
2. add passenger(s) to shuttle
3. remove placemark from the 3D Earth
4. remove marker from 2D map
5. display passenger(s) in shuttle

DROPOFF

Now, implement drop-offs! Recall from js/building.js, that each passenger live in a house. And recall from index.html, that, when the button labelled Drop Off is clicked, the function called dropoff in js/service.js is called. Implement drop-offs as follow :

  • If the button is clicked when the shuttle is within 30.0 meters of an aon-board passenger’s house, that passenger should be dropped of by emptying their seat.
  • If the shuttle is not within 30.0 meters of any passenger’s house, you should make an announcement to that effect. You should make an announcement.
  • No need to re-plant a placemark or marker for dropped-off passangers. Be sure not to make them change seats just because some other seat is now empty.

Take a look at the pseudocode below to get you done the pickup function.
Pseudocode :
1. check if in range of any houses –> loop through houses
2. remove passengers from shuttle

EXTRA FEATURES

Per the spec: http://cdn.cs50.net/2014/x/psets/8/pset8/pset8.html#_extra_features you’ll need to implement any three of the features as the spec says.

Once you’re done with that, you’ve completed CS50 Shuttle! Congrats! 😉
This was Problem Set 8. Your last!

Problem Set 7 : C$50 Finance

Hello world! Welcome back! This is CS50! Congratulations you’ve done the introduction of programming in C. Now, we will have new languages. This problem set teaches you how to teach yourself about, HTML, CSS, PHP and SQL. As always, you’ll want to read the below.
Recommended Reading :
http://diveintohtml5.info/
http://php.net/manual/en/langref.php


HTML

What is HTML actually? HTML (Hyper Text Markup Language) is the language where we use for webpage. But it doesn’t a language actually, because it doesn’t allows to express logic like for-loops, while-loops, conditions and alike rather is indeed a markup language that allows to specify what the webpage should look like, structurally and statically. And it does show by way what we called text. Let’s dive in the simple example for a webpage that print “Hello, World!”.
Open up gedit and let’s make a file called hello.html and save it into public directory that is indeed inside of localhost directory that is indeed inside of vhosts directory and this is is indeed inside of jharvard appliance :

 <!DOCTYPE html>

<html>
    <head>
       <title>hello</title>
    </head>
    <body>
       Hello, World!
    </body>
</html>

CSS

It turns out that HTML is not the only language that you can use for webpage. Well, you’ll want to use CSS (Cascading Style Sheet) as well. CSS allows you the specify much more precisely the aestethics of webpage include layouts, sizes, colors, fonts and much more. I made a css file in a separate window, not inside the html window because it is more readable and effective. For instance let’s take a look an example below :

 /* Header */
.large-header {
 position: relative;
 width: 100%;
 background: #333;
 overflow: hidden;
 background-size: cover;
 background-position: center center;
 z-index: 1;
 -webkit-filter: opacity(60%);
}

.demo-0 .large-header {
 background-image: url('../img/pset0-bg.jpg');
 background-position: center bottom;
 
}

.main-title {
 position: absolute;
 margin: 0;
 padding: 0;
 color: #ffffff;
 text-align: center;
 top: 50%;
 left: 50%;
 -webkit-transform: translate3d(-50%,-50%,0);
 transform: translate3d(-50%,-50%,0);
 
}

PHP

PHP stands for PHP Hypertext Processor or PHP Hyepertext Processor Hyrtext Processor and we’ll stop there.. PHP is a recursive acronym. So, let’s write “Hello, World!” in PHP which a bit different that the “Hello, World!” in C that we’ve come to know and love. So, instead of creating a file called hello.c we’ll create hello.php. All of the PHP code will be contain between :

<?php

?>

If we have any PHP code that is located outside of this border, it won’t execute. We can have many PHP blocks as we want inside the single php file. In PHP, there is no need a “main” function. Instead, our PHP code will be run in order to appears in our PHP file. Both C and PHP have “printf” function for outputting data. But in PHP, we don’t need “#include” any headers file like “<stdio.h>” that is because in PHP we won’t be compiling our code. Unlike C, PHP is interpreted rather than compiled language that means the PHP code we write will be run through a special program called in interpreter which will turn and execute our code. So, to run our PHP code, we’ll send it along to the PHP interpreter which will handle execution rather than compiling it to the machine code. So let’s see interpreter in action. Well, open up the terminal and run the PHP command followed by the path to the PHP file we’d like to run.

jharvard@appliance (~/vhosts/localhost/html): php hello.php 
Hello, world!

And there we go! That’s the output of our PHP program. We didn’t need to compile the file at all instead we had another program the PHP interpreter execute the source code that we wrote. PHP could do much more than simply “printf”. The syntax for constructs like if-else, while, for, switch, is the same in PHP and C. Just like C, each of this constructs use a braces { } to demarcate the body and just like in C, every line we write must end with a semicolon ;. However, variables are handled a bit differently in PHP. First, all of the variables we write have to use dollar sign $. Second, the PHP is loosely typed language. Which means you don’t need to explicitly list the type of the variable when you create it. So, where in C you say :

int x = 5; 
char y = 'a';

in PHP we can simply say:

$x = 5; 
$y = 'a'; 

The same apply to a functions rather than saying

int f() {....}

in PHP we can write :

function f () {....} 

So we don’t need to explicitly specify the return type of the function f. Functions in PHP also don’t have to return the same type everytime they execute. For example, we used “return false” on an error or another type if its succeed. This also make generic functions. Well, in C we use pointers for arrays in strings, we won’t use the pointers in PHP instead both arrays and strings are built in types in PHP. To create an array in PHP we could use :

$a = array(1,2,3);
 or we can use 
$a = [1,2,3];

We can indexed into this array using the same syntax that we’re use to from C. So, get the first element we’ll say :

$a[0];

PHP also have an associative array. And it just like a hashtable data structure that we’ve already seen in C. They mapped a key into a value. Example :

$staff = [
 "instructor" => "david",
 "tf" => "rob"
];

So here I have an associative array with two keys ‘instructor’ and ‘tf’. The => is use to separate the KEY and the corresponding VALUE. So, the value of $staff[“tf”] is a string “Rob”.
Or we’ll want to use :

$staff = [
 "instructor" => "david",
 "tfs" => [
      "rob",
      "tommy"
   ]
];

So now, the value of “tfs” is an ARRAY. That means the value inside in one associative array can be a different types. PHP arrays also do not having a fixed length. So, we can add or remove elements from an array. See http://php.net for more.

We’re about using PHP for web-development. PHP is a scripting language that can be use to implement a website on a web server. A web server is essentially a machine dedicated to providing content that can be access via the internet. So, when you navigate your way to facebook.com/home.php, the code in the file called home.php which lives on the facebook web server somewhere will be executed on that server. So, this code is likely generate some output which entirely sent from the server to your web browser. We’ll be using the CS50 appliance as web server. Well, we navigate to URL like http://localhost/hello.php we’ve configured the appliance via an application called Apache HTTP server to look for file called hello.php inside of home/jharvard/vhosts/localhost/html by default. If that file exists, then Apache will use the PHP interpreter to execute the PHP code in hello.php. If that file doesn’t exist, then Apache will throw it ‘Not Found’ error or 404 error which you’ll probably seen while browsing a web. So, let’s take a look at hello.php. We can see here that hello.php generates a single line of output.

<?php
printf("Hello, world!\n");
?>

When we ran hello.php at the command line below :

jharvard@appliance (~/vhosts/localhost/html): php hello.php 

That output will printed in the terminal. See below :

jharvard@appliance (~/vhosts/localhost/html): php hello.php
 Hello, world!

Now when we access the file via the URL in the web browser, its output will be send to a web browser. So, heading to URL http://localhost/hello.php on your web browser, we can see it will print “Hello World!” on our web browser.

SQL

Se-quel or SQL isn’t a programming language but instead, it’s a language that provides a standard set of commands to retrieve and manipulate data from a variety of database management systems. For the purpose of CS50, we’ll go over four basic commands : SELECT, INSERT, UPDATE, and DELETE. Furthermore, we’ll utilize a database web interface called phpMyAdmin.


Getting Started

Well, we’re going to do a web-development in this problem set. Like problem set6, this problem set comes with distribution code that you’ll need to download before getting started. Let’s get you started! Per instruction (http://cdn.cs50.net/2014/x/psets/7/pset7/pset7.html). Now open up your appliance, then open up the terminal window and execute the below :

cd ~/vhosts

In order to navigate your way to ~/vhosts directory. Then execute :

wget http://cdn.cs50.net/2013/fall/psets/7/pset7/pset7.zip

in order to download the ZIP file. If you then execute :

ls

you should see that you now have a file called pset7.zip in your ~/vhosts directory. Unzip the file by execute :

unzip set7.zip

if you again execute :

ls

you should see that you now have a file called pset7. You’re now welcome to delete the file called pest7.zip by execute :

rm -f pset7.zip

next, execute :

cd ~pset7

followed by

ls

you should see the pset7 contains three subdirectories : includes, public, and templates.

  • Next, ensure a few directories are world-executable by executing
    chmod a+x ~
    chmod a+x ~/vhosts
    chmod a+x ~/vhosts/pset7
    chmod a+x ~/vhosts/pset7/public

    so that the appliance’s web server (and you, from a browser) will be able to access your work. Then, navigate your way to ~/vhosts/pset7/public by executing the below.

    cd ~/vhosts/pset7/public

    If you execute

    ls

    you should see that public contains four subdirectories and three files. Ensure that the former are word-executable by executing the below.

    chmod a+x css fonts img js

    Finally, ensure that the files within those directories are world-readable by executing the below.

    chmod a+r css/* fonts/* img/* js/*

    If unfamiliar, * is a “wildcard character,” so css/*, for instance, simply means “all files within the css directory.”

    For security’s sake, don’t make ~/vhosts/pset7/includes or ~/vhosts/pset7/templates world-executable (or their contents world-readable), as they shouldn’t be accessible to the whole world (only to your PHP code, as you’ll soon see).

  • Even though your code for this problem set will live in ~/vhosts/pset7, let’s ensure that it’s nonetheless backed up via Dropbox, assuming you set up Dropbox inside of the appliance. In a terminal window, execute

    ln -s ~/vhosts/pset7 ~/Dropbox

    in order to create a “symbolic link” (i.e., alias or shortcut) to your ~/vhosts/pset7 directory within your ~/Dropbox directory so that Dropbox knows to start backing it up.

  • So why did we put pset7 inside of a directory called vhosts? Well, the appliance is configured to serve “virtual hosts” (i.e., websites) out of the latter. Specifically, if you visit, say, http://pset7/ using Chrome inside of the appliance, the appliance is configured to look in ~/vhosts/pset7/public for that website’s web-accessible files. But for that to work, we also need to associate the appliance’s own IP address with pset7 so that it “resolves” via DNS to it. Rather than set up a whole DNS server to do that, we can actually edit a file called hosts in a directory called etc. Let’s do that.

    In a terminal window, execute

    sudo gedit /etc/hosts

    in order to run gedit as the appliance’s “superuser” (aka “root”) so that you can edit what’s otherwise a read-only file. Carefully add this line at the bottom of that file, which will associate pset7 with the appliance’s “loopback” address (which won’t ever change):

    127.0.0.1 pset7

    Then save the file and quit gedit. Then enjoy http://xkcd.com/149/.

    If you encounter a Gtk-WARNING with gedit, try restarting the appliance, as via Menu > Log Out > Restart (or via VMware’s own Restart option), then try again; the warning appears to be a bug in Fedora (the appliance’s operating system).

  • Alright, time for a test! Open up Chrome inside of the appliance and visit http://pset7/ then you should see below.

cs50 finance

Now, head to http://pset7/phpMyAdmin using Chrome inside the appliance to access phpMyAdmin, a Web-based tool with which you can manage MySQL databases. (MySQL is a free, open-source database that lots of sites use). If you then, see the below and login as John Harvard (name jharvard and password crimson).

loginPMA

You should then find yourself at phpMyAdmin’s main page.

php main page

Then, go ahead and visit http://cdn.cs50.net/2013/fall/psets/7/pset7/pset7.sql using Chrome inside the appliance, and then open the file in gedit, as by clicking its name in Chrome’s bottom left corner. You should ultimately see a whole bunch of SQL within pset7.sql. Then highlight it and copy it by select Edit > Copy (or just hit ctrl-c).

pset7sql

Then, return to phpMyAdmin and click phpMyAdmin’s SQL tab, and paste everything you copied in that page’s big text box.

phpSQLtab

Then, click Go. You should see a green banner proclaiming Your SQL query has been executed successfully.

Okay, heads-up. Just to remind you that anytime you create a new file directory in ~/vhosts/pset7 or some subdirectory therein for this problem set, you’ll want to set its permissions with chmod. Thus far, we’ve relied on a+r and a+x, now we can use which more precise control over permissions.

For any PHP file, file, that you create, execute :

chmod 600 file

that is accessible only by you (and the appliance’s webserver).

For any non-PHP file, file, that you create (or upload), execute :

chmod 644 file

it’s accessible via browser.

And for any directory, directory, that you create, execute :

chmod 711 directory

that its contents are accessible via a browser.


You’re about to implement C$50 Finance, a Web-based tool with which you can manage portofolios of stocks. It will also let you buy and sell stocks! If you’re not quite sure what it means to buy and sell stocks, you’ll want to surf on over http://www.investopedia.com/university/stocks/ for tutorial. Then head to http://finance.yahoo.com for teaser. Then typed symbol DVN.V you’ll see the table like below.

DVN


Now, open up index.php on gedit. Know that index.php is the file that’s loaded by default when you visit a URL like http://pset7/ .

<?php

 // configuration
 require("../includes/config.php"); 
 
 $positions = [];
 
 $rows = query("SELECT symbol, shares FROM usertable WHERE id = ?", $_SESSION["id"]); 
 foreach ($rows as $row)
 {  
 $stock = lookup($row["symbol"]);
 if ($stock !== false)
 {
 $positions[] = [
 "name" => $stock["name"],
 "price" => $stock["price"],
 "shares" => $stock["shares"],
 "symbol" => $row["symbol"],
 ];
 
 }
 }

 // render portfolio
 render("portfolio.php", ["positions" => $positions, "title" => "Portfolio"]);

?> 

Turns out, that there’s not any HTML at all, index.php require config.php (inside the directory called includes) and then calls render ( a function that implemented in file called function.php and inside the directory called includes). And it turns out that index.php is considered a “controller”. Its purpose in life is to control the behaviour of  your website when the user visits http://pset7/. By the way, you’ll create another “controllers” inside of ~/vhosts/pset7/public. More on those later.

Next, open up config.php in gedit. You should see the below.

<?php

 /**
 * config.php
 *
 * Computer Science 50
 * Problem Set 7
 *
 * Configures pages.
 */

 // display errors, warnings, and notices
 ini_set("display_errors", true);
 error_reporting(E_ALL);

 // requirements
 require("constants.php");
 require("functions.php");

 // enable sessions
 session_start();

 // require authentication for most pages
 if (!preg_match("{(?:login|logout|register)\.php$}", $_SERVER["PHP_SELF"]))
 {
 if (empty($_SESSION["id"]))
 {
 redirect("login.php");
 }
 }

?>

Okay, so config.php calls session_start in order to enable $_SESSION a superglobal variable via which we’ll remember that a user logged in. Next, config.php calls $_SESSION is  an associative array in which you can store any data to which you’d like to have access for the duration of some user’s visit.

For instance, now, take your time to open up another files inside of each directories inside ~/vhosts/pset7/. You’ll want to navigate your way to ~/vhosts/pset7/templates and open up “portfolio.php” and another files. If you then, navigate your way to ~/vhosts/pset7/includes and open up “contstans.php” and “functions.php”. Then, you should find out what’s going on there.


Now, let’s  make it simple. I assume you’ve read over the spec http://cdn.cs50.net/2014/x/psets/7/pset7/pset7.html. In this problem set, you’ll developt a website, for instance it is all about buy and sell stocks. It will indeed using databases for each elements of it, like INSERT-ing, SELECT-ing, DELETE-ing, and then UPDATE-ing. And this is all about how do you create them? Well, you’ll want to use SQL to do it. Let’s tackle it! Before we go for some examples, I just wanna make sure that you have to implement each of those below :

  1. register.php
  2. quote.php
  3. portfolio.php
  4. sell.php
  5. buy.php
  6. history.php

Okay, so let’s talk about an example, I used a query from login.php, it is inside of ~/vhosts/pset7/public. Notice too that login.php “remembers” that a user is logged in by storing his or her unique ID inside of $_SESSION. Take a look at below :

// remember that user's now logged in by storing user's ID in session
 $_SESSION["id"] = $row["id"];

Then, take a look at the line below :

query("SELECT * FROM users WHERE username = ?", $_POST["username"]);

Read through its line carefully, taking note of how it queries the appliance’s MySQL using that query function. That function essentially simplifies use of PDO (PHP Data Object), see http://www.php.net/manual/en/class.pdo.php for more details, it is a library with which you can query MySQL (and other) databases.

Ok, now suppose that President Skroob tries to log into C$50 Finance by inputting his username and password. That line of code will ultimately execute the SQL statement below :

SELECT * FROM users WHERE username='skroob'

But, unlike SELECTs, some SQL queries like DELETE, UPDATE, and INSERT don’t actually return rows, so that query returns might sometimes be empty.


REGISTER.PHP

It’s time to code now! First, we’ll tackle register.php. In terminal window execute :

~/vhosts/pset7/templates

then, you’ll want to execute :

cp login_form.php register_form.php

Open up register_form.php with gedit and change the value of action attribute from login.php to register.php. Add an additional field of type password to the HTML form called confirmation. So, that users are prompted to input their choice of passwords twice (to discourage mistake).

Then, using gedit, create a new file called “register.php” with contents below, but don’t forget to save it in ~/vhosts/pset7/public.

<?php

// configuration
require("../includes/config.php");

// if form was submitted
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
// TODO
}

else
{
// else render form
render("register_form.php", ["title" => "Register"]);
}
?>

Pseudocode of TODO above :

  • If $_POST[“username”] or $_POST[“password”] is empty or if $_POST[“password”] does not equal $_POST[“confirmation”] , you’ll want to inform registrants of their error.
  • To insert new user, you might want to call :
query("INSERT INTO users (username, hash, cash) VALUES(?, ?, 10000.0)", $_POST["username"], crypt($_POST["password"]));
  • Query will return false if your INSERT fails (as can happen if, say, username already exists). Be sure to check for false with === and not ==.
  • If, though, your INSERT succeeds, know that you can find out which id was assigned to that user with code like below :
$rows = query("SELECT LAST_INSERT_ID() AS id");
$id = $rows[0]["id"];
  • If registration succeeds, you might as well log the new user in (as by “remembering” that id in $_SESSION), there after redirecting to index.php
    If done with register.php. Test it by heading to http://pset7/register.php using Chrome inside the appliance and try to register a new username. If you reach index.php, you done good! Be sure that html is valid via http://validator.w3.org/#validate_by_input .

(gambar register.php)

QUOTES.PHP

Now, let’s empower user to look up quotes for individual stocks. You’ll want to create a new controller called quotes.php inside the ~/vhosts/pset7/public plus two templates, the first of which to display an HTML form via which you can submit a stock’s symbol, the second of which displays, minimally, a stock’s lates price (if passed, via render, an appropriate value).How to look up a stock’s latest price? You’ll want to call lookup function in function.php, see below :

$stock = lookup($_POST["symbol"]);

Pseudocode :

  • Display form
    Display from allows the user to input the given stock symbol that they want to lookup. You’ll want to create a quote template (the form for stok lookup) for example : quote_form.php and save inside ~/vhosts/pset7/template. And don’t forget to add the form input that allows the uses to input symbol that they want to look up. Next, the form action is to send those informations to controller (i.e quote.php) that lies in the ~/vhosts/pset7/public.s
  • Retrieve stock quote
    The function “lookup” passing in the string of the symbol that will return an associative array.for example :
$s = lookup("AAPL");

Return an associative array :
– Symbol
– Name
– Price

  • Display stock quote
    We’re already have a controller called quote.php and a template called quote_form.php. Then how to display the stock quote? Well, you’ll want to create another template let’s say quote.php and save it inside the ~/vhosts/pset7/template. That will have the behaviours like below :
    – At minimum, display quote
    – Ensure the stock symbol is valid, else “apologize” as usual.
    – print(“Price: “ . $s[“price”]); but we need to format to 2 to 4 decimal places, if not sure try to read number_format functionality.

Be sure that html is valid via http://validator.w3.org/#validate_by_input .

PORTFOLIO.PHP

Portfolio means “collection of stocks (i.e shares company). At present, your database has no way of keeping track of user’s portfolios. How many different stocks might a user own? Better to maintain that data in a new table together so that we don’t impose limits on users’ portfolios. What sort of information need we keep in this new table in order to ‘remember’ users’ portfolios? Well, you’ll want to add a table with three fields ID, SYMBOL, and SHARES sounds pretty good. To create ne table click on pset7 in phpMyAdmin’s top left corner and click Create table as you see below, then click Go :

create-table

Next, define each of your fields (id, symbol, and shares), realize that ID should not be defined as primary key in this table. And, you shouldn’t let some id and shares to appear together in more than one row. But, you should define a “joint primary key” by selecting an Index of PRIMARY for both id and symbol. That way, INSERT will fail if you try to insert more than one row.

Be sure that html is valid via http://validator.w3.org/#validate_by_input .

Pseudocode :
For portfolio, you’ll want to display all of the stocks that the user has.
1. Make a portfolio table
2. Display the portfolio table

SELL.PHP

It’s time to implement sell with a controller called sell.php and some number of templates. I leave you to design of this feature to you. Know that you can delete rows from your tables with code like below :

DELETE FROM tbl WHERE id = 7 AND symbol = 'DVN.V'

What about the users’ balance? Your user is going to want the proceeds of all sales. So selling a stock will updating not only your table for users’ portfolios but users as well. Determine it by yourself. Example : let’s say the amount is ($400) with SQL like below it will take care of the deposit.

UPDATE users SET cash = cash + 400 WHERE id = 7

Pseudocode:

  • You’ll want to display form that allows the user (i.e the stock’s owner) to get stock to sell. So, create a new template for it. But they can only sell the stock that they own. So, with code like :
SELECT * FROM portfolio WHERE id = 7
  • Remove stock (that you’ve sold) from the portfolio, with code like :
DELETE FROM portfolio WHERE id = 7 AND symbol = "AAPL"
  • Updating cash where the stock is sold at its current price. So, look back at “lookup” function.

BUY.PHP
Implement ability to buy with controller called buy.php and some number of templates. See http://www.cs50.net/finance for inspirations. You’ll need to to ensure that a user cannot spend more cash than he or she has on hand. You’ll want to make sure that users can only buy whole of shares of stocks. You’ll want to call :

preg_match("/^\d+$/", $_POST["shares"])

see http://www.php.net/preg_match for details. Be sure that html is valid via http://validator.w3.org/#validate_by_input .

Pseudocode :

  • You’ll want to display form for the user to get the stocks, and number of shares. Well, the form is going to be an HTML form that will ask for symbol and number of shares.
  • You’ll want to add stock to the portfolio. We’ll first check whether the users can afford the stock, for example :
SELECT cash FROM users WHERE id = 7

Now, they want to buy more at the same stock, then you’ll want to allow them to update the given row in the portfolio,

INSERT INTO portfolio (id, symbol, shares) VALUES(7, 'DVN.V', 10) ON DUPLICATE KEY UPDATE shares = shares + VALUES(shares)
  • Then, you’ll want to update cash. A user’s cash is stored in users table. Then you’ll need to :
UPDATE users SET cash = cash – 9999 WHERE id =7

HISTORY.PHP

So your users can now buy and sell stocks and even check their portfolio’s value. But they have no way of viewing their history of transactions.
Enhance your implementations for buying and selling in such a way that you start logging transactions, recording for each:

• Whether a stock was bought or sold.
• The symbol bought or sold.
• The number of shares bought or sold.
• The price of a share at the time of transaction.
• The date and time of the transaction

Then, by way of a controller called, say, history.php and some number of templates, enable users to peruse their own history of transactions, formatted as you see fit.

Be sure that html is valid via http://validator.w3.org/#validate_by_input .

Pseudocode :

  • You’ll need to add history table
  • For every purchase and sale :

– Add a row to history
– Store the timestamp of transactions: you’ll want to use NOW() either CURRENT_TIMESTAMP functions.

FINAL THOUGHTS

Glance back at index.php now and, if not there already, make that it somehow links to, at least, buy.php , history.php , logout.php , quote.php , and sell.php (or their equivalents) so that each is only one click away from a user’s portfolio!

And now the icing on the cake. Only one feature to go, but you get to choose. Implement at least one (1) of the features below. You may interpret each of the below as you see fit; we leave all design decisions to you :

– Empower users (who’re already logged in) to change their passwords.
– Empower users who’ve forgotten their password to reset it (as by having them register with an email address so that you can email them a link via which to do so).
– Email users “receipts” anytime they buy or sell stocks.
– Empower users to deposit additional funds.

Be sure that html is valid via http://validator.w3.org/#validate_by_input .
For tips on how to send email programmatically, see https://manual.cs50.net/Sending_Mail

With that, you’ve completed C$50 Finance.

This was Problem Set 7.

Problem Set 6 : Dictionary

Hello fellow coder! Welcome back to CS50! So, this is the beginning of make your own data structure and optimize your code’s (real-world) running time. What is the problem actually? Well, this problem set is about to make a “Spell-checker”. Like problem set 5, it will comes with the distribution code. How is the spell checker works? Well, we’re going to find out later. This was the hardest problem set that I ever done to be honest.

Now, let’s get started!
Per the instruction open up the terminal window, and execute :

update50

To make sure your appliance is up-to-date.Then, execute :

~/Dropbox

In order to navigate your way to ~/Dropbox directory. Then, execute :

wget http://cdn.cs50.net/2013/fall/psets/6/pset6/pset6.zip

To download a ZIP of this problem set’s disro. Next, execute :

ls

You could see the file called pset6.zip in your ~/Dropbox directory. Then, you’ll want to unzip the file by executing the below :

unzip pset6.zip

Then execute :

ls

To ensure that you have a directory called pset6. If you then want to delete the zip file by execute :

rm -f pset6.zip

To remove the pset6.zip file. Next execute :

cd pset6

Now let’s open what’s inside the pset6 directory by execute :

ls

Then you should the the directory contains the below :

dictionary.c dictionary.h Makefile questions.txt speller.c

Now, let’s get started!

First, let’s be friends with “running time“. On input size of n, an algorithm with a running time of n is asymptotically equivalent in term big O, to an algorithm with a running time of 2n. In the real world, though, the fact of the matter is that the latter feels twice as slow as the former.
The challenge of this problem set is to implement the fastest spell-checker you can! By “fastest”, though, we’re talking actual, real-world, noticeable seconds-none of that asymptotic stuff this time.
Take your time to take a look at dictionary.h on gedit. In this file you should see the cs50’s staff declared a dictionary’s functionality.

dictionary.h
They declared the prototype of four functions, take a note of what each should do. Anyway, you’ll want to implement 4 functions to complete this problem set, and they are : check, load, size and unload. The prototypes inside the dictionary.h are :

// maximum length for a word
// (e.g., pneumonoultramicroscopicsilicovolcanoconiosis)
#define LENGTH 45
/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char* word);

/**
 * Loads dictionary into memory. Returns true if successful else false.
 */
bool load(const char* dictionary);

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void);

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */
bool unload(void);

#endif // DICTIONARY_H

Okay, next open up speller.c with gedit. And try to understand it. You won’t need to change anything in this file.

/****************************************************************************
 * speller.c
 *
 * Computer Science 50
 * Problem Set 6
 *
 * Implements a spell-checker.
 ***************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>

#include "dictionary.h"
#undef calculate
#undef getrusage

// default dictionary
#define DICTIONARY "/home/cs50/pset6/dictionaries/large"

// prototype
double calculate(const struct rusage* b, const struct rusage* a);

int main(int argc, char* argv[])
{
    // check for correct number of args
    if (argc != 2 && argc != 3)
    {
        printf("Usage: speller [dictionary] text\n");
        return 1;
    }

    // structs for timing data
    struct rusage before, after;

    // benchmarks
    double ti_load = 0.0, ti_check = 0.0, ti_size = 0.0, ti_unload = 0.0;

    // determine dictionary to use
    char* dictionary = (argc == 3) ? argv[1] : DICTIONARY;

    // load dictionary
    getrusage(RUSAGE_SELF, &before);
    bool loaded = load(dictionary);
    getrusage(RUSAGE_SELF, &after);

    // abort if dictionary not loaded
    if (!loaded)
    {
        printf("Could not load %s.\n", dictionary);
        return 1;
    }

    // calculate time to load dictionary
    ti_load = calculate(&before, &after);

    // try to open text
    char* text = (argc == 3) ? argv[2] : argv[1];
    FILE* fp = fopen(text, "r");
    if (fp == NULL)
    {
        printf("Could not open %s.\n", text);
        unload();
        return 1;
    }

    // prepare to report misspellings
    printf("\nMISSPELLED WORDS\n\n");

    // prepare to spell-check
    int index = 0, misspellings = 0, words = 0;
    char word[LENGTH+1];

    // spell-check each word in text
    for (int c = fgetc(fp); c != EOF; c = fgetc(fp))
    {
        // allow only alphabetical characters and apostrophes
        if (isalpha(c) || (c == '\'' && index > 0))
        {
            // append character to word
            word[index] = c;
            index++;

            // ignore alphabetical strings too long to be words
            if (index > LENGTH)
            {
                // consume remainder of alphabetical string
                while ((c = fgetc(fp)) != EOF && isalpha(c));

                // prepare for new word
                index = 0;
            }
        }

        // ignore words with numbers (like MS Word can)
        else if (isdigit(c))
        {
            // consume remainder of alphanumeric string
            while ((c = fgetc(fp)) != EOF && isalnum(c));

            // prepare for new word
            index = 0;
        }

        // we must have found a whole word
        else if (index > 0)
        {
            // terminate current word
            word[index] = '';

            // update counter
            words++;

            // check word's spelling
            getrusage(RUSAGE_SELF, &before);
            bool misspelled = !check(word);
            getrusage(RUSAGE_SELF, &after);

            // update benchmark
            ti_check += calculate(&before, &after);

            // print word if misspelled
            if (misspelled)
            {
                printf("%s\n", word);
                misspellings++;
            }

            // prepare for next word
            index = 0;
        }
    }

    // check whether there was an error
    if (ferror(fp))
    {
        fclose(fp);
        printf("Error reading %s.\n", text);
        unload();
        return 1;
    }

    // close text
    fclose(fp);

    // determine dictionary's size
    getrusage(RUSAGE_SELF, &before);
    unsigned int n = size();
    getrusage(RUSAGE_SELF, &after);

    // calculate time to determine dictionary's size
    ti_size = calculate(&before, &after);

    // unload dictionary
    getrusage(RUSAGE_SELF, &before);
    bool unloaded = unload();
    getrusage(RUSAGE_SELF, &after);

    // abort if dictionary not unloaded
    if (!unloaded)
    {
        printf("Could not unload %s.\n", dictionary);
        return 1;
    }

    // calculate time to unload dictionary
    ti_unload = calculate(&before, &after);

    // report benchmarks
    printf("\nWORDS MISSPELLED:     %d\n", misspellings);
    printf("WORDS IN DICTIONARY:  %d\n", n);
    printf("WORDS IN TEXT:        %d\n", words);
    printf("TIME IN load:         %.2f\n", ti_load);
    printf("TIME IN check:        %.2f\n", ti_check);
    printf("TIME IN size:         %.2f\n", ti_size);
    printf("TIME IN unload:       %.2f\n", ti_unload);
    printf("TIME IN TOTAL:        %.2f\n\n", 
     ti_load + ti_check + ti_size + ti_unload);

    // that's all folks
    return 0;
}

/**
 * Returns number of seconds between b and a.
 */
double calculate(const struct rusage* b, const struct rusage* a)
{
    if (b == NULL || a == NULL)
    {
        return 0.0;
    }
    else
    {
        return ((((a->ru_utime.tv_sec * 1000000 + a->ru_utime.tv_usec) -
                 (b->ru_utime.tv_sec * 1000000 + b->ru_utime.tv_usec)) +
                ((a->ru_stime.tv_sec * 1000000 + a->ru_stime.tv_usec) -
                 (b->ru_stime.tv_sec * 1000000 + b->ru_stime.tv_usec)))
                / 1000000.0);
    }
}

Alright, next challenge is to implement load, check, size and unload as efficiently as possible. Now, open up dictionary.c on gedit. But, before you dive in, be sure to read the specifications.

OK, I assume you have read the specs, now let’s get you started! What do we need to do in dictionary.c ? In the dictionary.c, we have the helper function LOAD, which is loads the dictionary. Then, function CHECK, to checks if a given word is in dictionary. Function SIZE, returns the number of words in the dictionary. And function UNLOAD to frees the dictionary from memory .

Implement LOAD
A spell-checker will call LOAD function on the dictionary text file. For each word in the dictionary text file, LOAD function will store those words in the dictionary data structure. You can use either HASHTABLE or TRIE. But before we’re about dealing with linked list aswell, since the linked list is the buckets. In linked list, each node has a value, as well as a pointer to the next node. Dealing with linked list, is very important do not lose any links. And the last node points to NULL. How do we define it in C?

Linked list :

typedef struct node
{
   char word[LENGTH+1];
   struct node * next;
}
node;

And there we have linked list. It just one linked list. But hashtable is an whole array in linked list. We have the same structure like before. But if we wanna go with an actual hashtable, we’re gonna make node pointer array , here for example size of 500.

typedef struct node
{
 char word[LENGTH+1];
 struct node* next;
}
node;
node* hashtable[500]

Then, you’ll want to malloc the node for every new word that you have.

node* new_node = malloc(sizeof(node));
fscanf(file, "%s", new_node → word)

Where new_node -> word is the destination of that word.

Now, we’ll want to hash that word. That’s why we gonna call the HASH Function. Well, hash function takes a string and returns an index, in this case the index has to be less than the number of buckets. And the hash function has to be deterministic, that means, the same value needs to map to the same bucket every time. So, new_node → word has the word from dictionary. Then, hashing new_node → word will give us the index of the bucket of the hashtable. And it will insert that in the specific linked list.

Now, how about TRIE ?
Well, in TRIE function every node contains an array of node* s. One for every letter in alphabet + ”\’. And each element in the array points to another node. The structure is:

typedef struct node
{
   bool is_word;
   struct node* children[27];
}
node;
node* root;

OK now, let’s implement the LOAD function with TRIE in the pseudocode below :

for every dictionary word, iterate thru the trie
each element in children corresponds to a different letter.
check the value at children[i]
  if NULL , malloc the node, have children[i] point to it
  if not NULL, move to the new node and continue
if at the end of word, set is_word to true

Implement CHECK

Speller.c will call CHECK function on every word in the inputted text file and printing all miss-spelled words. CHECK function must operate case-insensitivity. And assume the strings will only alphabetical and/ or apostrophes.

Let’s look at how you might CHECK with HASHTABLE :

if the word exist, it can be found in the hashtable
which bucket would the word be in?
  hashtable[hash(word)]
search in that linked list by using strcmp

Now, let’s look at how you might CHECK with TRIE :

for each letter in input word
  go to corresponding element in children
  if NULL, word is misspelled
  if not NULL, move to next letter
  once at the end of input file
  check if is_word is true

Implement SIZE
Speller.c will also call SIZE function to determine of words in the dictionary. Just returns number of words in dictionary if loaded else 0 if not yet loaded.

Implement UNLOAD
And the last, speller.c will call UNLOAD function to free up memory.
Here’s how you might UNLOAD with hashtable :

for every element in hashtable
for every node in the linked list, you’ll want to free that node.

Freeing linked list :

node* cursor = head;
while(cursor != NULL)
 {
    node *temporary = cursor;
    cursor = cursor->next;
    free(temporary);
 }

Then, how about using TRIE ?

unload from bottom to top
travel to the lowest possible node
 free all pointers in children
 backtrack upwards, freeing all elements in each children array until you hit root node
recursion will coming handy

To make sure you’ve properly freed everything that you’ve malloced you can use VALGRIND. Running valgrind, will run your program how many bytes of memory you’re using and make sure that you’ve freed them all .

valgrind --leak-check=full ./speller ~cs50/pset6/texts/austinpowers.txt

Once you’ve done with dictionary.c, then compile and run your program as always. Then, check how fast your “spell-checker” works  by compare it with the staff’s. If it is done, you’ll want to check your correctness with check50.

Be sure to answer the following questions inside the questions.txt on gedit.

0. What is pneumonoultramicroscopicsilicovolcanoconiosis ?
1. According to its man page, what does getrusage do?
2. Per that same man page, how many members are in a variable of type struct rusage ?
3. Why do you think we pass before and after by reference (instead of by value) to calculate , even though we’re not changing their contents?
4. Explain as precisely as possible, in a paragraph or more, how main goes about reading words from a file. In other words, convince us that you indeed understand how that function’s for loop works.
5. Why do you think we used fgetc to read each word’s characters one at a time rather than use fscanf with a format string like “%s” to read whole words at a time? Put another way, what problems might arise by relying on fscanf alone?
6. Why do you think we declared the parameters for check and load as const ?

This was Problem Set 6.

Problem Set 5 : Forensics

Hello guys! Welcome back. This is CS50! We’re going to start a Problem Set 5. In this problem set, you’ll get more comfortable with data structures, hexadecimal, and pointers. Also, acquaint you with file I/O. As always, before we get started you will want to read these :

Recommended Reading :
http://www.cprogramming.com/tutorial/cfileio.html
http://en.wikipedia.org/wiki/BMP_file_format
http://en.wikipedia.org/wiki/Hexadecimal
http://en.wikipedia.org/wiki/Jpg
But, the Wikipedia articles are a bit dense, so feel free to skip it.

Recommended watching :
File I/O : https://www.youtube.com/watch?v=KwvObCA04dU
Structs : https://www.youtube.com/watch?v=EzRwP7NV0LM
Valgrind : https://www.youtube.com/watch?v=EzRwP7NV0LM
GDB : https://www.youtube.com/watch?v=USPvePv1uzE


Getting Started

Welcome back!
As always, you’ll need to read a long the specification. http://d2o9nyf4hwsci4.cloudfront.net/2014/x/psets/5/pset5/pset5.html
Open you appliance, then open up the terminal window and execute

update50

To make sure your appliance is up-to-date.
Like Problem Set 3 and 4. This problem set comes with the distribution code that you’ll need to download before getting started. Go ahead, and execute :

cd ~/Dropbox

In order to navigate your way to ~/Dropbox. Next, execute :

wget http://cdn.cs50.net/2013/fall/psets/5/pset5/pset5.zip

In order to download a ZIP (i.e., compressed version) of this problem set’s distro.If you then execute :

ls

you should see that you now also have a pset5 directory. You’re now welcome to delete the ZIP file with the below :

rm -f pset5.zip

Now dive into that pset5 directory by executing the below :

cd pset5

Now execute :

ls

And you should see that the directory contains the below :

bmp/ jpg/ questions.txt

How fun! There are two subdirectories and a file. Who know what’s inside ? Let’s get started.
Have you ever seen Windows XP’s default wallpaper (think the rolling hills and blue skies) ? Then, you’ve seen BMP. If you ever looked at webpage you’ve probably seen GIF. If you’ve ever looked at digital photo you’ve probably seen JPEG. And, if you’ve ever taken a screenshot of Mac, you’ve seen PNG. Read up a bit of GIF, JPEG, BMP and PNG file formats, then open up questions.txt on gedit. Be sure you can answer these questions :

0. How many different colors does each format support?
1. Which of these formats supports animation?
2. What’s the difference between lossy and lossless compression?
3. Which of these formats is lossy-compressed?

Read up at the MIT’s article : http://cdn.cs50.net/2013/fall/psets/5/garfinkel.pdf
And try to answer these questions on ~/Dropbox/pset5/questions.txt.

4. What happens, technically speaking, when a file is deleted on a FAT file system?
5. What can someone like you do to ensure (with high probability) that files you delete cannot be recovered?


Anyway, you have to do 3 parts in this problem set and they are :

  • whodunit.c
  • resize.c
  • recover.c

WHODUNIT and RESIZE

http://d2o9nyf4hwsci4.cloudfront.net/2014/x/psets/5/pset5/pset5.html#_whodunit_and_more

WHODUNIT

We’re going to find out. In this game clue, you might be given a little red image. And the image is very red and spotty. Your job is to revealed the hidden message among this file’s red noise is a drawing whodunit.

rednoise

In whodunit, you are given a Bitmap image that was very spotty and red. And run the whodunit program to reveal the hidden message. So, let’s break this problem.

TODO :
1. Open the file
2. Update header info
3. Read clue scanline, pixel by pixel
4. Change pixel color as necessary
5. Write into verdict scanline, pixel by pixel

First, you’ll want to open the file, the clue that you’ve given. And also create a verdict bitmap file. And then you’ll want to update the bitmap header info for the verdict outfile. More on that later. And then, you’ll wan to read into the clue, scanline pixel by pixel, change pixel color as necessary and write into verdict scanline pixel by pixel. How do we start it? Luckily, we have a copy.c in the distribution code and this is going to prove quite useful to us. Here is the sneak peak of copy.c

openfile
And, then read infile and update the outfile’s header

readinfileandupdate
Then, read each pixel

read each pixel
And then, write the pixel into the outfile:

fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);

So, your first step might be to run the following command in the terminal:

cp copy.c whodunit.c

This would create a copy from a copy.c named whodunit.c

Pseudocode for whodunit.c :
1. Open the file (still same like copy.c , so no need to change anything)
2. Update header info (still same)
3. Read clue scanline, pixel by pixel (still same)
4. Change pixel color as necessary
5. Write into verdict scanline, pixel by pixel
Ok, I’ll walk you thru it.

1. Opening files :

FILE* inptr = fopen("foo.bmp", "r");

Opens foo.bmp for reading that represented by “r“.

 FILE* outptr = fopen("bar.bmp", "w"); 

Opens bar.bmp for writing that represented by “w“.

Next step, we’re going to update header info. What’s the header info ? Well, first we have to know what the bitmap is.

offset
Open up the bmp.h on gedit.
What does the structure of BITMAPFILEHEADER contain ? The BITMAPFILEHEADER structure contains information about the type, size, and layout of a file that contains a DIB [device-independent bitmap].

bitmapheaderinfo

Then, what does the structure of BITMAPINFOHEADER contain ? The BITMAPINFOHEADER structure contains information about the dimensions and color format of a DIB [device-independent bitmap].
bitmapinfoheader

Header :

  • biSizeImage : is the total size of image (in bytes) and include pixel and padding. More on those later.
  • biWidth : is the width of image (in pixels) , this doesn’t incude padding.
  • biHeight : is the height of image (in pixels).

There are 2 structs on Header : BITMAPFILEHEADER and BITMAPINFOHEADER.

So, how do we update the header info? We first want to see is anything changing in the clue (the infile) to the verdict (the outfile).
2. Updating Header Info :

  • New bmp → new header info
  • Is anything changing ? Well, no actually. Because we’re going to changing the color.
    File size (not changing).
    Image size (not changing).
    Width (not changing).
    Height (not changing).

So, you’re right for now by just copy it. Next, how do we read every pixel ?
3. Reading file :

fread(&data, size, number, inptr);

&data : is a pointer to a struct which will contain the bytes you’re reading.
size : size of each elements to read , here the function sizeof will coming handy.
number : is a number of each elements to read.
inptr : FILE* to read from
Then, let’s change the color as we need :

rgbtriple
As you can see, inside of the rgb structure, there are rgbtBlue, which is the amount of blue, rgbtRed which is the amount of red, and rgbtGreen which is the amount of green.

4. Changing pixel color :
Each color represented by 3 bytes :

  • amount of blue
  • amount of red
  • amount of green
    ff0000 blue
    ffffff → white

So, can you change the color to green ? You will want to call RGBTRIPLE (a struct to represent pixel). By using dot (.) operator.
See example below :

RGBTRIPLE triple;
triple.rgbtBlue = 0x00;
triple.rgbtGreen = 0xff;
triple.rgbtRed= 0x00;

With that, it gives me a green pixel. Next, what if I want to check the value of something?
See example below :
If you’d like check the value of blue. You may execute :

if (triple.rgbtBlue == 0xff)
{
   printf("I’m feeling blue!");
}

For whodunit, let me suggest you to use “remove all RED” method. But still, there are a couple of ways to solve this problem. Ok, so now assume we’ve changed the pixel color. The next step is write into the verdict scanline.

5. Writing into verdict scanline, pixel by pixel :

Again you’ll want to take a look copy.c and see how to writing files.

fwrite(&data, size, number, outptr);

&data : is a pointer to a struct which will contain the bytes you’re reading from.
size
number
outptr : FILE* to write to.

But, you also have to determine the padding. What is padding? Well, every RGBt pixel is 3 bytes long. But, the scanline for bitmap image has to be multiple of 4 bytes. If the number of pixels isn’t multiple of 4, we need “padding”. Padding is just the represented of zero. So, how do we read and write this ? Well, you can’t actually “fread” padding but you can calculate it.

Padding :

  • Padding isn’t a RGBTRIPLE so we can’t fread padding.
  • The clue and the verdict have the same width, so the padding is the same!
padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

Now, we have the padding formula. Then, how can we write it? Using “fputc”.

fputc (chr, outptr);

chr : char to write
outptr : FILE* to write to.

fputc(0x00, outptr);

Then, you’ll want to move file position indicator. Now, you’ll want to use “fseek”.

fseek(inptr, amount, from);

inptr : FILE* to seek in.
amount : number of bytes to move cursor.
from : relates to reference points.

  • SEEK_CUR : (current position in file).
  • SEEK_SET : (beginning of file).
  • SEEK_END : (end of file).

So, we’ll want to use fseek to skip over the padding of infile. So, once you open verdict, you can see who’s the creator of this problem. You’re done whodunit!

RESIZE

Alright, next challenge! Implement now in resize.c a program called resize that resizes 24-bit uncrompressed BMPs by a factor of n. Your program should accept exactly three-command line arguments, per the below usage, whereby the first(n) must be a positive integer less than or equal to 100, the second the name of the file to be resized, and the third name of resized version to be written.

Usage : ./resize infile outfile

With a program like this, we could have created large.bmp out of small.bmp by resizing the latter by a factor of 4 (i.e multiplying both its width and its height by 4), per the below :

./resize 4 small.bmp large.bmp

You’re welcome to get started by copying (yet again) copy.c and naming the copy resize.c. But spend some time thinking about what it means to resize a BMP.

TODO :

  1. Open file
  2. Update header info for outfile
  3. Read each scanline pixel by pixel
  4. Resize horizontally
  5. Remember padding!
  6. Resize vertically
  • Opening file

You know how to do that! It’s still same and also you’re welcome to get copying again copy.c by execute :

cp copy.c resize.c
  • Updating header info for outfile

Because we have new BMP we also have to update the header info. What’s changing ? File size, image size, width and height are have to change. Try to look at the header info (again) :
Header :

  • biSizeImage : is the total size of image (in bytes) and include pixel and padding.
  • biWidth : is the width of image (in pixels) , this doesn’t include padding.
  • biHeight : is the height of image (in pixels).
  • There are 2 structs on Header : BITMAPFILEHEADER and BITMAPINFOHEADER
  • Reading scanline pixel by pixel

Again, you’ll wan to call file I/O function “fread”. Look at below (again) :

fread(&data, size, number, inptr);

&data : is a pointer to a struct which will contain the bytes you’re reading.
size : size of each elements to read , here the function sizeof will coming handy.
number : is a number of each elements to read.
inptr : FILE* to read from.

  • Resizing horizontally

If I could assume a pixel as a block . How do we resize it horizontally ? well, let’s assume :

n = 2

Then, the block should be two times of the current width. OK, this time you’ll want to use “fwrite” function.

fwrite(&data, size, number, outptr);

&data : is a pointer to a struct which will contain the bytes you’re reading from.
size
number
outptr : FILE* to write to.
Can you figure out how? I leave you to determine it by yourself.

  •  Remember padding.

Do you remember how ? If don’t please take a look at the previous explanation about padding on whodunit.

  • Resize Vertically

Several ways to do this :

  1. “Rewrite” methods :
    • Remember all of the pixels in a array
    • And Write as many as needed

or

2. “Re-copy” methods :
• Go back to the start of the original row
• Repeat the horizontal resizing.

So, we’ll understand resize.c is all about :
1. Each pixel repeated n times
2. Every row repeated n times
With that you’ll have a Bitmap large image! If you’d like to check the correctness of your program with check50, you may execute the below.

check50 2014/x/pset5/resize bmp.h resize.c

If you’re done with it, be sure you can answer the following questions in ~/Dropbox/pset5/questions.txt.

6. What’s stdint.h ?
7. What’s the point of using uint8_t , uint32_t , int32_t , and uint16_t in a program?
8. How many bytes is a BYTE , a DWORD , a LONG , and a WORD , respectively? (Assume a 32-bit architecture like the CS50 Appliance.)
9. What (in ASCII, decimal, or hexadecimal) must the first two bytes of any BMP file be? (Leading bytes used to identify file formats(with high probability) are generally called “magic numbers.)”
10. What’s the difference between bfSize and biSize ?
11. What does it mean if biHeight is negative?

12. What field in BITMAPINFOHEADER specifies the BMP’s color depth (i.12. e., bits per pixel)?
13. Why might fopen return NULL in copy.c:37 ?
14. Why is the third argument to fread always 1 in our code?
15. What value does copy.c:70 assign padding if bi.biWidth is 3 ?
16. What does fseek do?
17. What is SEEK_CUR ?


 CSI (Computer Science Investigation)

Alright, so let’s pull up all your new skill into the last. Take a look at http://cdn.cs50.net/2014/x/psets/5/pset5/pset5.html#_csi_computer_science_investigation

Long story shorts, in this problem you have to recover 50 photos that’ve been deleted. Fortunately, in the Computer world “deleted” tends not to mean “deleted” so much as “forgotten”. Let’s make a file called recover.c inside the ~/Dropbox/pset5/jpg a program that will recover all photos.

What is the format for photos? Well, it should be a JPEG. You’ll know that JPEGs are more complicated than BMPs but luckily JPEGs have signatures patterns of bytes. Specially, the first four bytes of most JPEGs are either :

0xff 0xd8 0xff 0xe0
or
0xff 0xd8 0xff 0xe1

For simplicity, you should hard code ”card.raw” in your program, your program need not accept any command-line arguments. When executed, your program should recover every one of JPEGs from “card.raw“. Your program should number the files its outputs by naming each ###.jpg where ### is three-digits decimal number from 000 on up (you’ll want to call sprintf function). How to check whether your program is correct? Well, just simply double-click and take a look! If the photo are appears, your operation was likely a success!
Okay, let’s get started.

TODO :
1. Open memory card file
2. Find the beginning of JPG
3. Open a new JPG
4. Write 512 bytes until new JPG is found
5. Detect end of file

  • Opening memory card file

You know how to solve this already! Don’t forget to use File I/O function.

  • Find the beginning of JPG

Well, just like a BMP, JPEG is also just a sequence of bytes. As you’ve read above, the signatures of JPEGs are either :

0xff 0xd8 0xff 0xe0
or
0xff 0xd8 0xff 0xe1

And, it’s stored side by side in the memory card. How can do we read the 512 bytes? Well, let’s go back to “fread” struct.

fread(&data, size, number, inptr);

&data : buffer.
We have to read 512 bytes at the time. Can you figure out how? You’ll want to define BUFFER and storing it by 512.

  • Opening a new JPG

Since you’ve reached the first JPG, then how do we open it? Let’s make the new JPG. The file name of JPG is ###.jpg the ### is going to be number format. So, the first jpeg you’ve found is 000.jpg and so forth. So keep track!

Then, how do you actually make the jpg? You’ll want to call “sprintf” function. It’s a bit similar with“printf”. But, in this case, “sprintf” will print the file out in the current directory and not in the terminal.

sprint(title, "%d.jpg", 2);

title : char array to store the resultant string
%d.jpg : will give you name like 2.jpg.. so, how do you make it to be 002.jpg?

  • Write 512 bytes until new JPG is found

Remember “fwrite

  • Detect end of file

Ok, so it’s a bit confusing now. Let me get you the pseudocode for recover.c.
Pseudocode :

open card file
    while eof check
         fread first 512 bytes
         if signature is JPEG
              check if outptr != null
              close output file
              update file name counter
            create new filename
            open file
            write the current 512 bytes to the outfile
         else if signature is not JPG && outptr != null
            fwrite current 512 bytes to outfile
close any remaining file

With that you’ve recovered all of the photos! Congratulations! If you’d like to check your correctness of your program with check50, you may execute the below :

check50 2014/x/pset5/recover recover.c

And you’re done!

This was Problem Set 5.