24 Commits
v0.7 ... v1.0

Author SHA1 Message Date
7fa4d9d2bf Added stuff to CHANGELOG for v1.0 2017-02-13 17:08:30 +01:00
6ed153b9e2 Will be disabling merge requests. 2017-02-13 10:09:25 +01:00
c8d1c095ba Clarify. 2017-02-13 09:56:23 +01:00
ae8cbed179 Details... 2017-02-13 09:55:31 +01:00
69028a15c8 Promote patches. 2017-02-13 09:54:13 +01:00
b20733f3ac Append new primes to the end of a file. 2017-02-13 09:47:47 +01:00
2b5541d2c3 Fixed some memory leaks. 2017-02-12 19:33:57 +01:00
94248612ba Find the nth prime. 2017-02-06 18:00:34 +01:00
8ee18c8c4b Forget it, it's unnecessary. 2017-02-06 17:51:07 +01:00
bdea1979e8 Use inline functions. 2017-02-06 17:50:26 +01:00
a3ec19d47c Cleaned the code. 2017-02-02 19:53:29 +01:00
22239ec644 Preparing for v1.0 release. 2017-02-02 10:46:34 +01:00
22278999e7 Fixed algorithm problem. 2017-02-02 10:35:43 +01:00
a5b68282b3 Cancel if `primes.list[i] >= numRoot'.
It has been solved!!!
2017-02-01 23:12:23 +01:00
b9cafadf8e Parallelized, but needs algorithm optimization. 2017-02-01 19:36:05 +01:00
32076a67cd Remove parallelization code to start anew. 2017-02-01 17:18:03 +01:00
9673a4da57 Use shared as default. 2017-01-31 22:24:06 +01:00
76936644cd Almost completely parallelized. 2017-01-31 19:39:35 +01:00
a6ecea514f Restrict will no longer apply to `addToList' 2017-01-17 00:11:51 +01:00
22c7702cf0 We only need to test up to the sqrt(num). 2017-01-01 17:05:25 +01:00
f8726497a4 Don't test for divisibility by 2.
We skip all even numbers, so we can skip 2, this also means giving 3 as
a given.
2016-12-30 17:57:28 +01:00
3e902efd18 Small cleanup. 2016-12-30 17:51:48 +01:00
3246870b75 Better help information. 2016-12-28 14:43:17 +01:00
09166efe89 Small improvements and optimizations.
All error catching is now in `main.c' so we can neatly release memory as
well as adding the `restrict' optimizer to the `addToList()' function.
2016-12-28 00:30:31 +01:00
8 changed files with 205 additions and 137 deletions

View File

@ -30,3 +30,9 @@ Change Log
- v0.7: Data Saving - v0.7: Data Saving
- Allow user to save found primes to be loaded later. - Allow user to save found primes to be loaded later.
- User can save and read primes in raw output. - User can save and read primes in raw output.
- v1.0: Parallelization
- Now completely parallelized.
- Cleaned up/organized the code-base
- Exporting files uses less memory
- Allow searching for the nth prime number
- Clearing some memory leaks

View File

@ -1,6 +1,6 @@
Contributing Contributing
============ ============
We gladly accept contributions to Indivisible, however there are a few guidelines that must be followed. We gladly accept contributions to Indivisible (send Git patches to <deathsbreed@themusicinnoise.net>), however there are a few guidelines that must be followed.
1) Copyright & Licensing 1) Copyright & Licensing
------------------------ ------------------------
@ -8,7 +8,7 @@ The copyright of this project and all of its code, unless stated otherwise, belo
2) Documentation 2) Documentation
---------------- ----------------
All new features added must be well documented using DOxygen style comments. If your merge request adds a new feature and it is not well documented we will ask you to finish documenting the code before accepting a merge. This is simply so that both the maintainers of this repo and other users can understand the new API that bas been added. All new features added must be well documented using DOxygen style comments. If your patch adds a new feature and it is not well documented we will ask you to finish documenting the code before accepting a patch. This is simply so that both the maintainers of this repo and other users can understand the new API that bas been added.
3) Code-Style 3) Code-Style
------------- -------------
@ -16,8 +16,8 @@ The only aspects that will be religiously upheld for all contributions to this r
Things that would be nice is if you could avoid having the lines being too long, and please avoid having more than one empty line in a row. Things that would be nice is if you could avoid having the lines being too long, and please avoid having more than one empty line in a row.
4) Fractured Merge Requests 4) Fractured Patches
--------------------------- --------------------
Please make sure your merge requests are fractured into separate parts so that it may be easy for us to deal with them individually. The reason for this is to avoid having merge requests that both fix bugs and add features when in reality they should be separate requests. The only exception to this will be if the changes made to the code depend on one another to function properly. Please make sure your patches are fractured into separate parts so that it may be easy for us to deal with them individually. The reason for this is to avoid having patches that both fix bugs and add features when in reality they should be separate requests. The only exception to this will be if the changes made to the code depend on one another to function properly.
If your merge request meets all these requirements and is passed by one of the moderators it will be merged into the main repo. If your patch meets all these requirements and is passed by one of the moderators it will be merged into the main repo.

