Why does this stop running early? - c

I'm actually working on a projecteuler.com problem (#12 specifically) and I thought I had this nailed when I wasn't getting any compile errors.
It runs and gives me several results that appear to be correct, but it's not finishing. I haven't been using C all that long so I am probably overlooking something I'm just not familiar with. Can someone tell me why it's stopping? It is giving me correct triangle numbers up to 12.5M. I would also gladly accept optimization suggestions in the comments.
The results are first, even after a few hours it didn't move on past the first number with 30 factors, which it found rather quickly.
It gives me this, from the code following it:
$ ./euler12
Current= 1
Factors= 1
Current= 3
Factors= 2
Current= 6
Factors= 4
Current= 28
Factors= 6
Current= 36
Factors= 9
Current= 120
Factors= 16
Current= 300
Factors= 18
Current= 528
Factors= 20
Current= 630
Factors= 24
Current= 1008
Factors= 30
where Current gives me the number it got the factors from and obviously then Factors is the number of factors. I doesn't give me any errors and the only warning from -Wall is that I don't actually use the "useless" variable for anything.
#include <stdio.h>
#include <time.h>
/*
Tristen
euler12.c
December 23, 2013
What's the value of the first triangle number to have over 500 divisors?
*/
int main(void)
{
/*---------Variables----------*/
time_t t1 = time(NULL);
int g,l,i,j,k,t,number,val,flag1,flag2;
int h=1,x=0,p=0,n=5000,m=500,m2=600,twitch=0
int answer=0,count=0,useless=0,linlen=0; /*modify n to change size*/
/*----------Arrays------------*/
int numtocheck[n];
int factors[m2];
/*find triangle numbers*/
for(i=0;i<=n+1;i++){
x+=i;
if(x!=0){
numtocheck[i]=x;
}
else{
useless=0;
}
}
/*begin checking for factors*/
while(twitch!=1){
count=0;
for(l=1;l<m2;l++){
factors[l]=0;
}
number=numtocheck[h];
for(j=0;j<=number;j++){
for(k=0;k<=number;k++){
val=j*k;
if(val==number){
flag1=0,flag2=0;
for(g=0;g<m2;g++){
if(factors[g]==j){
flag1=1;
}
else if(factors[g]==k){
flag2=1;
}
else{
useless=0;
}
}
if(flag1==0){
factors[p]=j;
p+=1;
}
else if(flag2==0){
factors[p]=k;
p+=1;
}
else{
useless=0;
}
}
}
}
for(l=0;l<m2;l++){
if(factors[l]!=0){
count+=1;
}
}
if(count>=m){
answer=number;
printf("Current= %d\n",number);
printf("Factors= %d\n",linlen);
twitch=1;
}
else{
if(count>linlen){
linlen=count;
printf("Current= %d\n",number);
printf("Factors= %d\n",linlen);
}
else{
useless=0;
}
}
h+=1;
}
time_t t2 = time(NULL);
t=t2-t1;
printf("Survey says %d\n", answer);
printf("time %d\n", t);
getchar();
return 0;
}

Here are some points to consider (point 5 is the big problem):
1) you forgot a semicolon so this code won't compile, based on this, I'm a little concerned you don't have everything in here verbatim to how you have it...
int h=1,x=0,p=0,n=5000,m=500,m2=600,twitch=0 //<- ; needed
2) as noted in the comments your first for loop overflows the array:
int n=5000;
int numtocheck[n];
/* so numtocheck[] goes from 0 to 4999 */
/*find triangle numbers*/
for(i=0;i<=n+1;i++){ // this loops from 0 to 5001
So this needs to be:
for(i=0;i<n;i++){
3) since you don't initialize the 0th element of numtocheck that means there is garbage data in numtocheck[0]. Same thing later for factors[0], the latter is OK since you over write it, but it's just something to be careful about.
4) You use useless to avoid empty else cases... this is, as you aptly named it, useless. If you don't have anything to do, don't do anything.
For example instead of writing this:
if(count>linlen){
linlen=count;
printf("Current= %d\n",number);
printf("Factors= %d\n",linlen);
}
else{
useless=0;
}
Just remove the else, a if can be paired with an else, it does not need to be.
5) OK, here's the big problem:
if(flag1==0){
factors[p]=j;
p+=1;
}
else if(flag2==0){
factors[p]=k;
p+=1;
}
factors[] is an array of 600 elements, and you access using p a value that's initially 0 but is incremented every time it enters either of these checks. By the time your number is around 2346 p more than overflows the 600 elements in factors[] and you start doing bad things. This causes undefined behavior. On one implantation in Linux this caused a very nice setfault. On a different one in Windows this simply over wrote the values in numtocheck basically making you go into an infinite loop.

