Issue #23 - March 2009 full circle STEVE STALCUP THE INDEPENDENT MAGAZINE FOR THE UBUNTU COMMUNITY PROGRAM IN C - PART 7 WEB DEVELOPMENT - PART 4 SPREADING UBUNTU - PART 2

TROUBLESHOOTING TROUBLESHOOTING

USING THE COMMAND LINE HOW TO BE A GEEK GODDESS

Full Circle magazine is not affiliate1d with or endorsed by Canonical Ltd. p.04

Troubleshooting p.06

Program In C - Part 7 p.08 Web Development - Part 4 p.15 Spread Ubuntu - Part 2 p.19

full circle Becoming An Ubuntu User p.22 w w w . f u l l c i r c l e m a g a z i n e . o r g How To Be A Geek Goddess p.23 : Steve Stalcup p.24 p.26 p.28 p.30 P.23 P.24 p.32 P.08 P.15 p.33 : Task Managers p.35 p.37

30 .35 P.19 P..28 P. P icons: KDE4 Oxygen

The articles contained in this magazine are released under the Creative Commons Attribution-Share Alike 3.0 Unported license. This means you can adapt, copy, distribute and transmit the articles but only under the following conditions: You must attribute the work to the original author in some way (at least a name, email or URL) and to this magazine by name ('full circle magazine') and the URL www.fullcirclemagazine.org (but not attribute the article(s) in any way that suggests that they endorse you or your use of the work). If you alter, transform, or build upon this work, you must distribute the resulting work under the same, similar or a compatible license.

2 EEDDIITTOORRIIAALL

This magazine was created using :

t's true what they say, time does fly when you're having fun. Next month is the second anniversary of FCM. Full Circle magazine will Ibe two years old this coming April, and, in celebration of this (semi)monumental event, FCM#24 will be an uber-issue with surprises galore. What do we want for our birthday? I'm glad you asked. We'd like to see FCM slap-bang on the front page of SlashDot, and Digg if possible. Not only will it keep Robert happy, it's his life long aim to be on SlashDot, but it will expose FCM to many new readers. A readership of Ubuntu is a complete operating 25,000 each month is great, but we want more. We're greedy system that is perfect for laptops, desktops and servers. Whether at like that. I'm sure there are still many folks out there who haven't home, school or work Ubuntu heard of Full Circle magazine, and we can't have that. contains all the applications you'll ever need including word processor, Enjoy this month's issue, keep a close eye out for FCM#24 on the email application and . 24th of April and good luck in this month's competition. Oh, and keep those emails coming! Ubuntu is and always will be free of charge. You do not pay any licensing fees. You can download, use and share Ubuntu with your friends, family, school or business for Editor, Full Circle Magazine absolutely nothing. [email protected] Once installed, your system is ready to use with a full set of productivity, internet, drawing and graphics applications, and games.

3 French Police: We Saved Millions Xavier Guimard, who says that the Gendarmerie has been able NNEEWWSS By Adopting Ubuntu to reduced its annual IT budget France's Gendarmerie Nationale says by 70 percent without having to Ubuntu 9.04 Beta Released it has saved millions by migrating its reduce its capabilities. desktop software infrastructure away : http://arstechnica.com Both the from Windows and replacing it with server, and Ubuntu. desktop editions, of They began their transition to open Ubuntu 9.04 source software in 2005 when it Game Development Survey (Jaunty replaced Microsoft Office with Jackalope) OpenOffice.org. It gradually adopted Free Game Developer forum are beta have been released. It comes other software applications, including having a discussion about the with many new features, some of and Thunderbird. After the possible ways of funding an open which come courtesy of upstream. launch of Windows Vista in 2006, it source game project, and have A new GNOME release, a new decided to phase out Windows and placed the arguments into a X.org release, a new notification incrementally migrate to Ubuntu. survey to ask people their system, they're all in there. opinions. If you would like to At the current stage of the migration, take part in the survey, click the Since Ubuntu 9.04 comes with it has adopted Ubuntu on 5,000 source link below, as they are GNOME 2.26, it inherits its new workstations. Based on the success trying to get as many features: it comes with the of this migration, it plans to switch participants as possible. burning tool, better 15,000 workstations to Ubuntu by support for multiple monitors with the end of the year. It aims to have http://tinyurl.com/opensurvey a new configuration panel, better the entire organization, and all PulseAudio integration, and so on. 90,000 of its workstations, running This Ubuntu 9.04 beta also comes Ubuntu by 2015. with X.org 1.6, and several more A report published by the European video cards now use open drivers. Commission's Open Source Sorry if you didn't win this month, Observatory provides some details but in next months issue we'll be : http://www.osnews.com reviewing and from a recent presentation given by have copies to give away! Gendarmerie Lieutenant-Colonel