View File

@ -22,7 +22,7 @@ To build a release build run `cmake -DCMAKE_BUILD_TYPE=Release ..` instead.
Contributing Contributing
------------ ------------
If you would like to contribute to Uhn then please read the [contributing file](/CONTRIBUTING.md) before creating a merge request. If you would like to contribute to Indivisible then please read the [contributing file](/CONTRIBUTING.md) before sending a patch. You may send the patches to <deathsbreed@themusicinnoise.net>.
License License
------- -------

View File

@ -5,57 +5,62 @@
int inputPrimes(char *file, List *list) { int inputPrimes(char *file, List *list) {
// Assert safeguards // Assert safeguards
assert(file != NULL); assert(file);
assert(list != NULL); assert(list);
FILE *pFile = fopen(file, "r"); FILE *in = fopen(file, "r");
if(pFile == NULL) return 1; if(!in) return 1;
mpz_t n; mpz_t n;
mpz_init(n); mpz_init(n);
while(mpz_inp_raw(n, pFile) != 0) addToList(list, n); while(mpz_inp_raw(n, in))
if(fclose(pFile) != 0) return 2; if(addToList(list, n) == 1) return 3;
mpz_clear(n);
if(fclose(in)) return 2;
return 0; return 0;
} }
int outputPrimes(char *file, List *list) { int outputPrimes(char *file, List *list, size_t startPos) {
// Assert safeguards // Assert safeguards
assert(file != NULL); assert(file);
assert(list != NULL); assert(list);
FILE *out = fopen(file, "a");
if(!out) return 1;
FILE *oFile = fopen(file, "w");
if(oFile == NULL) return 1;
printf("Saving primes to `%s'...\n", file); printf("Saving primes to `%s'...\n", file);
puts("0%"); puts("0%");
for(size_t i = 0; i < list->end; ++i) { for(size_t i = startPos; i < list->end; ++i) {
if(mpz_out_raw(oFile, list->list[i]) == 0) return 3; if(!mpz_out_raw(out, list->list[i])) return 3;
if(i == list->end / 4) puts("25%"); if(i == list->end / 4) puts("25%");
else if(i == list->end / 2) puts("50%"); else if(i == list->end / 2) puts("50%");
else if(i == list->end * 3 / 4) puts("75%"); else if(i == list->end * 3 / 4) puts("75%");
} }
puts("100%"); puts("100%");
if(fclose(oFile) != 0) return 2;
if(fclose(out)) return 2;
return 0; return 0;
} }
int exportPrimes(char *file, List *list, int base) { int exportPrimes(char *efile, char *dfile, int base) {
// Assert safeguards // Assert safeguards
assert(file != NULL); assert(efile);
assert(list != NULL); assert(dfile);
assert(list->list != NULL);
FILE *eFile = fopen(file, "w"); FILE *in = fopen(dfile, "r");
if(eFile == NULL) return 1; FILE *out = fopen(efile, "w");
printf("Exporting primes to `%s'...\n", file); if(!in || !out) return 1;
puts("0%");
for(size_t i = 0; i < list->end; ++i) { printf("Exporting primes to `%s'...\n", efile);
if(mpz_out_str(eFile, base, list->list[i]) == 0) return 3; mpz_t n;
fprintf(eFile, "\n"); mpz_init(n);
if(i == list->end / 4) puts("25%"); while(mpz_inp_raw(n, in)) {
else if(i == list->end / 2) puts("50%"); if(!mpz_out_str(out, base, n)) return 3;
else if(i == list->end * 3 / 4) puts("75%"); fprintf(out, "\n");
} }
puts("100%");
if(fclose(eFile) != 0) return 2; if(fclose(in) || fclose(out)) return 2;
puts("Finished exporting primes.");
return 0; return 0;
} }

