This tutorial is also available in .TXT format
TABLE OF CONTENTSIn the early days of programming, it was usually the scientific elite doing the programming and they were usually trained above and beyond the average American to do their programming work. It was not until 1964 at Dartsmouth college that the Beginner' s All-purpose Symbolic Instruction Code would be introduced -- more commonly known as BASIC. Using common English to perform processor tasks, BASIC became quickly popular, although it was disliked by programmers of more "low-level" languages such as assem bly and FORTRAN. In 1985 Microsoft released their own version of BASIC called QBasic with their MS-DOS 5.0 operating system. Since then, nearly every PC user owns their own copy of QBasic, making it a widely known language.
QBasic is a very simple language to pick up, and yet it can accomplish a great deal. Granted you will probably never write Doom or Word Perfect with QBasic, but it has it's strong points. One of them is to introduce people to programming without having to worry about the internal workings of the computer. It's simple to create games, business applications, simple databases, and graphics. The best aspect of the language is it's close resemblance to English.
This small tutorial introduces the simple concepts of programming to get you started, so if you already know another language or are already familiar with programming, you may want to skim through the first couple sections. Good luck!
A variable, simply defined, is a name which can contain a value. Programming involves giving values to these names and presenting them in some form to the user. A variable has a type which is defined by the kind of value it holds. If the variable holds a number, it may be of integer, floating decimal, long integer, or imaginary. If the variable holds symbols or text, it may be a character variable or a string variable. These are terms you will become accustomed to as you continue programming.
Here are some examples of values a variable might contain:
STRING "hello, this is a string" INTEGER 5 LONG 92883 SINGLE 39.2932 DOUBLE 983288.18
The first is a string. Strings contain text. The last four are number types. But the computer does not know what kind of value you are trying to give a variable unless you tell it! There are two methods of telling the computer what kind of variable you are using:
1. Explicitly declare the variable AS a type. This is done by using the DIM statement. Say you wanted to make a variable called number which would contain an integer (whole number, no digits after the decimal point). You would do it like this:
DIM number AS INTEGER
Then you would use that variable as an integer. The word DIM actually originates from the word Dimension, but you won't see why until we discuss the topic of arrays.
2. Put a symbol after the variable name which is defined as representing that type. QBasic has a set of symbols which represent each variable type:
$ String % Integer & Long ! Single # Double
Appending one of these symbols to the name of a variable when you use it in the program tells the computer that you are using it as that type. This topic of data types is actually a difficult concept to grasp for newcomers to programming. The most com mon error in QBasic is the infamous Type Mismatch which you will see a lot. This means that you are trying to put a value into a variable of the wrong type. You might be trying to put the letters "hi there" into an integer variable. If you don't define th e type of the variable, then QBasic assumes it is of the Single type, which can often yield unexpected results. I personally prefer to use the type symbols after variable names, but some explicitly declare them usually at the head of their programs.
You know what a variable is and how to control them, it's time you learned some programming. QBasic (like all other languages) is set up using pre-defined statements according to the syntax specified for that statement. It may be helpful to look in t
he help index to learn a statement, although I've heard many complaint's that the help index is too hard. Indeed it is too hard for new programmers, but as you learn more and more statements and their syntaxes, you'll become accustomed to the index and u
se it as a casual reference. Lets make a program that prints some text on the screen. Type qbasic
at the DOS prompt and enter the following program.
CLS PRINT "This text will appear on the screen" END
The first statement -- CLS
-- stands for "clear screen." It erases whatever was on the screen before it was executed. PRINT
simply displays its argument to the screen at the current text cursor
location. The argument in this case is the text enclosed in quotes. PRINT
displays text within quotes directly, or it can display the value of a variable, like this:
CLS a% = 50 b% = 100 PRINT "The value of a is "; a%; " and the value of b is "; b% END
This will yield the output; The value of a is 50 and the value of b is 100. The semicolons indicate that the next time something is printed, it will be right after where the last PRINT
statement left off. Remember that PRINT
prints literally what is inside quotes, and the value of the variable which is not in quotes. a% and b% are integers containing values in this example, and their values are printed using the PRINT
statement.
Say you want to interact with the user now. You'll need to learn a statement called INPUT
. INPUT
displays a prompt (the first argument) and assigns what the user types in to a variable (the second argument)
CLS INPUT "What is your name? ", yourName$ INPUT "How old are you? ", age% PRINT "So, "; yourName$; ", you are "; age%; " years old. That's interesting." END
This firsts asks the user for their name and assigns it to the string variable yourName$. Then the age is requested, and the result is printed in a sentence. Try it out! So what happens if you input I DON'T KNOW for the age prompt? You'll get a wei
rd message that says REDO FROM START
. Why? The program is trying to assign a string (text) to an integer (number) type, and this makes no sense so the user is asked to do it over again.
Another cornerst
one of programming is the conditional test. Basically, the program tests if a condition is true, and if it is, it does something. It looks like English so it's not as hard as it sounds.
CLS PRINT "1. Say hello" ' option 1 PRINT "2. Say nice tie" ' option 2 INPUT "Enter your selection ", selection% IF selection% = 1 THEN PRINT "hello" IF selection% = 2 THEN PRINT "nice tie" END
The user is given a set of options, and then they input a value which is assigned to the variable selection%. The value of selection% is then tested, and code is executed based on the value. If the user pressed 1, it prints hello, but if they pressed 2, it prints nice tie. Also notice the text after the ' in the code. These are remark statements. Anything printed after a ' on a line does not affect the outcome of the program. Back to the actual code -- but what if the user doesn't i nput 1 or 2? What if they input 328? This must be taken into account as part of programming.  So the ELSE statement comes into play. The logic goes like this: IF the condition is true, THEN do something, but if the condition is anything ELSE, then do something else. The ELSE statement is used with IF...THEN to test if a condition is anything else.
CLS INPUT "Press 1 if you want some pizza.", number% IF number% = 1 THEN PRINT "Here's your pizza" ELSE PRINT "You don't get pizza" END
That's a fairly simple example, and real life things will be much more complex. Lets try a "real life" program. QBasic is capable of fairly sophisticated math, so lets put some of it to use. Say your Algebra teacher tells you to find the areas of th e circles with some given radii, and he gives you a sheet with hundreds of radii. You decide to boot up your computer and write the following program:
CLS pi! = 3.1415 INPUT "What is the radius of the circle? ", radius! area! = pi! * radius! ^ 2 PRINT "The area of the circle is ", area! END
First, we're defining the variable pi. It's a single number, which means that it can be a fairly large number with some decimal places. The exclamation mark tells QBasic that pi is of the single type. Next, the user is prompted for the radius of the
ir circle. Then the area is calculated. The * means "times," and the ^ (carrot) means "to the power of." radius! ^ 2 means "radius squared." This could also be written as pi! * radius! * radius!.
There's one big problem with that program. Th
e teacher gave you a sheet with hundreds of radii. For every radius, you must run the program over again. This is not practical. If we had some kind of a loop until we wanted to quit that just kept on repeating over and over it would be much more useful
. Of course, QBasic has the means of performing this feat. Loop structures. They start with the statement DO
, and end with the statement LOOP
. You can LOOP UNTIL
or WHILE
, or DO UNTIL
or WHILE
a condition is true. Another option (which we will use) is to break out of the loop manually as soon as a condition is true. Lets revise the previous code:
CLS pi! = 3.1415 DO ' Begin the loop here INPUT "What is the radius of the circle? (-1 to end) ", radius! IF radius! = -1 THEN EXIT DO area! = pi! * radius! ^ 2 PRINT "The area of the circle is ", area! PRINT LOOP ' End the loop here END
Now we can end the program by entering -1 as the radius. The program checks the radius after the user inputs it and checks if it is -1. If it is, it exits the loop. If it isn't it just keeps going it's merry way. The PRINT
with no a
rguments prints a blanks line so we can separate our answers. I highly recommend entering this program into QBasic just so you can see exactly how it works.
Say you want to print something in a certain pre-defined format. Say you want to print a series of digits with only 2 places after the decimal point and a dollar sign before the first digit. To do this requires the
PRINT USING
statement, which is very handy in applications for businesses. The PRINT USING
statement accepts two types of arguments. The first is a string which has already been defined. This is a special type of string, in th
at it contains format specifiers, which specify the format of the variables passed as the other arguments. Confused? You won't be. Here's a quick list of the most common format specifiers:
### digits & Prints an entire string \ \ Prints a string fit within the backslashes. Any thing longer is truncated $$ Puts a dollar sign to the left of a number . Prints a decimal point , Prints a comma every third digit to the left of the decimal point.
And these can be combined in a format string to make a user defined way to print something. So $$#,###.## will print a number with a dollar sign to the left of it. If the number has more than two decimal places, it is truncated to two. If it is mor
e than four digits long to the left of the decimal place, it is also truncated to fit. To use a PRINT USING
statement, you must first define the format string containing the format specifiers. Then you use PRINT USING,
then the
name of the format string, and variable values to fill the places defined in the format string. Here's a code example:
CLS ' get user input INPUT "Enter item name: ", itemname$ INPUT "How many items?: ", numitems% INPUT "What does one cost?: ", itemcost! CLS ' display inputs format$ = "\ \ #,### $$#,###.## $$#,###,###.##" PRINT "Item Name Quantity Cost Total Cost "
PRINT "-------------- -------- ---------- --------------" totalcost! = numitems% * itemcost! PRINT USING format$; itemname$; numitems%; itemcost!; totalcost! END
First, we get the item name, number of items, and cost per item from the user. Then we clear the screen and define the format string to be used. It contains a static length string (text that will be truncated if it is too long), up to 4 digits for th
e quantity, 4 digits and two decimals for the item cost, and 7 digits and two decimals for the total cost. Then we print out some column headers so we know what each value will represent, and some nice lines to go under the column headers. Then the tota
l cost is calculated by multiplying the number of items by the item cost. Finally, the four variable's values are displayed under the column headers using the PRINT USING
statement.
There are numerous methods to manipulate data and present it to the user in QBasic. One is called an array. An array is a variable which can contain more than one value. For example, you might have an array called a, and yo u could assign data to the members of that array. There might be a value for a(1), and a different value for a(6). Before an array can be used, it must be declared. Arrays are declared with the DIM statement used in section 1. Here is an example of an array declaration:
DIM a(1 TO 100) AS INTEGER
There are now 100 different values that can be assigned to the array a, and they must all be integers. It could also look like this:
DIM a%(1 TO 100)
Using the symbol % for integer. We call the different values for the array members of the array. Array a has 100 members. Array members can be assigned values by using a subscript number within parentheses after the array name, like this:
a%(1) = 10 a%(2) = 29 a%(3) = 39
And so on. Now you're probably wondering why the statement for declare is DIM
. This comes from a term used in earlier programming languages that means dimension. That still doesn't answer the question... why not use the statement
DECLARE
? Well, an array can have more than one dimension. Arrays with multiple dimensions have y members in the second dimension for every x member of the first dimension in the following algorithm:
DIM array( 1 TO x, 1 TO y) AS INTEGER
So if the actual declaration looked like this:
DIM a$( 1 TO 3, 1 TO 3)
You would have the following members to assign values to:
a$(1,1) a$(1,2) a$(1,3) a$(2,1) a$(2,2) a$(2,3) a$(3,1) a$(3,2) a$(3,3)
A two dimensional array is useful for tracking the status of each piece in a checkers game, or something of the like. Recall the last example program of section that we had a program that would ask the user for the item name, the item cost, and the qu antity of that item, the spit out the data just given in a nice format with the total in the right hand column. Well, with only one item, this program isn't very practical. But now with our newfound knowledge of arrays and the knowledge we already have of loops, we can create a somewhat useful application. The process will start with the program prompting the user for the number of items that will be calculated. Then the program loops for the number of times that the user entered at the beginning, ass igning the data entered into a member of an array we will declare. A variable called netTotal! will be displayed at the end of the program which will contain the total costs of the items. netTotal! will accumulate each time through the loop as the curre nt totalCost! is added to it. Type the following code:
CLS INPUT "How many items to be calculated? ", totalItems% DIM itemName$(1 TO totalItems%) ' Declare our arrays DIM itemCost!(1 TO totalItems%) DIM numItems%(1 TO totalItems%) DIM totalCost!(1 TO totalItems%) FOR i% = 1 TO totalItems% 'First loop: get inputs CLS PRINT "Item "; i% ' Display the current item number PRINT INPUT "Item name -- ", itemName$(i%) INPUT "Item cost -- ", itemCost!(i%) INPUT "Quantity --- ", numItems%(i%) totalCost!(i%) = itemCost!(i%) * numItems%(i%) NEXT i% CLS PRINT "Summary" PRINT format$ = "\ \ $$#,###.## #,### $$#,###,###.##" PRINT "Item name Item Cost Quantity Total Cost " PRINT "----------------- ---------- -------- --------------" FOR i% = 1 TO totalItems% PRINT USING format$; itemName$(i%); itemCost!(i%); numItems%(i%); totalCost!(i%) netTotal! = netTotal! + totalCost!(i%) NEXT i% PRINT PRINT "Net Total = "; netTotal! END
This program is much larger than anything we've done as of yet. It is kind of a review of everything we've done so far and one additional feature: the FOR...NEXT
loop. This kind of loop loops for the number
of times specified. A value is given to a variable and the program loops until that variable is equal or greater than the number specified after the TO
.
FOR i% = 1 TO 10
PRINT i%
NEXT i%
Will loop 10 times, printing the numbers 1 through 10. The loop ends with a NEXT
statement followed by the variable the loop increments for. So in our program, we have loops with index numbers (i%) starting at 1 and increasing for every
number between 1 and the totalItems%, which is given by the user in the first part of the program. After the user inputs the number of items that will be calculated, four arrays are DIMensioned. They are one dimensional arrays, so they aren't very comp
lex. The first FOR...NEXT
loop prompts the user for each item. Then the format string is defined and the column headers are printed. The second FOR...NEXT
loop cycles through the members of the four arrays and prints the data u
sing the format string. The data for each member was assigned in the first FOR...NEXT
loop. Each cycle through the second loop, the totalCost! of the current item being printed is added to the variable netTotal!. The netTotal! is the total
sum of the total costs. After the second FOR...NEXT
loop, the net total is printed and the program ends.
Say we have a game and when the user makes a record score, they get to write their name on a list of the 10 best scores. But the next time the user plays the game, we want the name and position they recorded the last time they played to still be there . To do this, we must write to what is called a file, and then read it again later. If you are computer literate, then no doubt you know what a file is, and since you are using the internet to read this, I'm assuming you are. So we need to write to file . Before you can do anything to a file, you must open it, and there are different ways you can open a file, believe it or not. A file can be opened so you can read from it or write to it, or it can be opened and split into records like a database. Here is a quick table of the different ways you can open a file:
| Input | Read data from the file |
| Output | Write data to the file |
| Append | Write data to the end of a file |
| Binary | Read from or write to a file in binary mode |
| Random | Read from or write to a file which is split up in records like a database |
The syntax for the OPEN
statement is quite peculiar. It's arguments require us to specify a file name, an access type (the 5 types defined above), and a file number. When the file is open, QBasic recognizes i
t by a number which we assign to the file when we open it. All references made to the file use this number. It can be any number from 1 to 255. An open statement may look like this:
OPEN "sample.txt" FOR INPUT AS #1
We will be reading data from this file because it was opened for input. Back to our problem about the game scores. Lets set up a program which will ask for their name and give them a random score. Then it will put their name on the list at the approp riate place on the top 10 (if it makes the list). We'll call the file "top10.dat." But say when the user buys the game, there are already 10 names and scores in there. We write the following program to put default names and scores into top10.dat:
CLS OPEN "top10.dat" FOR OUTPUT AS #1 FOR i% = 1 TO 10 playername$ = "Player" + STR$(i%) playerscore% = 1000 - (i% * 100) WRITE #1, playername$, playerscore% NEXT i% CLOSE #1 PRINT "Data written to file" END
There are a couple strange features of this program that we have not seen yet. In the second line of the program the file is opened for output so we can write to it. In the fourth line of the program we get into some light string manipulation. A nam
e is generated from the word player, and is concatenated with string form of the current loop number. You can concatenate two strings by using the + operator. The STR$
function returns the string representation o
f the number passed to it. The opposite of the STR$
function is the VAL
function, which returns the numeric value of the string passed to it. Lastly, the WRITE
statement w
rites to the file number specified as the first argument the values of the following arguments. Data is written to file in a format readable by the INPUT #
statement which we will use in the actual program. We need this short program for th
e big one to work so we can give the program data to read from, or else we will get a nasty INPUT PAST END OF FILE
error when we try to run it. Note that the file should be closed when we are done with it by using the CLOSE
state
ment followed by the file number.
And now we come to the big program, as I have referred to it. It is quite large and complex, and I have not fully described all the statements used in it, so I have broken it down to five sections which I will describe in detail afterwards. Here, at l ast, is the code:
' section 1 CLS RANDOMIZE TIMER yourScore% = INT(RND * 1000) PRINT "Game Over" PRINT "Your score is "; yourScore% DIM playername$(1 TO 10) 'Declare arrays for the 10 entries on the list DIM playerscore%(1 TO 10) ' section 2 OPEN "top10.dat" FOR INPUT AS #1 DO WHILE NOT EOF(1) ' EOF means "end of file" i% = i% + 1 INPUT #1, playername$(i%) 'Read from file INPUT #1, playerscore%(i%) LOOP CLOSE #1 PRINT ' section 3 FOR i% = 1 TO 10 IF yourScore% >= playerscore%(i%) THEN FOR ii% = 10 TO i% + 1 STEP -1 'Go backwards (i% < 10) playername$(ii%) = playername$(ii% - 1) playerscore%(ii%) = playerscore%(ii% - 1) NEXT ii% PRINT "Congratulations! You have made the top 10!" INPUT "What is your name? ", yourName$ playername$(i%) = yourName$ playerscore%(i%) = yourScore% EXIT FOR END IF NEXT i% ' section 4 OPEN "top10.dat" FOR OUTPUT AS #1 FOR i% = 1 TO 10 WRITE #1, playername$(i%), playerscore%(i%) NEXT i% CLOSE #1 ' section 5 PRINT PRINT "Here is the top 10" format$ = "\ \ #### " PRINT "Player Name Score" PRINT "-------------------------- -----" FOR i% = 1 TO 10 PRINT USING format$; playername$(i%); playerscore%(i%) NEXT i% END
Section 1: The screen is cleared. The second line contains the statement RANDOMIZE TIMER
. When dealing with random numbers, we must give the computer a number so it has something to base th
e random number it will create from. This number is called the random seed generator. A random seed generator can be specified with the RANDOMIZE
statement. For the seed, we need a number that will not be the same every time we run a progr
am, so we decide to use the number of seconds which have elapsed since midnight. The TIMER
statement accesses a system device called the system timer, and returns the current number of seconds which have elapsed since midnight. Since this n
umber will change in each program we run, this can be used for the random seed. The variable yourScore% is given a random number from 0 to 1000. In the last part of section one, we declare two arrays with 10 members each.
Section 2: In the first line we open the file for input, so we can read from it. The second line appears to be very weird at first. We are starting a loop with the DO
statement, and then a condition to do while. The function EOF
tests the file number passed to the function -- in this case 1 -- and if the end of the file (EOF
) has been encountered it returns true. So EOF(1)
is true if we are reading the end of the f
ile. But we are using the Boolean operator NOT
, so we want to loop while the end of file condition is false. We want to do the loop while we are not reading from the end of file 1. You will learn more about Boolean operators (NOT, AN
D, OR, XOR
, etc.) as you continue programming. Then we assign the current data in the file to the arrays we declared in section 1. The INPUT #
statement is used to read from the specified file into the specified variable(s) until a co
mma or carriage return is encountered.
Section 3: The main purpose of this section is to re-write the top 10 list if the player's randomly generated score places on the list. We do this by cycling through the list, and testing if yourScore% is greater than or equal to (>=) the c
urrent playerscore% being tested. If it is, then we have to shift each existing score below the current one down one to make room for the new score being added. The user is congratulated and prompted for their name. The loop is then exited using the
Section 4: This short section simply opens the file for output so we can write to it. Then we write each of the members of the array to file.
Section 5: In this final section we define the format string, print the headers, and then print all the members of the top 10 and their scores. And that's the end of the program!
Now on to a new topic, which will later become related to the previous. User defined types. Recall that a type is the type of value a variable can have, such as integer, string, long, double, or single. You can creat e your own types which contain one or more of the already defined types. Here is an example of a user defined type:
TYPE employeeType firstname AS STRING * 30 lastname AS STRING * 30 age AS INTEGER wage AS SINGLE END TYPE
We have defined a new type, which consists of four data members, as I call them. We can now declare a variable of this type:
DIM employee AS employeeType
A variable of a user defined type is like an array, in that it can have more than one value assigned to it. But you can have an array of a variable of a user defined type as well, so things can get rather complex. Anyway, now that you have a user def ined type, you can assign values to the data members of that variable. Use a period to access a data member of a type, like this:
employee.firstname = "Bob" employee.lastname = "Foster" employee.age = 24 employee.wage = 6.78
This could have been helpful in the last program we made with the top 10 list. We could have declared a user defined type called playerType, like this:
TYPE playerType name AS STRING * 20 score AS INTEGER END TYPE
and then declared an array of variables of that type
DIM player(1 TO 10) AS playerType
That would have made our code more efficient, but not necessarily more readable. Notice when we declare a string in a user defined type that it seems as if we are multiplying it by a number. Actually, we the number after the * defines the maximum len gth of the string. You must define this because the size of a user defined type must be known by the computer. Any value assigned to this string data member which exceeds the length specified is truncated.
User defined types can serve more than to be efficient. They are the heart of the random access file mode, which is commonly used in database files. A database is a method of organizing large quantities of information in records and fields. In a rec
ord, there are a set of fields which are constant in every record. A field's value changes from record to record, however. Just the name of the field remains constant. So how does this relate to user defined types? Well think of a variable of a user d
efined type as a record in the database, and the data members fields of the records. Employee may be a record, and firstname, lastname, age, and wage may be fields. Values can be assigned to the fields in each record, thus constructing a database. A fi
le opened for random access is organized in this fashion, with records split into fields. Each record in the random access file is given a record number which can be convenient in a database environment. In the LEN
function to get the size in bytes of the employee variable, which is an employeeType. Here's the code:
recordLen# = LEN(employee) OPEN "database.dat" FOR RANDOM AS #1 LEN = recordLen#
LEN
stands for length. You can also use the LEN
function to get the number of characters in a string, but that is kind of irrelevant right now. So let's construct a simple database that will keep tra
ck of the employees of a business.
' Section 1 CLS TYPE employeeType firstname AS STRING * 30 lastname AS STRING * 30 age AS INTEGER
wage AS SINGLE END TYPE DIM employee AS employeeType ' Section 2 PRINT "1.) Create new recordset" PRINT "2.) View existing recordset" INPUT "Which option? ", selection% ' Section 3 IF selection% = 1 THEN INPUT "How many employees are in the company? ", numRecords% recordLen# = LEN(employee) OPEN "database.dat" FOR RANDOM AS #1 LEN = recordLen# FOR i% = 1 TO numRecords% CLS INPUT "First name: ", employee.firstname INPUT "Last name: ", employee.lastname INPUT "Age: ", employee.age INPUT "Wage: ", employee.wage PUT #1, ,employee NEXT i% CLS CLOSE #1 PRINT "Recordset creation complete" END END IF ' Section 4 IF selection% = 2 THEN recordLen# = LEN(employee) OPEN "database.dat" FOR RANDOM AS #1 LEN = recordLen# format$ = "\ \,\ \ ### $$##.##" PRINT "Last name First name Age Wage " PRINT "------------------ ------------------ --- -------" DO WHILE NOT EOF(1) GET #1, ,employee 'Sorry about the length of this line!!! PRINT USING format$; employee.lastname; employee.firstname; employee.age; employee.wage LOOP CLOSE #1 END END IF
I've split this program into sections again because that seems to work well for the larger ones.
Section 1: We're defining the user defined type and declaring a variable of that type.
Section 2: The first thing the user sees is a menu with the option to either create a new database (recordset) or view the existing one. The user is prompted to make a selection which is stored in the variable selection%.
Section 3: If the user chose option 1 -- create a new recordset -- then this code is executed. First we prompt the user for how many employees are in the company so we know how many times to go through a loop. Then we open the file, prompt the
user for the data for each variable, and write the whole record to file. The record is written using the PUT
statement. The first argument in PUT
is the file number, the second is the record number,
and the third is the data to be written to file. If no record number is specified for the second argument, the current file position is used, which will just append what we specify after what is already there. This works fine, so we don't need to worry
about explicit record numbers. Notice that we are writing the whole employee variable to file. This is because we write records to file, and the whole variable contains the data for the data members (fields).
Section 4: If the user chooses to view the existing recordset, then we first open the file, define a format string for the printout, and print the headers. Next we have a loop until the end of file is encountered. Notic
e the GET
statement, which is used to read from a random access file. The first argument is the file number we want to read from, the second is the record number (which we are leaving blank because we can read from the current position [
CP] like we did in the PUT statement), and the third is the variable in which we read the data in to. This variable must be of the same type that we wrote with or else the types will be incompatible. You'd probably get a TYPE MISMATCH
error
if a different variable is used because the fields are not equal, so the program does not know what to assign the data to.
Well that's it for random access. If you have understood half of what I've said, feel good. You have a good knowledge of what QBasic is about. Now on to some more advanced programming!
Graphics programming in QBasic can get fairly complex. Lets start from the beginning. Your screen is made up of hundreds of pixels. The number of pixels horizontally and the vertically determines the resolution of you r monitor. In DOS you can be in one of any number of graphics modes, which define the current graphics resolution (pixels), text resolution (characters), number of colors, and number of video pages. There are 13 screen graphics modes in QBasic, and each has its different purpose. You can look in the help index in QBasic for a listing of the screen graphics modes and their specifications. Each of the aspects of a screen graphics type can be changed to create effects.
There are a number of graphics routines used in QBasic which allow a variety of graphical effects. Lets try a few:
SCREEN 12 LINE (0,0)-(640,480), 1 CIRCLE (320, 240), 20, 2 PSET (10,10), 14 DRAW "c15 bm100,400 l5e5f5l5" END
The first line initializes the graphics mode to 12, which is 16 colors, 1 page of video memory, and 640x480 resolution.
LINE
draws a line from one coordinate to another. The first optional argument after the coordinates (which are not optional) is the color. After that, a B
("box") or BF
("box fill") can be used to draw a box
or a box filled with the color specified. The first coordinate can be omitted and the - left in to draw a line from the current graphics position (CP) to the relative coordinates specified. LINE -(100,0)
will draw a line from the current g
raphics position to 100 pixels to the right.
CIRCLE
draws a circle with the center at the coordinates specified. The first argument (required) after the coordinates is the radius of the circle. Then comes the color. After that, if you want to draw an
arc, is the starting angle of the arc in radians, then the ending angle of the arc. To make an arc, first touch up on your geometry, then recall that to convert from degrees to radians is PI (3.14159265) divided by 180. The last argument is used
if you want to make an ellipse, and is the ratio of the y axis to the x axis. So CIRCLE (320,240), 20, 2, 3.1415, 0, .5
would draw an elliptical green arc with the center at the middle of the screen, starting at 180 degrees (PI) and going t
o 0 degrees, with a compression ratio of 1 to 2 (x axis twice as big as the y). This looks like a wide smiley face mouth.
PSET
fills a pixel at the screen coordinate you specify with the color you specify. In this case, yellow.
Finally, the DRAW
statement. The DRAW
statement has it's own commands which I strongly suggest you memorize. When we get in to scaling and rotation you will need to know your draw commands pretty
well. The draw command in the above code example can be read as "color 15 (white), move without drawing to screen coordinate 100,400, draw left 5 units, draw up and right 5 units, draw down and right 5 units, and draw left 5 units." In other words, a tr
iangle. A unit is set by the current scale mode, which by default is 4. Since default scale mode is 4, one unit represents 4 pixels. So our triangle is 40 pixels wide at the base.
There are 16 defined colors in QBasic, graphics mode 12. The COLOR
statement sets the current color for text output. I highly recommend memorizing the colors as well. Run this program:
SCREEN 12 FOR i% = 0 TO 15 COLOR i% PRINT "COLOR"; i% NEXT i%
This will print out the 16 colors used in QBasic. 0 is black, so that obviously won't show up. An quick reference for colors while you're in the QBasic IDE (integrated development environment) is to look under the OPTIONS | DISPLAY menu. The colors listed there are in the QBasic order, starting with black and ending with bright white.
Now you know the basic graphics routines and their uses... lets make a couple programs that demonstrate them to a greater extent. First, a program which prompts the user for a radius, calculates the area and circumference, and draws the circle in a ra ndom color on the screen.
SCREEN 12 RANDOMIZE TIMER CONST pi! = 3.1415 DO COLOR 15: INPUT "Radius (-1 to quit) --> ", radius! IF radius! = -1 THEN EXIT DO area! = pi! * radius! ^ 2 circum! = pi! * 2 * radius! COLOR 14 PRINT "Area = "; area! PRINT "Circumference = "; circum! CIRCLE (320,240), radius!, INT(RND * 15 + 1) DO: LOOP WHILE INKEY$ = "" CLS LOOP COLOR 9: PRINT "Good Bye!" END
We first set the screen graphics mode and generate a random seed number based on the system timer. Then we prompt for the radius in a vivid bright white, and test to see if we should end the program. We then calculate the area and circumference, and p
rint the results in yellow. Then we draw the circle from the middle of the screen at the radius given in a random color. This random color is set by first generating a random number from 0 to 14, adding 1 to it, and converting
it to an integer with the INT
function. The next line seems weird. The INKEY$
statement reads the keyboard and returns the string representation of the key pressed. We are looping while INKE
Y$
is nothing, or in other words, while the user isn't pressing anything. The loop goes on forever until the user presses any key, and at this time a value will be given to INKEY$
which you might decide to use. The screen is then clea
red for the next entry. If the user breaks the loop by entering -1 for the radius, we print Good Bye! in bright blue letters.
There are a lot more colors than just 16. In fact, you can change the values of each of the 16 colors to represent some other color that you specify. You do this with the PALETTE
statement. The following
applies to screen modes 12 and 13. This statement has two arguments: the color you want to change and the color you specify. Specifying a color is the hard part. Here is my version of the syntax of the palette statement
PALETTE
color, blueValue * 256 ^ 2 + greenValue * 256 + redValue
color is the color you are changing. The _Values are numbers from 0 to 63 which specify the intensity of that color. You must use the multipliers after the values and use the addition operator to separate them. So lets make a program that fades the s creen in and out, from black to purple. (blue and red make purple).
SCREEN 12 DO FOR i% = 1 TO 63 PALETTE 0, i% * 256 ^ 2 + i% NEXT i% FOR i% = 63 TO 1 STEP -1 PALETTE 0, i% * 256 ^ 2 + i% NEXT i% LOOP WHILE INKEY$ = "" END
We start by changing the value of black (0), which is the background color to purple, from one degree of blue + red to the next. Then we bring it back down to black by decreasing the blue + red value. We do this over and over until the user presses a key or begins to have seizures.
Scaling and rotation can be accomplished quite easily with the DRAW
statement, although it involves some weird looking code. First, lets define a shape that we can scale and rotate.
box$ = "bu5 l5 d10 r10 u10 l5 bd5"
Interpretation: "move up 5 spaces without drawing, draw 5 spaces left, draw 10 spaces down, draw 10 spaces right, draw 10 spaces up, draw 5 spaces left, and move 5 spaces down without drawing." This forms a box. Notice that I started at the center a
nd not at a corner or side which would seem to be easier. Well, when you rotate something, it draws based on the starting point of the object, and we want it to rotate so if we put a pen at each corner of the box, it would draw a perfect circle. Therefo
re we set the center of the box as the starting point of the object. I call this the "object handle," not to be confused with the handle used in the Windows API. The ta draw command stands for "turn angle," and obviously turns the object in the degrees
you specify. So if we turned the box from 0 to 360 degrees, drawing the box at each step and erasing the previous image, we would get a rotating box. But we need one more function: VARPTR$
.
VARPTR$
stands for "variable pointer," a term you can
completely ignore unless you get into C or Assembly programming.
We need to somehow get the box$ shape into the draw string command we use implement in the loop, so we have to take the address of the obje
ct string and plug it into the draw string. This can be accomplished by using the X command, which tells VARPTR$
where to plug in the string's address so it can be used. With box$ defined above, here's the code for a rotating box:
DO angle% = angle% + 1 IF angle% >= 360 THEN angle% = 1 DRAW "c0 bm320,240 ta" + STR$(angle% - 1) + "X" + VARPTR$(box$) DRAW "c1 bm320,240 ta" + STR$(angle%) + "X" + VARPTR$(box$) LOOP WHILE INKEY$ = "" END
Not that hard is it? We draw the box at the previous angle in black, and then draw the box at the current angle in blue.
Scaling is done pretty much the same way, but instead of changing the angle and erasing the previous image, we change the scale factor and erase the previous image. Recall that the default scale factor for the DRAW
st
atement is 4 pixels per unit. Well, if we increase this factor then we will have more pixels per unit, thus giving the image the effect of enlargement. So if we set up a FOR...NEXT
loop which will increase the scale factor from 2 to, say, 2
00, we will get the effect of scaling. But lets start with a smaller image which is maybe 8 pixels wide from the start instead of 40 so we get a more dramatic effect.
SCREEN 12 box$ = "bu4 l4 d8 r8 u8 l4 bd4" FOR s% = 2 TO 200 DRAW "c0 bm320,240 s" + STR$(s% - 1) + "X" + VARPTR$(box$) DRAW "c2 bm320,240 s" + STR$(s%) + "X" + VARPTR$(box$) NEXT s% END
Notice what we're doing here. We are starting the scale factor at one half of default (2) because the FOR...NEXT
loop starts with s% at 2. The s draw command sets the scale factor. Notice also that we must continuously anchor the object
handle at a point to keep it scaling about the handle. We do this by moving the object handle to 320,240 (center of screen) each time through the loop. Whenever we want to put a number into the draw string, we must concatenate the string format (
STR$
) of the number within the string. Instead of concatenating the box$ with the rest of the string, it is faster to only pass the address of the substring with the VARPTR$
function.
So what if you want to scale and rotate something at the same time? Simple, just set up a FOR...NEXT
loop which increases the scale factor as before, and within the loop increase the angle. But instead of subtracting a factor for the ang
le to erase the previous angle, lets do it this way: erase the previous image with the current angle, increase the angle, then draw the current image with the new current angle. This way if we want to change the factor at which the angle increases, we wi
ll only have to change one number instead of two
SCREEN 12 box$ = "bu4 l4 d8 r8 u8 l4 bd4" FOR s% = 2 TO 250 DRAW "c0 bm320,240 ta" + STR$(a%) + "s" + STR$(s% - 1) + "X" + VARPTR$(box$) a% = a% + 1 IF a% >= 360 THEN a% = 1 DRAW "c1 bm320,240 ta" + STR$(a%) + "s" + STR$(s%) + "X" + VARPTR$(box$) NEXT s% END
Try it out! Draw strings can get fairly complex, but you'll get used to them with practice and when you memorize the draw string commands.
The screen coordinates for different screen modes can be fairly difficult to work with, and they do tend to be weird numbers. To make your code simpler to write, you can define a logical plane over the physical plane. A
n example of a physical plane is the 640x480 resolution established by the SCREEN 12
screen mode. You can define a logical, or alternate user-defined plane with the WINDOW
statement.
SCREEN 12 WINDOW (0,0)-(100,100) CIRCLE (50,50),10,4 LINE (0,0)-(50,50),2 END
This trivial example defines a logical plane which is 100x100. 50,50 is now the center of the screen, so this draws a red circle from the center with a radius of 10. The line statement draws a green line from the lower left corner to the center of the
screen. Notice that defining a logical plane sets the origin (0,0) to the bottom left of the screen, instead of the default upper left. If you want the origin to be in the upper left with a logical plane, add the SCRE
EN
keyword after WINDOW
. So to define the graphics mode 12 screen resolution, the code is:
SCREEN 12 WINDOW SCREEN (0,0)-(640,480)
Use whatever is more comfortable, but I would recommend using WINDOW SCREEN
because there is less confusion when converting from logical to physical planes.
Finally, a little information on creating DRAW
effects with the other QBasic graphics routines. Hope you know some trigonometry for this part. Recall that in the unit circle, which has a radius of 1, that
the coordinates of a point on the circle given an angle is defined as ( COS(angle), SIN(angle) )
. Furthermore, if we are given a point on the circle, we can find the angle by drawing a vertical line perpendicular to the x axis from the point
. If we take the arctangent of the vertical length of this line divided by the horizontal distance of this line from the origin, we will get the angle. So the angle is defined as ATN(Y/X)
. With this knowledge, it would be possible to creat
e a spinning line using only the line command. If we create a loop which increments the angle from 0 to 360 then we can take to COS,SIN
of the angle to get the point we should draw to. But there's only one more problem. The QBasic functio
ns COS
and SIN
think in radians, so we must first convert the angle to radians by multiplying PI / 180. That is quite easily done. Here is the code:
SCREEN 12 CONST PI = 3.1415 WINDOW SCREEN (-1,1)-(1,-1) DO LINE (0,0)-(COS(a% * PI / 180),SIN(a% * PI / 180)), 0 a% = a% + 1 IF a% >= 360 THEN a% = 1 LINE (0,0)-(COS(a% * PI / 180),SIN(a% * PI / 180)), 14 LOOP WHILE INKEY$ = "" END
We start by initializing the graphics mode, then defining PI as a constant - a variable which will never change in the program execution. Then define the logical plane, and start the loop. The line starts from the center of the screen and goes to the
coordinate specified by the COS,SIN
of the angle. We loop until the user presses a key.
There is one more type of graphics that QBasic has a strong point for : text. Graphical effects can be made quite easily using only text in QBasic. There are a few functions that are quite useful when dealing with text. T
he first is the CHR$
function. If you pass a number to the CHR$
function, it will return the ASCII (American standard code for information interchange) text value of that number. To find a listing of
the ASCII character codes, look in the help contents, and there is a listing there. For example, to print a smiley face on the screen, the code is this:
CLS PRINT CHR$(1) END
Since the ASCII character code for a smiley face is 1, you can use the CHR$
function to get this. Another useful function is ASC, which returns the ASCII value of a text value you pass to it.
So ASC("A")
will return 65 because the ASCII value of A is
65. Every printable character (and then some) have an ASCII value, so these two functions make it quite easy.
Finally, the LOCATE
statement is extremely useful for any text based program. LOCATE
sets the text CP to the coordinates you specify. The first argument is the column, and the second is the row.
So
CLS LOCATE 5,10 PRINT CHR$(219) END
Will print a solid white block at column 5, row 10. And that's it for graphics! You now know nearly every graphics routine in QBasic, and have the knowledge to make a game or highly graphical program. Graphics depend on how you arrange them, so it requires an artistic skill to some degree. If you get creative with these graphics commands, you can create nearly any effect you need.
It is not practical in real world terms to set up an application in one long list of code. Many early programming languages were purely linear, meaning that they started from one point on a list of code, and ended at another point. All of the code I have written in this tutorial so far has been purely linear. However, linear programming is not practical in a team environment. If one person could write one aspect of code, and another write another part of the progr am, things would be much more organized. QBasic contains the capability to meet these needs, called modular programming. You can break a program into different "modules" which are separate from the main program and yet can be accessed by any part of it. I highly recommend the use of separate modules in programming applications, although it is not a simple task to learn.
These separate modules are also known as procedures in the QBasic environment. There are two types of procedures: subs and functions. Subs merely execute a task and return to the main program, which functions execute a task and return a value to the main program. An example of a sub might be a procedure which displays a title screen on the screen, while a function may be a procedure that returns a degree in degrees given a number in radians. Function procedures are also used in Calculus, so you Calculus people should already be familiar with functions.
Procedures can accept arguments in what is called an argument list. Each argument in the argument list has a defined type, and an object of that type must be passed to the procedure when it is called. For example, the CHR$
QBasic functio
n accepts a numeric argument. The function itself converts this numeric argument into a string representation of the ASCII value of the number passed, and returns this one character string.
Procedures in QBasic are given their own screen. When you enter the QBasic IDE, you are in the main procedure which can access all the others. Other procedures are created by typing the type of procedure (SUB
or FUNCTION
), t
he procedure name, followed by the complete argument list. You can view your procedures through the VIEW menu. Here is an example of a sub procedure which performs some operations for a program that will be using graphics, random numbers, and a logical
plane.
SUB initProgram() RANDOMIZE TIMER SCREEN 12 WINDOW (0,0)-(100,100) COLOR 15 END SUB
The only thing you need to type is SUB initProgram ()
, and the screen will be switched to that procedure. The END SUB
is placed there for you, so the only thing you need to type then is the code within the sub. Try typing thi
s out on your own to see how this works. This procedure is called by simply typing initProgram
in the main procedure. An alternative method is CALL initProcedure ()
. Right here the parentheses are optional, but if you were to
pass arguments to the procedure, parentheses would be required with the CALL
statement. Now lets try passing an argument to a procedure. We will pass two arguments to a procedure called center which are a string containing the text to be c
entered, and the horizontal location on the screen at which you wish to center it.
SUB center( text$, hLoc% ) LOCATE hLoc%, 41 - (LEN(text$) / 2) PRINT text$ END SUB
The first line after the sub declaration positions the starting point of the text at the horizontal location we passed at the second argument and vertical coordinate. The vertical coordinate is calculated by subtracting one half the screen's width in characters (41) and half the LENgth of the text we passed as the first argument. We would call center from the main procedure like this:
center "Programmed by QP7", 12
Or like this
CALL center ("Programmed by QP7", 12)
It's quite simple actually. Functions are slightly different and involve an additional part which subs do not: a return value. The return value is specified by assigning the value you want to return to the function name from within the function defin ition. When calling the function from within the main procedure, the name of the function is treated as a value which is evaluated at compile-time. Here is an example of a function definition:
FUNCTION convert.To.Radians (degree!) LET PI = 3.1415 convert.To.Radians = degree! * PI / 180 END SUB
The function is implicitly called in this program
CLS INPUT "Enter a value in degrees: ", degreeValue! radianValue! = convert.To.Radians(degreeValue!) PRINT "The radian equivalent is"; radianValue!; "radians" END
We treat the value returned from the function as a value we can immediately assign to another value. The variable radianValue! is given the value returned from convert.To.Radians
. These concepts are supported in all programming languages
, so this information will be beneficial to you in the future.
There is one final concept which has proven to be very successful in programming: a message loop. With QBasic, you can construct a loop which runs for the length of the program, receives input from the user, and executes a message based on what the us
er does. We will construct a basic application which receives input from the user in the form of an arrow key, and moves a box on the screen based on the direction the user pressed. The arrow keys are different from nor
mal inputted keys received with INKEY$
. On the enhanced 101 keyboards which have arrow keys, INKEY$
returns two values: the ASCII text representation of the key pressed, and the keyboard scan code of the key pressed. Since the
arrow keys do not have an ASCII text representation, we must use the keyboard scan codes for them. The keyboard scan codes can be viewed in the HELP | CONTENTS section of the QBasic menus. For this program, we will have two procedures in addition to the
main procedure. The first will initialize the program settings and position the character in his starting position. The other will move the guy in the direction which we pass to the function. The main procedure will call the sub procedures and contain
s the main message loop which retrieves input from the user. First of all, here is the code for the main procedure:
CONST UP = 1 CONST DOWN = 2 CONST LEFT = 3 CONST RIGHT = 4 TYPE objectType x AS INTEGER y AS INTEGER END TYPE DIM object AS objectType initScreen object.x = 41 object.y = 24 DO SELECT CASE INKEY$ CASE CHR$(0) + CHR$(72): move UP, object CASE CHR$(0) + CHR$(80): move DOWN, object CASE CHR$(0) + CHR$(75): move LEFT, object CASE CHR$(0) + CHR$(77): move RIGHT, object CASE CHR$(32): EXIT DO END SELECT LOOP LOCATE 1,1: PRINT "Thank you for playing" END
This code is fairly self explanatory with the exception of the SELECT CASE... END SELECT
structure which I have not yet explained. This type of conditional testing format tests a condition, and several
cases for that condition are then tested. In this case, we are seeing IF INKEY$ = CHR$(0) + CHR$(72)
, IF INKEY$ = CHR$(0) + CHR$(80)
, and so on. This is just a more legible format than IF...THEN...ELSE
. Note that
in the QuickBasic compiler, a CASE ELSE
statement is required in the structure for what reason I have no idea. The above code is the driver for the rest of the program. First some CONSTants are declared which remain co
nstant for the duration of the program and in any module. A user defined type is declared to store the coordinates of the character. Then an endless loop is executed, calling the appropriate procedure for the arrow key pressed until the user presses the
space bar (CHR$(32)
). Here is the code for the initScreen procedure:
SUB initScreen () SCREEN 12 COLOR 9 WIDTH 80,50 LOCATE 24,41 PRINT CHR$(1) END SUB
The WIDTH 80,50
statement sets the screen text resolution to 80 columns and 50 rows. We then print a smiley face in the middle of the screen in a nice bright blue color. Next we need to write the move proc
edure, and then we will be done with the program.
SUB move (way AS INTEGER, object AS objectType) LOCATE object.y, object.x PRINT CHR$(0) ' erase previous image SELECT CASE way CASE UP: IF object.y > 1 THEN object.y = object.y - 1 CASE DOWN: IF object.y < 49 THEN object.y = object.y + 1 CASE LEFT: IF object.x > 1 THEN object.x = object.x - 1 CASE RIGHT: IF object.x < 79 THEN object.x = object.x + 1 END SELECT LOCATE object.y, object.x PRINT CHR$(1) ' draw current image END SUB
And that's the whole program... confusing as it may be! Ideas should be going through your head about what you could do with this information. Entire games can be created with this simple construct.
There are more things to consider, but they are beyond the scope of this tutorial. If you were to design an application in QBasic, you would only need the information from this section and one heck of an imagination. Programming takes k nowledge of the language and a creative mind... programs are made by programmers with both. If you can develop a creative mind, then you can develop any program conceivable.
 That might not sound very prestigious, and you probably won't get a job in the real world by saying that, but ah well. QBasic is a fun and widespread language. But you might be wondering, what do I do now? My suggestion is to continue to learn another language. I would recommend Pascal if you are serious about programming because there are fundamental concepts that you still need to learn. There is also information which I have deliberately left out of this tutorial with the hope that I can teach you a style of programming which is becoming increasingly popular.
