text:
Editorial Note: This document describes SQLite version 2, which was deprecated and replaced by SQLite3 in 2004. This document is retained as part of the historical record of SQLite. Modern programmers should refer to more up-to-date documentation on SQLite is available elsewhere on this website. |
The SQLite library is designed to be very easy to use from a C or C++ program. This document gives an overview of the C/C++ programming interface.
The interface to the SQLite library consists of three core functions, one opaque data structure, and some constants used as return values. The core interface is as follows:
typedef struct sqlite sqlite; #define SQLITE_OK 0 /* Successful result */ sqlite *sqlite_open(const char *dbname, int mode, char **errmsg); void sqlite_close(sqlite *db); int sqlite_exec( sqlite *db, char *sql, int (*xCallback)(void*,int,char**,char**), void *pArg, char **errmsg );
The above is all you really need to know in order to use SQLite in your C or C++ programs. There are other interface functions available (and described below) but we will begin by describing the core functions shown above.
Use the sqlite_open function to open an existing SQLite database or to create a new SQLite database. The first argument is the database name. The second argument is intended to signal whether the database is going to be used for reading and writing or just for reading. But in the current implementation, the second argument to sqlite_open is ignored. The third argument is a pointer to a string pointer. If the third argument is not NULL and an error occurs while trying to open the database, then an error message will be written to memory obtained from malloc() and *errmsg will be made to point to this error message. The calling function is responsible for freeing the memory when it has finished with it.
The name of an SQLite database is the name of a file that will contain the database. If the file does not exist, SQLite attempts to create and initialize it. If the file is read-only (due to permission bits or because it is located on read-only media like a CD-ROM) then SQLite opens the database for reading only. The entire SQL database is stored in a single file on the disk. But additional temporary files may be created during the execution of an SQL command in order to store the database rollback journal or temporary and intermediate results of a query.
The return value of the sqlite_open function is a pointer to an opaque sqlite structure. This pointer will be the first argument to all subsequent SQLite function calls that deal with the same database. NULL is returned if the open fails for any reason.
To close an SQLite database, call the sqlite_close function passing it the sqlite structure pointer that was obtained from a prior call to sqlite_open. If a transaction is active when the database is closed, the transaction is rolled back.
The sqlite_exec function is used to process SQL statements and queries. This function requires 5 parameters as follows:
A pointer to the sqlite structure obtained from a prior call to sqlite_open.
A zero-terminated string containing the text of one or more SQL statements and/or queries to be processed.
A pointer to a callback function which is invoked once for each row in the result of a query. This argument may be NULL, in which case no callbacks will ever be invoked.
A pointer that is forwarded to become the first argument to the callback function.
A pointer to an error string. Error messages are written to space obtained from malloc() and the error string is made to point to the malloced space. The calling function is responsible for freeing this space when it has finished with it. This argument may be NULL, in which case error messages are not reported back to the calling function.
The callback function is used to receive the results of a query. A prototype for the callback function is as follows:
int Callback(void *pArg, int argc, char **argv, char **columnNames){ return 0; }
The first argument to the callback is just a copy of the fourth argument to sqlite_exec This parameter can be used to pass arbitrary information through to the callback function from client code. The second argument is the number of columns in the query result. The third argument is an array of pointers to strings where each string is a single column of the result for that record. Note that the callback function reports a NULL value in the database as a NULL pointer, which is very different from an empty string. If the i-th parameter is an empty string, we will get:
argv[i][0] == 0
But if the i-th parameter is NULL we will get:
argv[i] == 0
The names of the columns are contained in first argc entries of the fourth argument. If the SHOW_DATATYPES pragma is on (it is off by default) then the second argc entries in the 4th argument are the datatypes for the corresponding columns.
If the EMPTY_RESULT_CALLBACKS pragma is set to ON and the result of a query is an empty set, then the callback is invoked once with the third parameter (argv) set to 0. In other words
The second parameter (argc) and the fourth parameter (columnNames) are still valid and can be used to determine the number and names of the result columns if there had been a result. The default behavior is not to invoke the callback at all if the result set is empty.argv == 0
The callback function should normally return 0. If the callback function returns non-zero, the query is immediately aborted and sqlite_exec will return SQLITE_ABORT.
The sqlite_exec function normally returns SQLITE_OK. But if something goes wrong it can return a different value to indicate the type of error. Here is a complete list of the return codes:
#define SQLITE_OK 0 /* Successful result */ #define SQLITE_ERROR 1 /* SQL error or missing database */ #define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ #define SQLITE_BUSY 5 /* The database file is locked */ #define SQLITE_LOCKED 6 /* A table in the database is locked */ #define SQLITE_NOMEM 7 /* A malloc() failed */ #define SQLITE_READONLY 8 /* Attempt to write a readonly database */ #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */ #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ #define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */ #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ #define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* Too much data for one row of a table */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_ROW 100 /* sqlite_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite_step() has finished executing */
The meanings of these various return values are as follows:
This value is returned if everything worked and there were no errors.
This value indicates that an internal consistency check within the SQLite library failed. This can only happen if there is a bug in the SQLite library. If you ever get an SQLITE_INTERNAL reply from an sqlite_exec call, please report the problem on the SQLite mailing list.
This return value indicates that there was an error in the SQL that was passed into the sqlite_exec.
This return value says that the access permissions on the database file are such that the file cannot be opened.
This value is returned if the callback function returns non-zero.
This return code indicates that another program or thread has the database locked. SQLite allows two or more threads to read the database at the same time, but only one thread can have the database open for writing at the same time. Locking in SQLite is on the entire database.
This return code is similar to SQLITE_BUSY in that it indicates that the database is locked. But the source of the lock is a recursive call to sqlite_exec. This return can only occur if you attempt to invoke sqlite_exec from within a callback routine of a query from a prior invocation of sqlite_exec. Recursive calls to sqlite_exec are allowed as long as they do not attempt to write the same table.
This value is returned if a call to malloc fails.
This return code indicates that an attempt was made to write to a database file that is opened for reading only.
This value is returned if a call to sqlite_interrupt interrupts a database operation in progress.
This value is returned if the operating system informs SQLite that it is unable to perform some disk I/O operation. This could mean that there is no more space left on the disk.
This value is returned if SQLite detects that the database it is working on has become corrupted. Corruption might occur due to a rogue process writing to the database file or it might happen due to a previously undetected logic error in of SQLite. This value is also returned if a disk I/O error occurs in such a way that SQLite is forced to leave the database file in a corrupted state. The latter should only happen due to a hardware or operating system malfunction.
This value is returned if an insertion failed because there is no space left on the disk, or the database is too big to hold any more information. The latter case should only occur for databases that are larger than 2GB in size.
This value is returned if the database file could not be opened for some reason.
This value is returned if some other process is messing with file locks and has violated the file locking protocol that SQLite uses on its rollback journal files.
When the database first opened, SQLite reads the database schema into memory and uses that schema to parse new SQL statements. If another process changes the schema, the command currently being processed will abort because the virtual machine code generated assumed the old schema. This is the return code for such cases. Retrying the command usually will clear the problem.
SQLite will not store more than about 1 megabyte of data in a single row of a single table. If you attempt to store more than 1 megabyte in a single row, this is the return code you get.
This constant is returned if the SQL statement would have violated a database constraint.
This error occurs when there is an attempt to insert non-integer data into a column labeled INTEGER PRIMARY KEY. For most columns, SQLite ignores the data type and allows any kind of data to be stored. But an INTEGER PRIMARY KEY column is only allowed to store integer data.
This error might occur if one or more of the SQLite API routines is used incorrectly. Examples of incorrect usage include calling sqlite_exec after the database has been closed using sqlite_close or calling sqlite_exec with the same database pointer simultaneously from two separate threads.
This error means that you have attempts to create or access a file database file that is larger that 2GB on a legacy Unix machine that lacks large file support.
This error indicates that the authorizer callback has disallowed the SQL you are attempting to execute.
This is one of the return codes from the sqlite_step routine which is part of the non-callback API. It indicates that another row of result data is available.
This is one of the return codes from the sqlite_step routine which is part of the non-callback API. It indicates that the SQL statement has been completely executed and the sqlite_finalize routine is ready to be called.
The sqlite_exec routine described above used to be the only way to retrieve data from an SQLite database. But many programmers found it inconvenient to use a callback function to obtain results. So beginning with SQLite version 2.7.7, a second access interface is available that does not use callbacks.
The new interface uses three separate functions to replace the single sqlite_exec function.
typedef struct sqlite_vm sqlite_vm; int sqlite_compile( sqlite *db, /* The open database */ const char *zSql, /* SQL statement to be compiled */ const char **pzTail, /* OUT: uncompiled tail of zSql */ sqlite_vm **ppVm, /* OUT: the virtual machine to execute zSql */ char **pzErrmsg /* OUT: Error message. */ ); int sqlite_step( sqlite_vm *pVm, /* The virtual machine to execute */ int *pN, /* OUT: Number of columns in result */ const char ***pazValue, /* OUT: Column data */ const char ***pazColName /* OUT: Column names and datatypes */ ); int sqlite_finalize( sqlite_vm *pVm, /* The virtual machine to be finalized */ char **pzErrMsg /* OUT: Error message */ );
The strategy is to compile a single SQL statement using sqlite_compile then invoke sqlite_step multiple times, once for each row of output, and finally call sqlite_finalize to clean up after the SQL has finished execution.
The sqlite_compile "compiles" a single SQL statement (specified by the second parameter) and generates a virtual machine that is able to execute that statement. As with must interface routines, the first parameter must be a pointer to an sqlite structure that was obtained from a prior call to sqlite_open.
A pointer to the virtual machine is stored in a pointer which is passed in as the 4th parameter. Space to hold the virtual machine is dynamically allocated. To avoid a memory leak, the calling function must invoke sqlite_finalize on the virtual machine after it has finished with it. The 4th parameter may be set to NULL if an error is encountered during compilation.
If any errors are encountered during compilation, an error message is written into memory obtained from malloc and the 5th parameter is made to point to that memory. If the 5th parameter is NULL, then no error message is generated. If the 5th parameter is not NULL, then the calling function should dispose of the memory containing the error message by calling sqlite_freemem.
If the 2nd parameter actually contains two or more statements of SQL, only the first statement is compiled. (This is different from the behavior of sqlite_exec which executes all SQL statements in its input string.) The 3rd parameter to sqlite_compile is made to point to the first character beyond the end of the first statement of SQL in the input. If the 2nd parameter contains only a single SQL statement, then the 3rd parameter will be made to point to the '\000' terminator at the end of the 2nd parameter.
On success, sqlite_compile returns SQLITE_OK. Otherwise and error code is returned.
After a virtual machine has been generated using sqlite_compile it is executed by one or more calls to sqlite_step. Each invocation of sqlite_step, except the last one, returns a single row of the result. The number of columns in the result is stored in the integer that the 2nd parameter points to. The pointer specified by the 3rd parameter is made to point to an array of pointers to column values. The pointer in the 4th parameter is made to point to an array of pointers to column names and datatypes. The 2nd through 4th parameters to sqlite_step convey the same information as the 2nd through 4th parameters of the callback routine when using the sqlite_exec interface. Except, with sqlite_step the column datatype information is always included in the in the 4th parameter regardless of whether or not the SHOW_DATATYPES pragma is on or off.
Each invocation of sqlite_step returns an integer code that indicates what happened during that step. This code may be SQLITE_BUSY, SQLITE_ROW, SQLITE_DONE, SQLITE_ERROR, or SQLITE_MISUSE.
If the virtual machine is unable to open the database file because it is locked by another thread or process, sqlite_step will return SQLITE_BUSY. The calling function should do some other activity, or sleep, for a short amount of time to give the lock a chance to clear, then invoke sqlite_step again. This can be repeated as many times as desired.
Whenever another row of result data is available, sqlite_step will return SQLITE_ROW. The row data is stored in an array of pointers to strings and the 2nd parameter is made to point to this array.
When all processing is complete, sqlite_step will return either SQLITE_DONE or SQLITE_ERROR. SQLITE_DONE indicates that the statement completed successfully and SQLITE_ERROR indicates that there was a run-time error. (The details of the error are obtained from sqlite_finalize.) It is a misuse of the library to attempt to call sqlite_step again after it has returned SQLITE_DONE or SQLITE_ERROR.
When sqlite_step returns SQLITE_DONE or SQLITE_ERROR, the *pN and *pazColName values are set to the number of columns in the result set and to the names of the columns, just as they are for an SQLITE_ROW return. This allows the calling code to find the number of result columns and the column names and datatypes even if the result set is empty. The *pazValue parameter is always set to NULL when the return codes is SQLITE_DONE or SQLITE_ERROR. If the SQL being executed is a statement that does not return a result (such as an INSERT or an UPDATE) then *pN will be set to zero and *pazColName will be set to NULL.
If you abuse the library by trying to call sqlite_step inappropriately it will attempt return SQLITE_MISUSE. This can happen if you call sqlite_step() on the same virtual machine at the same time from two or more threads or if you call sqlite_step() again after it returned SQLITE_DONE or SQLITE_ERROR or if you pass in an invalid virtual machine pointer to sqlite_step(). You should not depend on the SQLITE_MISUSE return code to indicate an error. It is possible that a misuse of the interface will go undetected and result in a program crash. The SQLITE_MISUSE is intended as a debugging aid only - to help you detect incorrect usage prior to a mishap. The misuse detection logic is not guaranteed to work in every case.
Every virtual machine that sqlite_compile creates should eventually be handed to sqlite_finalize. The sqlite_finalize() procedure deallocates the memory and other resources that the virtual machine uses. Failure to call sqlite_finalize() will result in resource leaks in your program.
The sqlite_finalize routine also returns the result code that indicates success or failure of the SQL operation that the virtual machine carried out. The value returned by sqlite_finalize() will be the same as would have been returned had the same SQL been executed by sqlite_exec. The error message returned will also be the same.
It is acceptable to call sqlite_finalize on a virtual machine before sqlite_step has returned SQLITE_DONE. Doing so has the effect of interrupting the operation in progress. Partially completed changes will be rolled back and the database will be restored to its original state (unless an alternative recovery algorithm is selected using an ON CONFLICT clause in the SQL being executed.) The effect is the same as if a callback function of sqlite_exec had returned non-zero.
It is also acceptable to call sqlite_finalize on a virtual machine that has never been passed to sqlite_step even once.
Only the three core routines described in section 1.0 are required to use SQLite. But there are many other functions that provide useful interfaces. These extended routines are as follows:
int sqlite_last_insert_rowid(sqlite*); int sqlite_changes(sqlite*); int sqlite_get_table( sqlite*, char *sql, char ***result, int *nrow, int *ncolumn, char **errmsg ); void sqlite_free_table(char**); void sqlite_interrupt(sqlite*); int sqlite_complete(const char *sql); void sqlite_busy_handler(sqlite*, int (*)(void*,const char*,int), void*); void sqlite_busy_timeout(sqlite*, int ms); const char sqlite_version[]; const char sqlite_encoding[]; int sqlite_exec_printf( sqlite*, char *sql, int (*)(void*,int,char**,char**), void*, char **errmsg, ... ); int sqlite_exec_vprintf( sqlite*, char *sql, int (*)(void*,int,char**,char**), void*, char **errmsg, va_list ); int sqlite_get_table_printf( sqlite*, char *sql, char ***result, int *nrow, int *ncolumn, char **errmsg, ... ); int sqlite_get_table_vprintf( sqlite*, char *sql, char ***result, int *nrow, int *ncolumn, char **errmsg, va_list ); char *sqlite_mprintf(const char *zFormat, ...); char *sqlite_vmprintf(const char *zFormat, va_list); void sqlite_freemem(char*); void sqlite_progress_handler(sqlite*, int, int (*)(void*), void*);
All of the above definitions are included in the "sqlite.h" header file that comes in the source tree.
Every row of an SQLite table has a unique integer key. If the table has a column labeled INTEGER PRIMARY KEY, then that column serves as the key. If there is no INTEGER PRIMARY KEY column then the key is a unique integer. The key for a row can be accessed in a SELECT statement or used in a WHERE or ORDER BY clause using any of the names "ROWID", "OID", or "_ROWID_".
When you do an insert into a table that does not have an INTEGER PRIMARY KEY column, or if the table does have an INTEGER PRIMARY KEY but the value for that column is not specified in the VALUES clause of the insert, then the key is automatically generated. You can find the value of the key for the most recent INSERT statement using the sqlite_last_insert_rowid API function.
The sqlite_changes API function returns the number of rows that have been inserted, deleted, or modified since the database was last quiescent. A "quiescent" database is one in which there are no outstanding calls to sqlite_exec and no VMs created by sqlite_compile that have not been finalized by sqlite_finalize. In common usage, sqlite_changes returns the number of rows inserted, deleted, or modified by the most recent sqlite_exec call or since the most recent sqlite_compile. But if you have nested calls to sqlite_exec (that is, if the callback routine of one sqlite_exec invokes another sqlite_exec) or if you invoke sqlite_compile to create a new VM while there is still another VM in existence, then the meaning of the number returned by sqlite_changes is more complex. The number reported includes any changes that were later undone by a ROLLBACK or ABORT. But rows that are deleted because of a DROP TABLE are not counted.
SQLite implements the command "DELETE FROM table" (without a WHERE clause) by dropping the table then recreating it. This is much faster than deleting the elements of the table individually. But it also means that the value returned from sqlite_changes will be zero regardless of the number of elements that were originally in the table. If an accurate count of the number of elements deleted is necessary, use "DELETE FROM table WHERE 1" instead.
The sqlite_get_table function is a wrapper around sqlite_exec that collects all the information from successive callbacks and writes it into memory obtained from malloc(). This is a convenience function that allows the application to get the entire result of a database query with a single function call.
The main result from sqlite_get_table is an array of pointers to strings. There is one element in this array for each column of each row in the result. NULL results are represented by a NULL pointer. In addition to the regular data, there is an added row at the beginning of the array that contains the name of each column of the result.
As an example, consider the following query:
SELECT employee_name, login, host FROM users WHERE login LIKE 'd%';
This query will return the name, login and host computer name for every employee whose login begins with the letter "d". If this query is submitted to sqlite_get_table the result might look like this:
nrow = 2
ncolumn = 3
result[0] = "employee_name"
result[1] = "login"
result[2] = "host"
result[3] = "dummy"
result[4] = "No such user"
result[5] = 0
result[6] = "D. Richard Hipp"
result[7] = "drh"
result[8] = "zadok"
Notice that the "host" value for the "dummy" record is NULL so the result[] array contains a NULL pointer at that slot.
If the result set of a query is empty, then by default sqlite_get_table will set nrow to 0 and leave its result parameter is set to NULL. But if the EMPTY_RESULT_CALLBACKS pragma is ON then the result parameter is initialized to the names of the columns only. For example, consider this query which has an empty result set:
SELECT employee_name, login, host FROM users WHERE employee_name IS NULL;
The default behavior gives this results:
nrow = 0
ncolumn = 0
result = 0
But if the EMPTY_RESULT_CALLBACKS pragma is ON, then the following is returned:
nrow = 0
ncolumn = 3
result[0] = "employee_name"
result[1] = "login"
result[2] = "host"
Memory to hold the information returned by sqlite_get_table is obtained from malloc(). But the calling function should not try to free this information directly. Instead, pass the complete table to sqlite_free_table when the table is no longer needed. It is safe to call sqlite_free_table with a NULL pointer such as would be returned if the result set is empty.
The sqlite_get_table routine returns the same integer result code as sqlite_exec.
The sqlite_interrupt function can be called from a different thread or from a signal handler to cause the current database operation to exit at its first opportunity. When this happens, the sqlite_exec routine (or the equivalent) that started the database operation will return SQLITE_INTERRUPT.
The next interface routine to SQLite is a convenience function used to test whether or not a string forms a complete SQL statement. If the sqlite_complete function returns true when its input is a string, then the argument forms a complete SQL statement. There are no guarantees that the syntax of that statement is correct, but we at least know the statement is complete. If sqlite_complete returns false, then more text is required to complete the SQL statement.
For the purpose of the sqlite_complete function, an SQL statement is complete if it ends in a semicolon.
The sqlite command-line utility uses the sqlite_complete function to know when it needs to call sqlite_exec. After each line of input is received, sqlite calls sqlite_complete on all input in its buffer. If sqlite_complete returns true, then sqlite_exec is called and the input buffer is reset. If sqlite_complete returns false, then the prompt is changed to the continuation prompt and another line of text is read and added to the input buffer.
The SQLite library exports the string constant named sqlite_version which contains the version number of the library. The header file contains a macro SQLITE_VERSION with the same information. If desired, a program can compare the SQLITE_VERSION macro against the sqlite_version string constant to verify that the version number of the header file and the library match.
By default, SQLite assumes that all data uses a fixed-size 8-bit character (iso8859). But if you give the --enable-utf8 option to the configure script, then the library assumes UTF-8 variable sized characters. This makes a difference for the LIKE and GLOB operators and the LENGTH() and SUBSTR() functions. The static string sqlite_encoding will be set to either "UTF-8" or "iso8859" to indicate how the library was compiled. In addition, the sqlite.h header file will define one of the macros SQLITE_UTF8 or SQLITE_ISO8859, as appropriate.
Note that the character encoding mechanism used by SQLite cannot be changed at run-time. This is a compile-time option only. The sqlite_encoding character string just tells you how the library was compiled.
The sqlite_busy_handler procedure can be used to register a busy callback with an open SQLite database. The busy callback will be invoked whenever SQLite tries to access a database that is locked. The callback will typically do some other useful work, or perhaps sleep, in order to give the lock a chance to clear. If the callback returns non-zero, then SQLite tries again to access the database and the cycle repeats. If the callback returns zero, then SQLite aborts the current operation and returns SQLITE_BUSY.
The arguments to sqlite_busy_handler are the opaque structure returned from sqlite_open, a pointer to the busy callback function, and a generic pointer that will be passed as the first argument to the busy callback. When SQLite invokes the busy callback, it sends it three arguments: the generic pointer that was passed in as the third argument to sqlite_busy_handler, the name of the database table or index that the library is trying to access, and the number of times that the library has attempted to access the database table or index.
For the common case where we want the busy callback to sleep, the SQLite library provides a convenience routine sqlite_busy_timeout. The first argument to sqlite_busy_timeout is a pointer to an open SQLite database and the second argument is a number of milliseconds. After sqlite_busy_timeout has been executed, the SQLite library will wait for the lock to clear for at least the number of milliseconds specified before it returns SQLITE_BUSY. Specifying zero milliseconds for the timeout restores the default behavior.
The four utility functions
implement the same query functionality as sqlite_exec and sqlite_get_table. But instead of taking a complete SQL statement as their second argument, the four _printf routines take a printf-style format string. The SQL statement to be executed is generated from this format string and from whatever additional arguments are attached to the end of the function call.
There are two advantages to using the SQLite printf functions instead of sprintf. First of all, with the SQLite printf routines, there is never a danger of overflowing a static buffer as there is with sprintf. The SQLite printf routines automatically allocate (and later frees) as much memory as is necessary to hold the SQL statements generated.
The second advantage the SQLite printf routines have over sprintf are two new formatting options specifically designed to support string literals in SQL. Within the format string, the %q formatting option works very much like %s in that it reads a null-terminated string from the argument list and inserts it into the result. But %q translates the inserted string by making two copies of every single-quote (') character in the substituted string. This has the effect of escaping the end-of-string meaning of single-quote within a string literal. The %Q formatting option works similar; it translates the single-quotes like %q and additionally encloses the resulting string in single-quotes. If the argument for the %Q formatting options is a NULL pointer, the resulting string is NULL without single quotes.
Consider an example. Suppose you are trying to insert a string value into a database table where the string value was obtained from user input. Suppose the string to be inserted is stored in a variable named zString. The code to do the insertion might look like this:
sqlite_exec_printf(db, "INSERT INTO table1 VALUES('%s')", 0, 0, 0, zString);
If the zString variable holds text like "Hello", then this statement will work just fine. But suppose the user enters a string like "Hi y'all!". The SQL statement generated reads as follows:
INSERT INTO table1 VALUES('Hi y'all')
This is not valid SQL because of the apostrophe in the word "y'all". But if the %q formatting option is used instead of %s, like this:
sqlite_exec_printf(db, "INSERT INTO table1 VALUES('%q')", 0, 0, 0, zString);
Then the generated SQL will look like the following:
INSERT INTO table1 VALUES('Hi y''all')
Here the apostrophe has been escaped and the SQL statement is well-formed. When generating SQL on-the-fly from data that might contain a single-quote character ('), it is always a good idea to use the SQLite printf routines and the %q formatting option instead of sprintf.
If the %Q formatting option is used instead of %q, like this:
sqlite_exec_printf(db, "INSERT INTO table1 VALUES(%Q)", 0, 0, 0, zString);
Then the generated SQL will look like the following:
INSERT INTO table1 VALUES('Hi y''all')
If the value of the zString variable is NULL, the generated SQL will look like the following:
INSERT INTO table1 VALUES(NULL)
All of the _printf() routines above are built around the following two functions:
char *sqlite_mprintf(const char *zFormat, ...); char *sqlite_vmprintf(const char *zFormat, va_list);
The sqlite_mprintf() routine works like the standard library sprintf() except that it writes its results into memory obtained from malloc() and returns a pointer to the malloced buffer. sqlite_mprintf() also understands the %q and %Q extensions described above. The sqlite_vmprintf() is a varargs version of the same routine. The string pointer that these routines return should be freed by passing it to sqlite_freemem().
The sqlite_progress_handler() routine can be used to register a callback routine with an SQLite database to be invoked periodically during long running calls to sqlite_exec(), sqlite_step() and the various wrapper functions.
The callback is invoked every N virtual machine operations, where N is supplied as the second argument to sqlite_progress_handler(). The third and fourth arguments to sqlite_progress_handler() are a pointer to the routine to be invoked and a void pointer to be passed as the first argument to it.
The time taken to execute each virtual machine operation can vary based on many factors. A typical value for a 1 GHz PC is between half and three million per second but may be much higher or lower, depending on the query. As such it is difficult to schedule background operations based on virtual machine operations. Instead, it is recommended that a callback be scheduled relatively frequently (say every 1000 instructions) and external timer routines used to determine whether or not background jobs need to be run.
Beginning with version 2.4.0, SQLite allows the SQL language to be extended with new functions implemented as C code. The following interface is used:
typedef struct sqlite_func sqlite_func; int sqlite_create_function( sqlite *db, const char *zName, int nArg, void (*xFunc)(sqlite_func*,int,const char**), void *pUserData ); int sqlite_create_aggregate( sqlite *db, const char *zName, int nArg, void (*xStep)(sqlite_func*,int,const char**), void (*xFinalize)(sqlite_func*), void *pUserData ); char *sqlite_set_result_string(sqlite_func*,const char*,int); void sqlite_set_result_int(sqlite_func*,int); void sqlite_set_result_double(sqlite_func*,double); void sqlite_set_result_error(sqlite_func*,const char*,int); void *sqlite_user_data(sqlite_func*); void *sqlite_aggregate_context(sqlite_func*, int nBytes); int sqlite_aggregate_count(sqlite_func*);
The sqlite_create_function() interface is used to create regular functions and sqlite_create_aggregate() is used to create new aggregate functions. In both cases, the db parameter is an open SQLite database on which the functions should be registered, zName is the name of the new function, nArg is the number of arguments, and pUserData is a pointer which is passed through unchanged to the C implementation of the function. Both routines return 0 on success and non-zero if there are any errors.
The length of a function name may not exceed 255 characters. Any attempt to create a function whose name exceeds 255 characters in length will result in an error.
For regular functions, the xFunc callback is invoked once for each function call. The implementation of xFunc should call one of the sqlite_set_result_... interfaces to return its result. The sqlite_user_data() routine can be used to retrieve the pUserData pointer that was passed in when the function was registered.
For aggregate functions, the xStep callback is invoked once for each row in the result and then xFinalize is invoked at the end to compute a final answer. The xStep routine can use the sqlite_aggregate_context() interface to allocate memory that will be unique to that particular instance of the SQL function. This memory will be automatically deleted after xFinalize is called. The sqlite_aggregate_count() routine can be used to find out how many rows of data were passed to the aggregate. The xFinalize callback should invoke one of the sqlite_set_result_... interfaces to set the final result of the aggregate.
SQLite now implements all of its built-in functions using this interface. For additional information and examples on how to create new SQL functions, review the SQLite source code in the file func.c.
If SQLite is compiled with the THREADSAFE preprocessor macro set to 1, then it is safe to use SQLite from two or more threads of the same process at the same time. But each thread should have its own sqlite* pointer returned from sqlite_open. It is never safe for two or more threads to access the same sqlite* pointer at the same time.
In precompiled SQLite libraries available on the website, the Unix versions are compiled with THREADSAFE turned off but the Windows versions are compiled with THREADSAFE turned on. If you need something different that this you will have to recompile.
Under Unix, an sqlite* pointer should not be carried across a fork() system call into the child process. The child process should open its own copy of the database after the fork().
For examples of how the SQLite C/C++ interface can be used, refer to the source code for the sqlite program in the file src/shell.c of the source tree. Additional information about sqlite is available at cli.html. See also the sources to the Tcl interface for SQLite in the source file src/tclsqlite.c.
This page last modified on 2023-01-06 00:45:39 UTC


text:
Whatever you do...
What I'm about to share can build you a life-changing fortune for you...
And because I'm under a lot of pressure to take this page down...
It may not be here when you return.
So stick around for just a few more minutes...
Because if you do...
You'll be one of the limited number of people who can use my secret...
And FINALLY make a full-time income from online marketing.
While working part time, on YOUR own schedule.
When you STOP trading your precious time for money, this IS possible.
I'll show you how, right now!
My secret can help you:
But before I share the details with you...
I'm going to address the elephant in the room.
This isn't your typical internet marketing video.
I'm not riding in a Ferrari and flashing my money.
Instead, I'm just a regular guy standing here relaxing in my living room.
So who am I?
You're smart to ask this question.
So let me explain.
I'm not one of those so-called experts who make money from telling people they can make money.
This is why you've never seen or heard of me before.
You see, for the past several years I've been behind the scenes.
When I first started during the 90s, the internet was like the wild wild west.
Back then, online marketing was brand new.
Facebook didn't exist.
And MySpace was still a thing.
Google was barely introducing their new AdWords platform.
If you're unaware, AdWords is what you use to place ads on Google.
Nowadays you always see advertisements when you search on Google.
But in the early days...
This was a groundbreaking change to the internet.
Because of the insider info I had from a source of mine at Google...
I was one of the FIRST to start advertising using Google AdWords!
Early adopters like me made fortunes.
Because it was common to gain 100-200x return for every dollar spent on advertising.
That's an extra $100 to $200 for every $1 bill.
Insane right?
Like I said, people like me were making a killing.
You could predictably scale your income, day after day.
You didn't even need to be super smart to make money back then either.
I sure wasn't!
All of this sounds great, I know, but the reality is it wasn't perfect.
Because of all the money being made, out came the scammers.
These get-rich-quick wizards sold their lifestyle and promised the world...
Yet FAILED to deliver any value.
It sickens me to see these dishonest people.
Some of those guys are still around today.
You might have seen them before.
If you've been tricked by someone over-promising and under-delivering...
It's NOT your fault.
These digital snake oil peddlers are masters at deception.
They'll use every trick in the book to take your money.
But when it comes to actually helping you?
That's when they screw you over.
And put you right back where you started.
Stuck, lost, and even more confused.
My goal today is to end this vicious cycle.
And make it my mission to help out the "little guys" from the bottom.
I decided enough is enough!
People shouldn't be stripped of their hard-earned money...
Just because they're eager to live a better life.
As you can imagine, this video will upset a lot of people.
But I don't care.
I'm not doing this to boost my status or ego.
I couldn't care less about becoming an "internet celebrity".
This isn't about me.
I'm making this video to help YOU!
Once I tell you my secret, it's possible for you to FINALLY live the "laptop lifestyle" you've been reading about.
So what IS my secret?
And why is it so powerful?
More importantly, why am I the the ONLY person you can get it from?
I'm about to answer ALL these questions (and more).
Let me share with you...
Spend just 10 minutes searching how to make money online and you'll run across the big names.
People like: Frank Kern, Tai Lopez, and Neil Patel.
It's easy to get sucked into their lifestyle.
Their nice cars.
Private jets.
And even the women.
So this is great and all.
More power to them for marketing the lifestyle.
But what they rarely talk about is:
HOW they actually make money!
You see, if they shared this with you then *POOF* there goes their status.
So what aren't they telling you?
Let me share exactly what successful millionaire marketers actually do behind the scenes.
How can you be sure I know what it is?
Because making money online is what I've been doing for over a decade.
And because I've helped many of the "gurus" in this industry.
I know the big difference between what they teach.
And what they actually DO.
Today I'm putting an end to the "bait and switch".
And I'll reveal to you WHAT the gurus are REALLY doing to make money.
It starts with something called a funnel.
A funnel is a way to introduce people to your product or service.
It's called a funnel because the goal is to attract the most-people possible at the TOP...
So you can have the best chance possible at making sales throughout the funnel.
In the marketing world, these people are called leads.
The more leads you get in your funnel, the more sales you make.
For example, let's say you have a funnel that attracts 100 leads every day.
And on average, you make 1 sale for every 100 leads.
This means you're getting 1 sale a day, right?
But here's where the magic happens.
And where life-changing fortunes are made.
If you get 200 leads into your funnel, you're making 2 sales a day.
And if you're able to get 1,000 leads into your funnel...
Simple math, right?
The more leads you get in your funnel, the more sales you make.
Well, there are several ways.
You can do what I did back in the day and use Google AdWords.
Which STILL works today, but it's not as easy nor cheap as it once was.
It's going to cost you a TON of money.
I remember getting high-quality leads for 5 to 10 cents.
Nowadays, these same leads are about $10 to $100!
So unless your budget is tens or even hundreds of thousands of dollars...
You're going to have a hard time getting good leads.
But Google AdWords isn't the only method.
You can use Facebook ads, too.
Like AdWords, Facebook used to be cheap.
But now...
You'll be competing with BIG spenders on Facebook just to get one lead.
If all of this isn't "breaking news", I apologize.
I first had to cover the basics, before moving onto the juicy stuff.
What I'm about to tell you next will change how you think about making money online ENTIRELY.
Although it might sound strange...
And even a little unbelievable.
I promise you the following technique is 100% legal.
The beauty of what I'll share next is it enables you to "stretch" the cost per lead.
Let me explain.
If you got a 6-figure-a-day budget, good luck.
That's just your starting cost.
Expect to pay more over time as competition goes up.
Paying for fresh leads isn't easy.
And there are people like me who've been doing it for years.
So what's the better option?
What if I were to tell you, that you can use the SAME lead multiple times?
Which essentially allows you to "split" the cost of expensive leads?
If you got a 6-figure-a-day budget, good luck.
This means instead of paying $10 or $100 per lead...
You're splitting the cost between trusted partners.
Sounds great, right?
This is, in fact, what many top marketers do.
But rarely talk about.
Splitting the cost per lead is one of the biggest secrets in online marketing.
And it allows even those with a tiny budget to get started.
You might be thinking,
The answer is...
It depends.
Sharing leads WITHOUT their permission is a violation of the CAN-SPAM Act.
Which is of course what I'm NOT implying today.
Rather, there's a 100% legal "loophole" that only the smartest marketers use.
They're called permission-based leads.
Here's how they work.
When a new lead enters a funnel they have the option to request or deny more information.
If they say yes, then it's legal to send them promotions.
In fact, it's a disservice to NOT give them what they want.
They're literally telling you, "SEND ME MORE THINGS TO BUY!"
So how can they request more info?
All they have to do is click a small checkbox when they sign up.
You've probably seen these checkboxes before.
They usually say something like:
I estimate that millions of people check these boxes every day.
Meaning there are millions of potential customers "raising their hands"!
These leads WANT more information.
Once I figured this out, I stopped relying on doing the "hard work" of finding these leads from scratch.
And partnered with people who're willing to share their permission-based leads with me instead.
This little-known way to make money is rarely talked about by the gurus.
Even though they're making piles of money from what I just told you!
For the past decade...
Making it as simple to sell ANY product or service I want.
The best part?
It takes me no more than 20 minutes a day to send offers to my leads.
All I have to do is write an email and click send.
I like to keep things simple.
And it can't get more simple than that!
So for a non-tech guy like me, this is amazing.
Plus it feels great knowing I'm actually sending info to leads who actually WANT to hear from me.
Instead of annoying someone.
In fact...
It's even common for people to THANK me for sending them things to buy!
If you want to follow in my footsteps...
And build the SAME daily stream of high-quality leads like me.
I must WARN you.
It will NOT be easy.
I've spent decades "cracking this code".
And countless hours building the right relationships.
If you prefer to do things on your own, I wish you the best of luck.
But since I'm sick and tired of seeing all the scammers...
I want to do something special.
So let me ask you...
You heard that right.
I want to GIVE you 100 of my leads...
Why would I do that?
Well, I've been fortunate enough to profit from leads for years already.
I'm now at the point where I want to give back.
I still love making money.
But nowadays, seeing other people succeed is just as exciting.
This is why I'm willing to share the same leads sourced from within my private network.
It wasn't easy to talk my friends into this.
They're HIGHLY protective of their "gold mine".
It took a lot of convincing before they agreed.
The only catch is we're only making this offer available for a limited time.
What exactly will you get if you say yes?
We'll send you 100 hand-selected leads, every single day...
Including the first name...
Last name...
Email AND IP address...
And even the date of every lead we acquired!
What types of leads are they?
Those interested in Business Opportunity and Internet Marketing.
Which means if you're on this page, the leads are similar to you.
Because you share interests with these leads...
Writing emails to them isn't difficult.
In fact it's a lot like writing a message to a friend!
For that, you'll have two options.
The first is you can download them in a spreadsheet and upload to your own mail delivery system.
Because I wanted to make this easy for you, I had my tech team design a done-for-you mailing system.
Making your life easier by allowing you to easily log in and send emails...
And be done for the day in 20 minutes, even if you're not a tech wizard.
Because this opportunity is open to the public, we cannot make it free.
There is a small investment required on your end.
But if you're thinking I'm asking for thousands, don't worry.
Even though the cost to get these leads is high...
I'm going to make them available at an extremely low price, so you can get started even if you're new.
Which is an average of $5,500 per day.
Or $165,000 per month!
This is COMPLETELY out of reach for the average person.
And if you're like me when I was starting out, you can't afford that.
So what's the actual investment amount?
It's much less than $30,000... $10,000... or $1,000.
In fact, it's even less than $500.
Before I tell you what the actual amount is, I'm gonna share something cool.
Prior to making this video we offered our leads to a handful of random people.
Shortly after, we followed up with each one.
Here's what they had to say...
That's awesome, right?
Kim was just one of the few people who sent us positive feedback.
Here's another...
Don't let today be something you regret later.
I'm going to help you get started for a very low amount.
If I were offer my leads for just $100, I'm sure I'd get enough interest.
And within 1 day, we'd reach our cap for new members.
But I'm going to do something extra special right now.
And let you get access for an amazing price.
For only $1 a day...
And a setup fee of $30 that you ONLY pay once, you'll get to mail my high-quality leads.
And I'll send 100 of them to you every day.
PLUS, I'll give you my custom-built mailing system.
If you really want to make money online, this will help you save thousand of dollars...
And years of time and frustration from doing this on your own.
My friends and I cannot keep this insanely generous offer up for long.
Click the button below to take the next step.
You can review what you get before completing your order.
As soon as we reach our limit, this will no longer be available.
Take action now for just a one-time setup fee of $30...
And $1 a day for your 30 days, paid upfront.
You can tap into a money-making secret used by millionaire marketers.
After your first month, it's just $1 a day to continue your membership.
Once again, this page may be gone when you return.
Since we made this announcement we got a surge of new members.
And since my friends and I don't want to share our leads with too many people...
There's a limited time for you to join.
For just $1/day, you too can access the same types of leads millionaire marketers use to make money!

subset: commoncrawl


text:
About ADS Racing Shocks
Most people look for the easy road, the path of least resistance. Our customers are the ones who look for the road less travelled, the hard line, the hardcore route that sane people avoid. Our customers are not like most people, they are the ones who not only take on that challenge... they look for it!
At ADS our passion is off-roading. When ADS started doing business in 1992 the idea was to create a company that delivered components that met or exceeded the unique needs of off road drivers. To this day, everything we do is rooted from our passion for off road racing. Most of the people at ADS would rather spend a weekend in the desert than on a beach somewhere. ADS is a company of off-road racers for off-road racers.
ADS manufactures a variety of parts for off-road vehicles, but our premier product is our racing shock absorber. You can find ADS racing shocks on just about every type of off-road vehicle. From prerunners, sand cars, and full blown baja racers to the dual prupose daily driver, ADS shocks are designed to deliver uncompromising performance regardless of the vehicle or application. The thousands of hours that we spend testing and optimizing our shocks can be seen and felt in every shock absorber that we build.
If you live for off-roading, or only want the best products for your off-road vehicle, you are like us. We want to put the best parts we can get on our vehicles and we know you do too. At ADS, we come to work every day because our satisfaction comes from yours. Hearing the satisfaction in your voice, or seeing it on your face, is what drives us. Producing top quality racing shock absorbers is what we do, and providing unparalleled satisfaction to off-road enthusiast is why we do it. Take control of your off-road vehicle with ADS shocks!


text:
Each year since 2000, Broadway.com has asked our readers to pick their favorites of the season in our annual Broadway.com Audience Choice Awards. The 2017 results are in! After receiving nine Tony Award nominations, Dear Evan Hansen has topped the Broadway.com Audience Choice Award wins with eight. Other big winners included the Broadway revival of Falsettos and Hello, Dolly! star Bette Midler.
The 18th annual Broadway.com Audience Choice Awards will be presented at a private cocktail reception on May 25. Below are this year's winners of Broadway's most fan-friendly prize!
Dear Evan Hansen
Favorite New Musical: Dear Evan Hansen: Book by Steven Levenson, Music and Lyrics by Benj Pasek & Justin Paul
Favorite Leading Actor in a Musical: Ben Platt
Favorite Featured Actress in a Musical: Laura Dreyfuss
Favorite Funny Performance: Will Roland
Favorite Onstage Pair: Laura Dreyfuss & Ben Platt
Favorite Breakthrough Performance (Male): Mike Faist
Favorite Breakthrough Performance (Female): Laura Dreyfuss
Favorite New Song: "Waving Through a Window"
Favorite Musical Revival: Falsettos
Favorite Featured Actor in a Musical: Andrew Rannells
The Glass Menagerie
Favorite Play Revival: The Glass Menagerie
Favorite Leading Actress in a Play: Sally Field
Hello, Dolly!
Favorite Leading Actress in a Musical: Bette Midler
Favorite Diva Performance: Bette Midler
The Price
Favorite Leading Actor in a Play: Mark Ruffalo
Favorite Featured Actor in a Play: Danny DeVito
The Play That Goes Wrong
Favorite New Play: The Play That Goes Wrong
Lindsay Mendez
Favorite Featured Actress in a Play: Lindsay Mendez, Significant Other
Sara Bareilles
Favorite Replacement (Female): Sara Bareilles, Waitress
Todrick Hall
Favorite Replacement (Male): Todrick Hall, Kinky Boots
Favorite Tour: Wicked
Favorite Long-Running Show: Hamilton
Dear Evan Hansen - 8
Falsettos - 2
The Glass Menagerie - 2
Hello, Dolly! - 2
The Price - 2
Laura Dreyfuss - 3
Bette Midler - 2
Ben Platt - 2


text:
If the Desktop Live image is the default offering, does this mean the Desktop SIG defines the user experience for all of Fedora? What if another SIG disagrees?
The Design team is responsible for the look and feel of Fedora. The Desktop SIG is responsible for the default image and should work with the Design team on Fedora-specific configurations or upstreams for a consistent look and feel in that product. There are ample opportunities for all SIGs to work with the Design team and with upstream projects to improve modularity, compatibility, and interoperability.
This is a complicated issue to answer with a few simple sentences. Instead it is more useful to break down into a series of smaller questions that can be answered individually.
Who makes designs?
The Fedora Project has a Design team that acts as somewhat of a service team for other groups, consulting on and producing user interface designs and other outputs that can improve UX in Fedora.
In late 2008, Fedora's Art team began a process of rebranding to become the Fedora Design team. Their mission is to provide vision and execution for the art, user interface, and look and feel of the Fedora Project and distribution. Beyond providing a regular refresh of art and theme for each Fedora release, the team also exists as a design resource for teams working on user interface elements.
Designers can consult with developers on the user-facing functions of their work to improve the user experience of the end result. Developers sometimes create interfaces without design input, and some do have sufficient UI experience to produce satisfactory results, but this isn't an ideal solution. A goal for the Design team is to increase the number of user interaction designers involved in Fedora, who would drive the process of design for these types of interactions. Furthermore, they would be able to grow the overall open source design community, and provide a more substantial culture of design in the Fedora Project specifically. Some examples of designs might include the presentation of menus, the type and number of choices offered to the user when performing a specific activity, or the frequency and manner in which notifications that are delivered to the user.
Where do design decisions happen?
- In upstream communities.
- Some decisions that involve UI design are driven entirely by the upstream communities that write the code for the UI. UI elements are designed and written upstream. For instance, the participants in the Red Hat Desktop team work in the GNOME upstream and other communities that provide UI elements. Discussions and work on these elements happen upstream.
- In Fedora as an upstream.
- Some UI is done in Fedora where code originates, such as in the case of system-config-* tools and other Fedora-specific projects. Discussions and work on these elements generally happen on the Fedora Design team's communication channels, such as their mailing list and IRC. Sometimes they happen in the Fedora channels that are specific to a team working on the project, such as an Infrastructure project being worked on in the #fedora-admin IRC channel or the infrastructure list.
- In Fedora when electing a different configuration from upstream.
- In general Fedora tries to stick closely to upstream projects. However, at times the the option for a distinctive Fedora look and feel needs to be decided by the Fedora Project. In these cases the Fedora Design team should be consulted to help make decisions on a consistent basis to support the overall user experience.
Who participates in the process?
Any interested Fedora participant who can constructively contribute to the design process with focused analysis, critiques, or input.
Many of the members of the Desktop SIG are also developers of core desktop technologies in various upstream projects. Not every team in Fedora that maintains a desktop environment drives the UI design and implementation of that environment to the extent of the Desktop SIG. That doesn't mean those contributors cannot be involved in discussions around UI in Fedora's default image. In addition, the Fedora Design team is fairly small and we constantly look for ways to expand that team to include additional experienced designers. In the meantime, we realize that there will sometimes be a need for more design consultation than that team can provide. In those cases developers strive to make decisions that are consistent with good UI practice and the look and feel established by previous designs from the Design team and upstream.
Certainly members of the Red Hat Desktop team are involved in the Fedora Desktop SIG, which is responsible for the upkeep of the Fedora default image. The Fedora Desktop SIG also includes people not on that team, such as designers from the Fedora Design group and engineers from around the Fedora Project. The business of the SIG is normally conducted in public, both on their IRC channel and mailing list. Community members are encouraged on the Desktop wiki page to be involved in discussions there.
How are decisions made?
The standard process for decision making in this context is fairly identical to those used throughout the Fedora Project, as part of our meritocratic practice:
- Open discussion of the various options, possibly including the predicted results/costs/benefits of each
- Consultation with members of the Fedora Design team who have expertise in the UI/UX area
- A decision by the parties responsible for implementing the changes
- Notifying the community of the decision
Does the Desktop SIG define the UX for all of Fedora?
No. The Fedora Design team provides support for effective user interfaces, and works with the Fedora Desktop SIG to design a number of the components that are part of the default offering. Other designers also play a part because of their work upstream on code that is inherited by Fedora. (A side benefit of having Fedora community developers involved deeply in upstream code is the strong partnership that implies.) The Desktop SIG developers can't and don't do the same thing for all software in the entire Fedora distribution (repository). The Design team attempts to provide this service across the distribution, to the extent their time and personnel allow.
What if another SIG disagrees?
Anyone in Fedora has the ability to participate in the Desktop SIG's work, as is the case in other Fedora SIGs. However, alternate desktop environment SIGs exist because they may prefer the user interaction or experience provided by different upstream communities. Fedora offers alternate desktop environments that allow contributors who are interested in other user experiences to try them out instead. This can be done through Spins, or through simply installing the software needed for the alternate environment. SIGs often interact with communities outside the ones in which the Desktop SIG is involved. Therefore, SIG members have the ability and opportunity to influence work done in those communities if desired. SIG members also have the ability and opportunity to work on Fedora-specific upstreams, such as the system-config-* projects for example.
It's possible that a codebase supporting user interfaces or functions might cause a conflict, and there needs to be a clear way to resolve such conflicts. This might happen, for example, if a feature is introduced during the development cycle into the default desktop environment that affects alternate environment spins.
Fedora's role as a sort of research and development lab is best served by promoting innovative code, so often that approach doesn't favor holding back specific features until everyone catches up. However, this is the reason that upstream projects like freedesktop.org exist -- to provide standards and guidance so all upstream DEs can interoperate effectively. SIGs can bring upstream forces together to solve these issues, since that is usually preferable to carrying specific Fedora patches. In the example given, members of that spin's responsible SIG could work with the upstream community to ensure changes are made and tested to integrate properly with the new feature.
The default offering is discussed here in more detail. User experience (UX) is ISO defined as "a person's perceptions and responses that result from the use or anticipated use of a product, system or service."[1] User experience is thus subjective.
- ↑ ISO FDIS 9241-210:2009. Ergonomics of human system interaction - Part 210: Human-centred design for interactive systems (formerly known as 13407). International Organization for Standardization (ISO). Switzerland.


text:
The roar of its four engines, the plexiglass nose, the bristling machine guns — for history buffs and aviation enthusiasts, few thrills compare with that of a flight aboard aircraft like the B-17 Flying Fortress, the World War II bomber that helped smash the Nazi war machine.
"It made you feel like you were back in the 1940s," said commercial pilot Gloria Bouillon, who rode one last month and called it the best flight of her life. "They had it set up just like it would be if it was on a mission. You could put your head out of the hatch. It was windy. It was noisy. You could smell the fuel. It was much different from a flight now."
But a deadly crash in Connecticut this week of the very same B-17 has cast a pall over the band of brothers — and sisters — who enjoy riding in vintage planes and raised questions of whether machinery over 70 years old should be flying passengers.
The propeller-driven 1945 bomber went down at the Hartford airport on Wednesday, killing seven of the 13 people aboard, after the pilot reported engine trouble on takeoff. The cause of the fiery wreck is under investigation.
Arthur Alan Wolk, a lawyer who specializes in crash litigation in Philadelphia, said Friday that the accident shows the risks associated with flying old planes: They break. He said the rules for operating vintage aircraft are stringent, but he questioned whether compliance and training are adequate.
"No one alive ever flew or maintained one of these aircraft in service," he wrote in a blog post. "No one alive went through the military training program for these aircraft. The engines are old with no new parts being manufactured for decades. Even in service these aircraft needed the resources of a government to keep them flying. The aircraft and engines were never intended to last this long so intense maintenance and inspections are vital to continued safety."
Since 1982, the National Transportation Safety Board has investigated 21 accidents involving World War II-era bombers. They resulted in 23 deaths. Three of the accidents involved B-17Gs, not counting the one that crashed Wednesday.
Sen. Richard Blumenthal, D-Conn., asked that the NTSB during its investigation of the Connecticut accident look at the inspection and maintenance requirements on vintage planes and whether they need to be more rigorous.
An FAA spokeswoman said that if an issue is discovered during the investigation that might apply to the fleet, the agency will take appropriate action.
Vintage planes need to be certified as airworthy by the FAA and are subject to periodic inspections. Owners can obtain an FAA "living history flight exemption" to offer flights to paying customers, but they must comply with extra federal requirements for safety and maintenance.
"I would not have any hesitation about flying in these aircraft," said Dick Knapinski, a spokesman for the Experimental Aircraft Association of Oshkosh, Wisconsin, an organization of aviation enthusiasts and airplane restorers. The association flies one of the few remaining B-17s.
Its B-17 will visit Hyannis, Massachusetts, this weekend but will not offer passenger flights out of respect for those connected to the tragedy, Knapinski said.
The Connecticut crash reduces to nine the number of B-17s actively flying, according to the National Museum of the U.S. Air Force, near Dayton, Ohio.
The one that went down was associated with the Collings Foundation, an educational group in Massachusetts that brought its Wings of Freedom vintage aircraft display to the Hartford airport this week. It was FAA-certified through November 2022.
The pilot, 75-year-old Ernest McCauley, of Long Beach, California, had more than 7,000 hours of experience flying a B-17. He was killed in the crash.
Unlike commercial airline pilots, who must retire at 65, pilots of vintage aircraft can keep flying as long as their medical certificate, training and testing are current.
Knapinski dismissed concerns that the knowledge and equipment needed to keep World War II-vintage planes flying are dwindling, saying that pilots and mechanics are trained to a high standard, and that original parts or new ones manufactured to the same specifications are available.
The B-17 is one of the most celebrated warplanes in U.S. history, used to conduct near-suicidal daylight raids against German industrial sites at a terrible cost in allied lives. About 12,000 B-17s were built during the war, and roughly a third were lost in combat, while others were scrapped afterward, Knapinski said.
"Airplanes are built to fly. When you see them in museums, it's not the same as experiencing them at your local airport, in your community," he said. "The tragedy notwithstanding, we hope to be doing this for a very long time."
Bouillon, manager of Beverly Regional Airport north of Boston, was stunned to hear of the crash involving the same plane she rode in mid-September.
"I took a breath and said that could have been me," she said. "You pause and you're grateful that you're still breathing."
Associated Press writers David Sharp in Portland, Maine, Dave Collins in Hartford, Connecticut, and Mark Pratt in Boston contributed to this report.
Comments are no longer available on this story
Send questions/comments to the editors.


text:
Crowdsourcing Project: Broadcasting & Sharing local tech events via the airwaves with the Air Local channel
By Peter Organisciak, João Menezes, Jan Dittrich & Eugenia Ortiz A guest post from our Crowdsource Crowdsourcing project team who have spent the last few weeks tackling the Air Local channel. Find below, some of their observations, thoughts and proposals. … Continue reading


text:
Every gardener is used to seeing containers placed on hard surfaces. On either side of a front porch. On a set of steps or walkway. On a terrace. But containers can fit right into a spot in the landscape. We have worked in several places this week where containers were placed in the midst of the ongoing landscape. I like what I am seeing. Placing pots in the garden is an unusual placement, but unusual can be a good. The first rule of good design is to not take any rule as set in stone. Some of the most beautiful landscape designs I have seen break every rule. By this I mean, they break every rule, but do it convincingly. A great heart, and sure hand always trumps following the rules. I worried myself for days, given the decision to place this pot in the middle of the lawn in the rose garden. Once the deed was done, I wondered why. The placement seemed right.
This container is set in a landscape bed. A clematis has climbed and wound itself around a tall steel container. A bed of pachysandra, angelina and hens and chicks has been inter planted with with Persian Queen geraniums, euphorbia, and trailing annual verbena. The look of this garden is better than good. I like how the introduction of annual plants into the landscape, and the perennial clematis climbing the side of a container have created a look in which the container has become an integral part of the landscape. The annuals planted in ground-so charming, and so successful. This planting is not mine-it is all Jane's. Clients can be a great source of inspiration. They know their gardens backwards and forwards. Their decisions are based on a daily exposure. This corner is invariably burned by salt in the winter, so a summer/seasonal planting helps keep this spot luxuriant.A container set in a landscape bed is one way to create a focal point. This tall concrete pot planted with a lemon cypress, euphorbia, and petunias gives meaning to a landscape comprised of arborvitae and pachysandra. I like the ground cover growing up over the base of this planter. It looks as though the container has been there a while, and belongs there. A pot gracefully placed in a landscape can add another dimension to an outdoor space. Landscapes which offer many dimensions continue to interest the viewer. A pot placed in the landscape is a mark made by a designer. That said, I treasure the individual statement of a landscape above all. Some landscapes I see are all about a gardener in charge with a strong point of view.
We usually remove the grass underneath a container, excavate the soil, and replace that soil with gravel. The insures that the container drains unimpeded. Trimming the grass around the container is an extra step, maybe even a nuisance. But for the gardener that appreciates the small details, a placement like this is a pleasure. A pot placement in the landscape can be a temporary solution to a bigger problem. In this case, a tree directly behind this group of containers died this past winter. The tree, and its stump was of a size that replacement will not be easy. The pots draw one's eye away from the empty space. Given this placement of pots, a much smaller tree could be planted which would eventually fill that void.
A container in the landscape takes on the same sculptural quality as a birdbath, armillary, or sundial. The small footprint of any of these ornaments makes them easy to tuck into a small space that needs some visual interest. This client has a particular fondness for pots in her borders. This pot is set on a short concrete plinth. That small amount of additional height keeps the bottom of the pot in view, despite the ground covering geraniums.
This French glazed pot is of considerable size and stature. It has been placed in a bed of myrtle facing down a stand of mature trees. Pink and red mandevilleas growing on a simple trellis made of bamboo stakes makes a considerable statement by late summer. This spot, minus the pot, would be too sleepy looking for this client. Every gardener wants something different from their garden.
The landscape in the front of my house features two fairly large patches of herniaria. This spot asked for something short that would require little maintenance-it has done very well there. Years ago I set a pair of French glazed pots at opposite ends. A garden ornament which represents the end, or boundary of a garden is called a Herm, 0r a term-as in terminus. Though I have since moved the Russian sage in favor of a simpler arrangement, and switched out the French pot for a concrete pot with a yew topiary that can sit in this spot all year round, the idea is the same. The placement of containers can be anywhere there is a need.


text:
If you have decided to sell your home, do you know what items you can take, and which ones you're supposed to leave behind? While things like furniture and personal items are obvious, there are other things that may not be so cut-and-dried. If you're a little confused about what items are supposed to stay with the house, read on.
Window treatments
Not sure if you can take those window treatments you love and spent a small fortune on? Here's a good rule of thumb: if they're attached to the window, they should stay. That means curtains, which can easily be slipped off a rod, can go with you to your new place. However, the curtain rods and blinds that are more permanently attached need to stay.
Lighting fixtures
In nearly all cases, the lighting fixtures that are attached to the wall or ceiling need to stay with the house. The buyer is purchasing the home the way they saw it on the day of the viewing. You could find yourself in legal trouble if any of those permanent fixtures they saw are missing when they move in. If you have a lighting fixture that you absolutely love, say a beautiful chandelier, you should replace it before you list your home for sale.
Unless you specifically state that you are going to dig up the rosebushes and take them with you, they need to stay with the house. This goes for any trees, shrubs, or other plants in your yard. All of those items are considered part of the property and cannot be dug up when you sell your home unless agreed to in advance.
Outdoor fixtures anchored in the yard
In addition to plants and shrubs, there are other outdoor items that need to remain with the property. This includes anything that is anchored into the ground with cement, such as a light pole, birdhouse, or basketball hoop. If it's something that does not need to be removed with a tool, you should probably be able to take it with you.
Built-in appliances
Appliances can be somewhat of a grey area. In general, built-in appliances like dishwashers, ovens, and range hoods should remain with the house. If the appliances are freestanding, like a freestanding dishwasher or a refrigerator, they should be specifically addressed in the contract to make it clear whether or not the seller is planning to leave them behind. This is also true for air conditioners. If you have a window unit, it's safe to assume that you can take that with you. However, if you've cut a hole in the wall and installed the unit, it needs to stay with the house.
Wall-mounted brackets for TVs
While it may seem like you should be able to take your TV mount with you when you leave, you should probably leave it behind. The generally accepted rule is that if it requires tools to remove it, it should stay with the house. If you want to keep the mounting brackets it should be stated in the contract so there is no confusion for the buyer.
We hope this answers any questions you have about what stays behind when you sell your home. If you still aren't sure, or you would like more information about selling your home, we'd be happy to help!
Give us a call at (760)421-1733 or shoot us an email at [email protected].


text:
Mexico: Marches Against Political Corruption Met with Violence
Posted 11 years ago on Dec. 1, 2012, 1:27 p.m. EST by OccupyWallSt
yo soy 132,
Part of a march in Mexico City
Today across Mexico, protesters (including participants from the #YoSoy132 movement and others) have taken to the streets to march against election fraud and the imposition of Enrique Peña Nieto as President on his inauguration day. Using the slogan "#MéxicoNOTienePresidente" (#MexicoHasNOPresident"), the protesters marched on Congress in Mexico City and were met with large squadrons of riot police, enormous barricades, rubber bullets, tear gas, and gas bombs. Reports claim approximately 30 people have been injured, several critically.
For more information and livestreams from Mexico, see: http://1dmx.wordpress.com/ and http://www.yosoy132media.org/. On Twitter, follow @YoSoy132media, and use hashtags: #1dmx, #MexicoNOTienePresidente, #MexicoHasNOPresident, #YoSoy132, #OcupaSanLázaro.
There have also been solidarity protests in cities across the world outside Mexico, including many planned for tonight in various U.S. cities. Today in NYC, YoSoy132-NY will gather at the Mexican Consulate at 5pm (leer en español). They invite Occupiers to join them.
Demonstration for an authentic democracy
Yosoy132NY summons Mexicans living in New York to participate in a demonstration outside the Mexican Consulate on Saturday, December 1, on the occasion of the inauguration of Enrique Peña Nieto as president of our country.
We will march toward genuine democracy for Mexico and against the current Mexican political system, understood as a set of political, economic, and social institutions set up to the benefit of a minority and facilitate the imposition of candidates such as Enrique Peña Nieto.
This system includes but is not limited to:
- The political party system that restricts citizens' access to power and inadequately represents their interests.
- The practices of corruption, impunity, repression, violation of freedom of expression, and patronage committed by the PRI for decades of its hegemonic rule, and adopted by the PAN, the PRD and the rest of the political parties.
- The manipulation of information, especially through the mass media.
Join and participate! You can contribute to change our country! Your voice counts!
See also:
#TodosSomos132: Solidarity With the Mexican Spring
#YoSoy132 Blockades Mexico's Largest Media Company; Support Them At #OccupySaks!


text:
Our background
Interface Lab was started in 2010 as an offshore branch of the Interface RU company - the reputable Russian system integrator and software distributor since 1991, closely connected to the Russian Academy of Sciences and with huge experience in system integration, software distribution and software development.
Since then Interface Lab has been delivering end-to-end software development, quality assurance and support solutions to clients ranging from Fortune 500 companies to startups in all stages of funding.
Interface Lab is an expert in development, customization and integration of complex enterprise-level solutions, advanced web and mobile applications offering a well-balanced blend of technology skills, domain knowledge, hands-on experience, effective methodology and passion for IT.
Interface Lab is a premier full service Development and Quality Assurance partner, specializing in the development of time-sensitive and innovative SaaS, mobile and on-premises solutions. For our clients software is a critical success factor. To every project, we bring a combination of domain expertise, exceptional engineering talent, rigorous best practices, commitment to protection of client's IP and accountability of a US company with over two decades of impeccable reputation.
Our customers vary from large corporations to dynamic startups, from software vendors and SaaS companies to digital healthcare innovators, app vendors, marketing firms, financial services providers, publishers and educational institutions.
We have perfected a clean, economical approach for entering and exiting development and QA processes at the right time, using the right resources. Our lengthy and extensive track record has equipped us with the ability to provide rapid, cost-effective solutions that blend seamlessly with the product and business strategy, infrastructure analysis, architecture, UX design, rapid development, functional QA, or QA automation - or all of the above.
Our Services
The Services we provide:
• Custom Software Development
• Software Product Development
• Mobile Solutions
• Front-End, UX and UI development services
• Enterprise Application Integration
• System Modernization
• Maintenance and Support
• Quality Assurance and Testing Services
• Business Intelligence
Our human capital
We have a diverse talent in all areas of software development and delivery:
• Technical Leads
• Project Managers
• Business Analysts
• Data Scientists
• System Designers
• Software Engineers
• Integration and Release Engineers
• Test Development, Manual QA and QA Automation Engineers
• UI Designers
• Technical Writers
We do everything to make all our collaborations long-term basis ones, so we look for individual decision for each client and project, offer an Agile-based work style.


text:
Medical Specialists® Pharmacy are asking patients that have previously obtained Erectile Dysfunction (ED) medication from them or any other source, please provide feedback.
Note that all responses will be kept strictly anonymous in any future story or article that is published based on the information you provide.
. How long have you suffered with Erectile Dysfunction?
. Do you have underlying health conditions, linked to ED?
. Did you see your GP about ED, and what was the outcome?
. Do you feel there is a stigma surrounding ED and if you saw a GP, did you feel any embarrassment?
. Have you taken/used any of the most popular ED treatments such as Viagra, Cialis, Levitra, Spedra or Vitaros Cream?
. What were your experiences of the aforementioned treatments?
. Do you feel doctors prescribe enough ED medication to last you a considerable amount of time?
. Is there any other further information you wish to provide?