4 GNOME 2.26 Released burning backends. Note that the NEWS previous method of burning is NEWS still part of GNOME. Work on GNOME's mail and Canonical Launching Ubuntu groupware suite, Evolution , has Server Training Course focussed on users migrating from Windows. Evolution now Expanding its Ubuntu training supports importing Outlook .pst series, Canonical is planning to files, as well as support for make an Ubuntu Server training Microsoft Exchange's MAPI course available later this year. In protocol. This makes GNOME a blog posting Canonical, the much more suited to work with The GNOME team has released financial backer of Ubuntu , Exchange servers. said that the new course is being GNOME 2.26, the latest release in the designed in response to requests 2.x release branch. As everyone There are also a few media- from both students and partners. knows, GNOME is a multi-platform related improvements, such as open source desktop environment. the automatic subtitle 'Deploying Ubuntu in the The 2.26 release continues GNOME's downloader plugin in Media Enterprise Environment' will be a policy of incremental updates to a Player. There's also a new five-day course designed for stable base, and as such, it comes volume control applet that intermediate-to-advanced system packed with a boatload of new makes full use of PulseAudio's administrators working in features. advanced audio features. The organisations which are about to old Gstreamer mixer is still GNOME 2.26 includes the Brasero deploy, or have already deployed, available to those who aren't CD/DVD burning tool as the default Ubuntu desktops and servers in using PulseAudio. the office, Canonical said. burning application. Even though GNOME already supported burning Other new features include, “Participants will acquire the capabilities, Brasero brings new among others, video chat in skills they need to deploy, features to GNOME such as audio , better multi monitor configure and maintain Ubuntu track preview, track splitting, volume support, and fingerprint reader Server Edition within an normalisation, full multisession support. enterprise infrastructure.” support, integrity checks, a cover : http://www.osnews.com : http://www.tectonic.co.za editor, and support for multiple

5 to see if they show any CCOOMMMMAANNDD AANNDD CCOONNQQUUEERR indication of having recognized Written by Lucas Westermann your USB stick. If the drive is recognized by the system you 've noticed that there were to find out what you need to do to can, for a more specific error quite a few posts on Ubuntu resolve the issue. message, try mounting the USB Forums in the last couple of stick manually, and see why it is I A more difficult problem to weeks about how to troubleshoot failing. troubleshoot is if, for example, you errors that occur. Therefore, I insert a USB stick and it isn't decided I'd cover some basic The above commands and recognized by Nautilus. The first things I do when trying to find ideas can apply to almost any command that should be run is: where a problem is occurring, so issue that you might encounter, that I can google for a solution dmesg|tail as long as you have a basic (unless I can fix it without that). understanding of where to look. For general knowledge, logs are See if the output of that refers to The next suggestion, however, is stored under /var/log/, and there the insertion of a USB stick, or for slow boot times and to see are system logs (for everything), anything that relates to your specific what exactly is going on when and then a collection of logs for problem. If it doesn't appear in the you start the computer - in case applications or processes. output you can try either extending something is hanging and the amount of output you see by causing a large delay. The first thing that should be adding the -n argument to tail, and This is done by a program done - if an application crashes on the number of lines you want startup (e.g. Firefox freezes and called boot chart which is in the displayed. So seeing 14 lines of Ubuntu repositories. You can just crashes after you launch it) - is to output would be: launch the application from the install it with: terminal - then any errors that dmesg|tail -n 14 sudo apt-get install bootchart arise are displayed in the terminal. If that gives you an error Otherwise, you can remove and re- Once it's installed, you merely message, the best solution would insert the stick in a new USB slot, or have to restart your computer be to either copy and paste the check the outputs of and then you can view the gist of the error into google for a sudo fdisk -l resulting chart in eye of search, or else, if you understand (default image viewer) - by the error, to use that information lsusb navigating to the