BASIC is an extremely popular language with thousands of different versions world-wide, so it is mandatory that you learn it. But if you will continue in programming, knowing a Mid-level DOS language will not suffice in the real world. I suggest learn ing some Pascal next, and then moving on to the world of Windows. When I say "learn" I do not mean memorize every command in the language, I mean "get familiar with the concepts." You may not learn how to do anything beyond what you can do in QBasic, bu t that's fine.


Germany pumps 1 bn euros into 'embarrassing' mobile dead zones
German ministers agreed Monday to spend more than one billion euros plugging gaps in its mobile phone networks, whose patchy coverage has been blasted as "embarrassing" for the advanced industrial nation.
Berlin will unlock 1.1 billion euros ($1.2 billion) to build up to 5,000 new cell towers by 2024, bringing coverage up to 97.5 percent of the country's surface area, and wants to simplify planning rules.
Telecom companies have also promised to build 6,000 new masts.
Economy minister Peter Altmaier said last year that "I find it utterly embarrassing if I have to call back ministers abroad three or four times when the connection drops" on long car journeys.
Illustrating the continuing problems, public broadcaster ARD's live signal from the Meseberg palace near Berlin failed Monday during an early afternoon news show about the cabinet meeting.
"There's no lack of money for investment at the moment," Chancellor Angela Merkel told reporters afterwards.
"The problem is much, much more that it takes a very long time to plan" new masts.
Projects to build new base stations for the phone network also often meet resistance from local people who fear negative health effects from the radio signals.
The government plans a new communications campaign to soothe such fears.
Merkel stuck to her line that Chinese telecoms equipment maker Huawei should not be shut out from building parts of Germany's next-generation 5G network, batting aside objections from within her own party.
The US and Germany's own security services have warned about Huawei's close links with Beijing.
"We're convinced that we need to improve security levels... but that's not about individual companies, it's about security standards. It's about the certification we'll do ourselves," the chancellor said.