Related

Pattern problem in C programming language

I have the following pattern to print in the C programming language.
BBBB
BAAB
BAAB
BBBB
I have tried the following code, but it's not working.
My code :
#include <stdio.h>
int main() {
// Write C code here
int i,j;
for(i=1;i<=4;i++)
{
for(j=1;j<=4;j++)
{
if ((i==1&&j>=i)||(i==4&&j<=i)){
printf("%c",65+1);
}
else{
printf("%c",65);
}
}
printf("\n");
}
return 0;
}
However, the pattern I am getting is the following.
BBBB
AAAA
AAAA
BBBB
The problem with your code is your special case will only fire on the first and fourth row. We can see this a little better if we space things out.
if(
(i==1 && j>=i) || // `i==1` only on the first row
(i==4 && j<=i) // `i==4` only on the fourth row
) {
printf("%c",65+1);
}
Every other iteration will use your else block that just prints A.
else {
printf("%c",65);
}
Note: 'A' is much easier to read than 65, and 'B' much easier than 65+1.
There's plenty of ways to do this. Here's one elegant way with a single loop.
We can observe that we want to print BBBB at the start and every third row. If we start iterating at 0 we can do this when i is divisible by 3. 0/3 has a remainder of 0. 3/3 has a remainder of 0. We use the modulus operator % to get the remainder.
for(int i = 0; i < 4; i++) {
if( i % 3 == 0 ) {
puts("BBBB");
}
else {
puts("BAAB");
}
}
This will continue to repeat the pattern if you extend the loop. 6/3 has a remainder of 0. 9/3 has a remainder of 0. And so on.
(You could also start with i=1 and check i%3 == 1, but get used to starting counting at 0; it makes a lot of things easier.)

C program to check lottery numbers: why some tests fail?