6 /var/log/bootchart/ folder and little. For example, if you're working investigated in the man pages opening the correct image (they on a wireless connectivity issue, or a (using the “man” command are named by date). wireless device not being recognized, covered in an earlier article of post the output of commands such C&C), and using the commands Also, hardware issues can be as ifconfig, iwconfig, lshw -C will also greatly help your checked by the program lshw, Network; if it's a USB wireless understanding of them. which lists hardware information. dongle, then also the output of lsusb, The most useful way to do it is to if it's PCI then lspci, etc. This helps run it using the -C flag, and then because whoever decides to help the section (display, network, you won't have to ask for any more etc.). So, for example, wireless information if you supply enough in http://www.troubleshooters.com/t issues would be checked with: the first post, and any subsequent promag/200007/200007.htm sudo lshw -C Network replies may be able to answer your question without a long back and This command displays details forth, which usually can last for a day on your network devices (ethernet or two (depending on timezones and and wireless), and lists as much time of day the post was created). information as possible, from Just keep in mind that the more capabilities to drivers, and so information is supplied, the more forth. The most important is information someone has to work probably to check that it isn't with to solve a problem that they can disabled, and that the driver is neither see nor physically listed (it will be in the last line of troubleshoot. the device section and denoted with “driver=[drivername]”). This article was created to be a useful guide to give people has learned all he On a last note, if you run into somewhere to start when trying to knows from repeatedly breaking his system, then any errors or problems you are solve problems on their own, or to having no other option but to unable to troubleshoot or fix, improve their chances of getting discover how to fix it. When he attach as much information as support when they need to ask for it. finds time, he also publishes a possible that could be relevant to It is by no means exhaustive, nor are blog at http://lswest- any request you make. Too much the commands listed explained ubuntu.blogspot.com. information is better than too thoroughly. Any commands can be

7 HHOOWW--TTOO Written by Elie De Brauwer PPRROOGGRRAAMM IINN CC -- PPAARRTT 77

only what happens with memory (de)allocation. The tool discussed FCM#17-22 - Program In C - Parts 1-6 here is named gdb (The GNU debugger), and to this tool there are no real limits - if there is something related to an application which you want to examine, GDB is the tool. On a regular Ubuntu system, gdb can be installed by entering: Dev Graphics Internet Multimedia System sudo apt-get install gdb

All IDE's on a Linux system which allow debugging will typically have CD/DVD HardDrive USB Drive Laptop Wireless the text-mode gdb as a backend. Here, I will focus on using gdb from n part 6 of this series, I showed the command line, but know that panels. At the top, you have the you some non-intrusive ways when it comes to complex data panel where you can Iof examining applications. In debugging, it can sometimes be display variables and browse this article, I will present a tool useful to have a graphical view on through their contents. In the which allows you to dig deeper, to things. One of the older graphical middle, you can see the source do some post-mortem analysis, frontends on gdb is called (Data panel where the source code is and to examine the inner working Display Debugger), you can install it shown - here you can place of an application. Where by typing: breakpoints. And the bottom strace/ltrace/valgrind are really panel allows you to see the gdb sudo apt-get install ddd nice tools, they will show only a interaction. You can either type part of what really happens; Above right is a screenshot of ddd gdb commands in there, or you strace shows, for example, only in action. It consists of three large can click the matching buttons. system calls, while valgrind shows

8 The example in this article is called . There is already an ifstat application in Ubuntu, but 01. #include this application behaves the same 02. #include but is simpler. The application is 03. #include presented in Listing 1 and Listing 04. #include 2. The goal of the application is to 05. typedef unsigned long long ull print, every 2 seconds, the 06. int parseDevFile(const char * iface, ull *bRx, ull *pRx, 07. ull *bTx, ull *pTx) interface rate of a given network 08. { interface. It is basically a while 09. FILE * fp = NULL; loop (Lines 29-49) which reads 10. char * line = NULL; /proc/dev/net and prints the 11. unsigned int len = 0; incoming and outgoing interface 12. fp = fopen("/proc/net/dev", "r"); rate for a given network interface 13. if(fp==NULL) in both kilobytes per second and 14. { as packets per second. The main 15. return -1; function itself is rather simple 16. } 17. while(getline(&line,&len,fp)!= -1) (Lines 51-60). Here we check if 18. { there is one parameter given from 19. if(strstr(line,iface)!=NULL) the command line. This one 20. { parameter will become the 21. interface the user wants to sscanf(strstr(line,":")+1,"%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", monitor. If no parameters, or too 22. bRx, pRx, bTx, pTx); many parameters, are given, a 23. } message is printed which 24. } 25. fclose(fp); instructs the user how to use the 26. free(line); application. Up until now, nothing 27. return 0; really new has been shown, all 28. } new things are in the parseDevFile() function (Lines 5- Listing 1: ifstat.c (part 1) 28), so the new things are briefly discussed here. This function will open /proc/dev/net and parse its