---
layout: page
title: Pavilion VI Frescoes
permalink: /frescoes/
---
On the second floor of Pavilion VI is a room that is itself a work of art. The walls and
ceiling of this second-floor room are covered with frescoes, the work of artists
Jean-Robert and Martha La Montagne Saint Hubert, which were unveiled in 1924 as
part of a ceremony dedicating the pavilion’s newly christened Lafayette Room. The
scenes explore the friendship of Thomas Jefferson and the Marquis de Lafayette, whom
President Edwin Anderson Alderman imagined “wandering arm in arm over the green
lawn and through the pillars of this seminary of learning.” The commission for the frescoes was paid for with a $10,000 gift from Ormond G. Smith,
a publisher and president of the French Institute of America. Although Smith was
picture-shy, Jean-Robert Saint Hubert painted his portrait anyway, hiding it behind a
false door.The University of Virginia in 100 Objects
#57 Pavilion VI Frescoes


Create Your Own Memes
The teacher giving the whole class detention for talking and not completing their work
The one kid silently doing all his work
Create a meme
Image URL
Top text
Bottom text


This is a sample markdown file to show how to format an article with markdown. It's used to test the conversion to HTML.
Headings
h1 Heading
h2 Heading
h3 Heading
h4 Heading
h5 Heading
h6 Heading
Basic Formatting
Line Continuation
By default Markdown adds paragraphs at double line breaks. Single line breaks by themselves are simply wrapped together into a single line. If you want to have soft returns that break a single line, add two spaces at the end of the line.
This line has a paragraph break at the end (empty line after).
Theses two lines should display as a single
line because there's no double space at the end.
The following line has a soft break at the end (two spaces or a \
at end)
This line should be following on the very next line.
Text
This is bold text
This is bold text
This is italic text
This is italic text
Strikethrough
Bullet lists
- Carrots
- Tomatoes
- Radishes
- Something
- Another thing
- Last item
Numbered list
- First
- Second
- Third
Nested list
- First, get these ingredients:
- Boil some water.
- Dump everything in the pot.
Hyperlinks
If you don't have Blender installed on your computer, download the latest version here
Images
Simple Image
Image with alt text
Simply add text between the square brackets of an image tag to add alt text. This text should shortly explain what's going on in the image. Every image needs alt text before an article is published!
Image with alt and caption text (RWHTML specific)
You can add a caption to an image by ending the alt text with a pipe '|' and adding the caption text after.
[caption id="attachment_2" align="aligncenter" width="638"]What a pretty screen![/caption]
Notes
Simple Note
Note: Don't see the elements above? Simply select File ► New ► General to generate a default scene.
Multi line Note
Note: Don't see the elements above? Simply select File ► New ► General to generate a default scene.
This is another line.
Here's another one.
Note With Image
Note: Remember, you can add images to notes!
Spoiler (RWHTML specific)
[spoiler title="Solution Inside: Can't remember how to scale?"]
Press the S key, move inwards with your cursor and click to confirm.
[/spoiler]
Code
Inline Code
Add the Run()
method below var Location = "World"
Code Block
Add the language right behind the three ticks. This will enable syntax highlighting.
// Loop and spit stuff out to the console
for(var i=0; i++; i < 10)
{
Console.WriteLine(i);
}
Where to Go From Here?
Every article needs to end with an "Where to Go From Here?" section. The converter checks for this and will warn if it's missing.