View File

@ -12,7 +12,8 @@
* @param file File to input primes from. * @param file File to input primes from.
* @param list List to load primes into. * @param list List to load primes into.
* @returns If 0 then load was successful, if 1 then failed to open, * @returns If 0 then load was successful, if 1 then failed to open,
* if 2 failed to close. * if 2 failed to close, if 3 failed to allocate new memory to List
* (see `addToList()')
*/ */
int inputPrimes(char *file, List *list); int inputPrimes(char *file, List *list);
@ -20,17 +21,19 @@ int inputPrimes(char *file, List *list);
* @brief Output primes from a List into an Indivisible file. * @brief Output primes from a List into an Indivisible file.
* @param file File to output primes to. * @param file File to output primes to.
* @param list List to read primes from. * @param list List to read primes from.
* @param startPos The position in the List of primes at which to append
* to the file.
* @returns If 0 then load was successful, if 1 then failed to open, * @returns If 0 then load was successful, if 1 then failed to open,
* if 2 failed to close, if 3 failed when writing. * if 2 failed to close, if 3 failed when writing.
*/ */
int outputPrimes(char *file, List *list); int outputPrimes(char *file, List *list, size_t startPos);
/** /**
* @brief Export primes from a List to a plain text file. * @brief Export primes from a List to a plain text file.
* @param file File to output primes as plain text to. * @param efile File to export primes as plain text to.
* @param list List to read primes from. * @param dfile File to read primes from.
* @param base The base in which the primes will be written. * @param base The base in which the primes will be written.
* @returns If 0 then load was successful, if 1 then failed to open, * @returns If 0 then load was successful, if 1 then failed to open,
* if 2 failed to close, if 3 failed when writing. * if 2 failed to close, if 3 failed when writing.
*/ */
int exportPrimes(char *file, List *list, int base); int exportPrimes(char *efile, char *dfile, int base);

View File

@ -1,39 +1,34 @@
#include "list.h" #include "list.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
/** /**
* This is the number of elements by which the list expands. * This is the number of elements by which the list expands.
*/ */
#define BLOCK_SIZE 1024 #define BLOCK_SIZE 1024
void initList(List *restrict l) { int initList(List *restrict l) {
l->list = malloc(sizeof(mpz_t) * BLOCK_SIZE); l->list = malloc(sizeof(mpz_t) * BLOCK_SIZE);
if(!l->list) { if(!l->list) return 1;
fprintf(stderr, "Failed to allocate memory to list!\n");
exit(1);
}
l->size = BLOCK_SIZE; l->size = BLOCK_SIZE;
l->end = 0; l->end = 0;
return 0;
} }
void deInitList(List *restrict l) { void deInitList(List *restrict l) {
for(size_t i = 0; i < l->size; ++i) { for(size_t i = 0; i < l->end; ++i) {
mpz_clear(l->list[i]); mpz_clear(l->list[i]);
} }
free(l->list); free(l->list);
} }
void addToList(List *l, mpz_t n) { int addToList(List *restrict l, mpz_t n) {
if(l->end == l->size) { if(l->end == l->size) {
l->size += BLOCK_SIZE; l->size += BLOCK_SIZE;
void *tmp = realloc(l->list, sizeof(mpz_t) * l->size); void *tmp = realloc(l->list, sizeof(mpz_t) * l->size);
if(!tmp) { if(!tmp) return 1;
fprintf(stderr, "Failed to allocate more memory to list!\n");
exit(1);
}
l->list = tmp; l->list = tmp;
} }
mpz_init(l->list[l->end]); mpz_init(l->list[l->end]);
mpz_set(l->list[l->end++], n); mpz_set(l->list[l->end++], n);
return 0;
} }

View File

@ -7,7 +7,6 @@
*/ */
#pragma once #pragma once
#include <gmp.h> #include <gmp.h>
#include <stdbool.h>
/** /**
* @brief An infinitely expanding list type. * @brief An infinitely expanding list type.
@ -23,8 +22,9 @@ typedef struct {
* @details Initialize the list and its variables, allocating memory * @details Initialize the list and its variables, allocating memory
* to the pointer array inside. * to the pointer array inside.
* @param[in] l A pointer to a List type to be initialized. * @param[in] l A pointer to a List type to be initialized.
* @returns Returns 0 if successful and 1 if failed.
*/ */
void initList(List *restrict l); int initList(List *restrict l);
/** /**
* @brief Deinitialize a List. * @brief Deinitialize a List.
@ -38,5 +38,6 @@ void deInitList(List *restrict l);
* @details Add item `n' at the end of a List type. * @details Add item `n' at the end of a List type.
* @param[out] l List to which the variable should be appended. * @param[out] l List to which the variable should be appended.
* @param[in] n variable to be appended to the list. * @param[in] n variable to be appended to the list.
* @returns Returns 0 if successful and 1 if failed.
*/ */
void addToList(List *l, mpz_t n); int addToList(List *restrict l, mpz_t n);

View File

@ -4,13 +4,14 @@
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <gmp.h> #include <gmp.h>
#include <omp.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "list.h" #include "list.h"
#include "files.h" #include "files.h"
#define VERSION "v0.7" #define VERSION "v1.0"
static bool run; static bool run;
@ -23,12 +24,13 @@ int main(int argc, char *argv[]) {
f_version = false, f_version = false,
f_quiet = false; f_quiet = false;
int base = 10; int base = 10;
char *file = NULL; size_t n_prime = 0;
char *dfile = NULL;
char *efile = NULL; char *efile = NULL;
// Parse commandline arguments // Parse commandline arguments
int c; int c;
while((c = getopt(argc, argv, "hvqb:f:e:")) != -1) { while((c = getopt(argc, argv, "hvqb:f:e:n:")) != -1) {
switch(c) { switch(c) {
case 'h': case 'h':
f_help = true; f_help = true;
@ -45,15 +47,23 @@ int main(int argc, char *argv[]) {
fprintf(stderr, fprintf(stderr,
"Invalid base `%d'. Base must be between 2 and 62.\n", "Invalid base `%d'. Base must be between 2 and 62.\n",
base); base);
exit(1); return 1;
} }
break; break;
case 'f': case 'f':
file = optarg; dfile = optarg;
break; break;
case 'e': case 'e':
efile = optarg; efile = optarg;
break; break;
case 'n':
n_prime = atoi(optarg);
if(n_prime <= 2) {
fprintf(stderr,
"`n' must be larger than 2 (first two primes are 2 and 3).\n");
return 1;
}
break;
default: default:
printUsage(argv[0]); printUsage(argv[0]);
return 1; return 1;
@ -63,153 +73,201 @@ int main(int argc, char *argv[]) {
// Act based on which flags were used // Act based on which flags were used
if(f_help) { if(f_help) {
printUsage(argv[0]); printUsage(argv[0]);
puts("\nArguments:");
puts(" -h print this help information"); puts(" -h print this help information");
puts(" -v print version number of program"); puts(" -v print version number of program");
puts(" -q quiet mode"); puts(" -q quiet mode");
puts(" -b <base> base in which to print primes between 2 and 62 (default 10)"); puts(" -b <base> base in which to print primes between 2 and 62 (default 10)");
puts(" -f <file> file in/from which primes are stored and read from in raw format"); puts(" -f <file> file in/from which primes are stored and read from in raw format");
puts(" -e <file> export input file to plain text format"); puts(" -e <file> export input file to plain text format");
puts(" -n <n> run until the 'n'th prime\n");
return 0; return 0;
} else if(f_version) { } else if(f_version) {
printf("Indivisible %s\n", VERSION); printf("Indivisible %s\n", VERSION);
return 0; return 0;
} else if(f_quiet && !dfile) {
puts("Error: you cannot run in quiet mode without specifying a data file.");
printUsage(argv[0]);
return 0;
}
if(efile && !dfile) {
puts("Error: you must have a file to export to.");
printUsage(argv[0]);
return 0;
} else if(efile && dfile) {
exportPrimes(efile, dfile, base);
return 0;
}
if(!omp_get_cancellation()) {
puts("Warning: the OpenMP cancellation environment variable (`OMP_CANCELLATION') is not enabled.");
char in;
while(true) {
printf("[e]nable/[c]ontinue/[q]uit? ");
scanf("%c", &in);
if(in == 'e' || in == 'E') {
putenv("OMP_CANCELLATION=true");
execv(argv[0], argv);
} else if(in == 'c' || in == 'C') {
break;
} else if(in == 'q' || in == 'Q') {
return 0;
}
}
} }
// Quit on ^C by setting `run = false' // Quit on ^C by setting `run = false'
run = true; run = true;
signal(SIGINT, leave); signal(SIGINT, leave);
if(efile != NULL && file == NULL) { puts("Use Ctrl+C to exit.");
fprintf(stderr, "There must be an input file to export! Use `-h' for help.\n");
return 1;
}
bool newFile = true; bool newFile = true;
if(file != NULL) { if(dfile) {
struct stat s; struct stat s;
if(stat(file, &s) == 0) newFile = false; if(stat(dfile, &s) == 0) newFile = false;
} }
// Last position added from file
size_t startPos = 0;
int exitCode = 0; int exitCode = 0;
// Primes we've found // Primes we've found
List primes; List primes;
initList(&primes); if(initList(&primes) == 1) {
fprintf(stderr, "Failed to initialize primes list.\n");
exit(1);
}
// The number we're going to be testing for // The number we're going to be testing for
mpz_t num; mpz_t num;
mpz_init(num); mpz_init(num);
// Variable for half `num' // Variable for sqrt of `num'
mpz_t halfNum; mpz_t numRoot;
mpz_init(halfNum); mpz_init(numRoot);
// Index of the prime number above and closest to `numRoot'
if(efile == NULL) puts("Use Ctrl+C to exit."); size_t rootInd = 0;
if(newFile) { if(newFile) {
// Add 2, a known prime to this list // Add 2, a known prime to this list
mpz_set_ui(num, 2); mpz_set_ui(num, 2);
addToList(&primes, num); if(addToList(&primes, num) == 1) {
if(!f_quiet) { fprintf(stderr, "Failed to allocate more memory for list.\n");
if(mpz_out_str(stdout, base, num) == 0) { exitCode = 1;
fprintf(stderr, "Could not print to `stdout'!\n"); goto releaseMemory;
exitCode = 1; }
goto releaseMemory; // Add 3 as well to optimize the algorithm
} mpz_set_ui(num, 3);
printf("\n"); if(addToList(&primes, num) == 1) {
fprintf(stderr, "Failed to allocate more memory for list.\n");
exitCode = 1;
goto releaseMemory;
}
if(!f_quiet) {
puts("2\n3");
} }
mpz_add_ui(num, num, 1);
} else { } else {
// Load primes from file // Load primes from file
int err = inputPrimes(file, &primes); int err = inputPrimes(dfile, &primes);
startPos = primes.end;
if(err == 0) { if(err == 0) {
printf("Loaded %zu primes.\n", primes.end); printf("Loaded %zu primes.\n", primes.end);
} else { } else {
if(err == 1) if(err == 1)
fprintf(stderr, "Failed to open Indivisible file `%s'.\n", file); fprintf(stderr, "Failed to open Indivisible file `%s'.\n", dfile);
else if(err == 2) else if(err == 2)
fprintf(stderr, "Failed to close Indivisible file `%s'.\n", file); fprintf(stderr, "Failed to close Indivisible file `%s'.\n", dfile);
else if(err == 3)
fprintf(stderr, "Failed to allocate more memory for list.\n");
exitCode = 1; exitCode = 1;
goto releaseMemory; goto releaseMemory;
} }
/** /**
* Yes, I realize there's a -1 here, I don't know why but it won't * I set to `primes.end-1' because primes.end indicates the next new
* work if it's not there, so don't change it unless necessary. * element in the list that can be used, which is also equal to the total
* number of elements in the list.
*/ */
mpz_set(num, primes.list[primes.end-1]); mpz_set(num, primes.list[primes.end-1]);
} }
if(efile != NULL) { while(run) {
int err = exportPrimes(efile, &primes, base); mpz_add_ui(num, num, 2);
if(err == 0) { // Calculate the sqrt(num)
puts("Successfully exported primes."); mpz_sqrt(numRoot, num);
} else {
if(err == 1)
fprintf(stderr, "Failed to open/create plain text file `%s'.\n", efile);
else if(err == 2)
fprintf(stderr, "Failed to close plain text file `%s'.\n", efile);
else if(err == 3)
fprintf(stderr, "Failed to write prime to plain text file `%s'.\n", efile);
exitCode = 1;
}
goto releaseMemory;
}
do { while(mpz_cmp(primes.list[rootInd], numRoot) <= 0) {
// Calculate half of `num' if(++rootInd > primes.end) {
mpz_fdiv_q_ui(halfNum, num, 2); fprintf(stderr, "Error: `rootInd' surpassed `primes.end'.\n");
/**
* Loop through primes we've found until we get to half of the number
* we're analyzing
*/
for(size_t i = 0; mpz_cmp(primes.list[i], halfNum) < 0; ++i) {
// If `num' is divisible by a prime then go to the next number
if(mpz_divisible_p(num, primes.list[i]) != 0)
goto nextPrime;
}
// `num' is a prime so we add it to the list and print it
addToList(&primes, num);
if(!f_quiet) {
if(mpz_out_str(stdout, base, num) == 0) {
fprintf(stderr, "Could not print to `stdout'!\n");
exitCode = 1; exitCode = 1;
goto releaseMemory; goto releaseMemory;
} }
printf("\n");
} }
nextPrime: bool isPrime = true;
// Add 2 (skip even numbers since they're all divisible by 2) /**
mpz_add_ui(num, num, 2); * Loop through primes we've found until we get to the sqrt of the
} while(run); * number we're analyzing. Also, skip `2' since we're not testing even
* numbers.
*/
#pragma omp parallel
{
#pragma omp for
for(size_t i = 1; i < rootInd; ++i) {
if(mpz_divisible_p(num, primes.list[i])) {
#pragma omp atomic write
isPrime = false;
#pragma omp cancel for
}
#pragma omp cancellation point for
}
}
if(isPrime) {
// `num' is a prime so we add it to the list and print it
if(addToList(&primes, num) == 1) {
fprintf(stderr, "Failed to allocate more memory for list.\n");
exitCode = 1;
goto releaseMemory;
}
if(!f_quiet) {
if(!mpz_out_str(stdout, base, num))
fprintf(stderr, "Could not print to `stdout'!\n");
printf("\n");
}
}
if(primes.end == n_prime) break;
}
printf("Found %zu primes.\n", primes.end); printf("Found %zu primes.\n", primes.end);
if(file != NULL) { if(dfile) {
int err = outputPrimes(file, &primes); int err = outputPrimes(dfile, &primes, startPos);
if(err == 0) { if(err == 0) {
puts("Successfully saved primes."); puts("Successfully saved primes.");
} else { } else {
if(err == 1) if(err == 1)
fprintf(stderr, "Failed to open/create file `%s'.\n", file); fprintf(stderr, "Failed to open/create file `%s'.\n", dfile);
else if(err == 2) else if(err == 2)
fprintf(stderr, "Failed to close file `%s'.\n", file); fprintf(stderr, "Failed to close file `%s'.\n", dfile);
else if(err == 3) else if(err == 3)
fprintf(stderr, "Failed while writing a prime to `%s'.\n", file); fprintf(stderr, "Failed while writing a prime to `%s'.\n", dfile);
exitCode = 1; exitCode = 1;
goto releaseMemory; goto releaseMemory;
} }
} }
// Clear GMP variables
mpz_clear(halfNum);
mpz_clear(num);
releaseMemory: releaseMemory:
puts("Clearing memory..."); puts("Clearing memory...");
// Clear GMP variables
mpz_clear(numRoot);
mpz_clear(num);
// Deinitialize the list // Deinitialize the list
deInitList(&primes); deInitList(&primes);
@ -218,7 +276,7 @@ releaseMemory:
} }
void printUsage(char *progName) { void printUsage(char *progName) {
printf("%s [OPTIONS]\n", progName); printf("%s [[-f <file> [-e <file> | -q]] [-b <base>] [-n <n>] | [-h] | [-v]]\n", progName);
} }
void leave() { run = false; } void leave() { run = false; }