9 29. void dumpInterfaceUsage(const char * iface) contents, the counters we are 30. { interested in will be stored in the 31. ull ifaceBRxOld=0, ifaceBTxOld=0, ifacePRxOld=0, ifacePTxOld=0; bRx, pRx, bTx and pTx pointers 32. ull ifaceBRxNew=0, ifaceBTxNew=0, ifacePRxNew=0, ifacePTxNew=0; which are passed when calling 33. const int SLEEP_TIME = 2; 34. this function. By passing pointers, 35. we are capable of changing the if(parseDevFile(iface,&ifaceBRxOld,&ifacePRxOld,&ifaceBTxOld,&ifacePTx values of these variables from Old)==-1) return; within the function. The function 36. sleep(SLEEP_TIME); will return 0 on success, or -1 37. while(1) when opening the file has failed. 38. { 39. In this example, it is the first if(parseDevFile(iface,&ifaceBRxNew,&ifacePRxNew,&ifaceBTxNew,&ifac time we open a file - on Line 9 ePTxNew)==-1) return; there is a file pointer declared. 40. printf("%s In: %8.2f kbyte/s %5llu P/s Out: %8.2f kbyte/s Line 12 contains a call to fopen() %5llu P/s\n", iface, 41. (ifaceBRxNew-ifaceBRxOld)/(SLEEP_TIME * 1024.0), (man fopen for details), the first 42. (ifacePRxNew-ifacePRxOld)/SLEEP_TIME, argument is the file we want to 43. (ifaceBTxNew-ifaceBTxOld)/(SLEEP_TIME * 1024.0), open, the second argument says 44. (ifacePTxNew-ifacePTxOld)/SLEEP_TIME); how we want to open this file. In 45. ifaceBRxOld=ifaceBRxNew; ifaceBTxOld=ifaceBTxNew; this case “r” means we want to 46. ifacePRxOld=ifacePRxNew; ifacePTxOld=ifacePTxNew; open the file for reading. Once we 47. sleep(SLEEP_TIME); are done with reading from the 48. } file, we close it using fclose() on 49. } 50. Line 25. 51. int main(int argc, char **argv) 52. { 53. if(argc != 2) Let's discuss C-style I/O: 54. { fopen(), fclose(), fread(), fwrite() 55. printf("Usage: %s interfacename\n", argv[0]); calls are part of the C-standard, 56. exit(1); and these should be available on 57. } 58. dumpInterfaceUsage(argv[1]); each platform. open(), close(), 59. return 0; read(), write(), however, are part 60. } of the POSIX standard, and these Listing 2: ifstat.c (part 2) 10 are the actual internal system Lines 19-24 do the actual parsing flags passed to the compiler, this calls. One usually uses fread() of the line read from the file. Line 19 means that debugging symbols when reading from a file. checks if the interface name is are embedded within my binary, However, if you look at the somewhere within the line we read and this will allow the debugger manual page, it would tell you (meaning we read enough lines). If to get more precise information. that you need to specify a buffer - we are at the correct line, sscanf() the size of an element and how will be used to convert the values on When I try to start the many elements to read - and this the line to the unsigned long long application, and I pass by is not really convenient in our variable we are using in the accident 'b' as the interface case. This is why we make use of application. Notice that the '*' within name, the application behaves getline(); this function takes a the formatstring means that we are as follows: pointer to a pointer as first not interested in this value. edb@lapedb:~/fullcircle/c-7$ argument, and a pointer to an ./ifstat b Now, compiling and running the integer as a second argument. Segmentation fault application gives the output below Internally, this function will always when I examine the activity of my read a full line, and it will either Now, what happened here: wireless link. copy the data to the buffer passed apparently our application tried if there is enough room, or it will to access some memory which reallocate a new buffer if there is didn't belong to the application, not enough room (see man Unfortunately, this article is about the kernel didn't like this, and getline for details). All we should debugging, and although this sent us a signal SIGSEGV. As a keep in mind is to free the pointer example seems to behave now, it is result, the application getline() allocated for us (Line 26). far from perfect. Notice that I terminated. There are two compiled the example with the -ggdb options we could adopt in this situation; we could either restart the application in our debugger and do some live debugging edb@lapedb:~/fullcircle/c-7$ gcc -ggdb -o ifstat ifstat.c there. Or we could obtain a core edb@lapedb:~/fullcircle/c-7$ ./ifstat wlan0 wlan0 In: 1.36 kbyte/s 16 P/s Out: 1.50 kbyte/s 16 P/s file and do some post mortem wlan0 In: 103.25 kbyte/s 84 P/s Out: 4.61 kbyte/s 54 P/s debugging. When you encounter wlan0 In: 1.29 kbyte/s 15 P/s Out: 1.50 kbyte/s 16 P/s a situation like this with any of the packages your distribution has to offer, and you file a bug

11 report, people will often ask you the application was terminated due and we see here that we are stuck for a core file. It's useful to know to a segmentation violation. We at a line which contains a 'b' how to create these core files, so entered where, and gdb responded (which we passed as interface), that's what we'll do first. with a backtrace - a list of all but the strstr() which searches for functions that were called - we see a ':' has returned NULL since there edb@lapedb:~/fullcircle/c-7$ ulimit -c unlimited we started at main, then entered is not ':' in the header. So, dumpInterfaceUsage, then entered sscanf() tried to read from edb@lapedb:~/fullcircle/c-7$ parseDevFile, which called sscanf. memory address 1. ./ifstat b Thus, usually one hopes (and here In order to have the same effect one is usually correct) that the on a live session, start gdb, and Segmentation fault (core problem lies within the code you just pass the binary as the first dumped) wrote, and not within the library you argument. At the gdb prompt, you called. So our guess here would be edb@lapedb:~/fullcircle/c-7$ type run followed by the startup that we did something wrong when ls -hal core arguments. And the same will calling sscanf(). So, to be sure, I happen: -rw------1 edb edb 280K 2009- asked gdb to print the line variable, 03-07 13:33 core

With ulimit, limits to certain edb@lapedb:~/fullcircle/c-7$ gdb ifstat core resources can be set, the size of a GNU gdb 6.8-debian corefile is one of these resources, Copyright (C) 2008 Free Software Foundation, Inc. and nowadays this is by default License GPLv3+: GNU GPL version 3 or later set to 0. When we set this to unlimited, an application can This is free software: you are free to change and redistribute it. dump a core file (a core file is a There is NO WARRANTY, to the extent permitted by law. Type "show copying" dump of the working memory of and "show warranty" for details. an application). Now let's take a This GDB was configured as "i486-linux-gnu"... look at it using gdb (right). warning: Can't read pathname for load map: Input/output error. Now what have we done here? Reading symbols from /lib/tls/i686/cmov/libc.so.6...done. We started gdb, and passed our Loaded symbols for /lib/tls/i686/cmov/libc.so.6 binary, and the core file, as Reading symbols from /lib/ld-linux.so.2...done. startup arguments. gdb told us NOTE: and several other libc.so.6 errors. 12 edb@lapedb:~/fullcircle/c-7$ get a gdb prompt when the showing an expression every gdb ifstat breakpoint is encountered. We time) on the line pointer which decide to step through this function contains our string (the output is (gdb) run b by issuing a number of steps a bit trimmed down for Starting program: commands (this equals executing formatting reasons). But we see /home/edb/fullcircle/c- one line of code). After the fopen() that we go through the while 7/ifstat b call, we investigate whether the file loop without executing the Program received signal pointer is valid; it seems it is. So we sscanf. So we can only conclude SIGSEGV, Segmentation fault. decide to put a display (this is that the interface “bla” does not

0xb7fd26c7 in rawmemchr () from /lib/tls/i686/cmov/libc.so.6 edb@lapedb:~/fullcircle/c-7$ gdb ifstat (gdb) break parseDevFile But here we did not make use of Breakpoint 1 at 0x80485da: file ifstat.c, line 11. the core file. The following (right) (gdb) run bla Starting program: /home/edb/fullcircle/c-7/ifstat bla is the output of a live session. Breakpoint 1, parseDevFile (iface=0xbf96175d "bla", bRx=0xbf961290, When we started the pRx=0xbf961280, bTx=0xbf961288, pTx=0xbf961278) at ifstat.c:11 application with 'bla' as a 11 FILE * fp = NULL; (gdb) step parameter, we saw that all our 12 char * line = NULL; rates remained zero. So we (gdb) step decided to take a look. If 13 unsigned int len = 0; something goes wrong, we (gdb) step suspect it to be in parseDevFile, 15 fp = fopen("/proc/net/dev", "r"); so by calling break parseDevFile, (gdb) step we tell gdb to place a breakpoint 16 if(fp==NULL) when this function gets called. (gdb) print fp $1 = (FILE *) 0x9e20008 This means the application will (gdb) step start and work as normal, but it 21 while(getline(&line,&len,fp)!= -1) will interrupt and present a gdb (gdb) display line shell each time the breakpoint is 1: line = 0x0 met. After setting the breakpoint, (gdb) step we start the application and we 23 if(strstr(line,iface)!=NULL)

NOTE: and several 'line = 0x9e20170' errors. 13 exist. When we issue cont to But I hope that this is sufficient to let application! Make sure it prints a continue execution, we see the the reader understand that gdb warning when an interface next time the program encounters allows you to examine how an cannot be found, and make the the breakpoint we are dropped application is running; how it is interface matching more back to the gdb shell. making use of the system. And I intelligent. strongly advise everybody who works with C applications to invest In this article I introduced first some time in getting to learn to work is a the concept of C style I/O, and the with gdb, since this will prove to be Belgian Linux fanatic, and use of getline(), but I also gave a an extremely valuable tool when it apart from spending time with his family, he enjoys playing bird's eye overview of gdb. Due to comes to troubleshooting applications. When it comes to with technology, and spends his limited space, I have been able to days waiting for Blizzard to finally only scratch the surface of gdb. exercises for this article, fix the release Diablo III.

' ' is reviewed on page 23 of this issue.

14 HHOOWW--TTOO Written by Brett Alton WWEEBB DDEEVVEELLOOPPMMEENNTT -- PPAARRTT 44

many others), is not the be-all-and- end-all programming language used Assuming you made your first FCM#20 - 22 - Web Dev. Part 1 - 3 on the Internet. Nor is it the best. website after reading part two of A number of programming this web development series in languages are available for web Full Circle #21, we will continue developers, including, but not limited to modify the 'index.' file to, Python, Perl, Ruby (and Ruby on which we saved in the localhost Rails), Java (JSP), ASP, ASP.net, etc. folder. Heck, if you want to get into some Dev Graphics Internet Multimedia System esoteric programming, you can even use C, C++, or many other low-level programming languages. Editing many pages will quickly become a nuisance if But, what you need to understand you wanted to add, for example, CD/DVD HardDrive USB Drive Laptop Wireless is that every language is different a page called birds.html, or edit and has its different uses and the footer on all the pages purposes. Some are procedural, because it is now, for example, rogramming languages are some are object-oriented, and some 2010. In PHP, you can make your meant to automate tasks are mixed. If you want to try Python, page dynamic by splitting off Pand make life easier. PHP is go right ahead! In fact, I encourage each section and making it no exception. it. Plus, it looks great on a résumé to modular. However, PHP, no matter how know more programming languages great, easy to use, or heavily – right? Some employers will hire you First, we'll split off the CSS into propagated (an estimated 20 only if you have experience with another file. This isn't required, million installs, and used by ASP.net, while others will like you to but is done as good practice, websites and programs such as have only PHP and Python. Learn and you should do this for Facebook, Wikipedia (MediaWiki), what you feel comfortable with, and almost all aspects of your Digg, Wordpress, Yahoo!, and what the industry dictates (if you're website (CSS, , PHP or interested in money!).

15 anything that is repeated Now, to make the rest of the should contain the following files throughout the website). website more modular, take the code and folders: beginning with and Put the code (below) in a new localhost/ ending in '', and place it in a folder called '', and name the css/ folder called 'inc' under the filename file 'screen.css'. screen.css 'header.php'. inc/ In index.html, delete: footer.php Do the same for '

Menu:

' header.php called 'menu.php' inside the 'inc' index.php folder. and replace it with Now, inside 'index.php', add Lastly, create 'footer.php' inside the following code to the very ' and href="css/screen.css" /> end with ''. id="content">' to the div tag ('