Visualize it
Here we shall visualize and differentiate various kidney related problem
Let's get into more briefer aspects of renal and nephrology concepts
Healthy Kidneys Vs Diseased Kidneys
Overview
This is a comparison of normal Vs diseased kidney. We can notice how healthy kidney looks like rather than diseased one.
Chronic Kidney Diseases
Overview
It shows visualization of chronic kidney diseases where the right and left kidneys are infected.
Kidney Stones
Overview
We could notice the formation of stones with ranges shown in mm to see how it's spread across the kidney
Cysts
Overview
Visualizations of multiple cysts inside kidney and how it's populated can be seen here.
Dialysis
Overview
Visualization of dialysis treatment and how kidney looks in dialysis patients


pettails
Who are you and what is this?
I'm Alex Roche, and this is petstails. Petstails is an app and service to help you re-unite confused and concerned owners with their wonderful animal friends.
The application relies on the Estimote iBeacons as a means of triangulation to find lost pets. This is accomplished by using the smartphone most people carry around with them on a day to day basis as the base of operations from which information about the world at large is collected.
An end user would download the application and sign up on the site in order to take part. Once they have an Estimote and the application installed, they can pair the Estimote to their pet, and have a hard wearing tracker.
If the pet then manages to escape, the beacon is passively picked up by other people with the application, which in turn will feed a real time map of current animal locations, available to members.
inspiration
As a small child and throughout growing up, my dog was increasingly devious and too smart for his own good; He managed to escape more times than I can even remember.
However, despite all of these escapes, he was always found and brought home. This would have been a lot easier had there been a way to notify owners their beloved pets have been sighted.
To cut the beginnings of a ramble off, it's not a nice feeling and is a problem that has an easy remedy; petstails.
technologies
- Android,
- Cordova,
- Estimote,
- Gumby,
- HTML,
- Javascript,
- Java,
- MySql,
- NodeJS,
- Paypal,
- PHP
Membership
Sadly, we were unable to process your transaction at the moment.
Sadly, we are unable to offer full membership at the moment, as we're still in Beta testing at the moment. However, if you wish to pre-purchase a membership for when we do come out of Beta, you are more than welcome to, and offer Paypal payment as an opportunity.
We can also offer a Beta version of the proposed application, which is available from the download link at the top of the page.
Thank you, and we look forwards to serving you in the future!