This program takes as an input the following lines:
23 12 33 19 10 8
5
23 19 8 12 60 18
14 60 12 44 54 10
8 3 12 19 33 10
33 15 7 60 12 10
22 12 19 23 33 11
23 12 33 19 10 8 ( The first line ) are the lottery results.
n ( in this specific case, 5 ) informs how many lines will follow below.
Each line has 6 numbers. The number order doesn't matter.
The rules are: numbers range from 1 to 60 ( including 1 and 60 ) and they never repeat themselves in the same line.
The variable "quadra" stores how many lines have got 4 numbers right.
The variable "quina" stores how many lines have got 5 numbers right.
The variable "sena" stores how many lines have got 6 numbers right.
So, a computer program is running some tests over my code below and it's claiming that it goes wrong for most of them, but I can't see what's the problem here. Does anybody have a clue? Is this code wrong, or is there something wrong with the software that's testing this code?
#include <stdio.h>
int main(){
int mega[6];
int v[50500][6];
int n,swap;
int i,j,k; //counters
int quadra,quina,sena;
quadra = 0;
quina = 0;
sena = 0;
for(i=0;i<6;++i) scanf("%i",&mega[i]); //first line, lottery results
scanf("%i",&n);
for(i=0;i<n;++i){
for(j=0;j<6;++j){
scanf("%i",&v[i][j]);
}
}
for(i=0;i<n;++i){
for(j=0;j<6;++j){
for(k=0;k<6;++k){
if(v[i][j] == mega[k]){
v[i][j] = 61;
}
}
}
}
//reverse bubble sort
for(i=0;i<n;++i){
for(j=0;j<6;++j){
for(k=j+1;k<6;++k){
if(v[i][j] < v[i][k]){
swap = v[i][k];
v[i][k] = v[i][j];
v[i][j] = swap;
}
}
}
}
for(i=0;i<n;++i){
for(j=0;v[i][j] == 61 && j<6;++j);
if(j == 4) ++quadra;
else if(j == 5) ++quina;
else if(j == 6) ++sena;
}
return 0;
}
Your code is true, I understood and tried the flow of it. Looks fine but if you dont need to sort everyline (and use j as a counter in this loop for(j=0;v[i][j] == 61 && j<6;++j); ), you can use simpler ifstatements to compare real lottery results with the ones that entered. What I mean is that your algorithm is a little complex. Try a simple one and see how it works.
Yes, there are a couple of noteworthy issues with your code:
Compile time indicates possibility of uninitialized variable:
But, run-time results in fatal run-time at unknown source location. Stack overflow. It is likely due to this line:
int v[50500][6];
Increase your stack size. It needs to be about 2.5Mbytes for v alone.
Also, this line may not be what you intended:
for(i=0;i<6;++i) scanf("%i",&mega[i]); //first line, lottery results
^
If you meant to loop around the remainder of the code, remove the ; after the for() statement, and use curly braces:
for(i=0;i<6;++i) scanf("%i",&mega[i]) //first line, lottery results
{
scanf("%i",&n);
....

Galton Box/Bean Machine-C

I want to code a simple bean machine program. The program will accept user input for the number of balls and the number of slots, and will calculate the path of each ball. The number of balls in each slot will be printed as a histogram as well.
I tried my best to keep the code short and sweet, yet the best I have managed is 112 lines long. When I ran my code, I received no errors. However, the output seems to have run into some sort of an infinity loop (The '#' symbol which was used to represent numbers in the histogram keeps on printing forever for some reason unknown to me).
Apparently, there is something wrong with my logic somewhere... or a silly little mistake in syntax(but it would have shown up as error, wouldn't it?)... In a nutshell, I cannot figure out exactly what is the problem. (I attempted to walk through the whole code process from start to finish, but my mind kept getting tangled up somewhere in the middle of the code, nowhere near the end of the code either).
Where exactly does my logic go wrong?(Or have I taken the wrong approach to the whole problem?) I do not wish to know the correct code, so that I am able to learn during the whole process of re-editing my code.
Any help (hopefully no model-code answers though), even as a single comment, is tremendously appreciated! :)
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include <stdbool.h>
#include <time.h>
//Pls excuse my extensive use of libraries even though I don't really use them
int intchecker(float x)
{
if (floor(x)==x && ceilf(x)==x)
{
return 0;
}
else {
return 1;
}
}
int main(){
char line[] = " +----+----+----+----+----+----+----+----+----+----+---+";
char numbers[] = " 0 5 10 15 20 25 30 35 40 45 50";
float balls,slots;
int slotarry[9],tlevel,ballnum,column,lcounter=0,slotsduplicate=1,y;//tlevel-number of levels in the triangle
srand(time(NULL));
int r;
printf("==========================================================\nGalton Box Simulation Machine\n==========================================================\n");
printf("Enter the number of balls [5-100]: ");
scanf("%f",&balls);
while (balls>100 || balls<5) {
printf("\nInput is not within the range. Please try again.");
printf("\nEnter the number of balls [5-100]: ");
scanf("%f",&balls);
}
while (intchecker(balls)==1) {
printf("\nInput is not an integer. Please try again.");
printf("\nEnter the number of balls [5-100]: ");
scanf("%f",&balls);
}
printf("Enter the number of slots [2-10] : ");
scanf("%f",&slots);
while (slots>10 || slots<2) {
printf("\nInput is not within the range. Please try again.");
printf("\nEnter the number of slots [2-10] : ");
scanf("%f",&slots);
}
while (intchecker(slots)==1) {
printf("\nHow can there be a fraction of a slot? Please re-enter slot number.");
printf("\nEnter the number of slots [2-10] : ");
scanf("%f",&slots);
}
tlevel=slots-1;
for(ballnum=1,column=0;balls>0;balls--,ballnum++,column++){
if (column%5==0){
printf("\n");
}
if (ballnum<10){
printf("[0%d]",ballnum);
}
else{
printf("[%d]",ballnum);
}
for(;tlevel>0;tlevel--){
r = rand() % 2;
if (r==0){
printf("R");
}
else {
printf("L");
lcounter++;
}
}
slotarry[lcounter]++;
tlevel=slots-1;
lcounter=0;
printf(" ");
}
printf("\n\n%s",numbers);
printf("%s",line);
char line2[] = "\n +----+----+----+----+----+----+----+----+----+----+---+";
for(;slotsduplicate<=slots;slotsduplicate++){
if (slotsduplicate<10){
printf("0%d|",slotsduplicate);
}
else{
printf("%d|",slotsduplicate);
}
y=slotarry[slotsduplicate];
if (y==0){
printf(" 0");
}
else{
for (;y>0;y--){
printf("#");
}
printf(" %d",slotarry[slotsduplicate]);
}
printf("%s",line2);
}
return 0;
}
Note:This is not completely error-free. This is just my first draft. I just wish to find out why there is an infinite loop.
Here's how I found the problem. First of all, I think it is a bit of a code smell to have a for loop without anything in the initial assignment section. Couple that with the fact that it seems to print # forever, and it looks like y has a garbage value at the beginning of the loop to print the #s.
So I ran your code in the debugger and paused it when it started printing loads of hashes. I checked the value of y and sure enough it was some unfeasibly high number.
Then I checked where y comes from and found you get it from slotarray. I printed it in the debugger and found that all the values in it were unfeasibly high or massively negative numbers. Obviously, slotarray wasn't being initialised correctly, so I looked for where it was initialised and bingo!
Stack variables (of which slotarray is one) must be explicitly initialised in C. I fixed your code with a call to memset.
The whole debugging process I have just outlined took something less than a minute.
ETA As #EOF points out, there is another bug in that slotarray is defined to contain nine slots (indexed 0 - 8) but you allow people to enter 10 slots. This is a buffer overflow bug.

Quick sort implementation in C

To answer everyone's first question: Yes, this is for school.
That being said, I feel like I'm pretty close to getting this to work, at least partially. Seems to sort most of the data, but I can't see any pattern to what is not being sorted.
#include <stdio.h>
#include <stdlib.h>
void quicksort(int *values, int size);
void printout(int[], int size);
void main(){
printf("starting");
int size=20;
int values[size];
int i;
for (i=0;i<size;i++){
values[i]=(rand()%113);
}
printf("\nBefore Sort:\n");
printout(values,size);
quicksort(values, size);
printf("\nAfter Sort:\n");
printout(values,size);
}
void printout(int values[],int size){
int i;
for (i=0;i<size;i++){
if (i % 20 == 0){
printf("\n");
}
printf("%3i ", values[i]);
}
}
void quicksort(int *values, int size){
if (size < 2){
return;
}
int pivot=values[size];
int left[size];
int right[size];
int center[size];
int i,lc,rc,cc; //counters for left, right and center arrays
lc=rc=cc=0; //initially 0
for (i=0; i<size-1; i++){
if (values[i] < pivot){
left[lc]=values[i];
lc++;
}
else if (values[i] > pivot){
right[rc]=values[i];
rc++;
}
else{
center[cc]=values[i];
cc++;
}
}
quicksort(left, lc);
quicksort(right, rc);
int lc2,rc2,cc2;
lc2=rc2=cc2=0; //note the first variable is lowercase L, not 1
while (lc2+cc2+rc2 < size-1){ // here we recombine our arrays
while (lc2 < lc){
values[lc2+rc2+cc2] = left[lc2];
lc2+=1;
}
while (cc2 < cc){
values[lc2+rc2+cc2] = center[cc2];
cc2+=1;
}
while (rc2 < rc){
values[lc2+rc2+cc2] = right[rc2];
rc2+=1;
}
}
}
My output for this is as follows:
Before Sort:
41 48 6 58 72 17 65 91 68 56 55 8 3 103 17 39 57 77 81 12
After Sort:
6 8 17 41 48 58 72 65 68 56 55 3 17 39 91 57 77 103 81 12
It's definitely doing something... Anybody have any ideas as to what the heck I'm missing here?
I've included tips on debugging that you can apply in the future to find problems like these.
Problem 1
int pivot=values[size];
size is past the end of the range being sorted. At the top level when the range is the entire array that means it's outside the array. And at the other levels it's either outside the array or the pivot value is from a different range.
Discovering this defect may require either careful code review or a tool designed to catch this sort of error such as is built into some compilers.
A more difficult method involves inspecting the runtime behavior, either with print statements or a debugger, and recognizing that the first pivot is not a value in the array. Testing with known input instead of random input helps with this method because it makes it more likely that you'll notice anything unexpected.
Problem 2
You also do not move the pivot into the correct location.
One technique for discovering this would be to check post-conditions. For example at the end of quicksort() the range should be sorted. So if you insert printout(values,size); at the end of that function then might notice in a few short cases where just the last element is out of order. Additional print statements can help you trace what's causing this.
Problem 3
main() must return int, not void.
Using a stricter compiler will catch this for you.
You're choosing the pivot wrong - values[size] lies outside of the range. If you want to use the last element, use values[size - 1].

C array is displaying garbage data (memory problems?)

I'm making a driver for an 8x8 LED matrix that I'm driving from a computer's parallel port. It's meant to be a clock, inspired by a design I saw on Tokyoflash.
Part of the driver is an array of 3*5 number "sprites" that are drawn to the matrix. A coordinate of the matrix is assigned to a coordinate of the sprite and so forth, until the entire sprite is drawn on it. This process is repeated for the other digit with an offset. I have verified I have drawn the sprites correctly, and that the matrix is blank when it is written to. However, when I draw a number on the matrix I get errant 1s at Numpad6 for the left digit, Numpad1 for the right (Example with the left digit not drawn.)
I have a week of experience in C and this is baffling me.
Here is the driver in full if you want to compile it yourself. It is nowhere near finished.
//8x8 LED MATRIX DRIVER VER 0.1 APR062009
//CLOCK
//
// 01234567
// 0 BXXXXXXH B: Binary Mode Indicator
// 1 DXXXXXXM D: Decimal Mode Indicator
// 2 NNNNNNNN H: Hour Centric Display
// 3 LLLNNRRR M: Minute Centric Display
// 4 LNLNNRNR X: Secondary Information
// 5 LLLNNRRR L: Left Digit
// 6 LNLNNRNR R: Right digit
// 7 LLLNNRRR N: Not Used
#include <stdio.h>
#include <unistd.h>
//#include <math.h>
#include <time.h>
#include </usr/include/sys/io.h>
#define BASEPORT 0x378
int main()
{
//Increasing array parameters to seems to reduce glitching [best 10 5 3]
int Dig[10][5][3] = {0}; //ALPHANUMERIC ARRAY [NUMBER (0..9)][Y(0..4)][X(0..2)]
int Mat[7][7] = {0}; //[ROW][COL], Top L corner = [0][0]
int Aux1[7] = {0}; //Topmost Row
int Aux2[7] = {0}; //Second to Topmost Row
int Clk; //Clock
int Wait; //Delay; meant to eventually replace clock in its current state
int C1; //Counters
int C2;
int C3;
int L; //Left Digit
int R; //Right Digit
//break string left undefined atm
//ioperm (BASEPORT, 3, 1);
//outb(0, BASEPORT);
printf("Now running.\n");
//Set Variables
//3D DIGIT ARRAY [Num][Row][Col] (INITIALIZED BY INSTRUCTIONS)
//Dig array is meant to be read only once initialized
//3D arrays are unintuitive to declare so the numbers are
//"drawn" instead.
//Horizontals
//Some entries in the loop may have the variable in the middle
//coordinate instead of the 3rd and/or with a +2. This is to
//incorporate the incomplete columns some numbers have (eg "2") and
//saves coding additional loops.
for(C1=0; C1<=2; C1++){
Dig[0][0][C1]=1; Dig[0][4][C1]=1;
Dig[2][0][C1]=1; Dig[2][2][C1]=1; Dig[2][4][C1]=1; Dig[2][C1][2]=1; Dig[2][C1+2][0]=1;
Dig[3][0][C1]=1; Dig[3][2][C1]=1; Dig[3][4][C1]=1;
Dig[4][2][C1]=1; Dig[4][C1][0]=1;
Dig[5][0][C1]=1; Dig[5][2][C1]=1; Dig[5][4][C1]=1; Dig[5][C1][0]=1; Dig[5][C1+2][2]=1;
Dig[6][0][C1]=1; Dig[6][2][C1]=1; Dig[6][4][C1]=1; Dig[6][C1+2][2]=1;
Dig[7][0][C1]=1;
Dig[8][0][C1]=1; Dig[8][2][C1]=1; Dig[8][4][C1]=1;
Dig[9][0][C1]=1; Dig[9][2][C1]=1; Dig[9][4][C1]=1; Dig[9][C1][0]=1;
}
//Verticals
for(C1=0; C1<=4; C1++){
Dig[0][C1][0]=1; Dig[0][C1][2]=1;
Dig[1][C1][2]=1;
Dig[3][C1][2]=1;
Dig[4][C1][2]=1;
Dig[6][C1][0]=1;
Dig[7][C1][2]=1;
Dig[8][C1][0]=1; Dig[8][C1][2]=1;
Dig[9][C1][2]=1;
}
Clk=10000;
L=2; //Think about incorporating overflow protection for L,R
R=4;
//Print Left Digit to Matrix # (3, 0)
for(C1=0; C1<=4; C1++){ //For some reason produces column of 1s at numpad 6
for(C2=0; C2<=2; C2++){
Mat[C1+3][C2]=Dig[L][C1][C2];
printf("%d", Dig[L][C1][C2]); //Debug
}
printf(" %d %d %d\n", L, C1, C2); //Debug
}
//Print Right Digit to Matrix # (3, 5)
for(C1=0; C1<=4; C1++){ //For some reason produces column of 1s at numpad 1
for(C2=0; C2<=2; C2++){
Mat[C1+3][C2+5]=Dig[R][C1][C2];
}
}
//X Test Pattern
//for(C1=0; C1<=7; C1++){
// Mat[C1][C1]=5;
// Mat[7-C1][C1]=5;
//}
usleep(Clk);
//while(1){
//Breakfree [NOT FUNCTIONAL]
//Break_String=getch(); (Getch is not ANSI, need ncurses)
//if(Break_String != -1){
// if(Break_String = 27){
// break;
// }
//}
//Terminal Display
//for(C3=0; C3<=9; C3++){ //Debug Digit array [Successful, numbers draw correctly]
// for(C2=0; C2<=4; C2++){
// for(C1=0; C1<=2; C1++){
// printf("%d", Dig[C3][C2][C1]);
// }
// printf("\n");
// }
//printf("\n");
//usleep(1000000); //Debug
//}
usleep(3000000); //Debug
for(C1=0; C1<=7; C1++){ //Prints to terminal every second, when looping
for(C2=0; C2<=7; C2++){
printf("%d", Mat[C1][C2]);
}
printf("\n");
}
printf("\n");
//Hardware Display
for(C1=0; C1<=29; C1++){ //30 Hz
for(C3=0; C3<=7; C3++){ //COLUMN
//printf("%d %d \n", C3, C1); //Loop Debug
usleep(1000);
//CLOCK GROUND TO GO HERE, OUT STATUS
//for(C2=0; C2<=7; C2++){ //PX
//outb(Mat[C3][C2], BASEPORT);
//}
}
usleep(4*Clk);
}
//}
//ioperm(BASEPORT, 3, 0);
exit(0);
}
Also, I had to make my Sprite array bounds each one bigger than they should have been to make it work. I figure this is all some some memory snafu but I'm nowhere near that proficient in C to know what to do.
I would greatly appreciate any help.
I need to look through it more but one problem off the bat is that you're driving an 8x8 LED matrix but using a 7x7 matrix to hold the data. Declare your matrix as:
int Mat[8][8];
Bryan, I think you are just missing the fundamental understanding of how array indices work in C.
When you declare
int array[N]
you access the elements in a range of
array[0] ... array[N-1]
which gives you a total of N elements.
For example:
int array[4]
gives you
array[0]
array[1]
array[2]
array[3]
for a total of 4 elements.
When looping over this array, this is the convention that's almost always used:
for(i = 0; i < 4; i++)
I think that this issue is causing multiple problems in your code and if you go back over your arrays after understanding this you'll be able to fix the problems.
Bryan, I don't see the problem offhand, but what you're describing sounds like you are having an array indexing issue. (Rule of thumb, any time you think that there's something wrong with the computer causing your errors, you're mistaken.)
Two places new C programmers run into trouble with this is getting confused by 0 based indices -- an array of size 7 has indices from 0..6 -- and by not realizing that arrays are just laid out on top of one blob of memory, so an array that's [10][5][2] is really just one 100-cell piece of memory. If you make an indexing mistake, you can put things in what appear to be random places.
I'd go through the code and check what's where in smaller steps; what happens after one initialization, that sort of thing.

Resources