Nothing unusual to report, my Lord.
What do you wish to do?
Open the Castle Gate.
Close the Castle Gate.
Open the Throne Room Gate.
Close the Throne Room Gate.
Teleport (Out of the Gate)
Teleport (Into the Gate)


Rangers striker Alfredo Morelos reveals the truth about Aston Villa transfer link
Latest Aston Villa transfer news | Dean Smith's AVFC are said to be keen on the 23-year-old
by Shane Ireland, https://www.facebook.com/ShaneIrelandJournalistAlfredo Morelos has revealed he’s had no contact with any suitors about leaving Rangers in the January transfer window.
Aston Villa have been credited with a firm interest in the prolific striker who has already scored 20 goals this season.
At 23, Morelos’ age would appeal to Villa who have been keen to recruit players with the potential to grow since Dean Smith took charge.
The Colombia international has been valued at around £20m and it remains to be seen whether Villa will make their move.
But for now, Morelos has not held talks with any clubs about departing Ibrox in the New Year despite the rampant speculation which surrounds his future.
The only side who have previously tried to prise him away are French club Bordeaux, who had a bid rejected in the summer.
He told Antena 2: "There is much speculation about my departure, many teams that would be offering a good amount of money for me.
"I have not talked to anyone, but if God allows it I think that many clubs can come for good performances.
"But no, I've had no contact with anyone. The Bordeaux thing was true, but in the end no agreement was reached."
Aston Villa latest
This is your round up of all things Villa; the one-stop shop that will keep you updated on the latest goings on at the club and beyond.
Transfers, injuries, match-days and managers, we’ve got you covered.
We’ll be bringing the very latest on the Villains throughout the week and around the clock.
Make sure you keep yourself updated with our handy daily catch up...
Must reads...
- John McGinn's brilliant Liverpool verdict
- James Milner makes Aston Villa transfer admission
- Fans split on Villa transfer target
- Referee confirmed for Wolves v Villa - and fans won't like it
For all your latest AVFC news, opinion, analysis and transfer gossip, click here
You can follow our Villa reporter Ashley Preece on Twitter, and his email address is<EMAIL_ADDRESS>Rangers boss Steven Gerrard said at the weekend that Morelos will "100 per cent" remain a Rangers player beyond January.
The forward added: "As a player he (Gerrard) also has his mistakes, I have learned a lot and Gerrard has advised me a lot.
"The refereees always complicated me in that aspect (the cards) but I learned from that, I am doing things better and well in that sense.
"With him I have a lot of confidence and he puts me to play as defined nine."


Archive
- Learning SSH etc
- I love bixi but -!
- Learning les chiffres en français
- Random thoughts
- Where to gitignore what
- Glossary
- How to control spotify from the command line
- Choosing an Outreachy project
- im not a programmer
- Should I stay or should I go now
- MobX + React: Can you use this.props in @computeds?
- Wat the FLIP does Firefox think it's doing with 138% of my CPU power?!
- Adventures with Mozilla Con't
- I applied to Outreachy, and I didn't use my name
- Things that seem like they happen in jobs but never in job interviews
- Xianny's awesome Jekyll post generator
- How to use Heroku Scheduler with Node.js
- Oh god Vim is broken
- What is route protection?
- Day Whatever @ RC
- How to use Sails.js with Pug
- Day 11 (or 8) @ RC
- Day 3 @ RC
- Day 2 @ RC
- RC: Day -2
- How to publish an Vue.js directive to npm
- How to make a reusable “directive” in Vue.js
- How to auto-scroll to the bottom of a div
- How to make an interactive map in React
- Vue.js vs React.js
- Getting started with React and Webpack
- Prototyping a web app on Linux
- If GULP were a person…


Donald Trump Praises Rep. Elise Stefanik “A New Republican Star"
President Donald Trump praised Rep. Elise Stefanik over the weekend as the congresswoman continues to face attacks from the left.
by Charlie Spiering“A new Republican Star is born,” Trump wrote on Twitter, sharing a video of her appearance at Friday’s impeachment hearing. “Great going Elise Stefanik!”
Stefanik grilled former United States Ambassador to Ukraine Marie Yovanovitch on Friday, uncovering details of the Obama’s State Department’s concerns that Hunter Biden’s role on the Burisma board was problematic.
“President Obama’s own State Department was so concerned about potential conflicts of interest from Hunter Biden’s role at Burisma that they raised it themselves while prepping this wonderful ambassador nominee before her confirmation,” she said. “Yet our Democratic colleagues and the chairman of this committee cry foul when we dare ask that same question.”
Stefanik frequently criticized Schiff during the hearings, reminding him of his promise to hear testimony from the so-called “whistleblower.”
Her role earned her derision from the left, including from Washington Republican lawyer George Conway, who called her “lying trash” and shared a photoshopped image of the congresswoman flipping off cameras during the hearing.
“The one thing I’ve NEVER been called in my life is TRASH,” Stefanik replied to Conway. “You need serious help.


## Mako can find this base file because it's in the settings.py -> MAKO_TEMPLATES_DIRS list <%inherit file="base.htm" /> <%block name="content">
New User New Store New Catalog Item New Serialized Item New Bulk Item


Commercial paving
The commercial paving process differs from the residential process, as these areas need to endure a heavy traffic flow. Again, every paving process is unique to what the customer wants to achieve; whether it is a new pavement, an overlay, asphalt repairs, etc. From design to construction, we will stand by our work and provide our experience and creativity to make any of your dream projects come to life. Go Asphalt can enhance your property with an attractive and functional pavement surface that will last for decades to come. We would love to show you both the quality and affordability of our work first hand, so call us today at<PHONE_NUMBER> for a complimentary evaluation and quotation.
Blockquote
Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan faucibus. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis.


StepCalc performs a "step" data lookup based on the inputValue.
module modStepCalc <src_file = "stepcalc.cxx"> { int+IPort2 active = 1; float+IPort2 stepX[]; float+IPort2 stepY[]; float+IPort2 inputValue; float+OPort2 outputValue; cxxmethod+notify_inst+req update( .active+read+req, .stepX+read+notify+req, .stepY+read+notify+req, .inputValue+read+notify+req, .outputValue+write ); };
The modStepCalc module performs a "step" data lookup based on the inputValue input. It finds the first position in the StepX array that is greater than or equal to the input value, and then returns the corresponding value position from the StepY array as output.
active
Used to turn operation of module on and off. If zero, module will not execute.
stepX[]
Input array of float values which are used for comparison with inputValue parameter.
stepY[]
Input array of float values. Once a position index has been found in the input StepX array, the value at that index from this StepY array is copied to the output outputValue.
inputValue
The float value to use to search the StepX array. Once a value in the StepX array has been found which is greater than or equal to this value, that index is used to extract a value from the StepY array.
outputValue
The value from the StepY array at the same index at which the input value matched the requirements from the StepX array.
n/a
n/a
xp_comm_proj/stepcalc/stpcmods.v contains the modStepCalc module V definition.
The low-level StepCalcMods library containing the module modStepCalc does not specify a process. By default the express process will be used.
Brian Selle, Leon Thrane, Advanced Visual Systems Inc. Documentation - Ian Curington, Advanced Visual Systems Inc.
Paul G. Lever
n/a


[ IMDB ]: A look at Wolverine's early life, in particular his time with the government squad Team X and the impact it will have on his later years.
[ IMDB ]: A young woman is entranced by an Aerialist. When they fall into the dreamlike world of Cirque du Soleil and are separated, they travel through the different tent worlds trying to find each other.
[ IMDB ]: An airline pilot saves almost all his passengers on his malfunctioning airliner which eventually crashed, but an investigation into the accident reveals something troubling.
[ IMDB ]: After his son is captured in the Great Barrier Reef and taken to Sydney, a timid clownfish sets out on a journey to bring him home.
[ IMDB ]: A new theme park is built on the original site of Jurassic Park. Everything is going well until the park's newest attraction--a genetically modified giant stealth killing machine--escapes containment and goes on a killing spree.
[ IMDB ]: A tour into the heart of a Hollywood family chasing celebrity, one another and the relentless ghosts of their pasts.
[ IMDB ]: In London during World War II, this is the story of Wendy's daughter, Jane, who is kidnapped by Captain Hook and Peter Pan must come to the rescue.
[ IMDB ]: In a robot world, a young idealistic inventor travels to the big city to join his inspiration's company, only to find himself opposing its sinister new management.
[ IMDB ]: Deckard Shaw seeks revenge against Dominic Toretto and his family for his comatose brother.
[ IMDB ]: Six short stories involving distressed people.
[ IMDB ]: A woman rebels against a tyrannical ruler in post apocalyptic Australia in search for her homeland with the help of a group of female prisoners, a psychotic worshiper, and a drifter named Max.
[ IMDB ]: In 1962, the United States government enlists the help of Mutants with superhuman abilities to stop a malicious dictator who is determined to start World War III.
[ IMDB ]: A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.
[ IMDB ]: When Woody is stolen by a toy collector, Buzz and his friends vow to rescue him, but Woody finds the idea of immortality in a museum tempting.
[ IMDB ]: The Autobots learn of a Cybertronian spacecraft hidden on the moon, and race against the Decepticons to reach it and to learn its secrets.
[ IMDB ]: When Sid's attempt to adopt three dinosaur eggs gets him abducted by their real mother to an underground lost world, his friends attempt to rescue him.


Mood in Beijing about trade deal is pessimistic - CNBC
by Eren SengezerCiting a government source, CNBC's Beijing Bureau Chief, Eunice Yoon, reported that the mood in Beijing about reaching a trade deal was pessimistic.
"China troubled after Trump said no tariff rollback. China thought both had agreed in principle," Yoon tweeted out. "Strategy now to talk but wait due to impeachment, US election. Also, prioritize China economic support."
These comments seem to be weighing on the risk appetite and ramping up the demand for safe havens. As of writing, the USD/JPY pair, which rose to a session high of 109.06 earlier in the hour, was flat on the day at 108.75.


Developing and Testing Microservices with Docker
Often, when developing applications with a microservice architecture, you cannot fully test out all services until you deploy to a staging server. This takes much too long to get feedback. Docker helps to speed up this process by making it easier to link together small, independent services locally.
In this article we’ll look at how to configure and test a number of services locally with Docker and Docker Compose. We’ll also look at workflow and how to interact with and debug containers.
This post assumes prior knowledge of the following topics. Refer to the resources for more info:
| Topic | Resource |
|---|---|
| Docker | Get started with Docker |
| Docker Compose | Get started with Docker Compose |
| Node/Express API | Testing Node and Express |
NOTE: Looking for a more advanced implementation with React? Check out my other post - Developing Microservices - Node, React, and Docker.
Contents
- Objectives
- Project Setup
- Docker Config
- Postgres Setup
- Users Service Setup
- Locations Service Setup
- Web Services Setup
- Testing
- Workflow
- Test Setup
- Next Steps
Objectives
By the end of this tutorial, you should be able to…
- Configure and run a set of microservices locally with Docker and Docker Compose
- Utilize volumes to mount your code into a container
- Run unit and integration tests inside a Docker container
- Set up a separate container for functional tests
- Debug a running Docker container
- Utilize links for inter-container communication (AJAX)
- Secure your services via JWT-based authentication
Project Setup
Start by cloning the base project and then checking out the first tag:
$ git clone https://github.com/mjhea0/node-docker-api
$ cd node-docker-api
$ git checkout tags/v1
Take a quick look at the structure, broken down by service:
├── services
│ ├── locations
│ │ ├── gulpfile.js
│ │ ├── knexfile.js
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── app.js
│ │ │ ├── db
│ │ │ │ ├── connection.js
│ │ │ │ ├── create.sql
│ │ │ │ ├── migrations
│ │ │ │ │ └──<PHONE_NUMBER>4746_locations.js
│ │ │ │ ├── queries.js
│ │ │ │ └── seeds
│ │ │ │ └── locations.js
│ │ │ ├── routes
│ │ │ │ ├── _helpers.js
│ │ │ │ └── locations.js
│ │ │ └── server.js
│ │ └── tests
│ │ └── integration
│ │ ├── routes.index.test.js
│ │ └── routes.locations.test.js
│ └── users
│ ├── gulpfile.js
│ ├── knexfile.js
│ ├── npm-debug.log
│ ├── package.json
│ ├── src
│ │ ├── app.js
│ │ ├── auth
│ │ │ ├── _helpers.js
│ │ │ └── local.js
│ │ ├── db
│ │ │ ├── connection.js
│ │ │ ├── create.sql
│ │ │ ├── migrations
│ │ │ │ └──<PHONE_NUMBER>3908_users.js
│ │ │ └── seeds
│ │ │ └── users.js
│ │ ├── routes
│ │ │ └── users.js
│ │ └── server.js
│ └── tests
│ ├── integration
│ │ ├── routes.index.test.js
│ │ └── routes.users.test.js
│ └── unit
│ ├── auth.helpers.test.js
│ └── auth.local.test.js
├── tests
│ ├── main.test.js
│ └── package.json
└── web
├── gulpfile.js
├── package.json
└── src
├── app.js
├── public
│ ├── main.css
│ └── main.js
├── routes
│ ├── _helpers.js
│ └── index.js
├── server.js
└── views
├── _base.html
├── error.html
├── login.html
├── main.html
├── nav.html
├── register.html
└── user.html
Before we Dockerize the services, feel free to test the locations and/or users services…
Users:
- Navigate to “services/users”
npm install
node src/server.js
- Open http://localhost:3000/users/ping in your browser
Locations:
- Navigate to “services/locations”
npm install
node src/server.js
- Open http://localhost:3001/locations/ping in your browser
Kill the servers once done.
Docker Config
Add a docker-compose.yml file to the project root, which is a config file used by Docker Compose to link multiple services together:
version: '2.1'
NOTE: Why 2.1? Answer.
Then add a .dockerignore to the “services/locations”, “services/locations/src/db”, “services/users”, “services/users/src/db”, “tests”, and “web” directories:
.git
.gitignore
README.md
docker-compose.yml
node_modules
With that, let’s set up each service individually, testing as we go…
Postgres Setup
Add a Dockerfile to “services/locations/src/db” and “services/users/src/db”:
FROM postgres
# run create.sql on init
ADD create.sql /docker-entrypoint-initdb.d
Then update docker-compose.yml:
version: '2.1'
services:
users-db:
container_name: users-db
build: ./services/users/src/db
ports:
- '5433:5432'
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=admin
healthcheck:
test: exit 0
locations-db:
container_name: locations-db
build: ./services/locations/src/db
ports:
- '5434:5432'
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=admin
healthcheck:
test: exit 0
Here, we create two new containers called users-db
and locations-db
, from the Dockerfiles found in “services/users/src/db” and “services/locations/src/db”, respectively. We also add environment variables, expose ports, and send an exit code 0
once they are successfully up and running - which will be used by other services.
To fire up the containers, run:
$ docker-compose up --build -d
Once up, you can get a quick sanity check, by entering the shell:
$ docker-compose run users-db bash
# exit
$ docker-compose run locations-db bash
# exit
Users Service Setup
Again, add a Dockerfile to “services/users”, making sure to review the comments:
FROM node:latest
# set working directory
RUN mkdir /src
WORKDIR /src
# install app dependencies
ENV PATH /src/node_modules/.bin:$PATH
ADD package.json /src/package.json
RUN npm install
# start app
CMD ["npm", "start"]
Add the users-service
to the docker-compose.yml file:
users-service:
container_name: users-service
build: ./services/users/
volumes:
- './services/users:/src/app'
- './services/users/package.json:/src/package.json'
ports:
- '3000:3000'
environment:
- DATABASE_URL=postgres://admin:admin@users-db:5432/node_docker_api_users_dev
- DATABASE_TEST_URL=postgres://admin:admin@users-db:5432/node_docker_api_users_test
- NODE_ENV=${NODE_ENV}
- TOKEN_SECRET=changeme
depends_on:
users-db:
condition: service_healthy
links:
- users-db
What’s new here?
volumes
: volumes are used to mount a directory into a container so that you can make changes to the code without having to build a new image. This should be a default in your local development environment so you can get quick feedback on code changes.depends_on
: depends_on is used to start services in a specific order. So, theusers-service
will wait for theusers-db
to fire up successfully (with an exit code of0
) before it starts.links
: With links, code inside theusers-service
can access the database viausers-db:5432
.
Set the NODE_ENV
environment variable:
$ export NODE_ENV=development
Spin up the container:
$ docker-compose up --build -d users-service
Once up, create a new file in the project root called migrate.sh and add the Knex migrate and seed commands:
#!/bin/sh
docker-compose run users-service knex migrate:latest --env development --knexfile app/knexfile.js
docker-compose run users-service knex seed:run --env development --knexfile app/knexfile.js
Then run it:
$ sh migrate.sh
Test:
| Endpoint | HTTP Method | CRUD Method | Result |
|---|---|---|---|
| /users/ping | GET | READ | pong |
| /users/register | POST | CREATE | add a user |
| /users/login | POST | CREATE | log in a user |
| /users/user | GET | READ | get user info |
$ http POST http://localhost:3000/users/register username=michael password=herman
$ http POST http://localhost:3000/users/login username=michael password=herman
NOTE:
http
in the above commands is part of the HTTPie library, which is a wrapper on top of cURL.
Locations Service Setup
Add the Dockerfile:
FROM node:latest
# set working directory
RUN mkdir /src
WORKDIR /src
# install app dependencies
ENV PATH /src/node_modules/.bin:$PATH
ADD package.json /src/package.json
RUN npm install
# start app
CMD ["npm", "start"]
Add the service to docker-compose:
locations-service:
container_name: locations-service
build: ./services/locations/
volumes:
- './services/locations:/src/app'
- './services/locations/package.json:/src/package.json'
ports:
- '3001:3001'
environment:
- DATABASE_URL=postgres://admin:admin@locations-db:5432/node_docker_api_locations_dev
- DATABASE_TEST_URL=postgres://admin:admin@locations-db:5432/node_docker_api_locations_test
- NODE_ENV=${NODE_ENV}
- TOKEN_SECRET=changeme
- OPENWEATHERMAP_API_KEY=${OPENWEATHERMAP_API_KEY}
depends_on:
locations-db:
condition: service_healthy
users-service:
condition: service_started
links:
- locations-db
- users-service
Register with the OpenWeatherMap API, and add the key as an environment variable:
$ export OPENWEATHERMAP_API_KEY=YOUR_KEY_HERE
Spin up the container:
$ docker-compose up --build -d locations-service
Add the migrate and seed commands to migrate.sh:
docker-compose run locations-service knex migrate:latest --env development --knexfile app/knexfile.js
docker-compose run locations-service knex seed:run --env development --knexfile app/knexfile.js
Run it:
$ sh migrate.sh
Test:
| Endpoint | HTTP Method | CRUD Method | Result |
|---|---|---|---|
| /locations/ping | GET | READ | pong |
| /locations | GET | READ | get all locations |
| /locations/user | GET | READ | get all locations by user |
| /locations/:id | GET | READ | get a single location |
| /locations | POST | CREATE | add a single location |
| /locations/:id | PUT | UPDATE | update a single location |
| /locations/:id | DELETE | DELETE | delete a single location |
$ http GET http://localhost:3001/locations/ping
Web Services Setup
Moving right along…
Add the Dockerfile:
FROM node:latest
# set working directory
RUN mkdir /src
WORKDIR /src
# install app dependencies
ENV PATH /src/node_modules/.bin:$PATH
ADD package.json /src/package.json
RUN npm install
# start app
CMD ["npm", "start"]
Add the service to docker-compose:
web:
container_name: web
build: ./web/
volumes:
- './web:/src/app'
- './web/package.json:/src/package.json'
ports:
- '3003:3003'
environment:
- NODE_ENV=${NODE_ENV}
- SECRET_KEY=changeme
depends_on:
users-service:
condition: service_started
locations-service:
condition: service_started
links:
- users-service
- locations-service
Spin up the container:
$ docker-compose up --build -d web
Navigate to http://localhost:3003 in your browser and you should see the login page. Register a new user. Once redirected, you should see:
Take a look at the AJAX request in the GET /
route in web/src/routes/index.js. Why does the uri
point to locations-service
and not localhost
? Well, localhost
refers back to the container itself, so you need to set up a link in the Docker compose - which we’ve already done.
Testing
Did you notice the unit and integration tests in the “services/users/tests” and “services/locations/tests” folders? Well, to run the tests properly, we need to update the NODE_ENV
environment variable, since it is currently configured for the development environment.
$ export NODE_ENV=test
Update the containers:
$ docker-compose up -d
Then run the tests:
$ docker-compose run users-service npm test
$ docker-compose run locations-service npm test
Ready to develop again?
- Update the env variable -
export NODE_ENV=development
- Update the containers -
docker-compose up -d
Workflow
Let’s quickly look at how to work with code inside the containers…
- Live Reloading - Since the code is mounted in the container via a volume, you can make changes to the local code base which will be applied to the code in the container. Nodemon is used (along with Gulp) to restart the app when changes occur.
- Debugging -
console.log
can be used for testing and debugging. Simply add one to your code base and then open the logs… - Logs - run
docker-compose logs -f
to view the logs.
NOTE: Check out the repo to view more commands.
Try it out:
- Run
docker-compose logs -f
in the terminal - Add
console.log('here');
to the top of web/src/routes/index.js -
As soon as you save, you should see the following in the terminal:
web | [18:35:37] [nodemon] restarting due to changes... web | [18:35:37] [nodemon] running tasks... web | [18:35:39] Using gulpfile /src/app/gulpfile.js web | [18:35:39] Starting 'lint'... web | [18:35:40] web | /src/app/src/routes/index.js web | 1:1 warning Unexpected console statement no-console web | web | ✖ 1 problem (0 errors, 1 warning) web | web | [18:35:40] Finished 'lint' after 1.69 s web | [18:35:40] [nodemon] starting `node ./src/server` web | here
Essentially, Nodemon detected changes and restarted the app, which fired the linter and then the server fired back up.
Test Setup
Finally, to set up the last service, add the Dockerfile to the “tests” folder:
FROM node:latest
# set working directory
RUN mkdir /src
WORKDIR /src
# install app dependencies
ENV PATH /src/node_modules/.bin:$PATH
ADD package.json /src/package.json
RUN npm install
Then update the docker-compose.yml file:
tests:
container_name: tests
build: ./tests/
volumes:
- './tests:/src/app'
- './tests/package.json:/src/package.json'
depends_on:
users-service:
condition: service_started
locations-service:
condition: service_started
links:
- users-service
- locations-service
- web
Fire up the container:
$ docker-compose up --build -d tests
Update the environment variable, update the containers, and then run the tests:
$ export NODE_ENV=test
$ docker-compose up -d
$ docker-compose run tests npm test
Next Steps
What’s next?
- Dependency management: Right now we’re installing many of the same dependencies over and over again, in multiple containers. How can we manage this better to spin up new containers faster and save disc space? How about a data-only container that just houses dependencies?
- Deployment prep: Set up Docker Machine for spinning up Docker environments, nginx for load balancing, and Consul for service discovery. Update the environment variables for the base URL since these will be different in production. Add an image registry solution and a data-only container for piping logs to…
- Error handling: Right now errors are being thrown, but there really isn’t much info in the response as to why, which makes debugging difficult. Be a good citizen and handle your errors properly since you may not always have access to the code base from a different service.
- DRY: The code could be refactored in places, especially the tests.
Grab the final code from the node-docker-api repo. Comment below. Cheers!


This is an ideal semiconductor which is
open (off), if it is reversed biased (voltage drop
less than 0)
closed (on), if it is conducting (current >
0).
This is the behaviour if all parameters are exactly zero.
Note, there are circuits, where this ideal description with zero
resistance and zero conductance is not possible. In order to
prevent singularities during switching, the opened semiconductor
has a small conductance Gon and the closed semiconductor
has a low resistance Roff which is default.
The parameter Vknee which is the forward threshold
voltage, allows to displace the knee point
along the Gon-characteristic until v =
Vknee.
Please note: In case of useHeatPort=true the
temperature dependence of the electrical behavior is
not modelled.


Nav
School Info
Woodside University
Img
Location: Riverside
Size: 100 Students
Application Deadline: 4/30/2020
Average Salary: $45,000 - $65,000
More Info
More Info
Edit


drip, speciality, placeholder descriptor, another descriptor, roasters
placeholder descriptor, another descriptor


stress joint residual surface brazing interface distribution reaction plane YSZ flat layer machining Fig. shear tensile ceramic rumpled interface, machined shown using joint. speed failure microstructure processing grooves alloy compressive filler laser strength {border-style YSZ/TiAlV hardness femtosecond interface. px;} #ffffff;} observed μm/s, Mater. cracks effect morphology seen depth generated joint, near zirconia (Fig. Figure TiAlV image mechanical However, achieved based crack grooves. regions substrate testing Science carried increases joints relatively result Acta ceramics coatings higher inside method Materials Residual Zhang concave influence model models previous substrate, value ./j.actamat... brazed concentration fracture function high improve interlayer measured modelled modelling properties px; region thermal {font-family CTE actual corner direction edge font-size investigate layer. materials phases predicted propagation results sample sharp silver similar test . × Wang X-positive adjacent applied barrier composite decreases double; energy grooves, help induced leading low material maximum metal process reliability shows testing, used usually Brazing Cao Ceram. Effect Foundation Image International TiCu YSZ, alumina border-color border-width boundary braze cause composition cooling drawn feature generally generation groove increasing large micromachined plastic position propagate research seam solid solid; structure study successfully trend unlikely various {font-style {font-weight μm/s "jump" (). ./S-()- ./j.msea... Appl. C/C China Commons Creative Mechanical Sci. Soc. Stress Surface act alloy. analysis behavior bold calculate ceramic/metal corresponds courier; cracks, cracks. deformation detrimental driving elements em; failed force generate highest imported indicates inhibit investigated joining kind mainly mesh metals needs novel original path phase pt;} ranges reason set showing simulation size speed, speed: steel tool trend. width ×


Home
Documentation
Download Data
Source
DCell 1.4
a deep neural network simulating cell structure and function
Start App
© 2017-2018 UC, San Diego Trey Ideker Lab
Cytoscape
NRNB


I am a public interest technologist and law student exploring the intersection of technology, democracy, and law. I am currently a JD candidate at Stanford Law School and a PhD candidate at the UC Berkeley School of Information.
My ongoing dissertation work examines how platform governance decisions along with technical and policy choices of other actors in the election information ecosystem are shaping today’s online civic infrastructure and trust in democratic processes. Other research interests include algorithmic auditing, U.S. technology policy, and research ethics for computer science.
I am currently working with the Stanford Internet Observatory as a graduate research assistant. Previously, I’ve had the opportunity to work with some amazing teams at ACLU NorCal, Plaintext Group, Wellesley College Cred Lab, MIT Election Data and Science Lab, and the U.S. Census Bureau. I have a BA in Computer Science and Chinese Language & Culture from Wellesley College.
prounouns: she/her
| Search quality complaints and imaginary repair: Control in articulations of Google Search. Daniel Griffin* and Emma Lurie*. New Media & Society 2022. |
| Reconfiguring Diversity and Inclusion for AI Ethics. Nichole Chi, Emma Lurie, and Deirdre K. Mulligan. AIES 2021. |
| 'Highly Partisan' and 'Blatantly Wrong': Analyzing News Publishers' Critiques of Google's Reviewed Claims. Emma Lurie and Eni Mustafaraj. Truth and Trust Conference 2020. |
| The Case for Voter-Centered Audits of Search Engines During Political Elections. Eni Mustafaraj, Emma Lurie, and Claire Devine. ACM FAT* 2020. |
| Opening Up the Black Box: Auditing Google’s Top Stories Algorithm. Emma Lurie and Eni Mustafaraj. AAAI FLAIRS 2019. |
| Investigating the Effects of Google's Search Engine Result Page in Evaluating the Credibility of Online News Sources. Emma Lurie and Eni Mustafaraj. |
| Comparing Platform Research API Requirements. Tech Policy Press. March 2023. |
| TikTok just announced the data it’s willing to share. What’s missing? Stanford Internet Observatory Blog. February 2023. |
| Tips for Working with an Undergraduate Research Advisor. Medium. June 2021. |
| What is “good enough” for automated fact-checking? Towards Data Science. August 2019. |
| Googling for the Kansas Primary Medium. August 2018. |
| Why Google Isn't Always Right. The Spoke. October 2017. |


Description:
The goal of this course is to investigate the relationship between algebra and computation. The course is designed to expose students to algorithms used for symbolic computation, as well as to the concepts from modern algebra which are applied to the development of these algorithms. This course provides a hands-on introduction to many of the most important ideas used in symbolic mathematical computation, which involves solving system of polynomial equations (via Groebner bases), analytic integration, and solving linear difference equations. Throughout the course the computer algebra system Mathematica will be used for computation.


This way of updating the cellular space, although it does not fit
perfectly with the theoretical cellular automata model, may be
considered as an optimization because otherwise a set of nine flow
substates should be stored and managed to keep track of the substates
quantities interchanged at each step. Moreover the transition function
is applied only on cells where the thickness substate value
\(sh_{cell} > 0 \). The cellular space could be formed by a very large
number of cells (for example we applied the model to a discretization
of a flank of Mount Etna corresponding to a
\(517 \times 378 = 195426\) cells cellular space), but in the context
of “evolutive” phenomena such as volcano eruptions and consequent
lava flow modelling, that evolve starting from only a limited active
part of the space and growing as the time passes by, cells that are far
from lava are considered to be idle because they cannot be
neither sources nor receivers of any lava quantity, consequently
skipping their computation would not affect the final result. Hence
minimizing the number of times in which transition function is applied
on idle cells could be crucial for performances and in a serial
programming context this can be accomplished easily without any
overhead. The listing [code:skypIdleCell] shows how a serial
implementation of the cellular automata loops over the cellular space
and it selectively applies the transition function whether the if
predicate
\(sh_{cell} > 0 \) is true. The most computationally intesive part of
the transition function is so avoided for such cells.
for (int x = 0; x < COLS ; x++)
for (int y = 0; y < ROWS ; y++)
if (Sh[x][y] > 0 ) {
...
/*HEAVY WORK*/
...
Hence from here it’s clear that the minimization of the idle cells computation is an important optimization and we’ll see in sections [sect:RBBOptimization] and [sect:linearCellAtomic] that this idea is still valid in a parallel context.