diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..c64111d --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = pgloader +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_build/doctrees/bugreport.doctree b/docs/_build/doctrees/bugreport.doctree new file mode 100644 index 0000000..18b937b Binary files /dev/null and b/docs/_build/doctrees/bugreport.doctree differ diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle new file mode 100644 index 0000000..902a197 Binary files /dev/null and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree new file mode 100644 index 0000000..98788c1 Binary files /dev/null and b/docs/_build/doctrees/index.doctree differ diff --git a/docs/_build/doctrees/intro.doctree b/docs/_build/doctrees/intro.doctree new file mode 100644 index 0000000..4e007ec Binary files /dev/null and b/docs/_build/doctrees/intro.doctree differ diff --git a/docs/_build/doctrees/pgloader-usage-examples.doctree b/docs/_build/doctrees/pgloader-usage-examples.doctree new file mode 100644 index 0000000..feb3882 Binary files /dev/null and b/docs/_build/doctrees/pgloader-usage-examples.doctree differ diff --git a/docs/_build/doctrees/pgloader.doctree b/docs/_build/doctrees/pgloader.doctree new file mode 100644 index 0000000..e40b92a Binary files /dev/null and b/docs/_build/doctrees/pgloader.doctree differ diff --git a/docs/_build/doctrees/ref/archive.doctree b/docs/_build/doctrees/ref/archive.doctree new file mode 100644 index 0000000..bf65935 Binary files /dev/null and b/docs/_build/doctrees/ref/archive.doctree differ diff --git a/docs/_build/doctrees/ref/copy.doctree b/docs/_build/doctrees/ref/copy.doctree new file mode 100644 index 0000000..2c724f1 Binary files /dev/null and b/docs/_build/doctrees/ref/copy.doctree differ diff --git a/docs/_build/doctrees/ref/csv.doctree b/docs/_build/doctrees/ref/csv.doctree new file mode 100644 index 0000000..e67f2b5 Binary files /dev/null and b/docs/_build/doctrees/ref/csv.doctree differ diff --git a/docs/_build/doctrees/ref/dbf.doctree b/docs/_build/doctrees/ref/dbf.doctree new file mode 100644 index 0000000..59b7d5b Binary files /dev/null and b/docs/_build/doctrees/ref/dbf.doctree differ diff --git a/docs/_build/doctrees/ref/fixed.doctree b/docs/_build/doctrees/ref/fixed.doctree new file mode 100644 index 0000000..b9c3e95 Binary files /dev/null and b/docs/_build/doctrees/ref/fixed.doctree differ diff --git a/docs/_build/doctrees/ref/ixf.doctree b/docs/_build/doctrees/ref/ixf.doctree new file mode 100644 index 0000000..2e33fce Binary files /dev/null and b/docs/_build/doctrees/ref/ixf.doctree differ diff --git a/docs/_build/doctrees/ref/mssql.doctree b/docs/_build/doctrees/ref/mssql.doctree new file mode 100644 index 0000000..e661d1a Binary files /dev/null and b/docs/_build/doctrees/ref/mssql.doctree differ diff --git a/docs/_build/doctrees/ref/mysql.doctree b/docs/_build/doctrees/ref/mysql.doctree new file mode 100644 index 0000000..c511810 Binary files /dev/null and b/docs/_build/doctrees/ref/mysql.doctree differ diff --git a/docs/_build/doctrees/ref/sqlite.doctree b/docs/_build/doctrees/ref/sqlite.doctree new file mode 100644 index 0000000..9a8a981 Binary files /dev/null and b/docs/_build/doctrees/ref/sqlite.doctree differ diff --git a/docs/_build/doctrees/ref/transforms.doctree b/docs/_build/doctrees/ref/transforms.doctree new file mode 100644 index 0000000..959692e Binary files /dev/null and b/docs/_build/doctrees/ref/transforms.doctree differ diff --git a/docs/_build/doctrees/tutorial/csv.doctree b/docs/_build/doctrees/tutorial/csv.doctree new file mode 100644 index 0000000..094551b Binary files /dev/null and b/docs/_build/doctrees/tutorial/csv.doctree differ diff --git a/docs/_build/doctrees/tutorial/dBase.doctree b/docs/_build/doctrees/tutorial/dBase.doctree new file mode 100644 index 0000000..0c5ba5d Binary files /dev/null and b/docs/_build/doctrees/tutorial/dBase.doctree differ diff --git a/docs/_build/doctrees/tutorial/fixed.doctree b/docs/_build/doctrees/tutorial/fixed.doctree new file mode 100644 index 0000000..0f87ca3 Binary files /dev/null and b/docs/_build/doctrees/tutorial/fixed.doctree differ diff --git a/docs/_build/doctrees/tutorial/geolite.doctree b/docs/_build/doctrees/tutorial/geolite.doctree new file mode 100644 index 0000000..c4d3e69 Binary files /dev/null and b/docs/_build/doctrees/tutorial/geolite.doctree differ diff --git a/docs/_build/doctrees/tutorial/mysql.doctree b/docs/_build/doctrees/tutorial/mysql.doctree new file mode 100644 index 0000000..65b4322 Binary files /dev/null and b/docs/_build/doctrees/tutorial/mysql.doctree differ diff --git a/docs/_build/doctrees/tutorial/quickstart.doctree b/docs/_build/doctrees/tutorial/quickstart.doctree new file mode 100644 index 0000000..35430fd Binary files /dev/null and b/docs/_build/doctrees/tutorial/quickstart.doctree differ diff --git a/docs/_build/doctrees/tutorial/sqlite.doctree b/docs/_build/doctrees/tutorial/sqlite.doctree new file mode 100644 index 0000000..258a0e1 Binary files /dev/null and b/docs/_build/doctrees/tutorial/sqlite.doctree differ diff --git a/docs/_build/doctrees/tutorial/tutorial.doctree b/docs/_build/doctrees/tutorial/tutorial.doctree new file mode 100644 index 0000000..40878d4 Binary files /dev/null and b/docs/_build/doctrees/tutorial/tutorial.doctree differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 0000000..6cd40d1 --- /dev/null +++ b/docs/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 59392f424cbb8621f1b34cf4df7fbec1 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/.nojekyll b/docs/_build/html/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/_build/html/_sources/bugreport.rst.txt b/docs/_build/html/_sources/bugreport.rst.txt new file mode 100644 index 0000000..84726b5 --- /dev/null +++ b/docs/_build/html/_sources/bugreport.rst.txt @@ -0,0 +1,49 @@ +Reporting Bugs +============== + +pgloader is a software and as such contains bugs. Most bugs are easy to +solve and taken care of in a short delay. For this to be possible though, +bug reports need to follow those recommandations: + + - include pgloader version, + - include problematic input and output, + - include a description of the output you expected, + - explain the difference between the ouput you have and the one you expected, + - include a self-reproducing test-case + +Test Cases to Reproduce Bugs +---------------------------- + +Use the *inline* source type to help reproduce a bug, as in the pgloader tests:: + + LOAD CSV + FROM INLINE + INTO postgresql://dim@localhost/pgloader?public."HS" + + WITH truncate, + fields terminated by '\t', + fields not enclosed, + fields escaped by backslash-quote, + quote identifiers + + SET work_mem to '128MB', + standard_conforming_strings to 'on', + application_name to 'my app name' + + BEFORE LOAD DO + $$ create extension if not exists hstore; $$, + $$ drop table if exists "HS"; $$, + $$ CREATE TABLE "HS" + ( + id serial primary key, + kv hstore + ) + $$; + + + 1 email=>foo@example.com,a=>b + 2 test=>value + 3 a=>b,c=>"quoted hstore value",d=>other + 4 baddata + + diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt new file mode 100644 index 0000000..d69915e --- /dev/null +++ b/docs/_build/html/_sources/index.rst.txt @@ -0,0 +1,33 @@ +.. pgloader documentation master file, created by + sphinx-quickstart on Tue Dec 5 19:23:32 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to pgloader's documentation! +==================================== + +.. toctree:: + :maxdepth: 2 + :caption: Table Of Contents: + + intro + tutorial/tutorial + pgloader + ref/csv + ref/fixed + ref/copy + ref/dbf + ref/ixf + ref/archive + ref/mysql + ref/sqlite + ref/mssql + ref/transforms + bugreport + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/_build/html/_sources/intro.rst.txt b/docs/_build/html/_sources/intro.rst.txt new file mode 100644 index 0000000..0dc75e2 --- /dev/null +++ b/docs/_build/html/_sources/intro.rst.txt @@ -0,0 +1,63 @@ +Introduction +============ + +pgloader loads data from various sources into PostgreSQL. It can +transform the data it reads on the fly and submit raw SQL before and +after the loading. It uses the `COPY` PostgreSQL protocol to stream +the data into the server, and manages errors by filling a pair of +*reject.dat* and *reject.log* files. + +pgloader knows how to read data from different kind of sources: + + * Files + * CSV + * Fixed Format + * DBF + * Databases + * SQLite + * MySQL + * MS SQL Server + +The level of automation provided by pgloader depends on the data source +type. In the case of CSV and Fixed Format files, a full description of the +expected input properties must be given to pgloader. In the case of a +database, pgloader connects to the live service and knows how to fetch the +metadata it needs directly from it. + +Continuous Migration +-------------------- + +pgloader is meant to migrate a whole database in a single command line and +without any manual intervention. The goal is to be able to setup a +*Continuous Integration* environment as described in the `Project +Methodology `_ document of the `MySQL to +PostgreSQL `_ webpage. + + 1. Setup your target PostgreSQL Architecture + 2. Fork a Continuous Integration environment that uses PostgreSQL + 3. Migrate the data over and over again every night, from production + 4. As soon as the CI is all green using PostgreSQL, schedule the D-Day + 5. Migrate without suprise and enjoy! + +In order to be able to follow this great methodology, you need tooling to +implement the third step in a fully automated way. That's pgloader. + +Commands +-------- + +pgloader implements its own *Command Language*, a DSL that allows to specify +every aspect of the data load and migration to implement. Some of the +features provided in the language are only available for a specific source +type. + +Command Line +------------ + +The pgloader command line accepts those two variants:: + + pgloader [] []... + pgloader [] SOURCE TARGET + +Either you have a *command-file* containing migration specifications in the +pgloader *Command Language*, or you can give a *Source* for the data and a +PostgreSQL database connection *Target* where to load the data into. diff --git a/docs/_build/html/_sources/pgloader-usage-examples.rst.txt b/docs/_build/html/_sources/pgloader-usage-examples.rst.txt new file mode 100644 index 0000000..72223b9 --- /dev/null +++ b/docs/_build/html/_sources/pgloader-usage-examples.rst.txt @@ -0,0 +1,163 @@ +Pgloader Usage Examples +======================= + +Currently not included, because redundant with the tutorial. + +Usage Examples +-------------- + +Review the command line options and pgloader's version:: + + pgloader --help + pgloader --version + +Loading from a complex command +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use the command file as the pgloader command argument, pgloader will parse +that file and execute the commands found in it:: + + pgloader --verbose ./test/csv-districts.load + +CSV +^^^ + +Load data from a CSV file into a pre-existing table in your database, having +pgloader guess the CSV properties (separator, quote and escape character):: + + pgloader ./test/data/matching-1.csv pgsql:///pgloader?tablename=matching + +Load data from a CSV file into a pre-existing table in your database, with +expanded options:: + + pgloader --type csv \ + --field id --field field \ + --with truncate \ + --with "fields terminated by ','" \ + ./test/data/matching-1.csv \ + postgres:///pgloader?tablename=matching + +In that example the whole loading is driven from the command line, bypassing +the need for writing a command in the pgloader command syntax entirely. As +there's no command though, the extra inforamtion needed must be provided on +the command line using the `--type` and `--field` and `--with` switches. + +For documentation about the available syntaxes for the `--field` and +`--with` switches, please refer to the CSV section later in the man page. + +Note also that the PostgreSQL URI includes the target *tablename*. + +Reading from STDIN +^^^^^^^^^^^^^^^^^^ + +File based pgloader sources can be loaded from the standard input, as in the +following example:: + + pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \ + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + - \ + postgresql:///pgloader?districts_longlat \ + < test/data/2013_Gaz_113CDs_national.txt + +The dash (`-`) character as a source is used to mean *standard input*, as +usual in Unix command lines. It's possible to stream compressed content to +pgloader with this technique, using the Unix pipe: + + gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo + +Loading from CSV available through HTTP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The same command as just above can also be run if the CSV file happens to be +found on a remote HTTP location:: + + pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \ + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt \ + postgresql:///pgloader?districts_longlat + +Some more options have to be used in that case, as the file contains a +one-line header (most commonly that's column names, could be a copyright +notice). Also, in that case, we specify all the fields right into a single +`--field` option argument. + +Again, the PostgreSQL target connection string must contain the *tablename* +option and you have to ensure that the target table exists and may fit the +data. Here's the SQL command used in that example in case you want to try it +yourself:: + + create table districts_longlat + ( + usps text, + geoid text, + aland bigint, + awater bigint, + aland_sqmi double precision, + awater_sqmi double precision, + intptlat double precision, + intptlong double precision + ); + +Also notice that the same command will work against an archived version of +the same data, e.g. +http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz. + +Finally, it's important to note that pgloader first fetches the content from +the HTTP URL it to a local file, then expand the archive when it's +recognized to be one, and only then processes the locally expanded file. + +In some cases, either because pgloader has no direct support for your +archive format or maybe because expanding the archive is not feasible in +your environment, you might want to *stream* the content straight from its +remote location into PostgreSQL. Here's how to do that, using the old battle +tested Unix Pipes trick:: + + curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \ + | gunzip -c \ + | pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + - \ + postgresql:///pgloader?districts_longlat + +Now the OS will take care of the streaming and buffering between the network +and the commands and pgloader will take care of streaming the data down to +PostgreSQL. + +Migrating from SQLite +^^^^^^^^^^^^^^^^^^^^^ + +The following command will open the SQLite database, discover its tables +definitions including indexes and foreign keys, migrate those definitions +while *casting* the data type specifications to their PostgreSQL equivalent +and then migrate the data over:: + + createdb newdb + pgloader ./test/sqlite/sqlite.db postgresql:///newdb + +Migrating from MySQL +^^^^^^^^^^^^^^^^^^^^ + +Just create a database where to host the MySQL data and definitions and have +pgloader do the migration for you in a single command line:: + + createdb pagila + pgloader mysql://user@localhost/sakila postgresql:///pagila + +Fetching an archived DBF file from a HTTP remote location +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's possible for pgloader to download a file from HTTP, unarchive it, and +only then open it to discover the schema then load the data:: + + createdb foo + pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo + +Here it's not possible for pgloader to guess the kind of data source it's +being given, so it's necessary to use the `--type` command line switch. + diff --git a/docs/_build/html/_sources/pgloader.rst.txt b/docs/_build/html/_sources/pgloader.rst.txt new file mode 100644 index 0000000..fb51bdf --- /dev/null +++ b/docs/_build/html/_sources/pgloader.rst.txt @@ -0,0 +1,713 @@ +PgLoader Reference Manual +========================= + +pgloader loads data from various sources into PostgreSQL. It can +transform the data it reads on the fly and submit raw SQL before and +after the loading. It uses the `COPY` PostgreSQL protocol to stream +the data into the server, and manages errors by filling a pair of +*reject.dat* and *reject.log* files. + +pgloader operates either using commands which are read from files:: + + pgloader commands.load + +or by using arguments and options all provided on the command line:: + + pgloader SOURCE TARGET + +Arguments +--------- + +The pgloader arguments can be as many load files as needed, or a couple of +connection strings to a specific input file. + +Source Connection String +^^^^^^^^^^^^^^^^^^^^^^^^ + +The source connection string format is as follows:: + + format:///absolute/path/to/file.ext + format://./relative/path/to/file.ext + +Where format might be one of `csv`, `fixed`, `copy`, `dbf`, `db3` or `ixf`.:: + + db://user:pass@host:port/dbname + +Where db might be of `sqlite`, `mysql` or `mssql`. + +When using a file based source format, pgloader also support natively +fetching the file from an http location and decompressing an archive if +needed. In that case it's necessary to use the `--type` option to specify +the expected format of the file. See the examples below. + +Also note that some file formats require describing some implementation +details such as columns to be read and delimiters and quoting when loading +from csv. + +For more complex loading scenarios, you will need to write a full fledge +load command in the syntax described later in this document. + +Target Connection String +^^^^^^^^^^^^^^^^^^^^^^^^ + +The target connection string format is described in details later in this +document, see Section Connection String. + +Options +------- + +Inquiry Options +^^^^^^^^^^^^^^^ + +Use these options when you want to know more about how to use `pgloader`, as +those options will cause `pgloader` not to load any data. + + * `-h`, `--help` + + Show command usage summary and exit. + + * `-V`, `--version` + + Show pgloader version string and exit. + + * `-E`, `--list-encodings` + + List known encodings in this version of pgloader. + + * `-U`, `--upgrade-config` + + Parse given files in the command line as `pgloader.conf` files with the + `INI` syntax that was in use in pgloader versions 2.x, and output the + new command syntax for pgloader on standard output. + + +General Options +^^^^^^^^^^^^^^^ + +Those options are meant to tweak `pgloader` behavior when loading data. + + * `-v`, `--verbose` + + Be verbose. + + * `-q`, `--quiet` + + Be quiet. + + * `-d`, `--debug` + + Show debug level information messages. + + * `-D`, `--root-dir` + + Set the root working directory (default to "/tmp/pgloader"). + + * `-L`, `--logfile` + + Set the pgloader log file (default to "/tmp/pgloader.log"). + + * `--log-min-messages` + + Minimum level of verbosity needed for log message to make it to the + logfile. One of critical, log, error, warning, notice, info or debug. + + * `--client-min-messages` + + Minimum level of verbosity needed for log message to make it to the + console. One of critical, log, error, warning, notice, info or debug. + + * `-S`, `--summary` + + A filename where to copy the summary output. When relative, the filename + is expanded into `*root-dir*`. + + The format of the filename defaults to being *human readable*. It is + possible to have the output in machine friendly formats such as *CSV*, + *COPY* (PostgreSQL's own COPY format) or *JSON* by specifying a filename + with the extension resp. `.csv`, `.copy` or `.json`. + + * `-l `, `--load-lisp-file ` + + Specify a lisp to compile and load into the pgloader image before + reading the commands, allowing to define extra transformation function. + Those functions should be defined in the `pgloader.transforms` package. + This option can appear more than once in the command line. + + * `--dry-run` + + Allow testing a `.load` file without actually trying to load any data. + It's useful to debug it until it's ok, in particular to fix connection + strings. + + * `--on-error-stop` + + Alter pgloader behavior: rather than trying to be smart about error + handling and continue loading good data, separating away the bad one, + just stop as soon as PostgreSQL refuses anything sent to it. Useful to + debug data processing, transformation function and specific type + casting. + + * `--self-upgrade ` + + Specify a where to find pgloader sources so that one of the + very first things it does is dynamically loading-in (and compiling to + machine code) another version of itself, usually a newer one like a very + recent git checkout. + +Command Line Only Operations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Those options are meant to be used when using `pgloader` from the command +line only, rather than using a command file and the rich command clauses and +parser. In simple cases, it can be much easier to use the *SOURCE* and +*TARGET* directly on the command line, then tweak the loading with those +options: + + * `--with "option"` + + Allows setting options from the command line. You can use that option as + many times as you want. The option arguments must follow the *WITH* + clause for the source type of the `SOURCE` specification, as described + later in this document. + + * `--set "guc_name='value'"` + + Allows setting PostgreSQL configuration from the command line. Note that + the option parsing is the same as when used from the *SET* command + clause, in particular you must enclose the guc value with single-quotes. + + * `--field "..."` + + Allows setting a source field definition. Fields are accumulated in the + order given on the command line. It's possible to either use a `--field` + option per field in the source file, or to separate field definitions by + a comma, as you would do in the *HAVING FIELDS* clause. + + * `--cast "..."` + + Allows setting a specific casting rule for loading the data. + + * `--type csv|fixed|db3|ixf|sqlite|mysql|mssql` + + Allows forcing the source type, in case when the *SOURCE* parsing isn't + satisfying. + + * `--encoding ` + + Set the encoding of the source file to load data from. + + * `--before ` + + Parse given filename for SQL queries and run them against the target + database before loading the data from the source. The queries are parsed + by pgloader itself: they need to be terminated by a semi-colon (;) and + the file may include `\i` or `\ir` commands to *include* another file. + + * `--after ` + + Parse given filename for SQL queries and run them against the target + database after having loaded the data from the source. The queries are + parsed in the same way as with the `--before` option, see above. + +More Debug Information +^^^^^^^^^^^^^^^^^^^^^^ + +To get the maximum amount of debug information, you can use both the +`--verbose` and the `--debug` switches at the same time, which is equivalent +to saying `--client-min-messages data`. Then the log messages will show the +data being processed, in the cases where the code has explicit support for +it. + +Batches And Retry Behaviour +--------------------------- + +To load data to PostgreSQL, pgloader uses the `COPY` streaming protocol. +While this is the faster way to load data, `COPY` has an important drawback: +as soon as PostgreSQL emits an error with any bit of data sent to it, +whatever the problem is, the whole data set is rejected by PostgreSQL. + +To work around that, pgloader cuts the data into *batches* of 25000 rows +each, so that when a problem occurs it's only impacting that many rows of +data. Each batch is kept in memory while the `COPY` streaming happens, in +order to be able to handle errors should some happen. + +When PostgreSQL rejects the whole batch, pgloader logs the error message +then isolates the bad row(s) from the accepted ones by retrying the batched +rows in smaller batches. To do that, pgloader parses the *CONTEXT* error +message from the failed COPY, as the message contains the line number where +the error was found in the batch, as in the following example:: + + CONTEXT: COPY errors, line 3, column b: "2006-13-11" + +Using that information, pgloader will reload all rows in the batch before +the erroneous one, log the erroneous one as rejected, then try loading the +remaining of the batch in a single attempt, which may or may not contain +other erroneous data. + +At the end of a load containing rejected rows, you will find two files in +the *root-dir* location, under a directory named the same as the target +database of your setup. The filenames are the target table, and their +extensions are `.dat` for the rejected data and `.log` for the file +containing the full PostgreSQL client side logs about the rejected data. + +The `.dat` file is formatted in PostgreSQL the text COPY format as documented +in `http://www.postgresql.org/docs/9.2/static/sql-copy.html#AEN66609`. + +A Note About Performance +------------------------ + +pgloader has been developed with performance in mind, to be able to cope +with ever growing needs in loading large amounts of data into PostgreSQL. + +The basic architecture it uses is the old Unix pipe model, where a thread is +responsible for loading the data (reading a CSV file, querying MySQL, etc) +and fills pre-processed data into a queue. Another threads feeds from the +queue, apply some more *transformations* to the input data and stream the +end result to PostgreSQL using the COPY protocol. + +When given a file that the PostgreSQL `COPY` command knows how to parse, and +if the file contains no erroneous data, then pgloader will never be as fast +as just using the PostgreSQL `COPY` command. + +Note that while the `COPY` command is restricted to read either from its +standard input or from a local file on the server's file system, the command +line tool `psql` implements a `\copy` command that knows how to stream a +file local to the client over the network and into the PostgreSQL server, +using the same protocol as pgloader uses. + +A Note About Parallelism +------------------------ + +pgloader uses several concurrent tasks to process the data being loaded: + + - a reader task reads the data in and pushes it to a queue, + + - at last one write task feeds from the queue and formats the raw into the + PostgreSQL COPY format in batches (so that it's possible to then retry a + failed batch without reading the data from source again), and then sends + the data to PostgreSQL using the COPY protocol. + +The parameter *workers* allows to control how many worker threads are +allowed to be active at any time (that's the parallelism level); and the +parameter *concurrency* allows to control how many tasks are started to +handle the data (they may not all run at the same time, depending on the +*workers* setting). + +We allow *workers* simultaneous workers to be active at the same time in the +context of a single table. A single unit of work consist of several kinds of +workers: + + - a reader getting raw data from the source, + - N writers preparing and sending the data down to PostgreSQL. + +The N here is setup to the *concurrency* parameter: with a *CONCURRENCY* of +2, we start (+ 1 2) = 3 concurrent tasks, with a *concurrency* of 4 we start +(+ 1 4) = 9 concurrent tasks, of which only *workers* may be active +simultaneously. + +The defaults are `workers = 4, concurrency = 1` when loading from a database +source, and `workers = 8, concurrency = 2` when loading from something else +(currently, a file). Those defaults are arbitrary and waiting for feedback +from users, so please consider providing feedback if you play with the +settings. + +As the `CREATE INDEX` threads started by pgloader are only waiting until +PostgreSQL is done with the real work, those threads are *NOT* counted into +the concurrency levels as detailed here. + +By default, as many `CREATE INDEX` threads as the maximum number of indexes +per table are found in your source schema. It is possible to set the `max +parallel create index` *WITH* option to another number in case there's just +too many of them to create. + +Source Formats +-------------- + +pgloader supports the following input formats: + + - csv, which includes also tsv and other common variants where you can + change the *separator* and the *quoting* rules and how to *escape* the + *quotes* themselves; + + - fixed columns file, where pgloader is flexible enough to accomodate with + source files missing columns (*ragged fixed length column files* do + exist); + + - PostgreSLQ COPY formatted files, following the COPY TEXT documentation + of PostgreSQL, such as the reject files prepared by pgloader; + + - dbase files known as db3 or dbf file; + + - ixf formated files, ixf being a binary storage format from IBM; + + - sqlite databases with fully automated discovery of the schema and + advanced cast rules; + + - mysql databases with fully automated discovery of the schema and + advanced cast rules; + + - MS SQL databases with fully automated discovery of the schema and + advanced cast rules. + +Pgloader Commands Syntax +------------------------ + +pgloader implements a Domain Specific Language allowing to setup complex +data loading scripts handling computed columns and on-the-fly sanitization +of the input data. For more complex data loading scenarios, you will be +required to learn that DSL's syntax. It's meant to look familiar to DBA by +being inspired by SQL where it makes sense, which is not that much after +all. + +The pgloader commands follow the same global grammar rules. Each of them +might support only a subset of the general options and provide specific +options. + +:: + + LOAD + FROM + [ HAVING FIELDS ] + INTO + [ TARGET TABLE [ "" ]."" ] + [ TARGET COLUMNS ] + + [ WITH ] + + [ SET ] + + [ BEFORE LOAD [ DO | EXECUTE ] ... ] + [ AFTER LOAD [ DO | EXECUTE ] ... ] + ; + +The main clauses are the `LOAD`, `FROM`, `INTO` and `WITH` clauses that each +command implements. Some command then implement the `SET` command, or some +specific clauses such as the `CAST` clause. + +Templating with Mustache +------------------------ + +pgloader implements the https://mustache.github.io/ templating system so +that you may have dynamic parts of your commands. See the documentation for +this template system online. + +A specific feature of pgloader is the ability to fetch a variable from the +OS environment of the pgloader process, making it possible to run pgloader +as in the following example:: + + $ DBPATH=sqlite/sqlite.db pgloader ./test/sqlite-env.load + +or in several steps:: + + $ export DBPATH=sqlite/sqlite.db + $ pgloader ./test/sqlite-env.load + +The variable can then be used in a typical mustache fashion:: + + load database + from '{{DBPATH}}' + into postgresql:///pgloader; + +It's also possible to prepare a INI file such as the following:: + + [pgloader] + + DBPATH = sqlite/sqlite.db + +And run the following command, feeding the INI values as a *context* for +pgloader templating system:: + + $ pgloader --context ./test/sqlite.ini ./test/sqlite-ini.load + +The mustache templates implementation with OS environment support replaces +former `GETENV` implementation, which didn't work anyway. + +Common Clauses +-------------- + +Some clauses are common to all commands: + +FROM +^^^^ + +The *FROM* clause specifies where to read the data from, and each command +introduces its own variant of sources. For instance, the *CSV* source +supports `inline`, `stdin`, a filename, a quoted filename, and a *FILENAME +MATCHING* clause (see above); whereas the *MySQL* source only supports a +MySQL database URI specification. + +INTO +^^^^ + +The PostgreSQL connection URI must contains the name of the target table +where to load the data into. That table must have already been created in +PostgreSQL, and the name might be schema qualified. + +Then *INTO* option also supports an optional comma separated list of target +columns, which are either the name of an input *field* or the white space +separated list of the target column name, its PostgreSQL data type and a +*USING* expression. + +The *USING* expression can be any valid Common Lisp form and will be read +with the current package set to `pgloader.transforms`, so that you can use +functions defined in that package, such as functions loaded dynamically with +the `--load` command line parameter. + +Each *USING* expression is compiled at runtime to native code. + +This feature allows pgloader to load any number of fields in a CSV file into +a possibly different number of columns in the database, using custom code +for that projection. + +WITH +^^^^ + +Set of options to apply to the command, using a global syntax of either: + + - *key = value* + - *use option* + - *do not use option* + +See each specific command for details. + +All data sources specific commands support the following options: + + - *on error stop* + - *batch rows = R* + - *batch size = ... MB* + - *prefetch rows = ...* + +See the section BATCH BEHAVIOUR OPTIONS for more details. + +In addition, the following settings are available: + + - *workers = W* + - *concurrency = C* + - *max parallel create index = I* + +See section A NOTE ABOUT PARALLELISM for more details. + +SET +^^^ + +This clause allows to specify session parameters to be set for all the +sessions opened by pgloader. It expects a list of parameter name, the equal +sign, then the single-quoted value as a comma separated list. + +The names and values of the parameters are not validated by pgloader, they +are given as-is to PostgreSQL. + +BEFORE LOAD DO +^^^^^^^^^^^^^^ + +You can run SQL queries against the database before loading the data from +the `CSV` file. Most common SQL queries are `CREATE TABLE IF NOT EXISTS` so +that the data can be loaded. + +Each command must be *dollar-quoted*: it must begin and end with a double +dollar sign, `$$`. Dollar-quoted queries are then comma separated. No extra +punctuation is expected after the last SQL query. + +BEFORE LOAD EXECUTE +^^^^^^^^^^^^^^^^^^^ + +Same behaviour as in the *BEFORE LOAD DO* clause. Allows you to read the SQL +queries from a SQL file. Implements support for PostgreSQL dollar-quoting +and the `\i` and `\ir` include facilities as in `psql` batch mode (where +they are the same thing). + +AFTER LOAD DO +^^^^^^^^^^^^^ + +Same format as *BEFORE LOAD DO*, the dollar-quoted queries found in that +section are executed once the load is done. That's the right time to create +indexes and constraints, or re-enable triggers. + +AFTER LOAD EXECUTE +^^^^^^^^^^^^^^^^^^ + +Same behaviour as in the *AFTER LOAD DO* clause. Allows you to read the SQL +queries from a SQL file. Implements support for PostgreSQL dollar-quoting +and the `\i` and `\ir` include facilities as in `psql` batch mode (where +they are the same thing). + +Connection String +^^^^^^^^^^^^^^^^^ + +The `` parameter is expected to be given as a *Connection URI* +as documented in the PostgreSQL documentation at +http://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNSTRING. + +:: + + postgresql://[user[:password]@][netloc][:port][/dbname][?option=value&...] + +Where: + + - *user* + + Can contain any character, including colon (`:`) which must then be + doubled (`::`) and at-sign (`@`) which must then be doubled (`@@`). + + When omitted, the *user* name defaults to the value of the `PGUSER` + environment variable, and if it is unset, the value of the `USER` + environment variable. + + - *password* + + Can contain any character, including the at sign (`@`) which must then + be doubled (`@@`). To leave the password empty, when the *user* name + ends with at at sign, you then have to use the syntax user:@. + + When omitted, the *password* defaults to the value of the `PGPASSWORD` + environment variable if it is set, otherwise the password is left + unset. + + When no *password* is found either in the connection URI nor in the + environment, then pgloader looks for a `.pgpass` file as documented at + https://www.postgresql.org/docs/current/static/libpq-pgpass.html. The + implementation is not that of `libpq` though. As with `libpq` you can + set the environment variable `PGPASSFILE` to point to a `.pgpass` file, + and pgloader defaults to `~/.pgpass` on unix like systems and + `%APPDATA%\postgresql\pgpass.conf` on windows. Matching rules and syntax + are the same as with `libpq`, refer to its documentation. + + - *netloc* + + Can be either a hostname in dotted notation, or an ipv4, or an Unix + domain socket path. Empty is the default network location, under a + system providing *unix domain socket* that method is preferred, otherwise + the *netloc* default to `localhost`. + + It's possible to force the *unix domain socket* path by using the syntax + `unix:/path/to/where/the/socket/file/is`, so to force a non default + socket path and a non default port, you would have: + + postgresql://unix:/tmp:54321/dbname + + The *netloc* defaults to the value of the `PGHOST` environment + variable, and if it is unset, to either the default `unix` socket path + when running on a Unix system, and `localhost` otherwise. + + Socket path containing colons are supported by doubling the colons + within the path, as in the following example: + + postgresql://unix:/tmp/project::region::instance:5432/dbname + + - *dbname* + + Should be a proper identifier (letter followed by a mix of letters, + digits and the punctuation signs comma (`,`), dash (`-`) and underscore + (`_`). + + When omitted, the *dbname* defaults to the value of the environment + variable `PGDATABASE`, and if that is unset, to the *user* value as + determined above. + + - *options* + + The optional parameters must be supplied with the form `name=value`, and + you may use several parameters by separating them away using an + ampersand (`&`) character. + + Only some options are supported here, *tablename* (which might be + qualified with a schema name) *sslmode*, *host*, *port*, *dbname*, + *user* and *password*. + + The *sslmode* parameter values can be one of `disable`, `allow`, + `prefer` or `require`. + + For backward compatibility reasons, it's possible to specify the + *tablename* option directly, without spelling out the `tablename=` + parts. + + The options override the main URI components when both are given, and + using the percent-encoded option parameters allow using passwords + starting with a colon and bypassing other URI components parsing + limitations. + +Regular Expressions +^^^^^^^^^^^^^^^^^^^ + +Several clauses listed in the following accept *regular expressions* with +the following input rules: + + - A regular expression begins with a tilde sign (`~`), + + - is then followed with an opening sign, + + - then any character is allowed and considered part of the regular + expression, except for the closing sign, + + - then a closing sign is expected. + +The opening and closing sign are allowed by pair, here's the complete list +of allowed delimiters:: + + ~// + ~[] + ~{} + ~() + ~<> + ~"" + ~'' + ~|| + ~## + +Pick the set of delimiters that don't collide with the *regular expression* +you're trying to input. If your expression is such that none of the +solutions allow you to enter it, the places where such expressions are +allowed should allow for a list of expressions. + +Comments +^^^^^^^^ + +Any command may contain comments, following those input rules: + + - the `--` delimiter begins a comment that ends with the end of the + current line, + + - the delimiters `/*` and `*/` respectively start and end a comment, which + can be found in the middle of a command or span several lines. + +Any place where you could enter a *whitespace* will accept a comment too. + +Batch behaviour options +^^^^^^^^^^^^^^^^^^^^^^^ + +All pgloader commands have support for a *WITH* clause that allows for +specifying options. Some options are generic and accepted by all commands, +such as the *batch behaviour options*, and some options are specific to a +data source kind, such as the CSV *skip header* option. + +The global batch behaviour options are: + + - *batch rows* + + Takes a numeric value as argument, used as the maximum number of rows + allowed in a batch. The default is `25 000` and can be changed to try + having better performance characteristics or to control pgloader memory + usage; + + - *batch size* + + Takes a memory unit as argument, such as *20 MB*, its default value. + Accepted multipliers are *kB*, *MB*, *GB*, *TB* and *PB*. The case is + important so as not to be confused about bits versus bytes, we're only + talking bytes here. + + - *prefetch rows* + + Takes a numeric value as argument, defaults to `100000`. That's the + number of rows that pgloader is allowed to read in memory in each reader + thread. See the *workers* setting for how many reader threads are + allowed to run at the same time. + +Other options are specific to each input source, please refer to specific +parts of the documentation for their listing and covering. + +A batch is then closed as soon as either the *batch rows* or the *batch +size* threshold is crossed, whichever comes first. In cases when a batch has +to be closed because of the *batch size* setting, a *debug* level log +message is printed with how many rows did fit in the *oversized* batch. + diff --git a/docs/_build/html/_sources/ref/archive.rst.txt b/docs/_build/html/_sources/ref/archive.rst.txt new file mode 100644 index 0000000..1cb95c2 --- /dev/null +++ b/docs/_build/html/_sources/ref/archive.rst.txt @@ -0,0 +1,104 @@ +Loading From an Archive +======================= + +This command instructs pgloader to load data from one or more files contained +in an archive. Currently the only supported archive format is *ZIP*, and the +archive might be downloaded from an *HTTP* URL. + +Here's an example:: + + LOAD ARCHIVE + FROM /Users/dim/Downloads/GeoLiteCity-latest.zip + INTO postgresql:///ip4r + + BEFORE LOAD + DO $$ create extension if not exists ip4r; $$, + $$ create schema if not exists geolite; $$, + + EXECUTE 'geolite.sql' + + LOAD CSV + FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/ + WITH ENCODING iso-8859-1 + ( + locId, + country, + region null if blanks, + city null if blanks, + postalCode null if blanks, + latitude, + longitude, + metroCode null if blanks, + areaCode null if blanks + ) + INTO postgresql:///ip4r?geolite.location + ( + locid,country,region,city,postalCode, + location point using (format nil "(~a,~a)" longitude latitude), + metroCode,areaCode + ) + WITH skip header = 2, + fields optionally enclosed by '"', + fields escaped by double-quote, + fields terminated by ',' + + AND LOAD CSV + FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/ + WITH ENCODING iso-8859-1 + ( + startIpNum, endIpNum, locId + ) + INTO postgresql:///ip4r?geolite.blocks + ( + iprange ip4r using (ip-range startIpNum endIpNum), + locId + ) + WITH skip header = 2, + fields optionally enclosed by '"', + fields escaped by double-quote, + fields terminated by ',' + + FINALLY DO + $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$; + +The `archive` command accepts the following clauses and options. + +Archive Source Specification: FROM +---------------------------------- + +Filename or HTTP URI where to load the data from. When given an HTTP URL the +linked file will get downloaded locally before processing. + +If the file is a `zip` file, the command line utility `unzip` is used to +expand the archive into files in `$TMPDIR`, or `/tmp` if `$TMPDIR` is unset +or set to a non-existing directory. + +Then the following commands are used from the top level directory where the +archive has been expanded. + +Archive Sub Commands +-------------------- + + - command [ *AND* command ... ] + + A series of commands against the contents of the archive, at the moment + only `CSV`,`'FIXED` and `DBF` commands are supported. + + Note that commands are supporting the clause *FROM FILENAME MATCHING* + which allows the pgloader command not to depend on the exact names of + the archive directories. + + The same clause can also be applied to several files with using the + spelling *FROM ALL FILENAMES MATCHING* and a regular expression. + + The whole *matching* clause must follow the following rule:: + + FROM [ ALL FILENAMES | [ FIRST ] FILENAME ] MATCHING + +Archive Final SQL Commands +-------------------------- + + - *FINALLY DO* + + SQL Queries to run once the data is loaded, such as `CREATE INDEX`. + diff --git a/docs/_build/html/_sources/ref/copy.rst.txt b/docs/_build/html/_sources/ref/copy.rst.txt new file mode 100644 index 0000000..e8b156d --- /dev/null +++ b/docs/_build/html/_sources/ref/copy.rst.txt @@ -0,0 +1,115 @@ +Loading COPY Formatted Files +============================ + +This commands instructs pgloader to load from a file containing COPY TEXT +data as described in the PostgreSQL documentation. Here's an example:: + + LOAD COPY + FROM copy://./data/track.copy + ( + trackid, track, album, media, genre, composer, + milliseconds, bytes, unitprice + ) + INTO postgresql:///pgloader + TARGET TABLE track_full + + WITH truncate + + SET work_mem to '14MB', + standard_conforming_strings to 'on' + + BEFORE LOAD DO + $$ drop table if exists track_full; $$, + $$ create table track_full ( + trackid bigserial, + track text, + album text, + media text, + genre text, + composer text, + milliseconds bigint, + bytes bigint, + unitprice numeric + ); + $$; + +The `COPY` format command accepts the following clauses and options. + +COPY Formatted Files Source Specification: FROM +----------------------------------------------- + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + + - *inline* + + The data is found after the end of the parsed commands. Any number of + empty lines between the end of the commands and the beginning of the + data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above for + exact syntax, several options can be used here) to filenames. It's then + possible to load data from only the first match of all of them. + + The optional *IN DIRECTORY* clause allows specifying which directory to + walk for finding the data files, and can be either relative to where the + command file is read from, or absolute. The given directory must exists. + +COPY Formatted File Options: WITH +--------------------------------- + + +When loading from a `COPY` file, the following options are supported: + + - *delimiter* + + Takes a single character as argument, which must be found inside single + quotes, and might be given as the printable character itself, the + special value \t to denote a tabulation character, or `0x` then an + hexadecimal value read as the ASCII code for the character. + + This character is used as the *delimiter* when reading the data, in a + similar way to the PostgreSQL `COPY` option. + + - *null* + + Takes a quoted string as an argument (quotes can be either double quotes + or single quotes) and uses that string as the `NULL` representation in + the data. + + This is similar to the *null* `COPY` option in PostgreSQL. + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that many + lines at the beginning of the input file. diff --git a/docs/_build/html/_sources/ref/csv.rst.txt b/docs/_build/html/_sources/ref/csv.rst.txt new file mode 100644 index 0000000..243e8e6 --- /dev/null +++ b/docs/_build/html/_sources/ref/csv.rst.txt @@ -0,0 +1,237 @@ +Loading CSV data +================ + +This command instructs pgloader to load data from a `CSV` file. Here's an +example:: + + LOAD CSV + FROM 'GeoLiteCity-Blocks.csv' WITH ENCODING iso-646-us + HAVING FIELDS + ( + startIpNum, endIpNum, locId + ) + INTO postgresql://user@localhost:54393/dbname + TARGET TABLE geolite.blocks + TARGET COLUMNS + ( + iprange ip4r using (ip-range startIpNum endIpNum), + locId + ) + WITH truncate, + skip header = 2, + fields optionally enclosed by '"', + fields escaped by backslash-quote, + fields terminated by '\t' + + SET work_mem to '32 MB', maintenance_work_mem to '64 MB'; + +The `csv` format command accepts the following clauses and options. + +CSV Source Specification: FROM +------------------------------ + +Filename where to load the data from. Accepts an *ENCODING* option. Use the +`--list-encodings` option to know which encoding names are supported. + +The filename may be enclosed by single quotes, and could be one of the +following special values: + + - *inline* + + The data is found after the end of the parsed commands. Any number + of empty lines between the end of the commands and the beginning of + the data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above + for exact syntax, several options can be used here) to filenames. + It's then possible to load data from only the first match of all of + them. + + The optional *IN DIRECTORY* clause allows specifying which directory + to walk for finding the data files, and can be either relative to + where the command file is read from, or absolute. The given + directory must exists. + +Fields Specifications +--------------------- + +The *FROM* option also supports an optional comma separated list of *field* +names describing what is expected in the `CSV` data file, optionally +introduced by the clause `HAVING FIELDS`. + +Each field name can be either only one name or a name following with +specific reader options for that field, enclosed in square brackets and +comma-separated. Supported per-field reader options are: + + - *terminated by* + + See the description of *field terminated by* below. + + The processing of this option is not currently implemented. + + - *date format* + + When the field is expected of the date type, then this option allows + to specify the date format used in the file. + + Date format string are template strings modeled against the + PostgreSQL `to_char` template strings support, limited to the + following patterns: + + - YYYY, YYY, YY for the year part + - MM for the numeric month part + - DD for the numeric day part + - HH, HH12, HH24 for the hour part + - am, AM, a.m., A.M. + - pm, PM, p.m., P.M. + - MI for the minutes part + - SS for the seconds part + - MS for the milliseconds part (4 digits) + - US for the microseconds part (6 digits) + - unparsed punctuation signs: - . * # @ T / \ and space + + Here's an example of a *date format* specification:: + + column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] + + - *null if* + + This option takes an argument which is either the keyword *blanks* + or a double-quoted string. + + When *blanks* is used and the field value that is read contains + only space characters, then it's automatically converted to an SQL + `NULL` value. + + When a double-quoted string is used and that string is read as the + field value, then the field value is automatically converted to an + SQL `NULL` value. + + - *trim both whitespace*, *trim left whitespace*, *trim right whitespace* + + This option allows to trim whitespaces in the read data, either from + both sides of the data, or only the whitespace characters found on + the left of the streaing, or only those on the right of the string. + +CSV Loading Options: WITH +------------------------- + +When loading from a `CSV` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command + against the PostgreSQL target table before reading the data file. + + - *drop indexes* + + When this option is listed, pgloader issues `DROP INDEX` commands + against all the indexes defined on the target table before copying + the data, then `CREATE INDEX` commands once the `COPY` is done. + + In order to get the best performance possible, all the indexes are + created in parallel and when done the primary keys are built again + from the unique indexes just created. This two step process allows + creating the primary key index in parallel with the other indexes, + as only the `ALTER TABLE` command needs an *access exclusive lock* + on the target table. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... + DISABLE TRIGGER ALL` command against the PostgreSQL target table + before copying the data, then the command `ALTER TABLE ... ENABLE + TRIGGER ALL` once the `COPY` is done. + + This option allows loading data into a pre-existing table ignoring + the *foreign key constraints* and user defined triggers and may + result in invalid *foreign key constraints* once the data is loaded. + Use with care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that + many lines at the beginning of the input file. + + - *csv header* + + Use the first line read after *skip header* as the list of csv field + names to be found in the CSV file, using the same CSV parameters as + for the CSV data. + + - *trim unquoted blanks* + + When reading unquoted values in the `CSV` file, remove the blanks + found in between the separator and the value. That behaviour is the + default. + + - *keep unquoted blanks* + + When reading unquoted values in the `CSV` file, keep blanks found in + between the separator and the value. + + - *fields optionally enclosed by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used as the quoting character in the `CSV` file, + and defaults to double-quote. + + - *fields not enclosed* + + By default, pgloader will use the double-quote character as the + enclosing character. If you have a CSV file where fields are not + enclosed and are using double-quote as an expected ordinary + character, then use the option *fields not enclosed* for the CSV + parser to accept those values. + + - *fields escaped by* + + Takes either the special value *backslash-quote* or *double-quote*, + or any value supported by the *fields terminated by* option (see + below). This value is used to recognize escaped field separators + when they are to be found within the data fields themselves. + Defaults to *double-quote*. + + - *csv escape mode* + + Takes either the special value *quote* (the default) or *following* + and allows the CSV parser to parse either only escaped field + separator or any character (including CSV data) when using the + *following* value. + + - *fields terminated by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used as the *field separator* when reading the + `CSV` data. + + - *lines terminated by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used to recognize *end-of-line* condition when + reading the `CSV` data. + diff --git a/docs/_build/html/_sources/ref/dbf.rst.txt b/docs/_build/html/_sources/ref/dbf.rst.txt new file mode 100644 index 0000000..28269f3 --- /dev/null +++ b/docs/_build/html/_sources/ref/dbf.rst.txt @@ -0,0 +1,53 @@ +Loading DBF data +================= + +This command instructs pgloader to load data from a `DBF` file. Here's an +example:: + + LOAD DBF + FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/reg2013.dbf + INTO postgresql://user@localhost/dbname + WITH truncate, create table; + +The `dbf` format command accepts the following clauses and options. + +DBF Source Specification: FROM +------------------------------ + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + +DBF Loading Options: WITH +------------------------- + +When loading from a `DBF` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create table* + + When this option is listed, pgloader creates the table using the meta + data found in the `DBF` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *table name* + + This options expects as its value the possibly qualified name of the + table to create. diff --git a/docs/_build/html/_sources/ref/fixed.rst.txt b/docs/_build/html/_sources/ref/fixed.rst.txt new file mode 100644 index 0000000..dd567da --- /dev/null +++ b/docs/_build/html/_sources/ref/fixed.rst.txt @@ -0,0 +1,182 @@ +Loading Fixed Cols File Formats +=============================== + +This command instructs pgloader to load data from a text file containing +columns arranged in a *fixed size* manner. Here's an example:: + + LOAD FIXED + FROM inline + ( + a from 0 for 10, + b from 10 for 8, + c from 18 for 8, + d from 26 for 17 [null if blanks, trim right whitespace] + ) + INTO postgresql:///pgloader + TARGET TABLE fixed + ( + a, b, + c time using (time-with-no-separator c), + d + ) + + WITH truncate + + SET work_mem to '14MB', + standard_conforming_strings to 'on' + + BEFORE LOAD DO + $$ drop table if exists fixed; $$, + $$ create table fixed ( + a integer, + b date, + c time, + d text + ); + $$; + + 01234567892008052011431250firstline + 01234562008052115182300left blank-padded + 12345678902008052208231560another line + 2345609872014092914371500 + 2345678902014092914371520 + +The `fixed` format command accepts the following clauses and options. + +Fixed File Format Source Specification: FROM +-------------------------------------------- + +Filename where to load the data from. Accepts an *ENCODING* option. Use the +`--list-encodings` option to know which encoding names are supported. + +The filename may be enclosed by single quotes, and could be one of the +following special values: + + - *inline* + + The data is found after the end of the parsed commands. Any number + of empty lines between the end of the commands and the beginning of + the data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above + for exact syntax, several options can be used here) to filenames. + It's then possible to load data from only the first match of all of + them. + + The optional *IN DIRECTORY* clause allows specifying which directory + to walk for finding the data files, and can be either relative to + where the command file is read from, or absolute. The given + directory must exists. + +Fields Specifications +--------------------- + +The *FROM* option also supports an optional comma separated list of *field* +names describing what is expected in the `FIXED` data file. + +Each field name is composed of the field name followed with specific reader +options for that field. Supported per-field reader options are the +following, where only *start* and *length* are required. + + - *start* + + Position in the line where to start reading that field's value. Can + be entered with decimal digits or `0x` then hexadecimal digits. + + - *length* + + How many bytes to read from the *start* position to read that + field's value. Same format as *start*. + +Those optional parameters must be enclosed in square brackets and +comma-separated: + + - *terminated by* + + See the description of *field terminated by* below. + + The processing of this option is not currently implemented. + + - *date format* + + When the field is expected of the date type, then this option allows + to specify the date format used in the file. + + Date format string are template strings modeled against the + PostgreSQL `to_char` template strings support, limited to the + following patterns: + + - YYYY, YYY, YY for the year part + - MM for the numeric month part + - DD for the numeric day part + - HH, HH12, HH24 for the hour part + - am, AM, a.m., A.M. + - pm, PM, p.m., P.M. + - MI for the minutes part + - SS for the seconds part + - MS for the milliseconds part (4 digits) + - US for the microseconds part (6 digits) + - unparsed punctuation signs: - . * # @ T / \ and space + + Here's an example of a *date format* specification:: + + column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] + + - *null if* + + This option takes an argument which is either the keyword *blanks* + or a double-quoted string. + + When *blanks* is used and the field value that is read contains only + space characters, then it's automatically converted to an SQL `NULL` + value. + + When a double-quoted string is used and that string is read as the + field value, then the field value is automatically converted to an + SQL `NULL` value. + + - *trim both whitespace*, *trim left whitespace*, *trim right whitespace* + + This option allows to trim whitespaces in the read data, either from + both sides of the data, or only the whitespace characters found on + the left of the streaing, or only those on the right of the string. + +Fixed File Format Loading Options: WITH +--------------------------------------- + +When loading from a `FIXED` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command + against the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... + DISABLE TRIGGER ALL` command against the PostgreSQL target table + before copying the data, then the command `ALTER TABLE ... ENABLE + TRIGGER ALL` once the `COPY` is done. + + This option allows loading data into a pre-existing table ignoring + the *foreign key constraints* and user defined triggers and may + result in invalid *foreign key constraints* once the data is loaded. + Use with care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that + many lines at the beginning of the input file. + diff --git a/docs/_build/html/_sources/ref/ixf.rst.txt b/docs/_build/html/_sources/ref/ixf.rst.txt new file mode 100644 index 0000000..3f698fa --- /dev/null +++ b/docs/_build/html/_sources/ref/ixf.rst.txt @@ -0,0 +1,66 @@ +Loading IXF Data +================ + +This command instructs pgloader to load data from an IBM `IXF` file. Here's +an example:: + + LOAD IXF + FROM data/nsitra.test1.ixf + INTO postgresql:///pgloader + TARGET TABLE nsitra.test1 + WITH truncate, create table, timezone UTC + + BEFORE LOAD DO + $$ create schema if not exists nsitra; $$, + $$ drop table if exists nsitra.test1; $$; + +The `ixf` format command accepts the following clauses and options. + +IXF Source Specification: FROM +------------------------------ + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single ixf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + +IXF Loading Options: WITH +------------------------- + +When loading from a `IXF` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create table* + + When this option is listed, pgloader creates the table using the meta + data found in the `DBF` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *table name* + + This options expects as its value the possibly qualified name of the + table to create. + + - *timezone* + + This options allows to specify which timezone is used when parsing + timestamps from an IXF file, and defaults to *UTC*. Expected values are + either `UTC`, `GMT` or a single quoted location name such as + `'Universal'` or `'Europe/Paris'`. + diff --git a/docs/_build/html/_sources/ref/mssql.rst.txt b/docs/_build/html/_sources/ref/mssql.rst.txt new file mode 100644 index 0000000..89ff6f3 --- /dev/null +++ b/docs/_build/html/_sources/ref/mssql.rst.txt @@ -0,0 +1,159 @@ +Migrating a MS SQL Database to PostgreSQL +========================================= + +This command instructs pgloader to load data from a MS SQL database. +Automatic discovery of the schema is supported, including build of the +indexes, primary and foreign keys constraints. + +Here's an example:: + + load database + from mssql://user@host/dbname + into postgresql:///dbname + + including only table names like 'GlobalAccount' in schema 'dbo' + + set work_mem to '16MB', maintenance_work_mem to '512 MB' + + before load do $$ drop schema if exists dbo cascade; $$; + +The `mssql` command accepts the following clauses and options. + +MS SQL Database Source Specification: FROM +------------------------------------------ + +Connection string to an existing MS SQL database server that listens and +welcome external TCP/IP connection. As pgloader currently piggybacks on the +FreeTDS driver, to change the port of the server please export the `TDSPORT` +environment variable. + +MS SQL Database Migration Options: WITH +--------------------------------------- + +When loading from a `MS SQL` database, the same options as when loading a +`MySQL` database are supported. Please refer to the MySQL section. The +following options are added: + + - *create schemas* + + When this option is listed, pgloader creates the same schemas as found + on the MS SQL instance. This is the default. + + - *create no schemas* + + When this option is listed, pgloader refrains from creating any schemas + at all, you must then ensure that the target schema do exist. + +MS SQL Database Casting Rules +----------------------------- + +CAST +^^^^ + +The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases. + +Please refer to the MySQL CAST clause for details. + +MS SQL Partial Migration +------------------------ + + +INCLUDING ONLY TABLE NAMES LIKE +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Introduce a comma separated list of table name patterns used to limit the +tables to migrate to a sublist. More than one such clause may be used, they +will be accumulated together. + +Example:: + + including only table names lile 'GlobalAccount' in schema 'dbo' + +EXCLUDING TABLE NAMES LIKE +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Introduce a comma separated list of table name patterns used to exclude +table names from the migration. This filter only applies to the result of +the *INCLUDING* filter. + +:: + + excluding table names matching 'LocalAccount' in schema 'dbo' + +MS SQL Schema Transformations +----------------------------- + +ALTER SCHEMA '...' RENAME TO '...' +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Allows to rename a schema on the flight, so that for instance the tables +found in the schema 'dbo' in your source database will get migrated into the +schema 'public' in the target database with this command:: + + alter schema 'dbo' rename to 'public' + +ALTER TABLE NAMES MATCHING ... IN SCHEMA '...' +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +See the MySQL explanation for this clause above. It works the same in the +context of migrating from MS SQL, only with the added option to specify the +name of the schema where to find the definition of the target tables. + +The matching is done in pgloader itself, with a Common Lisp regular +expression lib, so doesn't depend on the *LIKE* implementation of MS SQL, +nor on the lack of support for regular expressions in the engine. + +MS SQL Driver setup and encoding +-------------------------------- + +pgloader is using the `FreeTDS` driver, and internally expects the data to +be sent in utf-8. To achieve that, you can configure the FreeTDS driver with +those defaults, in the file `~/.freetds.conf`:: + + [global] + tds version = 7.4 + client charset = UTF-8 + +Default MS SQL Casting Rules +---------------------------- + +When migrating from MS SQL the following Casting Rules are provided: + +Numbers:: + + type tinyint to smallint + + type float to float using float-to-string + type real to real using float-to-string + type double to double precision using float-to-string + type numeric to numeric using float-to-string + type decimal to numeric using float-to-string + type money to numeric using float-to-string + type smallmoney to numeric using float-to-string + +Texts:: + + type char to text drop typemod + type nchat to text drop typemod + type varchar to text drop typemod + type nvarchar to text drop typemod + type xml to text drop typemod + +Binary:: + + type binary to bytea using byte-vector-to-bytea + type varbinary to bytea using byte-vector-to-bytea + +Date:: + + type datetime to timestamptz + type datetime2 to timestamptz + +Others:: + + type bit to boolean + type hierarchyid to bytea + type geography to bytea + type uniqueidentifier to uuid using sql-server-uniqueidentifier-to-uuid + diff --git a/docs/_build/html/_sources/ref/mysql.rst.txt b/docs/_build/html/_sources/ref/mysql.rst.txt new file mode 100644 index 0000000..b484d5b --- /dev/null +++ b/docs/_build/html/_sources/ref/mysql.rst.txt @@ -0,0 +1,623 @@ +Migrating a MySQL Database to PostgreSQL +======================================== + +This command instructs pgloader to load data from a database connection. The +only supported database source is currently *MySQL*, and pgloader supports +dynamically converting the schema of the source database and the indexes +building. + +A default set of casting rules are provided and might be overloaded and +appended to by the command. + +Here's an example using as many options as possible, some of them even being +defaults. Chances are you don't need that complex a setup, don't copy and +paste it, use it only as a reference! + +:: + + LOAD DATABASE + FROM mysql://root@localhost/sakila + INTO postgresql://localhost:54393/sakila + + WITH include drop, create tables, create indexes, reset sequences, + workers = 8, concurrency = 1, + multiple readers per thread, rows per range = 50000 + + SET PostgreSQL PARAMETERS + maintenance_work_mem to '128MB', + work_mem to '12MB', + search_path to 'sakila, public, "$user"' + + SET MySQL PARAMETERS + net_read_timeout = '120', + net_write_timeout = '120' + + CAST type bigint when (= precision 20) to bigserial drop typemod, + type date drop not null drop default using zero-dates-to-null, + -- type tinyint to boolean using tinyint-to-boolean, + type year to integer + + MATERIALIZE VIEWS film_list, staff_list + + -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor' + -- EXCLUDING TABLE NAMES MATCHING ~ + -- DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8 + -- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films' + -- ALTER TABLE NAMES MATCHING ~/_list$/ SET SCHEMA 'mv' + + ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/ + SET SCHEMA 'mv' + + ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films' + ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40') + + ALTER SCHEMA 'sakila' RENAME TO 'pagila' + + BEFORE LOAD DO + $$ create schema if not exists pagila; $$, + $$ create schema if not exists mv; $$, + $$ alter database sakila set search_path to pagila, mv, public; $$; + + +The `database` command accepts the following clauses and options. + +MySQL Database Source Specification: FROM +----------------------------------------- + +Must be a connection URL pointing to a MySQL database. + +If the connection URI contains a table name, then only this table is +migrated from MySQL to PostgreSQL. + +See the `SOURCE CONNECTION STRING` section above for details on how to write +the connection string. The MySQL connection string accepts the same +parameter *sslmode* as the PostgreSQL connection string, but the *verify* +mode is not implemented (yet). + +Environment variables described in + can be +used as default values too. If the user is not provided, then it defaults to +`USER` environment variable value. The password can be provided with the +environment variable `MYSQL_PWD`. The host can be provided with the +environment variable `MYSQL_HOST` and otherwise defaults to `localhost`. The +port can be provided with the environment variable `MYSQL_TCP_PORT` and +otherwise defaults to `3306`. + +MySQL Database Migration Options: WITH +-------------------------------------- + +When loading from a `MySQL` database, the following options are supported, +and the default *WITH* clause is: *no truncate*, *create schema*, *create +tables*, *include drop*, *create indexes*, *reset sequences*, *foreign +keys*, *downcase identifiers*, *uniquify index names*. + + - *include drop* + + When this option is listed, pgloader drops all the tables in the target + PostgreSQL database whose names appear in the MySQL database. This + option allows for using the same command several times in a row until + you figure out all the options, starting automatically from a clean + environment. Please note that `CASCADE` is used to ensure that tables + are dropped even if there are foreign keys pointing to them. This is + precisely what `include drop` is intended to do: drop all target tables + and recreate them. + + Great care needs to be taken when using `include drop`, as it will + cascade to *all* objects referencing the target tables, possibly + including other tables that are not being loaded from the source DB. + + - *include no drop* + + When this option is listed, pgloader will not include any `DROP` + statement when loading the data. + + - *truncate* + + When this option is listed, pgloader issue the `TRUNCATE` command + against each PostgreSQL table just before loading data into it. + + - *no truncate* + + When this option is listed, pgloader issues no `TRUNCATE` command. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create tables* + + When this option is listed, pgloader creates the table using the meta + data found in the `MySQL` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *create no tables* + + When this option is listed, pgloader skips the creation of table before + loading data, target tables must then already exist. + + Also, when using *create no tables* pgloader fetches the metadata from + the current target database and checks type casting, then will remove + constraints and indexes prior to loading the data and install them back + again once the loading is done. + + - *create indexes* + + When this option is listed, pgloader gets the definitions of all the + indexes found in the MySQL database and create the same set of index + definitions against the PostgreSQL database. + + - *create no indexes* + + When this option is listed, pgloader skips the creating indexes. + + - *drop indexes* + + When this option is listed, pgloader drops the indexes in the target + database before loading the data, and creates them again at the end + of the data copy. + + - *uniquify index names*, *preserve index names* + + MySQL index names are unique per-table whereas in PostgreSQL index names + have to be unique per-schema. The default for pgloader is to change the + index name by prefixing it with `idx_OID` where `OID` is the internal + numeric identifier of the table the index is built against. + + In somes cases like when the DDL are entirely left to a framework it + might be sensible for pgloader to refrain from handling index unique + names, that is achieved by using the *preserve index names* option. + + The default is to *uniquify index names*. + + Even when using the option *preserve index names*, MySQL primary key + indexes named "PRIMARY" will get their names uniquified. Failing to do + so would prevent the primary keys to be created again in PostgreSQL + where the index names must be unique per schema. + + - *drop schema* + + When this option is listed, pgloader drops the target schema in the + target PostgreSQL database before creating it again and all the objects + it contains. The default behavior doesn't drop the target schemas. + + - *foreign keys* + + When this option is listed, pgloader gets the definitions of all the + foreign keys found in the MySQL database and create the same set of + foreign key definitions against the PostgreSQL database. + + - *no foreign keys* + + When this option is listed, pgloader skips creating foreign keys. + + - *reset sequences* + + When this option is listed, at the end of the data loading and after the + indexes have all been created, pgloader resets all the PostgreSQL + sequences created to the current maximum value of the column they are + attached to. + + The options *schema only* and *data only* have no effects on this + option. + + - *reset no sequences* + + When this option is listed, pgloader skips resetting sequences after the + load. + + The options *schema only* and *data only* have no effects on this + option. + + - *downcase identifiers* + + When this option is listed, pgloader converts all MySQL identifiers + (table names, index names, column names) to *downcase*, except for + PostgreSQL *reserved* keywords. + + The PostgreSQL *reserved* keywords are determined dynamically by using + the system function `pg_get_keywords()`. + + - *quote identifiers* + + When this option is listed, pgloader quotes all MySQL identifiers so + that their case is respected. Note that you will then have to do the + same thing in your application code queries. + + - *schema only* + + When this option is listed pgloader refrains from migrating the data + over. Note that the schema in this context includes the indexes when the + option *create indexes* has been listed. + + - *data only* + + When this option is listed pgloader only issues the `COPY` statements, + without doing any other processing. + + - *single reader per thread*, *multiple readers per thread* + + The default is *single reader per thread* and it means that each + MySQL table is read by a single thread as a whole, with a single + `SELECT` statement using no `WHERE` clause. + + When using *multiple readers per thread* pgloader may be able to + divide the reading work into several threads, as many as the + *concurrency* setting, which needs to be greater than 1 for this + option to kick be activated. + + For each source table, pgloader searches for a primary key over a + single numeric column, or a multiple-column primary key index for + which the first column is of a numeric data type (one of `integer` + or `bigint`). When such an index exists, pgloader runs a query to + find the *min* and *max* values on this column, and then split that + range into many ranges containing a maximum of *rows per range*. + + When the range list we then obtain contains at least as many ranges + than our concurrency setting, then we distribute those ranges to + each reader thread. + + So when all the conditions are met, pgloader then starts as many + reader thread as the *concurrency* setting, and each reader thread + issues several queries with a `WHERE id >= x AND id < y`, where `y - + x = rows per range` or less (for the last range, depending on the + max value just obtained. + + - *rows per range* + + How many rows are fetched per `SELECT` query when using *multiple + readers per thread*, see above for details. + + - *SET MySQL PARAMETERS* + + The *SET MySQL PARAMETERS* allows setting MySQL parameters using the + MySQL `SET` command each time pgloader connects to it. + +MySQL Database Casting Rules +---------------------------- + +The command *CAST* introduces user-defined casting rules. + +The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases. + +A casting rule is expected to follow one of the forms:: + + type [ ... ] to [ or other required elements. + thead: [ 1, "
", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support: IE <=9 + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // + // Support: Firefox <=42 + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + return ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +function manipulationTarget( elem, content ) { + if ( jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return elem.getElementsByTagName( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + style = elem.style; + + computed = computed || getStyles( elem ); + + // Support: IE <=9 only + // getPropertyValue is only needed for .css('filter') (#12537) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + + // If we already have the right measurement, avoid augmentation + 4 : + + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var val, + valueIsBorderBox = true, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + if ( elem.getClientRects().length ) { + val = elem.getBoundingClientRect()[ name ]; + } + + // Some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + style[ name ] = value; + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, timerId, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function raf() { + if ( timerId ) { + window.requestAnimationFrame( raf ); + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + if ( percent < 1 && length ) { + return remaining; + } else { + deferred.resolveWith( elem, [ animation ] ); + return false; + } + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + // attach callbacks from options + return animation.progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnotwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off or if document is hidden + if ( jQuery.fx.off || document.hidden ) { + opt.duration = 0; + + } else { + opt.duration = typeof opt.duration === "number" ? + opt.duration : opt.duration in jQuery.fx.speeds ? + jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + if ( timer() ) { + jQuery.fx.start(); + } else { + jQuery.timers.pop(); + } +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( !timerId ) { + timerId = window.requestAnimationFrame ? + window.requestAnimationFrame( raf ) : + window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); + } +}; + +jQuery.fx.stop = function() { + if ( window.cancelAnimationFrame ) { + window.cancelAnimationFrame( timerId ); + } else { + window.clearInterval( timerId ); + } + + timerId = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + jQuery.nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + attrNames = value && value.match( rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + return tabindex ? + parseInt( tabindex, 10 ) : + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && elem.href ? + 0 : + -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + +var rclass = /[\t\r\n\f]/g; + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnotwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = jQuery.trim( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnotwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = jQuery.trim( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnotwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + getClass( elem ) + " " ).replace( rclass, " " ) + .indexOf( className ) > -1 + ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g, + rspaces = /[\x20\t\r\n\f]+/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + + // Handle most common string cases + ret.replace( rreturn, "" ) : + + // Handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " ); + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rts = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add anti-cache in uncached url if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rts, "" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Reporting Bugs

+

pgloader is a software and as such contains bugs. Most bugs are easy to +solve and taken care of in a short delay. For this to be possible though, +bug reports need to follow those recommandations:

+
+
    +
  • include pgloader version,
  • +
  • include problematic input and output,
  • +
  • include a description of the output you expected,
  • +
  • explain the difference between the ouput you have and the one you expected,
  • +
  • include a self-reproducing test-case
  • +
+
+
+

Test Cases to Reproduce Bugs

+

Use the inline source type to help reproduce a bug, as in the pgloader tests:

+
LOAD CSV
+   FROM INLINE
+   INTO postgresql://dim@localhost/pgloader?public."HS"
+
+   WITH truncate,
+        fields terminated by '\t',
+        fields not enclosed,
+        fields escaped by backslash-quote,
+        quote identifiers
+
+    SET work_mem to '128MB',
+        standard_conforming_strings to 'on',
+        application_name to 'my app name'
+
+ BEFORE LOAD DO
+  $$ create extension if not exists hstore; $$,
+  $$ drop table if exists "HS"; $$,
+  $$ CREATE TABLE "HS"
+     (
+        id     serial primary key,
+        kv     hstore
+     )
+  $$;
+
+
+1     email=>foo@example.com,a=>b
+2     test=>value
+3     a=>b,c=>"quoted hstore value",d=>other
+4     baddata
+
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html new file mode 100644 index 0000000..9e8d443 --- /dev/null +++ b/docs/_build/html/genindex.html @@ -0,0 +1,88 @@ + + + + + + + + Index — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ + +

Index

+ +
+ +
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html new file mode 100644 index 0000000..14daa3e --- /dev/null +++ b/docs/_build/html/index.html @@ -0,0 +1,198 @@ + + + + + + + Welcome to pgloader’s documentation! — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Welcome to pgloader’s documentation!

+
+

Table Of Contents:

+ +
+
+
+

Indices and tables

+ +
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/intro.html b/docs/_build/html/intro.html new file mode 100644 index 0000000..09b664f --- /dev/null +++ b/docs/_build/html/intro.html @@ -0,0 +1,151 @@ + + + + + + + Introduction — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Introduction

+

pgloader loads data from various sources into PostgreSQL. It can +transform the data it reads on the fly and submit raw SQL before and +after the loading. It uses the COPY PostgreSQL protocol to stream +the data into the server, and manages errors by filling a pair of +reject.dat and reject.log files.

+

pgloader knows how to read data from different kind of sources:

+
+
    +
  • Files +* CSV +* Fixed Format +* DBF
  • +
  • Databases +* SQLite +* MySQL +* MS SQL Server
  • +
+
+

The level of automation provided by pgloader depends on the data source +type. In the case of CSV and Fixed Format files, a full description of the +expected input properties must be given to pgloader. In the case of a +database, pgloader connects to the live service and knows how to fetch the +metadata it needs directly from it.

+
+

Continuous Migration

+

pgloader is meant to migrate a whole database in a single command line and +without any manual intervention. The goal is to be able to setup a +Continuous Integration environment as described in the Project +Methodology document of the MySQL to +PostgreSQL webpage.

+
+
    +
  1. Setup your target PostgreSQL Architecture
  2. +
  3. Fork a Continuous Integration environment that uses PostgreSQL
  4. +
  5. Migrate the data over and over again every night, from production
  6. +
  7. As soon as the CI is all green using PostgreSQL, schedule the D-Day
  8. +
  9. Migrate without suprise and enjoy!
  10. +
+
+

In order to be able to follow this great methodology, you need tooling to +implement the third step in a fully automated way. That’s pgloader.

+
+
+

Commands

+

pgloader implements its own Command Language, a DSL that allows to specify +every aspect of the data load and migration to implement. Some of the +features provided in the language are only available for a specific source +type.

+
+
+

Command Line

+

The pgloader command line accepts those two variants:

+
pgloader [<options>] [<command-file>]...
+pgloader [<options>] SOURCE TARGET
+
+
+

Either you have a command-file containing migration specifications in the +pgloader Command Language, or you can give a Source for the data and a +PostgreSQL database connection Target where to load the data into.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv new file mode 100644 index 0000000..e887187 Binary files /dev/null and b/docs/_build/html/objects.inv differ diff --git a/docs/_build/html/pgloader-usage-examples.html b/docs/_build/html/pgloader-usage-examples.html new file mode 100644 index 0000000..ee73f61 --- /dev/null +++ b/docs/_build/html/pgloader-usage-examples.html @@ -0,0 +1,237 @@ + + + + + + + Pgloader Usage Examples — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Pgloader Usage Examples

+

Currently not included, because redundant with the tutorial.

+
+

Usage Examples

+

Review the command line options and pgloader’s version:

+
pgloader --help
+pgloader --version
+
+
+
+

Loading from a complex command

+

Use the command file as the pgloader command argument, pgloader will parse +that file and execute the commands found in it:

+
pgloader --verbose ./test/csv-districts.load
+
+
+
+
+

CSV

+

Load data from a CSV file into a pre-existing table in your database, having +pgloader guess the CSV properties (separator, quote and escape character):

+
pgloader ./test/data/matching-1.csv pgsql:///pgloader?tablename=matching
+
+
+

Load data from a CSV file into a pre-existing table in your database, with +expanded options:

+
pgloader --type csv                                   \
+         --field id --field field                     \
+         --with truncate                              \
+         --with "fields terminated by ','"            \
+         ./test/data/matching-1.csv                   \
+         postgres:///pgloader?tablename=matching
+
+
+

In that example the whole loading is driven from the command line, bypassing +the need for writing a command in the pgloader command syntax entirely. As +there’s no command though, the extra inforamtion needed must be provided on +the command line using the –type and –field and –with switches.

+

For documentation about the available syntaxes for the –field and +–with switches, please refer to the CSV section later in the man page.

+

Note also that the PostgreSQL URI includes the target tablename.

+
+
+

Reading from STDIN

+

File based pgloader sources can be loaded from the standard input, as in the +following example:

+
pgloader --type csv                                         \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                          \
+         --with "fields terminated by '\t'"                \
+         -                                                 \
+         postgresql:///pgloader?districts_longlat          \
+         < test/data/2013_Gaz_113CDs_national.txt
+
+
+

The dash (-) character as a source is used to mean standard input, as +usual in Unix command lines. It’s possible to stream compressed content to +pgloader with this technique, using the Unix pipe:

+
+
gunzip -c source.gz | pgloader –type csv … - pgsql:///target?foo
+
+
+

Loading from CSV available through HTTP

+

The same command as just above can also be run if the CSV file happens to be +found on a remote HTTP location:

+
pgloader --type csv                                                     \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                                       \
+         --with "fields terminated by '\t'"                             \
+         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \
+         postgresql:///pgloader?districts_longlat
+
+
+

Some more options have to be used in that case, as the file contains a +one-line header (most commonly that’s column names, could be a copyright +notice). Also, in that case, we specify all the fields right into a single +–field option argument.

+

Again, the PostgreSQL target connection string must contain the tablename +option and you have to ensure that the target table exists and may fit the +data. Here’s the SQL command used in that example in case you want to try it +yourself:

+
create table districts_longlat
+(
+         usps        text,
+         geoid       text,
+         aland       bigint,
+         awater      bigint,
+         aland_sqmi  double precision,
+         awater_sqmi double precision,
+         intptlat    double precision,
+         intptlong   double precision
+);
+
+
+

Also notice that the same command will work against an archived version of +the same data, e.g. +http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz.

+

Finally, it’s important to note that pgloader first fetches the content from +the HTTP URL it to a local file, then expand the archive when it’s +recognized to be one, and only then processes the locally expanded file.

+

In some cases, either because pgloader has no direct support for your +archive format or maybe because expanding the archive is not feasible in +your environment, you might want to stream the content straight from its +remote location into PostgreSQL. Here’s how to do that, using the old battle +tested Unix Pipes trick:

+
curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \
+| gunzip -c                                                        \
+| pgloader --type csv                                              \
+           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong"
+           --with "skip header = 1"                                \
+           --with "fields terminated by '\t'"                      \
+           -                                                       \
+           postgresql:///pgloader?districts_longlat
+
+
+

Now the OS will take care of the streaming and buffering between the network +and the commands and pgloader will take care of streaming the data down to +PostgreSQL.

+
+
+

Migrating from SQLite

+

The following command will open the SQLite database, discover its tables +definitions including indexes and foreign keys, migrate those definitions +while casting the data type specifications to their PostgreSQL equivalent +and then migrate the data over:

+
createdb newdb
+pgloader ./test/sqlite/sqlite.db postgresql:///newdb
+
+
+
+
+

Migrating from MySQL

+

Just create a database where to host the MySQL data and definitions and have +pgloader do the migration for you in a single command line:

+
createdb pagila
+pgloader mysql://user@localhost/sakila postgresql:///pagila
+
+
+
+
+

Fetching an archived DBF file from a HTTP remote location

+

It’s possible for pgloader to download a file from HTTP, unarchive it, and +only then open it to discover the schema then load the data:

+
createdb foo
+pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo
+
+
+

Here it’s not possible for pgloader to guess the kind of data source it’s +being given, so it’s necessary to use the –type command line switch.

+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/archive.html b/docs/_build/html/ref/archive.html new file mode 100644 index 0000000..7bab0bf --- /dev/null +++ b/docs/_build/html/ref/archive.html @@ -0,0 +1,191 @@ + + + + + + + Loading From an Archive — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading From an Archive

+

This command instructs pgloader to load data from one or more files contained +in an archive. Currently the only supported archive format is ZIP, and the +archive might be downloaded from an HTTP URL.

+

Here’s an example:

+
LOAD ARCHIVE
+   FROM /Users/dim/Downloads/GeoLiteCity-latest.zip
+   INTO postgresql:///ip4r
+
+   BEFORE LOAD
+     DO $$ create extension if not exists ip4r; $$,
+        $$ create schema if not exists geolite; $$,
+
+     EXECUTE 'geolite.sql'
+
+   LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/
+             WITH ENCODING iso-8859-1
+             (
+                locId,
+                country,
+                region     null if blanks,
+                city       null if blanks,
+                postalCode null if blanks,
+                latitude,
+                longitude,
+                metroCode  null if blanks,
+                areaCode   null if blanks
+             )
+        INTO postgresql:///ip4r?geolite.location
+             (
+                locid,country,region,city,postalCode,
+                location point using (format nil "(~a,~a)" longitude latitude),
+                metroCode,areaCode
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+  AND LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/
+             WITH ENCODING iso-8859-1
+             (
+                startIpNum, endIpNum, locId
+             )
+        INTO postgresql:///ip4r?geolite.blocks
+             (
+                iprange ip4r using (ip-range startIpNum endIpNum),
+                locId
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+   FINALLY DO
+     $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$;
+
+
+

The archive command accepts the following clauses and options.

+
+

Archive Source Specification: FROM

+

Filename or HTTP URI where to load the data from. When given an HTTP URL the +linked file will get downloaded locally before processing.

+

If the file is a zip file, the command line utility unzip is used to +expand the archive into files in $TMPDIR, or /tmp if $TMPDIR is unset +or set to a non-existing directory.

+

Then the following commands are used from the top level directory where the +archive has been expanded.

+
+
+

Archive Sub Commands

+
+
    +
  • command [ AND command … ]

    +

    A series of commands against the contents of the archive, at the moment +only CSV,`’FIXED` and DBF commands are supported.

    +

    Note that commands are supporting the clause FROM FILENAME MATCHING +which allows the pgloader command not to depend on the exact names of +the archive directories.

    +

    The same clause can also be applied to several files with using the +spelling FROM ALL FILENAMES MATCHING and a regular expression.

    +

    The whole matching clause must follow the following rule:

    +
    FROM [ ALL FILENAMES | [ FIRST ] FILENAME ] MATCHING
    +
    +
    +
  • +
+
+
+
+

Archive Final SQL Commands

+
+
    +
  • FINALLY DO

    +

    SQL Queries to run once the data is loaded, such as CREATE INDEX.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/copy.html b/docs/_build/html/ref/copy.html new file mode 100644 index 0000000..c03182f --- /dev/null +++ b/docs/_build/html/ref/copy.html @@ -0,0 +1,196 @@ + + + + + + + Loading COPY Formatted Files — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading COPY Formatted Files

+

This commands instructs pgloader to load from a file containing COPY TEXT +data as described in the PostgreSQL documentation. Here’s an example:

+
LOAD COPY
+     FROM copy://./data/track.copy
+          (
+            trackid, track, album, media, genre, composer,
+            milliseconds, bytes, unitprice
+          )
+     INTO postgresql:///pgloader
+   TARGET TABLE track_full
+
+     WITH truncate
+
+      SET work_mem to '14MB',
+          standard_conforming_strings to 'on'
+
+BEFORE LOAD DO
+     $$ drop table if exists track_full; $$,
+     $$ create table track_full (
+          trackid      bigserial,
+          track        text,
+          album        text,
+          media        text,
+          genre        text,
+          composer     text,
+          milliseconds bigint,
+          bytes        bigint,
+          unitprice    numeric
+        );
+     $$;
+
+
+

The COPY format command accepts the following clauses and options.

+
+

COPY Formatted Files Source Specification: FROM

+

Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported.

+
+
    +
  • inline

    +

    The data is found after the end of the parsed commands. Any number of +empty lines between the end of the commands and the beginning of the +data is accepted.

    +
  • +
  • stdin

    +

    Reads the data from the standard input stream.

    +
  • +
  • FILENAMES MATCHING

    +

    The whole matching clause must follow the following rule:

    +
    [ ALL FILENAMES | [ FIRST ] FILENAME ]
    +MATCHING regexp
    +[ IN DIRECTORY '...' ]
    +
    +
    +

    The matching clause applies given regular expression (see above for +exact syntax, several options can be used here) to filenames. It’s then +possible to load data from only the first match of all of them.

    +

    The optional IN DIRECTORY clause allows specifying which directory to +walk for finding the data files, and can be either relative to where the +command file is read from, or absolute. The given directory must exists.

    +
  • +
+
+
+
+

COPY Formatted File Options: WITH

+

When loading from a COPY file, the following options are supported:

+
+
    +
  • delimiter

    +

    Takes a single character as argument, which must be found inside single +quotes, and might be given as the printable character itself, the +special value t to denote a tabulation character, or 0x then an +hexadecimal value read as the ASCII code for the character.

    +

    This character is used as the delimiter when reading the data, in a +similar way to the PostgreSQL COPY option.

    +
  • +
  • null

    +

    Takes a quoted string as an argument (quotes can be either double quotes +or single quotes) and uses that string as the NULL representation in +the data.

    +

    This is similar to the null COPY option in PostgreSQL.

    +
  • +
  • truncate

    +

    When this option is listed, pgloader issues a TRUNCATE command against +the PostgreSQL target table before reading the data file.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … DISABLE +TRIGGER ALL command against the PostgreSQL target table before copying +the data, then the command ALTER TABLE … ENABLE TRIGGER ALL once the +COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring the +foreign key constraints and user defined triggers and may result in +invalid foreign key constraints once the data is loaded. Use with +care.

    +
  • +
  • skip header

    +

    Takes a numeric value as argument. Instruct pgloader to skip that many +lines at the beginning of the input file.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/csv.html b/docs/_build/html/ref/csv.html new file mode 100644 index 0000000..7483619 --- /dev/null +++ b/docs/_build/html/ref/csv.html @@ -0,0 +1,310 @@ + + + + + + + Loading CSV data — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading CSV data

+

This command instructs pgloader to load data from a CSV file. Here’s an +example:

+
LOAD CSV
+   FROM 'GeoLiteCity-Blocks.csv' WITH ENCODING iso-646-us
+        HAVING FIELDS
+        (
+           startIpNum, endIpNum, locId
+        )
+   INTO postgresql://user@localhost:54393/dbname
+        TARGET TABLE geolite.blocks
+        TARGET COLUMNS
+        (
+           iprange ip4r using (ip-range startIpNum endIpNum),
+           locId
+        )
+   WITH truncate,
+        skip header = 2,
+        fields optionally enclosed by '"',
+        fields escaped by backslash-quote,
+        fields terminated by '\t'
+
+    SET work_mem to '32 MB', maintenance_work_mem to '64 MB';
+
+
+

The csv format command accepts the following clauses and options.

+
+

CSV Source Specification: FROM

+

Filename where to load the data from. Accepts an ENCODING option. Use the +–list-encodings option to know which encoding names are supported.

+

The filename may be enclosed by single quotes, and could be one of the +following special values:

+
+
    +
  • inline

    +

    The data is found after the end of the parsed commands. Any number +of empty lines between the end of the commands and the beginning of +the data is accepted.

    +
  • +
  • stdin

    +

    Reads the data from the standard input stream.

    +
  • +
  • FILENAMES MATCHING

    +

    The whole matching clause must follow the following rule:

    +
    [ ALL FILENAMES | [ FIRST ] FILENAME ]
    +MATCHING regexp
    +[ IN DIRECTORY '...' ]
    +
    +
    +

    The matching clause applies given regular expression (see above +for exact syntax, several options can be used here) to filenames. +It’s then possible to load data from only the first match of all of +them.

    +

    The optional IN DIRECTORY clause allows specifying which directory +to walk for finding the data files, and can be either relative to +where the command file is read from, or absolute. The given +directory must exists.

    +
  • +
+
+
+
+

Fields Specifications

+

The FROM option also supports an optional comma separated list of field +names describing what is expected in the CSV data file, optionally +introduced by the clause HAVING FIELDS.

+

Each field name can be either only one name or a name following with +specific reader options for that field, enclosed in square brackets and +comma-separated. Supported per-field reader options are:

+
+
    +
  • terminated by

    +
    +

    See the description of field terminated by below.

    +

    The processing of this option is not currently implemented.

    +
    +
  • +
  • date format

    +

    When the field is expected of the date type, then this option allows +to specify the date format used in the file.

    +

    Date format string are template strings modeled against the +PostgreSQL to_char template strings support, limited to the +following patterns:

    +
    +
      +
    • YYYY, YYY, YY for the year part
    • +
    • MM for the numeric month part
    • +
    • DD for the numeric day part
    • +
    • HH, HH12, HH24 for the hour part
    • +
    • am, AM, a.m., A.M.
    • +
    • pm, PM, p.m., P.M.
    • +
    • MI for the minutes part
    • +
    • SS for the seconds part
    • +
    • MS for the milliseconds part (4 digits)
    • +
    • US for the microseconds part (6 digits)
    • +
    • unparsed punctuation signs: - . * # @ T / and space
    • +
    +
    +

    Here’s an example of a date format specification:

    +
    column-name [date format 'YYYY-MM-DD HH24-MI-SS.US']
    +
    +
    +
  • +
  • null if

    +
    +

    This option takes an argument which is either the keyword blanks +or a double-quoted string.

    +

    When blanks is used and the field value that is read contains +only space characters, then it’s automatically converted to an SQL +NULL value.

    +

    When a double-quoted string is used and that string is read as the +field value, then the field value is automatically converted to an +SQL NULL value.

    +
    +
  • +
  • trim both whitespace, trim left whitespace, trim right whitespace

    +

    This option allows to trim whitespaces in the read data, either from +both sides of the data, or only the whitespace characters found on +the left of the streaing, or only those on the right of the string.

    +
  • +
+
+
+
+

CSV Loading Options: WITH

+

When loading from a CSV file, the following options are supported:

+
+
    +
  • truncate

    +
    +

    When this option is listed, pgloader issues a TRUNCATE command +against the PostgreSQL target table before reading the data file.

    +
    +
  • +
  • drop indexes

    +

    When this option is listed, pgloader issues DROP INDEX commands +against all the indexes defined on the target table before copying +the data, then CREATE INDEX commands once the COPY is done.

    +

    In order to get the best performance possible, all the indexes are +created in parallel and when done the primary keys are built again +from the unique indexes just created. This two step process allows +creating the primary key index in parallel with the other indexes, +as only the ALTER TABLE command needs an access exclusive lock +on the target table.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … +DISABLE TRIGGER ALL command against the PostgreSQL target table +before copying the data, then the command ALTER TABLE … ENABLE +TRIGGER ALL once the COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring +the foreign key constraints and user defined triggers and may +result in invalid foreign key constraints once the data is loaded. +Use with care.

    +
  • +
  • skip header

    +

    Takes a numeric value as argument. Instruct pgloader to skip that +many lines at the beginning of the input file.

    +
  • +
  • csv header

    +

    Use the first line read after skip header as the list of csv field +names to be found in the CSV file, using the same CSV parameters as +for the CSV data.

    +
  • +
  • trim unquoted blanks

    +

    When reading unquoted values in the CSV file, remove the blanks +found in between the separator and the value. That behaviour is the +default.

    +
  • +
  • keep unquoted blanks

    +

    When reading unquoted values in the CSV file, keep blanks found in +between the separator and the value.

    +
  • +
  • fields optionally enclosed by

    +

    Takes a single character as argument, which must be found inside +single quotes, and might be given as the printable character itself, +the special value t to denote a tabulation character, or 0x then +an hexadecimal value read as the ASCII code for the character.

    +

    This character is used as the quoting character in the CSV file, +and defaults to double-quote.

    +
  • +
  • fields not enclosed

    +

    By default, pgloader will use the double-quote character as the +enclosing character. If you have a CSV file where fields are not +enclosed and are using double-quote as an expected ordinary +character, then use the option fields not enclosed for the CSV +parser to accept those values.

    +
  • +
  • fields escaped by

    +

    Takes either the special value backslash-quote or double-quote, +or any value supported by the fields terminated by option (see +below). This value is used to recognize escaped field separators +when they are to be found within the data fields themselves. +Defaults to double-quote.

    +
  • +
  • csv escape mode

    +

    Takes either the special value quote (the default) or following +and allows the CSV parser to parse either only escaped field +separator or any character (including CSV data) when using the +following value.

    +
  • +
  • fields terminated by

    +

    Takes a single character as argument, which must be found inside +single quotes, and might be given as the printable character itself, +the special value t to denote a tabulation character, or 0x then +an hexadecimal value read as the ASCII code for the character.

    +

    This character is used as the field separator when reading the +CSV data.

    +
  • +
  • lines terminated by

    +

    Takes a single character as argument, which must be found inside +single quotes, and might be given as the printable character itself, +the special value t to denote a tabulation character, or 0x then +an hexadecimal value read as the ASCII code for the character.

    +

    This character is used to recognize end-of-line condition when +reading the CSV data.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/dbf.html b/docs/_build/html/ref/dbf.html new file mode 100644 index 0000000..7d54a68 --- /dev/null +++ b/docs/_build/html/ref/dbf.html @@ -0,0 +1,138 @@ + + + + + + + Loading DBF data — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading DBF data

+

This command instructs pgloader to load data from a DBF file. Here’s an +example:

+
LOAD DBF
+        FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/reg2013.dbf
+    INTO postgresql://user@localhost/dbname
+    WITH truncate, create table;
+
+
+

The dbf format command accepts the following clauses and options.

+
+

DBF Source Specification: FROM

+

Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported.

+
+
+

DBF Loading Options: WITH

+

When loading from a DBF file, the following options are supported:

+
+
    +
  • truncate

    +

    When this option is listed, pgloader issues a TRUNCATE command against +the PostgreSQL target table before reading the data file.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … DISABLE +TRIGGER ALL command against the PostgreSQL target table before copying +the data, then the command ALTER TABLE … ENABLE TRIGGER ALL once the +COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring the +foreign key constraints and user defined triggers and may result in +invalid foreign key constraints once the data is loaded. Use with +care.

    +
  • +
  • create table

    +

    When this option is listed, pgloader creates the table using the meta +data found in the DBF file, which must contain a list of fields with +their data type. A standard data type conversion from DBF to PostgreSQL +is done.

    +
  • +
  • table name

    +

    This options expects as its value the possibly qualified name of the +table to create.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/fixed.html b/docs/_build/html/ref/fixed.html new file mode 100644 index 0000000..e5b6c9a --- /dev/null +++ b/docs/_build/html/ref/fixed.html @@ -0,0 +1,270 @@ + + + + + + + Loading Fixed Cols File Formats — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading Fixed Cols File Formats

+

This command instructs pgloader to load data from a text file containing +columns arranged in a fixed size manner. Here’s an example:

+
LOAD FIXED
+     FROM inline
+          (
+           a from  0 for 10,
+           b from 10 for  8,
+           c from 18 for  8,
+           d from 26 for 17 [null if blanks, trim right whitespace]
+          )
+     INTO postgresql:///pgloader
+   TARGET TABLE fixed
+          (
+             a, b,
+             c time using (time-with-no-separator c),
+             d
+          )
+
+     WITH truncate
+
+      SET work_mem to '14MB',
+          standard_conforming_strings to 'on'
+
+BEFORE LOAD DO
+     $$ drop table if exists fixed; $$,
+     $$ create table fixed (
+         a integer,
+         b date,
+         c time,
+         d text
+        );
+     $$;
+
+ 01234567892008052011431250firstline
+    01234562008052115182300left blank-padded
+ 12345678902008052208231560another line
+  2345609872014092914371500
+  2345678902014092914371520
+
+
+

The fixed format command accepts the following clauses and options.

+
+

Fixed File Format Source Specification: FROM

+

Filename where to load the data from. Accepts an ENCODING option. Use the +–list-encodings option to know which encoding names are supported.

+

The filename may be enclosed by single quotes, and could be one of the +following special values:

+
+
    +
  • inline

    +
    +

    The data is found after the end of the parsed commands. Any number +of empty lines between the end of the commands and the beginning of +the data is accepted.

    +
    +
  • +
  • stdin

    +
    +

    Reads the data from the standard input stream.

    +
    +
  • +
  • FILENAMES MATCHING

    +

    The whole matching clause must follow the following rule:

    +
    [ ALL FILENAMES | [ FIRST ] FILENAME ]
    +MATCHING regexp
    +[ IN DIRECTORY '...' ]
    +
    +
    +

    The matching clause applies given regular expression (see above +for exact syntax, several options can be used here) to filenames. +It’s then possible to load data from only the first match of all of +them.

    +

    The optional IN DIRECTORY clause allows specifying which directory +to walk for finding the data files, and can be either relative to +where the command file is read from, or absolute. The given +directory must exists.

    +
  • +
+
+
+
+

Fields Specifications

+

The FROM option also supports an optional comma separated list of field +names describing what is expected in the FIXED data file.

+

Each field name is composed of the field name followed with specific reader +options for that field. Supported per-field reader options are the +following, where only start and length are required.

+
+
    +
  • start

    +

    Position in the line where to start reading that field’s value. Can +be entered with decimal digits or 0x then hexadecimal digits.

    +
  • +
  • length

    +

    How many bytes to read from the start position to read that +field’s value. Same format as start.

    +
  • +
+
+

Those optional parameters must be enclosed in square brackets and +comma-separated:

+
+
    +
  • terminated by

    +
    +

    See the description of field terminated by below.

    +

    The processing of this option is not currently implemented.

    +
    +
  • +
  • date format

    +

    When the field is expected of the date type, then this option allows +to specify the date format used in the file.

    +

    Date format string are template strings modeled against the +PostgreSQL to_char template strings support, limited to the +following patterns:

    +
    +
      +
    • YYYY, YYY, YY for the year part
    • +
    • MM for the numeric month part
    • +
    • DD for the numeric day part
    • +
    • HH, HH12, HH24 for the hour part
    • +
    • am, AM, a.m., A.M.
    • +
    • pm, PM, p.m., P.M.
    • +
    • MI for the minutes part
    • +
    • SS for the seconds part
    • +
    • MS for the milliseconds part (4 digits)
    • +
    • US for the microseconds part (6 digits)
    • +
    • unparsed punctuation signs: - . * # @ T / and space
    • +
    +
    +

    Here’s an example of a date format specification:

    +
    column-name [date format 'YYYY-MM-DD HH24-MI-SS.US']
    +
    +
    +
  • +
  • null if

    +

    This option takes an argument which is either the keyword blanks +or a double-quoted string.

    +

    When blanks is used and the field value that is read contains only +space characters, then it’s automatically converted to an SQL NULL +value.

    +

    When a double-quoted string is used and that string is read as the +field value, then the field value is automatically converted to an +SQL NULL value.

    +
  • +
  • trim both whitespace, trim left whitespace, trim right whitespace

    +

    This option allows to trim whitespaces in the read data, either from +both sides of the data, or only the whitespace characters found on +the left of the streaing, or only those on the right of the string.

    +
  • +
+
+
+
+

Fixed File Format Loading Options: WITH

+

When loading from a FIXED file, the following options are supported:

+
+
    +
  • truncate

    +

    When this option is listed, pgloader issues a TRUNCATE command +against the PostgreSQL target table before reading the data file.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … +DISABLE TRIGGER ALL command against the PostgreSQL target table +before copying the data, then the command ALTER TABLE … ENABLE +TRIGGER ALL once the COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring +the foreign key constraints and user defined triggers and may +result in invalid foreign key constraints once the data is loaded. +Use with care.

    +
  • +
  • skip header

    +

    Takes a numeric value as argument. Instruct pgloader to skip that +many lines at the beginning of the input file.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/ixf.html b/docs/_build/html/ref/ixf.html new file mode 100644 index 0000000..eb568f1 --- /dev/null +++ b/docs/_build/html/ref/ixf.html @@ -0,0 +1,149 @@ + + + + + + + Loading IXF Data — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading IXF Data

+

This command instructs pgloader to load data from an IBM IXF file. Here’s +an example:

+
LOAD IXF
+    FROM data/nsitra.test1.ixf
+    INTO postgresql:///pgloader
+  TARGET TABLE nsitra.test1
+    WITH truncate, create table, timezone UTC
+
+  BEFORE LOAD DO
+   $$ create schema if not exists nsitra; $$,
+   $$ drop table if exists nsitra.test1; $$;
+
+
+

The ixf format command accepts the following clauses and options.

+
+

IXF Source Specification: FROM

+

Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single ixf file of the same name. Fetch such a +zip file from an HTTP address is of course supported.

+
+
+

IXF Loading Options: WITH

+

When loading from a IXF file, the following options are supported:

+
+
    +
  • truncate

    +

    When this option is listed, pgloader issues a TRUNCATE command against +the PostgreSQL target table before reading the data file.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … DISABLE +TRIGGER ALL command against the PostgreSQL target table before copying +the data, then the command ALTER TABLE … ENABLE TRIGGER ALL once the +COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring the +foreign key constraints and user defined triggers and may result in +invalid foreign key constraints once the data is loaded. Use with +care.

    +
  • +
  • create table

    +

    When this option is listed, pgloader creates the table using the meta +data found in the DBF file, which must contain a list of fields with +their data type. A standard data type conversion from DBF to PostgreSQL +is done.

    +
  • +
  • table name

    +

    This options expects as its value the possibly qualified name of the +table to create.

    +
  • +
  • timezone

    +

    This options allows to specify which timezone is used when parsing +timestamps from an IXF file, and defaults to UTC. Expected values are +either UTC, GMT or a single quoted location name such as +‘Universal’ or ‘Europe/Paris’.

    +
  • +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/mssql.html b/docs/_build/html/ref/mssql.html new file mode 100644 index 0000000..0dac5ad --- /dev/null +++ b/docs/_build/html/ref/mssql.html @@ -0,0 +1,236 @@ + + + + + + + Migrating a MS SQL Database to PostgreSQL — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Migrating a MS SQL Database to PostgreSQL

+

This command instructs pgloader to load data from a MS SQL database. +Automatic discovery of the schema is supported, including build of the +indexes, primary and foreign keys constraints.

+

Here’s an example:

+
load database
+     from mssql://user@host/dbname
+     into postgresql:///dbname
+
+including only table names like 'GlobalAccount' in schema 'dbo'
+
+set work_mem to '16MB', maintenance_work_mem to '512 MB'
+
+before load do $$ drop schema if exists dbo cascade; $$;
+
+
+

The mssql command accepts the following clauses and options.

+
+

MS SQL Database Source Specification: FROM

+

Connection string to an existing MS SQL database server that listens and +welcome external TCP/IP connection. As pgloader currently piggybacks on the +FreeTDS driver, to change the port of the server please export the TDSPORT +environment variable.

+
+
+

MS SQL Database Migration Options: WITH

+

When loading from a MS SQL database, the same options as when loading a +MySQL database are supported. Please refer to the MySQL section. The +following options are added:

+
+
    +
  • create schemas

    +

    When this option is listed, pgloader creates the same schemas as found +on the MS SQL instance. This is the default.

    +
  • +
  • create no schemas

    +

    When this option is listed, pgloader refrains from creating any schemas +at all, you must then ensure that the target schema do exist.

    +
  • +
+
+
+
+

MS SQL Database Casting Rules

+
+

CAST

+

The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases.

+

Please refer to the MySQL CAST clause for details.

+
+
+
+

MS SQL Partial Migration

+
+

INCLUDING ONLY TABLE NAMES LIKE

+

Introduce a comma separated list of table name patterns used to limit the +tables to migrate to a sublist. More than one such clause may be used, they +will be accumulated together.

+

Example:

+
including only table names lile 'GlobalAccount' in schema 'dbo'
+
+
+
+
+

EXCLUDING TABLE NAMES LIKE

+

Introduce a comma separated list of table name patterns used to exclude +table names from the migration. This filter only applies to the result of +the INCLUDING filter.

+
excluding table names matching 'LocalAccount' in schema 'dbo'
+
+
+
+
+
+

MS SQL Schema Transformations

+
+

ALTER SCHEMA ‘…’ RENAME TO ‘…’

+

Allows to rename a schema on the flight, so that for instance the tables +found in the schema ‘dbo’ in your source database will get migrated into the +schema ‘public’ in the target database with this command:

+
alter schema 'dbo' rename to 'public'
+
+
+
+
+

ALTER TABLE NAMES MATCHING … IN SCHEMA ‘…’

+

See the MySQL explanation for this clause above. It works the same in the +context of migrating from MS SQL, only with the added option to specify the +name of the schema where to find the definition of the target tables.

+

The matching is done in pgloader itself, with a Common Lisp regular +expression lib, so doesn’t depend on the LIKE implementation of MS SQL, +nor on the lack of support for regular expressions in the engine.

+
+
+
+

MS SQL Driver setup and encoding

+

pgloader is using the FreeTDS driver, and internally expects the data to +be sent in utf-8. To achieve that, you can configure the FreeTDS driver with +those defaults, in the file ~/.freetds.conf:

+
[global]
+    tds version = 7.4
+    client charset = UTF-8
+
+
+
+
+

Default MS SQL Casting Rules

+

When migrating from MS SQL the following Casting Rules are provided:

+

Numbers:

+
type tinyint to smallint
+
+type float to float   using float-to-string
+type real to real     using float-to-string
+type double to double precision     using float-to-string
+type numeric to numeric     using float-to-string
+type decimal to numeric     using float-to-string
+type money to numeric     using float-to-string
+type smallmoney to numeric     using float-to-string
+
+
+

Texts:

+
type char      to text drop typemod
+type nchat     to text drop typemod
+type varchar   to text drop typemod
+type nvarchar  to text drop typemod
+type xml       to text drop typemod
+
+
+

Binary:

+
type binary    to bytea using byte-vector-to-bytea
+type varbinary to bytea using byte-vector-to-bytea
+
+
+

Date:

+
type datetime    to timestamptz
+type datetime2   to timestamptz
+
+
+

Others:

+
type bit to boolean
+type hierarchyid to bytea
+type geography to bytea
+type uniqueidentifier to uuid using sql-server-uniqueidentifier-to-uuid
+
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/mysql.html b/docs/_build/html/ref/mysql.html new file mode 100644 index 0000000..9e7c2cc --- /dev/null +++ b/docs/_build/html/ref/mysql.html @@ -0,0 +1,639 @@ + + + + + + + Migrating a MySQL Database to PostgreSQL — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Migrating a MySQL Database to PostgreSQL

+

This command instructs pgloader to load data from a database connection. The +only supported database source is currently MySQL, and pgloader supports +dynamically converting the schema of the source database and the indexes +building.

+

A default set of casting rules are provided and might be overloaded and +appended to by the command.

+

Here’s an example using as many options as possible, some of them even being +defaults. Chances are you don’t need that complex a setup, don’t copy and +paste it, use it only as a reference!

+
LOAD DATABASE
+     FROM      mysql://root@localhost/sakila
+     INTO postgresql://localhost:54393/sakila
+
+ WITH include drop, create tables, create indexes, reset sequences,
+      workers = 8, concurrency = 1,
+      multiple readers per thread, rows per range = 50000
+
+  SET PostgreSQL PARAMETERS
+      maintenance_work_mem to '128MB',
+      work_mem to '12MB',
+      search_path to 'sakila, public, "$user"'
+
+  SET MySQL PARAMETERS
+      net_read_timeout  = '120',
+      net_write_timeout = '120'
+
+ CAST type bigint when (= precision 20) to bigserial drop typemod,
+      type date drop not null drop default using zero-dates-to-null,
+      -- type tinyint to boolean using tinyint-to-boolean,
+      type year to integer
+
+ MATERIALIZE VIEWS film_list, staff_list
+
+ -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'
+ -- EXCLUDING TABLE NAMES MATCHING ~<ory>
+ -- DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8
+ -- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'
+ -- ALTER TABLE NAMES MATCHING ~/_list$/ SET SCHEMA 'mv'
+
+ ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/
+  SET SCHEMA 'mv'
+
+ ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'
+ ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40')
+
+ ALTER SCHEMA 'sakila' RENAME TO 'pagila'
+
+ BEFORE LOAD DO
+   $$ create schema if not exists pagila; $$,
+   $$ create schema if not exists mv;     $$,
+   $$ alter database sakila set search_path to pagila, mv, public; $$;
+
+
+

The database command accepts the following clauses and options.

+
+

MySQL Database Source Specification: FROM

+

Must be a connection URL pointing to a MySQL database.

+

If the connection URI contains a table name, then only this table is +migrated from MySQL to PostgreSQL.

+

See the SOURCE CONNECTION STRING section above for details on how to write +the connection string. The MySQL connection string accepts the same +parameter sslmode as the PostgreSQL connection string, but the verify +mode is not implemented (yet).

+

Environment variables described in +<http://dev.mysql.com/doc/refman/5.0/en/environment-variables.html> can be +used as default values too. If the user is not provided, then it defaults to +USER environment variable value. The password can be provided with the +environment variable MYSQL_PWD. The host can be provided with the +environment variable MYSQL_HOST and otherwise defaults to localhost. The +port can be provided with the environment variable MYSQL_TCP_PORT and +otherwise defaults to 3306.

+
+
+

MySQL Database Migration Options: WITH

+

When loading from a MySQL database, the following options are supported, +and the default WITH clause is: no truncate, create schema, create +tables, include drop, create indexes, reset sequences, foreign +keys, downcase identifiers, uniquify index names.

+
+
    +
  • include drop

    +

    When this option is listed, pgloader drops all the tables in the target +PostgreSQL database whose names appear in the MySQL database. This +option allows for using the same command several times in a row until +you figure out all the options, starting automatically from a clean +environment. Please note that CASCADE is used to ensure that tables +are dropped even if there are foreign keys pointing to them. This is +precisely what include drop is intended to do: drop all target tables +and recreate them.

    +

    Great care needs to be taken when using include drop, as it will +cascade to all objects referencing the target tables, possibly +including other tables that are not being loaded from the source DB.

    +
  • +
  • include no drop

    +

    When this option is listed, pgloader will not include any DROP +statement when loading the data.

    +
  • +
  • truncate

    +

    When this option is listed, pgloader issue the TRUNCATE command +against each PostgreSQL table just before loading data into it.

    +
  • +
  • no truncate

    +

    When this option is listed, pgloader issues no TRUNCATE command.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … DISABLE +TRIGGER ALL command against the PostgreSQL target table before copying +the data, then the command ALTER TABLE … ENABLE TRIGGER ALL once the +COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring the +foreign key constraints and user defined triggers and may result in +invalid foreign key constraints once the data is loaded. Use with +care.

    +
  • +
  • create tables

    +

    When this option is listed, pgloader creates the table using the meta +data found in the MySQL file, which must contain a list of fields with +their data type. A standard data type conversion from DBF to PostgreSQL +is done.

    +
  • +
  • create no tables

    +

    When this option is listed, pgloader skips the creation of table before +loading data, target tables must then already exist.

    +

    Also, when using create no tables pgloader fetches the metadata from +the current target database and checks type casting, then will remove +constraints and indexes prior to loading the data and install them back +again once the loading is done.

    +
  • +
  • create indexes

    +

    When this option is listed, pgloader gets the definitions of all the +indexes found in the MySQL database and create the same set of index +definitions against the PostgreSQL database.

    +
  • +
  • create no indexes

    +

    When this option is listed, pgloader skips the creating indexes.

    +
  • +
  • drop indexes

    +

    When this option is listed, pgloader drops the indexes in the target +database before loading the data, and creates them again at the end +of the data copy.

    +
  • +
  • uniquify index names, preserve index names

    +

    MySQL index names are unique per-table whereas in PostgreSQL index names +have to be unique per-schema. The default for pgloader is to change the +index name by prefixing it with idx_OID where OID is the internal +numeric identifier of the table the index is built against.

    +

    In somes cases like when the DDL are entirely left to a framework it +might be sensible for pgloader to refrain from handling index unique +names, that is achieved by using the preserve index names option.

    +

    The default is to uniquify index names.

    +

    Even when using the option preserve index names, MySQL primary key +indexes named “PRIMARY” will get their names uniquified. Failing to do +so would prevent the primary keys to be created again in PostgreSQL +where the index names must be unique per schema.

    +
  • +
  • drop schema

    +

    When this option is listed, pgloader drops the target schema in the +target PostgreSQL database before creating it again and all the objects +it contains. The default behavior doesn’t drop the target schemas.

    +
  • +
  • foreign keys

    +

    When this option is listed, pgloader gets the definitions of all the +foreign keys found in the MySQL database and create the same set of +foreign key definitions against the PostgreSQL database.

    +
  • +
  • no foreign keys

    +

    When this option is listed, pgloader skips creating foreign keys.

    +
  • +
  • reset sequences

    +

    When this option is listed, at the end of the data loading and after the +indexes have all been created, pgloader resets all the PostgreSQL +sequences created to the current maximum value of the column they are +attached to.

    +

    The options schema only and data only have no effects on this +option.

    +
  • +
  • reset no sequences

    +

    When this option is listed, pgloader skips resetting sequences after the +load.

    +

    The options schema only and data only have no effects on this +option.

    +
  • +
  • downcase identifiers

    +

    When this option is listed, pgloader converts all MySQL identifiers +(table names, index names, column names) to downcase, except for +PostgreSQL reserved keywords.

    +

    The PostgreSQL reserved keywords are determined dynamically by using +the system function pg_get_keywords().

    +
  • +
  • quote identifiers

    +

    When this option is listed, pgloader quotes all MySQL identifiers so +that their case is respected. Note that you will then have to do the +same thing in your application code queries.

    +
  • +
  • schema only

    +

    When this option is listed pgloader refrains from migrating the data +over. Note that the schema in this context includes the indexes when the +option create indexes has been listed.

    +
  • +
  • data only

    +

    When this option is listed pgloader only issues the COPY statements, +without doing any other processing.

    +
  • +
  • single reader per thread, multiple readers per thread

    +

    The default is single reader per thread and it means that each +MySQL table is read by a single thread as a whole, with a single +SELECT statement using no WHERE clause.

    +

    When using multiple readers per thread pgloader may be able to +divide the reading work into several threads, as many as the +concurrency setting, which needs to be greater than 1 for this +option to kick be activated.

    +

    For each source table, pgloader searches for a primary key over a +single numeric column, or a multiple-column primary key index for +which the first column is of a numeric data type (one of integer +or bigint). When such an index exists, pgloader runs a query to +find the min and max values on this column, and then split that +range into many ranges containing a maximum of rows per range.

    +

    When the range list we then obtain contains at least as many ranges +than our concurrency setting, then we distribute those ranges to +each reader thread.

    +

    So when all the conditions are met, pgloader then starts as many +reader thread as the concurrency setting, and each reader thread +issues several queries with a WHERE id >= x AND id < y, where y - +x = rows per range or less (for the last range, depending on the +max value just obtained.

    +
  • +
  • rows per range

    +

    How many rows are fetched per SELECT query when using multiple +readers per thread, see above for details.

    +
  • +
  • SET MySQL PARAMETERS

    +

    The SET MySQL PARAMETERS allows setting MySQL parameters using the +MySQL SET command each time pgloader connects to it.

    +
  • +
+
+
+
+

MySQL Database Casting Rules

+

The command CAST introduces user-defined casting rules.

+

The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases.

+

A casting rule is expected to follow one of the forms:

+
type <mysql-type-name> [ <guard> ... ] to <pgsql-type-name> [ <option> ... ]
+column <table-name>.<column-name> [ <guards> ] to ...
+
+
+

It’s possible for a casting rule to either match against a MySQL data type +or against a given column name in a given table name. That flexibility +allows to cope with cases where the type tinyint might have been used as a +boolean in some cases but as a smallint in others.

+

The casting rules are applied in order, the first match prevents following +rules to be applied, and user defined rules are evaluated first.

+

The supported guards are:

+
+
    +
  • when unsigned

    +

    The casting rule is only applied against MySQL columns of the source +type that have the keyword unsigned in their data type definition.

    +

    Example of a casting rule using a unsigned guard:

    +
    type smallint when unsigned to integer drop typemod
    +
    +
    +
  • +
  • when default ‘value’

    +

    The casting rule is only applied against MySQL columns of the source +type that have given value, which must be a single-quoted or a +double-quoted string.

    +
  • +
  • when typemod expression

    +

    The casting rule is only applied against MySQL columns of the source +type that have a typemod value matching the given typemod +expression. The typemod is separated into its precision and scale +components.

    +

    Example of a cast rule using a typemod guard:

    +
    type char when (= precision 1) to char keep typemod
    +
    +
    +

    This expression casts MySQL char(1) column to a PostgreSQL column of +type char(1) while allowing for the general case char(N) will be +converted by the default cast rule into a PostgreSQL type varchar(N).

    +
  • +
  • with extra auto_increment

    +

    The casting rule is only applied against MySQL columns having the +extra column auto_increment option set, so that it’s possible to +target e.g. serial rather than integer.

    +

    The default matching behavior, when this option isn’t set, is to match +both columns with the extra definition and without.

    +

    This means that if you want to implement a casting rule that target +either serial or integer from a smallint definition depending on +the auto_increment extra bit of information from MySQL, then you need +to spell out two casting rules as following:

    +
    type smallint  with extra auto_increment
    +  to serial drop typemod keep default keep not null,
    +
    +type smallint
    +  to integer drop typemod keep default keep not null
    +
    +
    +
  • +
+
+

The supported casting options are:

+
+
    +
  • drop default, keep default

    +

    When the option drop default is listed, pgloader drops any +existing default expression in the MySQL database for columns of the +source type from the CREATE TABLE statement it generates.

    +

    The spelling keep default explicitly prevents that behaviour and +can be used to overload the default casting rules.

    +
  • +
  • drop not null, keep not null, set not null

    +

    When the option drop not null is listed, pgloader drops any +existing NOT NULL constraint associated with the given source +MySQL datatype when it creates the tables in the PostgreSQL +database.

    +

    The spelling keep not null explicitly prevents that behaviour and +can be used to overload the default casting rules.

    +

    When the option set not null is listed, pgloader sets a NOT NULL +constraint on the target column regardless whether it has been set +in the source MySQL column.

    +
  • +
  • drop typemod, keep typemod

    +

    When the option drop typemod is listed, pgloader drops any +existing typemod definition (e.g. precision and scale) from +the datatype definition found in the MySQL columns of the source +type when it created the tables in the PostgreSQL database.

    +

    The spelling keep typemod explicitly prevents that behaviour and +can be used to overload the default casting rules.

    +
  • +
  • using

    +

    This option takes as its single argument the name of a function to +be found in the pgloader.transforms Common Lisp package. See above +for details.

    +

    It’s possible to augment a default cast rule (such as one that +applies against ENUM data type for example) with a transformation +function by omitting entirely the type parts of the casting rule, +as in the following example:

    +
    column enumerate.foo using empty-string-to-null
    +
    +
    +
  • +
+
+
+
+

MySQL Views Support

+

MySQL views support allows pgloader to migrate view as if they were base +tables. This feature then allows for on-the-fly transformation from MySQL to +PostgreSQL, as the view definition is used rather than the base data.

+
+

MATERIALIZE VIEWS

+

This clause allows you to implement custom data processing at the data +source by providing a view definition against which pgloader will query +the data. It’s not possible to just allow for plain SQL because we want to +know a lot about the exact data types of each column involved in the query +output.

+

This clause expect a comma separated list of view definitions, each one +being either the name of an existing view in your database or the following +expression:

+
*name* `AS` `$$` *sql query* `$$`
+
+
+

The name and the sql query will be used in a CREATE VIEW statement at +the beginning of the data loading, and the resulting view will then be +dropped at the end of the data loading.

+
+
+

MATERIALIZE ALL VIEWS

+

Same behaviour as MATERIALIZE VIEWS using the dynamic list of views as +returned by MySQL rather than asking the user to specify the list.

+
+
+
+

MySQL Partial Migration

+
+

INCLUDING ONLY TABLE NAMES MATCHING

+

Introduce a comma separated list of table names or regular expression used +to limit the tables to migrate to a sublist.

+

Example:

+
including only table names matching ~/film/, 'actor'
+
+
+
+
+

EXCLUDING TABLE NAMES MATCHING

+

Introduce a comma separated list of table names or regular expression used +to exclude table names from the migration. This filter only applies to the +result of the INCLUDING filter.

+
excluding table names matching ~<ory>
+
+
+
+
+
+

MySQL Encoding Support

+
+

DECODING TABLE NAMES MATCHING

+

Introduce a comma separated list of table names or regular expressions +used to force the encoding to use when processing data from MySQL. If the +data encoding known to you is different from MySQL’s idea about it, this is +the option to use.

+
decoding table names matching ~/messed/, ~/encoding/ AS utf8
+
+
+

You can use as many such rules as you need, all with possibly different +encodings.

+
+
+
+

MySQL Schema Transformations

+
+

ALTER TABLE NAMES MATCHING

+

Introduce a comma separated list of table names or regular expressions +that you want to target in the pgloader ALTER TABLE command. The only two +available actions are SET SCHEMA and RENAME TO, both take a quoted +string as parameter:

+
ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/
+ SET SCHEMA 'mv'
+
+ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'
+
+ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40')
+
+
+

You can use as many such rules as you need. The list of tables to be +migrated is searched in pgloader memory against the ALTER TABLE matching +rules, and for each command pgloader stops at the first matching criteria +(regexp or string).

+

No ALTER TABLE command is sent to PostgreSQL, the modification happens at +the level of the pgloader in-memory representation of your source database +schema. In case of a name change, the mapping is kept and reused in the +foreign key and index support.

+

The SET () action takes effect as a WITH clause for the CREATE TABLE +command that pgloader will run when it has to create a table.

+
+
+
+

MySQL Migration: limitations

+

The database command currently only supports MySQL source database and has +the following limitations:

+
+
    +
  • Views are not migrated,

    +

    Supporting views might require implementing a full SQL parser for the +MySQL dialect with a porting engine to rewrite the SQL against +PostgreSQL, including renaming functions and changing some constructs.

    +

    While it’s not theoretically impossible, don’t hold your breath.

    +
  • +
  • Triggers are not migrated

    +

    The difficulty of doing so is not yet assessed.

    +
  • +
  • Of the geometric datatypes, only the POINT database has been covered. +The other ones should be easy enough to implement now, it’s just not +done yet.

    +
  • +
+
+
+
+

Default MySQL Casting Rules

+

When migrating from MySQL the following Casting Rules are provided:

+

Numbers:

+
type int with extra auto_increment to serial when (< precision 10)
+type int with extra auto_increment to bigserial when (<= 10 precision)
+type int to int       when  (< precision 10)
+type int to bigint    when  (<= 10 precision)
+type tinyint   with extra auto_increment to serial
+type smallint  with extra auto_increment to serial
+type mediumint with extra auto_increment to serial
+type bigint    with extra auto_increment to bigserial
+
+type tinyint to boolean when (= 1 precision) using tinyint-to-boolean
+
+type tinyint when unsigned to smallint   drop typemod
+type smallint when unsigned to integer  drop typemod
+type mediumint when unsigned to integer  drop typemod
+type integer when unsigned to bigint    drop typemod
+
+type tinyint to smallint   drop typemod
+type smallint to smallint  drop typemod
+type mediumint to integer  drop typemod
+type integer to integer    drop typemod
+type bigint to bigint      drop typemod
+
+type float to float        drop typemod
+type double to double precision drop typemod
+
+type numeric to numeric keep typemod
+type decimal to decimal keep typemod
+
+
+

Texts:

+
type char       to char keep typemod using remove-null-characters
+type varchar    to varchar keep typemod using remove-null-characters
+type tinytext   to text using remove-null-characters
+type text       to text using remove-null-characters
+type mediumtext to text using remove-null-characters
+type longtext   to text using remove-null-characters
+
+
+

Binary:

+
+
type binary to bytea +type varbinary to bytea +type tinyblob to bytea +type blob to bytea +type mediumblob to bytea +type longblob to bytea
+

Date:

+
type datetime when default "0000-00-00 00:00:00" and not null
+  to timestamptz drop not null drop default
+      using zero-dates-to-null
+
+type datetime when default "0000-00-00 00:00:00"
+  to timestamptz drop default
+      using zero-dates-to-null
+
+type timestamp when default "0000-00-00 00:00:00" and not null
+  to timestamptz drop not null drop default
+      using zero-dates-to-null
+
+type timestamp when default "0000-00-00 00:00:00"
+  to timestamptz drop default
+      using zero-dates-to-null
+
+type date when default "0000-00-00" to date drop default
+      using zero-dates-to-null
+
+type date to date
+type datetime to timestamptz
+type timestamp to timestamptz
+type year to integer drop typemod
+
+
+

Geometric:

+
type point to point using pgloader.transforms::convert-mysql-point
+
+
+

Enum types are declared inline in MySQL and separately with a CREATE TYPE +command in PostgreSQL, so each column of Enum Type is converted to a type +named after the table and column names defined with the same labels in the +same order.

+

When the source type definition is not matched in the default casting rules +nor in the casting rules provided in the command, then the type name with +the typemod is used.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/sqlite.html b/docs/_build/html/ref/sqlite.html new file mode 100644 index 0000000..4da185d --- /dev/null +++ b/docs/_build/html/ref/sqlite.html @@ -0,0 +1,268 @@ + + + + + + + Migrating a SQLite database to PostgreSQL — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Migrating a SQLite database to PostgreSQL

+

This command instructs pgloader to load data from a SQLite file. Automatic +discovery of the schema is supported, including build of the indexes.

+

Here’s an example:

+
load database
+     from sqlite:///Users/dim/Downloads/lastfm_tags.db
+     into postgresql:///tags
+
+ with include drop, create tables, create indexes, reset sequences
+
+  set work_mem to '16MB', maintenance_work_mem to '512 MB';
+
+
+

The sqlite command accepts the following clauses and options.

+
+

SQLite Database Source Specification: FROM

+

Path or HTTP URL to a SQLite file, might be a .zip file.

+
+
+

SQLite Database Migration Options: WITH

+

When loading from a SQLite database, the following options are +supported:

+

When loading from a SQLite database, the following options are +supported, and the default WITH clause is: no truncate, create +tables, include drop, create indexes, reset sequences, downcase +identifiers, encoding ‘utf-8’.

+
+
    +
  • include drop

    +

    When this option is listed, pgloader drops all the tables in the target +PostgreSQL database whose names appear in the SQLite database. This +option allows for using the same command several times in a row until +you figure out all the options, starting automatically from a clean +environment. Please note that CASCADE is used to ensure that tables +are dropped even if there are foreign keys pointing to them. This is +precisely what include drop is intended to do: drop all target tables +and recreate them.

    +

    Great care needs to be taken when using include drop, as it will +cascade to all objects referencing the target tables, possibly +including other tables that are not being loaded from the source DB.

    +
  • +
  • include no drop

    +

    When this option is listed, pgloader will not include any DROP +statement when loading the data.

    +
  • +
  • truncate

    +

    When this option is listed, pgloader issue the TRUNCATE command +against each PostgreSQL table just before loading data into it.

    +
  • +
  • no truncate

    +

    When this option is listed, pgloader issues no TRUNCATE command.

    +
  • +
  • disable triggers

    +

    When this option is listed, pgloader issues an ALTER TABLE … DISABLE +TRIGGER ALL command against the PostgreSQL target table before copying +the data, then the command ALTER TABLE … ENABLE TRIGGER ALL once the +COPY is done.

    +

    This option allows loading data into a pre-existing table ignoring +the foreign key constraints and user defined triggers and may +result in invalid foreign key constraints once the data is loaded. +Use with care.

    +
  • +
  • create tables

    +

    When this option is listed, pgloader creates the table using the meta +data found in the SQLite file, which must contain a list of fields +with their data type. A standard data type conversion from SQLite to +PostgreSQL is done.

    +
  • +
  • create no tables

    +

    When this option is listed, pgloader skips the creation of table before +loading data, target tables must then already exist.

    +

    Also, when using create no tables pgloader fetches the metadata +from the current target database and checks type casting, then will +remove constraints and indexes prior to loading the data and install +them back again once the loading is done.

    +
  • +
  • create indexes

    +

    When this option is listed, pgloader gets the definitions of all the +indexes found in the SQLite database and create the same set of index +definitions against the PostgreSQL database.

    +
  • +
  • create no indexes

    +

    When this option is listed, pgloader skips the creating indexes.

    +
  • +
  • drop indexes

    +

    When this option is listed, pgloader drops the indexes in the target +database before loading the data, and creates them again at the end +of the data copy.

    +
  • +
  • reset sequences

    +

    When this option is listed, at the end of the data loading and after +the indexes have all been created, pgloader resets all the +PostgreSQL sequences created to the current maximum value of the +column they are attached to.

    +
  • +
  • reset no sequences

    +

    When this option is listed, pgloader skips resetting sequences after the +load.

    +

    The options schema only and data only have no effects on this +option.

    +
  • +
  • schema only

    +

    When this option is listed pgloader will refrain from migrating the data +over. Note that the schema in this context includes the indexes when the +option create indexes has been listed.

    +
  • +
  • data only

    +

    When this option is listed pgloader only issues the COPY statements, +without doing any other processing.

    +
  • +
  • encoding

    +

    This option allows to control which encoding to parse the SQLite text +data with. Defaults to UTF-8.

    +
  • +
+
+
+
+

SQLite Database Casting Rules

+

The command CAST introduces user-defined casting rules.

+

The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases.

+
+
+

SQlite Database Partial Migrations

+
+

INCLUDING ONLY TABLE NAMES LIKE

+

Introduce a comma separated list of table name patterns used to limit the +tables to migrate to a sublist.

+

Example:

+
including only table names like 'Invoice%'
+
+
+
+
+

EXCLUDING TABLE NAMES LIKE

+

Introduce a comma separated list of table name patterns used to exclude +table names from the migration. This filter only applies to the result of +the INCLUDING filter.

+
excluding table names like 'appointments'
+
+
+
+
+
+

Default SQLite Casting Rules

+

When migrating from SQLite the following Casting Rules are provided:

+

Numbers:

+
type tinyint to smallint using integer-to-string
+type integer to bigint   using integer-to-string
+
+type float to float   using float-to-string
+type real to real     using float-to-string
+type double to double precision     using float-to-string
+type numeric to numeric     using float-to-string
+
+
+

Texts:

+
type character  to text drop typemod
+type varchar    to text drop typemod
+type nvarchar   to text drop typemod
+type char       to text drop typemod
+type nchar      to text drop typemod
+type nvarchar   to text drop typemod
+type clob       to text drop typemod
+
+
+

Binary:

+
type blob       to bytea
+
+
+

Date:

+
type datetime    to timestamptz using sqlite-timestamp-to-timestamp
+type timestamp   to timestamptz using sqlite-timestamp-to-timestamp
+type timestamptz to timestamptz using sqlite-timestamp-to-timestamp
+
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ref/transforms.html b/docs/_build/html/ref/transforms.html new file mode 100644 index 0000000..e3cffd8 --- /dev/null +++ b/docs/_build/html/ref/transforms.html @@ -0,0 +1,214 @@ + + + + + + + Transformation Functions — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Transformation Functions

+

Some data types are implemented in a different enough way that a +transformation function is necessary. This function must be written in +Common lisp and is searched in the pgloader.transforms package.

+

Some default transformation function are provided with pgloader, and you can +use the –load command line option to load and compile your own lisp file +into pgloader at runtime. For your functions to be found, remember to begin +your lisp file with the following form:

+
(in-package #:pgloader.transforms)
+
+
+

The provided transformation functions are:

+
+
    +
  • zero-dates-to-null

    +

    When the input date is all zeroes, return nil, which gets loaded as a +PostgreSQL NULL value.

    +
  • +
  • date-with-no-separator

    +

    Applies zero-dates-to-null then transform the given date into a format +that PostgreSQL will actually process:

    +
    In:  "20041002152952"
    +Out: "2004-10-02 15:29:52"
    +
    +
    +
  • +
  • time-with-no-separator

    +

    Transform the given time into a format that PostgreSQL will actually +process:

    +
    In:  "08231560"
    +Out: "08:23:15.60"
    +
    +
    +
  • +
  • tinyint-to-boolean

    +

    As MySQL lacks a proper boolean type, tinyint is often used to +implement that. This function transforms 0 to ‘false’ and anything +else to ‘true’.

    +
  • +
  • bits-to-boolean

    +

    As MySQL lacks a proper boolean type, BIT is often used to implement +that. This function transforms 1-bit bit vectors from 0 to f and any +other value to t..

    +
  • +
  • int-to-ip

    +

    Convert an integer into a dotted representation of an ip4.

    +
    In:  18435761
    +Out: "1.25.78.177"
    +
    +
    +
  • +
  • ip-range

    +

    Converts a couple of integers given as strings into a range of ip4.

    +
    In:  "16825344" "16825599"
    +Out: "1.0.188.0-1.0.188.255"
    +
    +
    +
  • +
  • convert-mysql-point

    +

    Converts from the astext representation of points in MySQL to the +PostgreSQL representation.

    +
    In:  "POINT(48.5513589 7.6926827)"
    +Out: "(48.5513589,7.6926827)"
    +
    +
    +
  • +
  • integer-to-string

    +

    Converts a integer string or a Common Lisp integer into a string +suitable for a PostgreSQL integer. Takes care of quoted integers.

    +
    In:  "\"0\""
    +Out: "0"
    +
    +
    +
  • +
  • float-to-string

    +

    Converts a Common Lisp float into a string suitable for a PostgreSQL float:

    +
    In:  100.0d0
    +Out: "100.0"
    +
    +
    +
  • +
  • set-to-enum-array

    +

    Converts a string representing a MySQL SET into a PostgreSQL Array of +Enum values from the set.

    +
    In: "foo,bar"
    +Out: "{foo,bar}"
    +
    +
    +
  • +
  • empty-string-to-null

    +

    Convert an empty string to a null.

    +
  • +
  • right-trim

    +

    Remove whitespace at end of string.

    +
  • +
  • remove-null-characters

    +

    Remove NUL characters (0x0) from given strings.

    +
  • +
  • byte-vector-to-bytea

    +

    Transform a simple array of unsigned bytes to the PostgreSQL bytea Hex +Format representation as documented at +http://www.postgresql.org/docs/9.3/interactive/datatype-binary.html

    +
  • +
  • sqlite-timestamp-to-timestamp

    +

    SQLite type system is quite interesting, so cope with it here to produce +timestamp literals as expected by PostgreSQL. That covers year only on 4 +digits, 0 dates to null, and proper date strings.

    +
  • +
  • sql-server-uniqueidentifier-to-uuid

    +

    The SQL Server driver receives data fo type uniqueidentifier as byte +vector that we then need to convert to an UUID string for PostgreSQL +COPY input format to process.

    +
  • +
  • unix-timestamp-to-timestamptz

    +

    Converts a unix timestamp (number of seconds elapsed since beginning of +1970) into a proper PostgreSQL timestamp format.

    +
  • +
  • varbinary-to-string

    +

    Converts binary encoded string (such as a MySQL varbinary entry) to a +decoded text, using the table’s encoding that may be overloaded with the +DECODING TABLE NAMES MATCHING clause.

    +
  • +
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html new file mode 100644 index 0000000..35dce69 --- /dev/null +++ b/docs/_build/html/search.html @@ -0,0 +1,101 @@ + + + + + + + Search — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js new file mode 100644 index 0000000..67dc5a1 --- /dev/null +++ b/docs/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["bugreport","index","intro","pgloader","pgloader-usage-examples","ref/archive","ref/copy","ref/csv","ref/dbf","ref/fixed","ref/ixf","ref/mssql","ref/mysql","ref/sqlite","ref/transforms","tutorial/csv","tutorial/dBase","tutorial/fixed","tutorial/geolite","tutorial/mysql","tutorial/quickstart","tutorial/sqlite","tutorial/tutorial"],envversion:53,filenames:["bugreport.rst","index.rst","intro.rst","pgloader.rst","pgloader-usage-examples.rst","ref/archive.rst","ref/copy.rst","ref/csv.rst","ref/dbf.rst","ref/fixed.rst","ref/ixf.rst","ref/mssql.rst","ref/mysql.rst","ref/sqlite.rst","ref/transforms.rst","tutorial/csv.rst","tutorial/dBase.rst","tutorial/fixed.rst","tutorial/geolite.rst","tutorial/mysql.rst","tutorial/quickstart.rst","tutorial/sqlite.rst","tutorial/tutorial.rst"],objects:{},objnames:{},objtypes:{},terms:{"000s":[19,21,22],"001s":[19,22],"003s":[21,22],"006s":[19,21,22],"007s":[19,22],"008s":[21,22],"010s":[16,22],"01234562008052115182300left":9,"01234567892008052011431250firstlin":9,"012s":[18,19,21,22],"013s":[17,21,22],"014s":[21,22],"016s":[21,22],"017s":[21,22],"018s":[19,21,22],"019s":[15,17,18,22],"021s":[21,22],"023s":[19,21,22],"025s":[21,22],"027s":[21,22],"031s":[21,22],"032s":[21,22],"033s":[21,22],"034s":[21,22],"035s":[19,22],"036s":[19,22],"037s":[19,22],"039s":[15,22],"040s":[21,22],"041s":[19,22],"043s":[21,22],"052s":[21,22],"058s":[15,19,22],"059s":[19,22],"068s":[19,22],"070s":[19,21,22],"071s":[16,19,21,22],"073s":[19,22],"077s":[21,22],"080s":[19,22],"0d0":14,"0x0":14,"105s":[21,22],"111s":[21,22],"12345678902008052208231560anoth":9,"128mb":[0,12,19,22],"12mb":[12,15,19,22],"130s":[19,22],"135s":[19,22],"136s":[19,22],"14mb":[6,9],"150s":[19,22],"154s":[19,22],"160s":[21,22],"167s":[16,22],"16mb":[11,13,21,22],"16t08":[19,22],"1m8":[18,22],"2013_gaz_113cds_nat":[4,20,22],"205s":[19,22],"208s":[19,22],"20t16":[21,22],"214s":[19,22],"227s":[19,22],"228s":[19,22],"236s":[19,22],"247s":[19,22],"254s":[19,22],"268s":[19,22],"279s":[21,22],"303s":[19,22],"313s":[21,22],"332s":[18,22],"365s":[19,22],"390s":[18,22],"402s":[19,22],"42p16":[21,22],"476s":[21,22],"494s":[17,22],"497s":[19,22],"499s":[17,22],"502s":[19,22],"527s":[19,22],"539s":[19,22],"547s":[19,22],"583s":[19,22],"592s":[18,22],"648s":[19,22],"658s":[16,19,22],"669s":[21,22],"692s":[18,22],"743s":[18,22],"877s":[21,22],"892s":[19,22],"906s":[16,22],"964s":[19,22],"9n8v8pw54t1gngfff0lj16040000gn":[16,17,18,22],"boolean":[11,12,14,19,22],"byte":[3,6,9,11,14],"case":[1,2,3,4,11,12,13,19,20,21,22],"char":[11,12,13,15,17,22],"default":[1,3,7,10,14,19,22],"enum":[12,14],"export":[3,11],"final":[1,4,18,20,22],"float":[11,12,13,14,18,22],"function":[1,3,12],"import":[3,4,15,16,17,18,19,20,21,22],"int":[12,14],"long":[17,22],"new":3,"null":[5,6,7,9,12,14,17,18,19,22],"public":[0,11,12],"return":[12,14],"short":0,"static":3,"switch":[3,4,20,22],"true":14,"try":[3,4,20,22],"var":[16,17,18,22],"while":[3,4,12,18,19,20,22],AND:[5,12,18,22],And:[1,18,22],For:[0,3,4,12,14,20,22],INTO:[0,5,6,7,8,9,10,12,15,16,17,18,22],Its:[21,22],NOT:[3,12],One:3,That:[2,3,7,12,14,18,22],The:[2,3,4,5,6,7,8,9,10,11,12,13,14,20],Then:[3,5],USING:[3,18,21,22],Use:[0,3,4,6,7,8,9,10,12,13],Useful:3,Using:[3,18,22],WITH:[0,1,5,15,16,17,18,19,22],_list:12,abil:3,abl:[2,3,12],about:[1,4,12,20,22],abov:[3,4,6,7,9,11,12,15,20,22],absolut:[3,6,7,9],accept:[2,3,5,6,7,8,9,10,11,12,13,21,22],access:7,accomod:3,accumul:[3,11],achiev:[11,12],action:12,activ:[3,12],actor:[12,19,22],actual:[3,14,18,22],add:[19,21,22],added:11,addit:3,address:[6,8,10,18,19,22],administr:[16,22],advanc:[3,19,21,22],aen66609:3,after:[2,6,7,9,12,13],again:[2,3,4,7,12,13,19,20,22],against:[3,4,5,6,7,8,9,10,12,13,20,21,22],al0100124abbevil:[17,22],al0100460adamsvil:[17,22],al0100484addison:[17,22],al0100676akron:[17,22],al0100820alabast:[17,22],al0100988albertvil:[17,22],al0101132alexand:[17,22],aland:[4,20,22],aland_sqmi:[4,20,22],album:[6,21,22],all:[2,3,4,5,6,7,8,9,10,11,13,14,19,20,21,22],allow:[2,3,5,6,7,8,9,10,11,12,13,15,17,19,21,22],alon:[19,22],alreadi:[3,12,13],also:[3,4,5,7,9,12,13,18,20,21,22],alter:[3,6,7,8,9,10,13,21,22],amend:[11,12,13],amount:3,ampersand:3,ani:[2,3,6,7,9,11,12,13,14],anoth:3,anyth:[3,14],anywai:3,api:[19,22],app:0,appdata:3,appear:[3,12,13],append:12,appli:[3,5,6,7,9,11,12,13,14],applic:12,application_nam:0,appoint:13,appropri:[18,22],arbitrari:3,architectur:[2,3],archiv:[1,3,16,17,18],areacod:[5,18,22],argument:[1,4,6,7,9,12,20,22],around:[3,19,22],arrai:14,arrang:9,artist:[21,22],ascii:[6,7],ask:12,aspect:2,assess:12,associ:12,astext:14,attach:[12,13],attempt:3,augment:12,auto_incr:[12,19,22],autom:[2,3],automat:[7,9,11,12,13,19,22],avail:[2,3,12],awai:[3,19,22],awat:[4,20,22],awater_sqmi:[4,20,22],back:[12,13],backslash:[0,7],backward:3,bad:3,baddata:0,bar:14,base:[3,4,12,20,22],basic:3,batch:1,battl:[4,20,22],becaus:[3,4,12,20,22],been:[3,5,12,13,15,16,17,18,19,21,22],befor:[0,2,5,6,7,8,9,10,11,12,13,15,16,17,18,19,21,22],begin:[3,6,7,9,12,14],behavior:[3,12],behaviour:[1,7,12],being:[3,4,12,13,20,22],below:[3,7,9],benefit:[16,19,21,22],best:7,better:3,between:[0,4,6,7,9,20,22],bigint:[4,6,12,13,15,20,22],bigseri:[6,12,19,22],binari:[3,11,12,13,14],bit:[3,11,12,14],blank:[5,7,9,17,18,22],blob:[12,13],block:[5,7,18,22],blocks_ip4r_idx:[5,18,22],both:[3,7,9,12,19,22],bracket:[7,9],breath:12,brows:[15,16,17,18,19,21,22],buffer:[4,20,22],bug:1,build:[11,12,13,19,21,22],built:[7,12],bypass:[3,4,20,22],bytea:[11,12,13,14],calendar:[19,22],can:[2,3,4,5,6,7,9,11,12,14,15,16,17,18,19,20,21,22],canada:[15,22],capabl:[16,19,21,22],care:[0,4,6,7,8,9,10,12,13,14,19,20,21,22],cascad:[11,12,13,18,22],cast:[1,3,4,19,20,22],categori:[19,22],caus:3,censu:[17,22],chanc:12,chang:[3,11,12],charact:[3,4,6,7,9,12,13,14,20,22],characterist:3,charset:11,check:[12,13],checkout:3,chinook:[21,22],chinook_sqlite_autoincrementpk:[21,22],chinookdatabas:[21,22],choic:[19,22],circuit:[19,22],citi:[5,17,18,19,22],claus:[1,5,6,7,8,9,10,11,12,13,14,19,22],clean:[12,13],client:[3,11],client_encod:[15,16,22],clob:13,close:3,code:[3,6,7,12],cog:[4,8,16,20,22],col:1,collid:3,colon:3,column:[3,4,7,9,12,13,15,17,18,19,20,22],com:[0,12,18,19,21,22],come:3,comma:[3,7,9,11,12,13,15,22],command:[1,6,7,8,9,10,11,12,13,14,20],comment:[19,21,22],commerci:[19,22],common:[1,11,12,14],commonli:[4,20,22],compat:3,compil:[3,14],complet:[3,19,21,22],complex:[3,12],compon:[3,12],compos:[6,9],compress:4,comput:3,concurr:[3,12,21,22],condit:[7,12],conf:[3,11],config:3,configur:[3,11],confus:3,connect:[2,4,11,12,20,22],connstr:3,consid:3,consist:[3,18,22],consol:3,constraint:[3,6,7,8,9,10,11,12,13,19,21,22],construct:12,constructor:[19,22],constructorresult:[19,22],constructorstand:[19,22],contain:[0,2,3,4,5,6,7,8,9,10,12,13,18,20,21,22],content:[1,4,5,15,17,18,19,20,22],context:[3,11,12,13],continu:[1,3],control:[3,13],convers:[8,10,12,13],convert:[7,9,12,14],cope:[3,12,14,19,22],copi:[1,2,3,7,8,9,10,12,13,14,19,21,22],copyright:[4,20,22],could:[3,4,7,9,20,22],count:3,countri:[5,18,19,22],coupl:[3,14,17,22],cours:[6,8,10,18,22],cover:[3,12,14],creat:[0,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22],createdb:[4,19,20,21,22],creation:[12,13],criteria:12,critic:3,cross:3,csv:[0,1,2,3,5,18],curl:[4,20,22],current:[3,4,5,7,9,11,12,13],current_timestamp:[19,22],custom:[3,11,12,13,19,21,22],cut:3,dai:[2,7,9],dash:[3,4,20,22],dat:[2,3],data:[1,2,3,4,5,6,9,11,12,13,14,19],databas:[1,2,3,4,15,18,19,20,21,22],dataset:[18,22],datasourc:[21,22],datatyp:[12,14,18,22],date:[7,9,11,12,13,14,19,22],datetim:[11,12,13,19,22],datetime2:11,db3:3,dba:3,dbase:[1,3],dbf:[1,2,3,5,6,10,12,16],dbname:[3,7,8,11],dbo:11,dbpath:3,ddl:12,decim:[9,11,12],declar:12,decod:14,decompress:3,defin:[3,6,7,8,9,10,12,13,15,16,17,18,19,21,22],definit:[3,4,11,12,13,19,20,21,22],delai:0,delimit:[3,6],denot:[6,7],depend:[2,3,5,11,12],describ:[2,3,6,7,9,12,15,16,19,21,22],descript:[0,2,7,9],detail:[3,11,12,15,16,17,18,19,21,22],determin:[3,12],dev:[12,15,16,17,18,19,21,22],develop:3,dialect:[12,19,22],did:[3,16,17,21,22],didn:3,differ:[0,2,3,12,14],difficulti:12,digit:[3,7,9,14],dim:[0,5,13,15,16,17,18,19,21,22],dir:3,direct:[4,20,22],directli:[2,3,18,22],directori:[3,5,6,7,9],disabl:[3,6,7,8,9,10,12,13],discov:[4,20,22],discoveri:[3,11,13],distribut:12,district:4,districts_longlat:[4,20,22],divid:12,doc:[3,12,14,17,22],document:[2,3,4,6,14,20,22],doe:[3,19,21,22],doesn:[11,12],doing:[12,13,19,22],dollar:3,domain:3,don:[3,12],done:[3,6,7,8,9,10,11,12,13,18,19,21,22],dot:[3,14],doubl:[3,4,5,6,7,9,11,12,13,15,18,20,22],down:[3,4,20,22],downcas:[12,13],download:[4,5,13,16,17,18,19,20,21,22],drawback:3,driven:[4,20,22],driver:[1,14,19,22],driverstand:[19,22],drop:[0,6,7,9,10,11,12,13,15,17,18,19,21,22],dry:3,dsl:[2,3],dynam:[3,12,18,22],each:[3,7,9,12,13,17,18,22],easi:[0,12,20,22],easier:3,edit:[15,16,17,18,19,21,22],effect:[12,13],either:[2,3,4,6,7,9,10,11,12,13,19,20,22],elaps:14,els:[3,14],email:0,embed:[21,22],emit:3,employe:[21,22],empti:[3,6,7,9,12,14,19,21,22],enabl:[3,6,7,8,9,10,12,13],enclos:[0,3,5,7,9,15,18,22],encod:[1,3,5,7,9,13,14,17,18,22],end:[3,6,7,9,12,13,14,18,19,22],endipnum:[5,7,18,22],engin:[11,12],enjoi:2,enough:[3,12,14],ensur:[4,11,12,13,20,22],enter:[3,9],entir:[4,12,20,22],entri:14,enumer:12,env:3,environ:[2,3,4,11,12,13,20,22],equal:3,equival:[3,4,20,22],ergast:[19,22],erron:3,error:[2,3,15,16,17,18,19,21,22],escap:[0,3,4,5,7,15,18,22],etc:[3,21,22],europ:10,evalu:12,even:[12,13],ever:3,everi:2,exact:[5,6,7,9,12],exampl:[0,3,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,22],excel:[16,22],except:[3,12],exclud:[19,22],exclus:7,execut:[4,5],exist:[0,3,4,5,6,7,8,9,10,11,12,13,15,17,18,19,20,21,22],exit:3,expand:[3,4,5,20,22],expect:[0,2,3,7,8,9,10,11,12,14,19,21,22],explain:0,explan:11,explicit:3,explicitli:12,express:[5,6,7,9,11,12],ext:3,extens:[0,3,5,18,22],extern:11,extra:[3,4,12,20,22],extract:[16,17,18,22],f1db:[19,22],facil:3,facilit:[15,16,17,18,19,21,22],fact:[19,22],fail:[3,12],fals:14,familiar:3,fashion:3,fast:3,faster:3,feasibl:[4,20,22],featur:[2,3,12],feed:3,feedback:3,fetch:[2,3,6,8,10,12,13,16,17,18,19,21],field:[0,1,3,4,5,8,10,12,13,15,18,20,22],figur:[12,13],file:[1,2,3,5,7,8,10,11,12,13,14,15,18,19],filemak:[16,22],filenam:[3,5,6,7,8,9,10,17,18,22],fill:[2,3],fillfactor:12,film:[12,19,22],film_actor:[19,22],film_categori:[19,22],film_list:[12,19,22],film_text:[19,22],filter:[11,12,13,15,22],finali:[19,22],find:[3,6,7,9,11,12,16,17,18,22],fip:[17,22],fips_cod:[17,22],first:[3,4,5,6,7,9,12,17,20,22],fit:[3,4,20,22],fix:[1,2,3,5],fledg:3,flexibl:[3,12],flight:11,fly:[2,3,12,18,22],folder:[16,17,18,22],follow:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,20,22],foo:[0,4,12,14,18,20,22],forc:[3,12],foreign:[4,6,7,8,9,10,11,12,13,19,20,21,22],fork:2,form:[3,12,14],format:[1,2,4,5,7,8,10,14,16,17,18,20,22],former:3,found:[3,4,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22],framework:12,free:[18,22],freetd:11,french:[16,22],friendli:3,from:[0,1,2,14,15,16,17,18,21],full:[2,3,12,17,18,22],fulli:[2,3],gazett:[17,22],gazetteer2000:[17,22],gener:12,genr:[6,21,22],geo:[17,22],geographi:11,geoid:[4,20,22],geoip:[18,22],geolit:[1,5,7],geolitec:[5,7,18,22],geolitecity_csv:[18,22],geoloc:[18,22],geometr:12,get:[3,5,7,11,12,13,14,15,22],getenv:3,gist:[5,18,22],git:3,github:[3,21,22],give:[2,19,22],given:[2,3,4,5,6,7,9,12,14,17,18,19,20,21,22],global:[3,11],globalaccount:11,gmt:10,goal:2,good:[3,21,22],gov:[17,22],grammar:3,great:[2,12,13],greater:12,green:2,grow:3,guard:12,guc:3,guc_nam:3,guess:[4,20,22],gunzip:[4,20,22],had:[19,22],handl:[3,12,21,22],happen:[3,4,12,20,22],has:[3,4,5,12,13,15,16,17,18,19,20,21,22],have:[0,2,3,4,7,12,13,19,20,21,22],header:[3,4,5,6,7,9,15,18,20,22],help:[0,3,4,21,22],here:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22],hex:14,hexadecim:[6,7,9],hh12:[7,9],hh24:[7,9],hierarchyid:11,histor:[19,22],historiq2013:[4,16,20,22],hold:12,host:[3,4,11,12,16,19,20,21,22],hostnam:3,hour:[7,9],how:[2,3,4,9,12,15,18,20,22],hstore:0,html:[3,12,14,17,22],http:[3,5,6,8,10,12,13,14,15,16,17,18,19,21],human:3,ibm:[3,10],idea:12,identifi:[0,3,12,13],idx_66873_sqlite_autoindex_playlisttrack_1:[21,22],idx_oid:12,ignor:[6,7,8,9,10,12,13],imag:3,impact:3,implement:[2,3,7,9,11,12,14],imposs:12,includ:[0,3,4,7,18,19,20,21,22],index:[1,3,4,5,7,11,12,13,17,18,19,20,21,22],info:3,inforamt:4,inform:[12,16,19,20,21,22],ini:3,inlin:[0,3,6,7,9,12],input:[0,2,3,4,6,7,9,14,15,18,20,22],inse:[4,8,16,20,22],insid:[6,7],inspir:3,instal:[12,13,19,21,22],instanc:[3,11],instead:[18,22],instruct:[5,6,7,8,9,10,11,12,13],integ:[9,12,13,14,18,22],integr:2,intend:[12,13],interact:14,interest:14,intern:[11,12],intervent:2,intptlat:[4,20,22],intptlong:[4,20,22],introduc:[3,7,11,12,13],introduct:1,invalid:[6,7,8,9,10,12,13],inventori:[19,22],invoic:[13,21,22],invoicelin:[21,22],involv:12,ip4:14,ip4r:[5,7,18,22],iprang:[5,7,18,22],ipv4:[3,18,22],isn:[3,12],iso:[5,7,18,22],isol:3,issu:[6,7,8,9,10,12,13],its:[2,3,4,8,10,12,15,16,17,18,19,20,21,22],itself:[3,6,7,11,16,17,22],ixf:[1,3],join:[18,22],json:3,just:[3,4,7,12,13,20,22],keep:[7,12],kei:[0,3,4,6,7,8,9,10,11,12,13,18,19,20,21,22],kept:[3,12],keyword:[7,9,12],kick:12,kind:[2,3,4,20,22],kingdom:[15,22],know:[2,3,7,9,12],known:[3,12],label:12,lack:[11,14],land:[17,22],languag:[2,3,19,22],laptim:[19,22],larg:3,last:[3,12],lastest:[18,22],lastfm_tag:13,lat:[17,22],later:[3,4,20,22],latest:[5,18,22],latin1:[15,16,17,22],latitud:[5,18,22],ldm:[17,22],learn:3,least:12,leav:[3,19,22],left:[3,7,9,12],length:[3,9,17,22],lerocha:[21,22],less:12,let:[16,17,19,21,22],letter:3,level:[2,3,5,12,16,22],lib:11,libpq:3,light:[18,22],like:[3,12],lile:11,limit:[1,3,7,9,11,13],line:[1,4,5,6,7,9,14,17,20],link:5,lisp:[3,11,12,14],list:[3,6,7,8,9,10,11,12,13,16,22],listen:11,liter:14,live:2,load:[0,1,2,11,12,13,14,19],loc_nam:[17,22],local:[3,4,5,6,8,10,20,22],localaccount:11,localhost:[0,3,4,7,8,12,19,20,22],locat:[3,5,10,16,17,18,21],locationnam:[17,22],locid:[5,7,18,22],lock:7,log:[2,3,15,16,17,18,19,21,22],logfil:3,longblob:12,longitud:[5,18,22],longtext:12,look:3,lot:12,machin:3,mai:[3,4,6,7,8,9,10,11,12,13,14,19,20,21,22],main:[3,18,19,22],maintenance_work_mem:[7,11,12,13,19,21,22],make:[3,21,22],man:[4,20,22],manag:[2,3,21,22],mani:[3,6,7,9,12],manner:9,manual:[1,2],map:[12,17,22],master:[21,22],match:[3,4,5,6,7,9,14,17,18,19,20,22],materi:[19,22],max:[3,12],maximum:[3,12,13],maxmind:1,mayb:[4,20,22],mean:[4,12,15,20,22],meant:[2,3],media:6,mediatyp:[21,22],mediumblob:12,mediumint:12,mediumtext:12,memori:[3,12],mess:12,messag:[3,19,21,22],met:12,meta:[8,10,12,13,16,19,21,22],metadata:[2,12,13],method:[3,4,8,16,20,22],methodolog:2,metrocod:[5,18,22],microsecond:[7,9],middl:3,might:[3,4,5,6,7,12,13,20,22],migrat:[1,21],million:[18,22],millisecond:[6,7,9],min:[3,12],mind:3,minimum:3,minut:[7,9],miss:3,mix:3,mode:[3,7,12],model:[3,7,9],modern:[16,22],modif:12,modul:1,moment:5,monei:11,month:[7,9],more:[4,5,11,16,17,20,21,22],most:[0,3,4,19,20,22],motor:[19,22],mrd:[19,22],mssql:[3,11],much:3,multipl:[12,21,22],multipli:3,must:[2,3,4,5,6,7,8,9,10,11,12,13,14,20,22],mustach:1,mysql:[1,2,3,11,14],mysql_host:12,mysql_pwd:12,mysql_tcp_port:12,name:[0,3,4,5,6,7,8,9,10,14,15,16,17,18,19,20,21,22],nativ:3,natur:[21,22],nchar:13,nchat:11,necessari:[3,4,14,20,22],need:[0,2,3,4,7,12,13,14,15,16,17,18,19,20,21,22],net_read_timeout:12,net_write_timeout:12,netloc:3,network:[3,4,20,22],never:3,newdb:[4,20,22],newer:3,night:2,nil:[5,14,18,22],nomenclatur:[4,8,16,20,22],non:[3,5,19,22],none:3,nor:[3,11,12],notat:3,note:[1,4,5,12,13,15,16,17,18,19,20,21,22],notic:[3,4,20,22],now:[4,12,19,20,21,22],nsitra:10,nul:14,number:[3,6,7,9,11,12,13,14],numer:[3,6,7,9,11,12,13],nvarchar:[11,13],object:[12,13],obtain:12,occur:3,offer:[16,18,22],often:[14,15,22],oid:[12,19,21,22],old:[3,4,20,22],omit:[3,12],onc:[3,5,6,7,8,9,10,12,13,19,22],one:[0,3,4,5,7,9,11,12,20,22],ones:[3,12],onli:[2,4,5,6,7,9,14,15,17,19,20,22],onlin:[3,15,16,17,18,19,21,22],open:[3,4,20,22],oper:[15,16,17,18,19,21,22],option:[1,2,4,5,14,15,18,19,20,21,22],order:[2,3,7,12],ordinari:7,org:[3,4,14,18,20,21,22],ori:[12,19,22],other:[0,3,7,11,12,13,14,19,22],otherwis:[3,12],ouput:[0,15,18,22],our:[12,15,16,17,18,19,21,22],out:[3,12,13,14],output:[0,3,12,16,17,19,21,22],over:[2,3,4,12,13,19,20,22],overload:[11,12,13,14],overrid:3,overs:3,own:[2,3,14],packag:[3,12,14],pad:[9,17,22],page:[1,4,20,22],pagila:[4,12,20,22],pair:[2,3,18,22],parallel:[1,7],paramet:[3,7,9,12],pari:10,pars:[3,4,6,7,9,10,13,15,16,17,18,19,21,22],parser:[3,7,12],part:[3,7,9,12],partial:1,particular:[3,19,22],pass:3,password:[3,12],past:12,path:[3,13,15,22],pattern:[7,9,11,13],payment:[19,22],per:[3,7,9,12,19,22],percent:3,perform:[1,7],pg_get_keyword:12,pgdatabas:3,pghost:3,pgloader:[0,2,5,6,7,8,9,10,11,12,13,14,19],pgpass:3,pgpassfil:3,pgpassword:3,pgsql:[4,12,18,19,20,21,22],pguser:3,pick:3,piggyback:11,pipe:[3,4,20,22],pitstop:[19,22],place:[3,16,17,22],places2k:[17,22],plai:3,plain:12,playlist:[21,22],playlisttrack:[21,22],pleas:[3,4,11,12,13,20,22],point:[3,5,12,13,14,18,22],popular:[18,22],port:[3,11,12],posit:[9,17,22],possibl:[0,3,4,6,7,8,9,10,12,13,19,20,22],postalcod:[5,18,22],postgr:[4,20,21,22],postgreslq:3,postgresql:[0,1,2,3,4,5,6,7,8,9,10,14,15,16,17,18,20,21],postgresqlpgpass:3,pow:[18,22],pre:[3,4,6,7,8,9,10,12,13,20,22],precis:[4,11,12,13,20,22],prefer:3,prefetch:3,prefix:12,prepar:3,preserv:12,prevent:12,primari:[0,7,11,12,18,19,21,22],print:3,printabl:[6,7],prior:[12,13],privat:[16,17,18,19,21,22],problem:[3,19,22],problemat:0,process:[3,4,5,7,9,12,13,14,18,20,22],produc:14,product:2,project:[2,3,21,22],proper:[3,14],properti:[2,4],protocol:[2,3],provid:[2,3,4,11,12,13,14,16,17,18,19,20,22],psql:3,punctuat:[3,7,9],purpos:[19,22],push:3,qualifi:[3,8,10,19,22],queri:[3,5,12,18,21,22],queue:3,quick:[1,18],quiet:3,quit:[14,15,18,22],quot:[0,3,4,5,6,7,9,10,12,14,15,18,22],race:[19,22],rag:3,rang:[5,7,12,14,17,18,22],rather:[3,12],raw:[2,3,21,22],read:[2,3,6,7,8,9,10,12,15,16,17,18,19,21],readabl:3,reader:[3,7,9,12],readi:[15,16,17,18,19,21,22],real:[3,11,13],reason:3,receiv:14,recent:3,recogn:[4,7,20,22],recommand:0,record:[18,19,22],recreat:[12,13],redund:4,refer:[1,4,11,12,20,22],referenc:[12,13],refman:12,refrain:[11,12,13],refus:3,reg2013:8,regardless:12,regexp:[6,7,9,12],region:[3,5,18,22],regular:[5,6,7,9,11,12],reject:[2,3,19,22],rel:[3,6,7,9],reload:3,remain:3,rememb:14,remov:[7,12,13,14],renam:12,rental:[19,22],replac:3,report:[1,19,21,22],repres:[14,18,22],represent:[6,12,14,18,22],reproduc:1,requir:[3,9,12],reserv:[12,17,22],reset:[12,13,19,21,22],resp:3,respect:[3,12,21,22],respons:3,restrict:3,result:[3,6,7,8,9,10,11,12,13,19],retri:1,reus:12,review:4,rewrit:12,rich:3,right:[3,4,7,9,14,16,17,20,22],root:[3,12,19,22],row:[3,12,13,15,22],rule:[1,3,5,6,7,9,19,22],run:[3,4,5,12,19,20,21,22],runtim:[3,14],sai:3,sakila:[4,12,19,20,22],sales_bi:12,sales_by_stor:12,same:[3,4,5,6,7,8,9,10,11,12,13,20,21,22],sampl:[19,22],sanit:[3,19,22],satisfi:3,scale:12,scenario:3,schedul:2,schema:[1,3,4,5,10,13,18,19,20,21,22],script:3,search:[1,12,14],search_path:[12,19,22],season:[19,22],second:[7,9,14],section:[3,4,11,12,20,22],see:[3,6,7,9,11,12,15,16,17,19,21,22],select:[12,18,19,22],self:[0,3],semi:3,send:3,sens:3,sensibl:12,sent:[3,11,12],separ:[3,4,7,9,11,12,13,14,15,22],sequenc:[12,13,19,21,22],seri:5,serial:[0,12],server:[2,3,11,14],servic:2,session:3,set:[0,5,6,7,9,11,12,13,14,15,16,18,19,21,22],setup:[1,2,3,12],sever:[3,5,6,7,9,12,13,21,22],shorter:[17,22],should:[3,12],show:[3,17,22],side:[3,7,9],sign:[3,7,9,15,22],similar:6,simpl:[3,14,20,22],simultan:3,sinc:14,singl:[2,3,4,6,7,8,9,10,12,18,20],size:[3,9],skip:[3,4,5,6,7,9,12,13,15,18,19,20,21,22],smaller:3,smallint:[11,12,13,19,22],smallmonei:11,smart:3,socket:3,softwar:0,solut:[3,21,22],solv:0,some:[2,3,4,12,14,15,16,17,18,19,20,21,22],someth:3,soon:[2,3],sourc:[0,1,2,4,19,20,21,22],space:[3,7,9],span:3,speak:[16,22],spec:[15,22],special:[6,7,9,11,12,13,18,19,21,22],specif:[1,2,3,4,15,18,19,20,22],specifi:[2,3,4,6,7,9,10,11,12,13,17,20,22],speed:[18,22],spell:[3,5,12],split:12,sql:[1,2,3,4,7,9,12,14,19,20,21,22],sqlite:[1,2,3,14],squar:[7,9],sslmode:[3,12],staff:[19,22],staff_list:[12,19,22],standard:[3,4,6,7,8,9,10,12,13,20,22],standard_conforming_str:[0,6,9,15,22],start:[1,3,9,12,13,15,16,17,18,19,21],startipnum:[5,7,18,22],state:[15,22],statement:[3,12,13],statu:[19,22],stdin:[3,6,7,9],step:[2,3,7,18,22],still:[16,17,22],stop:[3,12],storag:3,store:[19,22],straight:[4,20,22],strea:[7,9],stream:[2,3,4,6,7,9,21],string:[4,6,7,9,11,12,13,14,20,22],sub:1,sublist:[11,12,13],submit:[2,3],subset:3,suitabl:14,summari:[3,19,21,22],suppli:3,support:[1,3,4,5,6,7,8,9,10,11,13,16,20,22],supris:2,syntax:[1,4,6,7,9,20,22],system:[3,12,14,15,16,17,18,19,21,22],tabl:[0,3,4,6,7,8,9,10,14,15,16,17,18,19,20,21,22],tablenam:[3,4,20,22],tabul:[6,7],tag:13,take:[3,4,6,7,9,12,14,19,20,21,22],taken:[0,12,13],talk:3,tapoueh:[4,18,20,22],target:[2,4,6,7,8,9,10,11,12,13,20,22],task:3,tcp:11,tds:11,tdsport:11,techniqu:[4,20,22],telecharg:[4,8,16,20,22],temp:[4,18,20,22],templat:[1,7,9],termin:[0,3,4,5,7,9,15,18,20,22],test1:10,test:[1,3,4,15,16,17,18,19,20,21,22],text:[3,4,6,9,11,12,13,14,15,18,20,22],than:[3,11,12,17,22],thei:[3,7,11,12,13,19,22],them:[3,6,7,9,11,12,13,16,17,22],themselv:[3,7],theoret:12,thi:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,22],thing:[3,12],third:2,tho:[19,21,22],those:[0,2,3,4,7,9,11,12,15,19,20,22],though:[0,3,4,20,22],thread:[3,12,19,21,22],threshold:3,tild:3,time:[3,9,12,13,14,15,16,17,18,19,21,22],timestamp:[10,12,13,14],timestamptz:[11,12,13,14,19,22],timezon:10,tinyblob:12,tinyint:[11,12,13,14,19,22],tinytext:12,tmp:[3,5,19,21,22],tmpdir:5,to_char:[7,9],togeth:11,too:[3,12,16,19,22],tool:[2,3,16,19,22],top:5,topic:[19,22],total:[15,16,17,18,19,21,22],town:[17,22],track:[6,21,22],track_ful:6,trackid:6,transform:[1,2,3,18,22],translat:[19,22],trick:[4,20,22],trigger:[3,6,7,8,9,10,12,13,19,21,22],trim:[7,9,14,17,22],truncat:[0,4,6,7,8,9,10,12,13,15,16,18,19,20,21,22],tsv:3,turn:[19,22],tutori:[1,4],tweak:3,two:[2,3,7,12],txt:[4,17,20,22],type:[0,2,3,4,7,8,9,10,11,12,13,14,18,19,20,21,22],typemod:[11,12,13],typic:3,unarch:[4,20,22],under:3,underscor:3,uniqu:[7,12],uniqueidentifi:[11,14],uniquifi:12,unit:[3,15,22],unitpric:6,univers:10,unix:[3,4,14,20,22],unpars:[7,9],unquot:7,unset:[3,5],unsign:[12,14],until:[3,12,13],unzip:[5,16,17,21,22],updat:[19,22],upgrad:3,uri:[3,4,5,12,20,22],url:[3,4,5,6,8,10,12,13,16,17,20,21,22],usag:3,use:[3,4,7,12,14,16,17,18,19,20,21,22],used:[3,4,5,6,7,9,10,11,12,13,14,18,20,22],useful:[3,19,22],user:[3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22],uses:[2,3,6,19,21,22],using:[2,3,4,5,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22],usp:[4,17,20,22],usual:[3,4,17,20,22],utc:10,utf8:12,utf:[11,13],util:5,uuid:[11,14],valid:3,valu:[0,3,6,7,8,9,10,12,13,14,15,19,22],varbinari:[11,12,14],varchar:[11,12,13,17,22],vari:[15,22],variabl:[3,11,12],variant:[2,3],variou:[2,3],vector:[11,14],verbos:[3,4],veri:[3,18,20,21,22],verifi:12,version:[0,3,4,11,18,20,22],versu:3,view:[1,19,22],wai:[2,3,6,14],wait:3,walk:[6,7,9],want:[3,4,12,18,19,20,22],warn:[3,19,21,22],water:[17,22],webpag:2,websit:[16,22],welcom:11,were:12,what:[7,9,12,13,15,22],whatev:3,when:[3,4,5,6,7,8,9,10,11,12,13,14,17,19,20,21,22],where:[2,3,4,5,6,7,8,9,10,11,12,17,18,20,22],wherea:[3,12],whether:12,which:[3,5,6,7,8,9,10,12,13,14,18,19,21,22],whichev:3,white:3,whitespac:[3,7,9,14,17,22],whole:[2,3,4,5,6,7,9,12,19,20,22],whose:[12,13],width:1,window:3,within:[3,7],without:[2,3,12,13],work:[3,4,11,12,20,22],work_mem:[0,6,7,9,11,12,13,15,19,21,22],worker:[3,12],would:[3,12,19,22],write:[3,4,12,20,22],writer:3,written:14,wtm:[17,22],www:[3,4,8,14,16,17,20,21,22],xml:11,xxx:[19,22],year:[7,9,12,14],yet:12,you:[0,2,3,4,7,11,12,13,14,15,16,17,18,19,20,21,22],your:[2,3,4,11,12,14,18,19,20,21,22],yourself:[4,20,22],yyi:[7,9],yyyi:[7,9],zero:[12,14,19,22],zip:[4,5,6,8,10,13,16,17,18,20,22]},titles:["Reporting Bugs","Welcome to pgloader\u2019s documentation!","Introduction","PgLoader Reference Manual","Pgloader Usage Examples","Loading From an Archive","Loading COPY Formatted Files","Loading CSV data","Loading DBF data","Loading Fixed Cols File Formats","Loading IXF Data","Migrating a MS SQL Database to PostgreSQL","Migrating a MySQL Database to PostgreSQL","Migrating a SQLite database to PostgreSQL","Transformation Functions","Loading CSV Data with pgloader","Loading dBase files with pgloader","Loading Fixed Width Data File with pgloader","Loading MaxMind Geolite Data with pgloader","Migrating from MySQL to PostgreSQL","PgLoader Quick Start","Loading SQLite files with pgloader","PgLoader Tutorial"],titleterms:{"case":0,"default":[11,12,13],"final":5,"function":14,And:3,INTO:3,The:[15,16,17,18,19,21,22],WITH:[3,6,7,8,9,10,11,12,13],about:3,after:3,all:12,alter:[11,12],archiv:[4,5,20,22],argument:3,avail:[4,20,22],batch:3,befor:3,behaviour:3,bug:0,cast:[11,12,13],claus:3,col:9,command:[2,3,4,5,15,16,17,18,19,21,22],comment:3,common:3,complex:4,compress:[20,22],connect:3,continu:2,copi:6,csv:[4,7,15,20,22],data:[7,8,10,15,16,17,18,20,21,22],databas:[11,12,13],dbase:[16,22],dbf:[4,8,20,22],debug:3,decod:12,document:1,driver:11,encod:[11,12],exampl:4,exclud:[11,12,13],execut:3,express:3,fetch:[4,20,22],field:[7,9],file:[4,6,9,16,17,20,21,22],fix:[9,17,22],format:[3,6,9],from:[3,4,5,6,7,8,9,10,11,12,13,19,20,22],gener:3,geolit:[18,22],http:[4,20,22],includ:[11,12,13],indic:1,inform:3,inquiri:3,introduct:2,ixf:10,like:[11,13],limit:12,line:[2,3,19,21,22],load:[3,4,5,6,7,8,9,10,15,16,17,18,20,21,22],locat:[4,20,22],manual:3,match:[11,12],materi:12,maxmind:[18,22],migrat:[2,4,11,12,13,19,20,22],more:3,mustach:3,mysql:[4,12,19,20,22],name:[11,12,13],note:3,onli:[3,11,12,13],oper:3,option:[3,6,7,8,9,10,11,12,13],parallel:3,partial:[11,12,13],perform:3,pgloader:[1,3,4,15,16,17,18,20,21,22],postgresql:[11,12,13,19,22],quick:[20,22],read:[4,20,22],refer:3,regular:3,remot:[4,20,22],renam:11,report:0,reproduc:0,result:[15,22],retri:3,rule:[11,12,13],schema:[11,12],set:3,setup:11,singl:[19,21,22],sourc:[3,5,6,7,8,9,10,11,12,13],specif:[5,6,7,8,9,10,11,12,13],sql:[5,11],sqlite:[4,13,20,21,22],start:[20,22],stdin:[4,20,22],stream:[20,22],string:3,sub:5,support:12,syntax:3,tabl:[1,11,12,13],target:3,templat:3,test:0,through:[4,20,22],transform:[11,12,14],tutori:22,usag:4,view:12,welcom:1,width:[17,22]}}) \ No newline at end of file diff --git a/docs/_build/html/tutorial/csv.html b/docs/_build/html/tutorial/csv.html new file mode 100644 index 0000000..bbec8ef --- /dev/null +++ b/docs/_build/html/tutorial/csv.html @@ -0,0 +1,169 @@ + + + + + + + Loading CSV Data with pgloader — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading CSV Data with pgloader

+

CSV means comma separated values and is often found with quite varying +specifications. pgloader allows you to describe those specs in its command.

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading CSV +data:

+
LOAD CSV
+     FROM 'path/to/file.csv' (x, y, a, b, c, d)
+     INTO postgresql:///pgloader?csv (a, b, d, c)
+
+     WITH truncate,
+          skip header = 1,
+          fields optionally enclosed by '"',
+          fields escaped by double-quote,
+          fields terminated by ','
+
+      SET client_encoding to 'latin1',
+          work_mem to '12MB',
+          standard_conforming_strings to 'on'
+
+   BEFORE LOAD DO
+    $$ drop table if exists csv; $$,
+    $$ create table csv (
+        a bigint,
+        b bigint,
+        c char(2),
+        d text
+       );
+  $$;
+
+
+
+
+

The Data

+

This command allows loading the following CSV file content:

+
Header, with a © sign
+"2.6.190.56","2.6.190.63","33996344","33996351","GB","United Kingdom"
+"3.0.0.0","4.17.135.31","50331648","68257567","US","United States"
+"4.17.135.32","4.17.135.63","68257568","68257599","CA","Canada"
+"4.17.135.64","4.17.142.255","68257600","68259583","US","United States"
+"4.17.143.0","4.17.143.15","68259584","68259599","CA","Canada"
+"4.17.143.16","4.18.32.71","68259600","68296775","US","United States"
+
+
+
+
+

Loading the data

+

Here’s how to start loading the data. Note that the ouput here has been +edited so as to facilitate its browsing online:

+
$ pgloader csv.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/csv.load"
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+      before load          2          2          0          0.039s
+-----------------  ---------  ---------  ---------  --------------
+              csv          6          6          0          0.019s
+-----------------  ---------  ---------  ---------  --------------
+Total import time          6          6          0          0.058s
+
+
+
+
+

The result

+

As you can see, the command described above is filtering the input and only +importing some of the columns from the example data file. Here’s what gets +loaded in the PostgreSQL database:

+
pgloader# table csv;
+    a     |    b     | c  |       d
+----------+----------+----+----------------
+ 33996344 | 33996351 | GB | United Kingdom
+ 50331648 | 68257567 | US | United States
+ 68257568 | 68257599 | CA | Canada
+ 68257600 | 68259583 | US | United States
+ 68259584 | 68259599 | CA | Canada
+ 68259600 | 68296775 | US | United States
+(6 rows)
+
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/dBase.html b/docs/_build/html/tutorial/dBase.html new file mode 100644 index 0000000..ae47be7 --- /dev/null +++ b/docs/_build/html/tutorial/dBase.html @@ -0,0 +1,134 @@ + + + + + + + Loading dBase files with pgloader — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading dBase files with pgloader

+

The dBase format is still in use in some places as modern tools such as +Filemaker and Excel offer some level of support for it. Speaking of +support in modern tools, pgloader is right there on the list too!

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading a +dBase file, using a file provided by the french administration.

+

You can find more files from them at the Insee +website.

+

Here’s our command:

+
LOAD DBF
+    FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip
+    INTO postgresql:///pgloader
+    WITH truncate, create table
+     SET client_encoding TO 'latin1';
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the dBase file to create a PostgreSQL table capable of hosting the data as +described, then load the data.

+
+
+

Loading the data

+

Let’s start the pgloader command with our dbf-zip.load command file:

+
$ pgloader dbf-zip.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/dbf-zip.load"
+... LOG Fetching 'http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//historiq2013.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0          0.167s
+          extract          0          0          0          1.010s
+ create, truncate          0          0          0          0.071s
+-----------------  ---------  ---------  ---------  --------------
+     historiq2013       9181       9181          0          0.658s
+-----------------  ---------  ---------  ---------  --------------
+Total import time       9181       9181          0          1.906s
+
+
+

We can see that pgloader did download the file from +its HTTP URL location then unziped it before the loading itself.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/fixed.html b/docs/_build/html/tutorial/fixed.html new file mode 100644 index 0000000..1a38f88 --- /dev/null +++ b/docs/_build/html/tutorial/fixed.html @@ -0,0 +1,176 @@ + + + + + + + Loading Fixed Width Data File with pgloader — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading Fixed Width Data File with pgloader

+

Some data providers still use a format where each column is specified with a +starting index position and a given length. Usually the columns are +blank-padded when the data is shorter than the full reserved range.

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading +Fixed Width Data, using a file provided by the US census.

+

You can find more files from them at the +[Census 2000 Gazetteer Files](http://www.census.gov/geo/maps-data/data/gazetteer2000.html).

+

Here’s our command:

+
LOAD ARCHIVE
+   FROM http://www.census.gov/geo/maps-data/data/docs/gazetteer/places2k.zip
+   INTO postgresql:///pgloader
+
+   BEFORE LOAD DO
+     $$ drop table if exists places; $$,
+     $$ create table places
+       (
+          usps      char(2)  not null,
+          fips      char(2)  not null,
+          fips_code char(5),
+          loc_name  varchar(64)
+       );
+     $$
+
+   LOAD FIXED
+        FROM FILENAME MATCHING ~/places2k.txt/
+             WITH ENCODING latin1
+             (
+                usps           from   0 for  2,
+                fips           from   2 for  2,
+                fips_code      from   4 for  5,
+                "LocationName" from   9 for 64 [trim right whitespace],
+                p              from  73 for  9,
+                h              from  82 for  9,
+                land           from  91 for 14,
+                water          from 105 for 14,
+                ldm            from 119 for 14,
+                wtm            from 131 for 14,
+                lat            from 143 for 10,
+                long           from 153 for 11
+             )
+        INTO postgresql:///pgloader?places
+             (
+            usps, fips, fips_code, "LocationName"
+             );
+
+
+
+
+

The Data

+

This command allows loading the following file content, where we are only +showing the first couple of lines:

+
AL0100124Abbeville city                                                       2987     1353      40301945        120383   15.560669    0.046480 31.566367 -85.251300
+AL0100460Adamsville city                                                      4965     2042      50779330         14126   19.606010    0.005454 33.590411 -86.949166
+AL0100484Addison town                                                          723      339       9101325             0    3.514041    0.000000 34.200042 -87.177851
+AL0100676Akron town                                                            521      239       1436797             0    0.554750    0.000000 32.876425 -87.740978
+AL0100820Alabaster city                                                      22619     8594      53023800        141711   20.472605    0.054715 33.231162 -86.823829
+AL0100988Albertville city                                                    17247     7090      67212867        258738   25.951034    0.099899 34.265362 -86.211261
+AL0101132Alexander City city                                                 15008     6855     100534344        433413   38.816529    0.167342 32.933157 -85.936008
+
+
+
+
+

Loading the data

+

Let’s start the pgloader command with our census-places.load command file:

+
$ pgloader census-places.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/census-places.load"
+... LOG Fetching 'http://www.census.gov/geo/maps-data/data/docs/gazetteer/places2k.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//places2k.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0          1.494s
+          extract          0          0          0          1.013s
+      before load          2          2          0          0.013s
+-----------------  ---------  ---------  ---------  --------------
+           places      25375      25375          0          0.499s
+-----------------  ---------  ---------  ---------  --------------
+Total import time      25375      25375          0          3.019s
+
+
+

We can see that pgloader did download the file from its HTTP URL location +then unziped it before the loading itself.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/geolite.html b/docs/_build/html/tutorial/geolite.html new file mode 100644 index 0000000..a7da1cf --- /dev/null +++ b/docs/_build/html/tutorial/geolite.html @@ -0,0 +1,239 @@ + + + + + + + Loading MaxMind Geolite Data with pgloader — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading MaxMind Geolite Data with pgloader

+

MaxMind provides a free dataset for +geolocation, which is quite popular. Using pgloader you can download the +lastest version of it, extract the CSV files from the archive and load their +content into your database directly.

+
+

The Command

+

To load data with pgloader you need to define in a command the operations +in some details. Here’s our example for loading the Geolite data:

+
/*
+ * Loading from a ZIP archive containing CSV files. The full test can be
+ * done with using the archive found at
+ * http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip
+ *
+ * And a very light version of this data set is found at
+ * http://pgsql.tapoueh.org/temp/foo.zip for quick testing.
+ */
+
+LOAD ARCHIVE
+   FROM http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip
+   INTO postgresql:///ip4r
+
+   BEFORE LOAD DO
+     $$ create extension if not exists ip4r; $$,
+     $$ create schema if not exists geolite; $$,
+     $$ create table if not exists geolite.location
+       (
+          locid      integer primary key,
+          country    text,
+          region     text,
+          city       text,
+          postalcode text,
+          location   point,
+          metrocode  text,
+          areacode   text
+       );
+     $$,
+     $$ create table if not exists geolite.blocks
+       (
+          iprange    ip4r,
+          locid      integer
+       );
+     $$,
+     $$ drop index if exists geolite.blocks_ip4r_idx; $$,
+     $$ truncate table geolite.blocks, geolite.location cascade; $$
+
+   LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/
+             WITH ENCODING iso-8859-1
+             (
+                locId,
+                country,
+                region     null if blanks,
+                city       null if blanks,
+                postalCode null if blanks,
+                latitude,
+                longitude,
+                metroCode  null if blanks,
+                areaCode   null if blanks
+             )
+        INTO postgresql:///ip4r?geolite.location
+             (
+                locid,country,region,city,postalCode,
+                location point using (format nil "(~a,~a)" longitude latitude),
+                metroCode,areaCode
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+  AND LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/
+             WITH ENCODING iso-8859-1
+             (
+                startIpNum, endIpNum, locId
+             )
+        INTO postgresql:///ip4r?geolite.blocks
+             (
+                iprange ip4r using (ip-range startIpNum endIpNum),
+                locId
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+   FINALLY DO
+     $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$;
+
+
+

Note that while the Geolite data is using a pair of integers (start, +end) to represent ipv4 data, we use the very poweful ip4r PostgreSQL Extension instead.

+

The transformation from a pair of integers into an IP is done dynamically by +the pgloader process.

+

Also, the location is given as a pair of float columns for the longitude +and the latitude where PostgreSQL offers the +point +datatype, so the pgloader command here will actually transform the data on +the fly to use the appropriate data type and its input representation.

+
+
+

Loading the data

+

Here’s how to start loading the data. Note that the ouput here has been +edited so as to facilitate its browsing online:

+
$ pgloader archive.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/archive.load"
+... LOG Fetching 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//GeoLiteCity-latest.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0         11.592s
+          extract          0          0          0          1.012s
+      before load          6          6          0          0.019s
+-----------------  ---------  ---------  ---------  --------------
+ geolite.location     470387     470387          0          7.743s
+   geolite.blocks    1903155    1903155          0         16.332s
+-----------------  ---------  ---------  ---------  --------------
+          finally          1          1          0         31.692s
+-----------------  ---------  ---------  ---------  --------------
+Total import time    2373542    2373542          0        1m8.390s
+
+
+

The timing of course includes the transformation of the 1.9 million pairs +of integer into a single ipv4 range each. The finally step consists of +creating the GiST specialized index as given in the main command:

+
CREATE INDEX blocks_ip4r_idx ON geolite.blocks USING gist(iprange);
+
+
+

That index will then be used to speed up queries wanting to find which +recorded geolocation contains a specific IP address:

+
ip4r> select *
+        from      geolite.location l
+             join geolite.blocks b using(locid)
+       where iprange >>= '8.8.8.8';
+
+-[ RECORD 1 ]------------------
+locid      | 223
+country    | US
+region     |
+city       |
+postalcode |
+location   | (-97,38)
+metrocode  |
+areacode   |
+iprange    | 8.8.8.8-8.8.37.255
+
+Time: 0.747 ms
+
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/mysql.html b/docs/_build/html/tutorial/mysql.html new file mode 100644 index 0000000..e854de6 --- /dev/null +++ b/docs/_build/html/tutorial/mysql.html @@ -0,0 +1,246 @@ + + + + + + + Migrating from MySQL to PostgreSQL — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Migrating from MySQL to PostgreSQL

+

If you want to migrate your data over to PostgreSQL from MySQL then pgloader is the tool of +choice!

+

Most tools around are skipping the main problem with migrating from MySQL, +which is to do with the type casting and data sanitizing that needs to be +done. pgloader will not leave you alone on those topics.

+
+

In a Single Command Line

+

As an example, we will use the f1db database from <http://ergast.com/mrd/> +which which provides a historical record of motor racing data for +non-commercial purposes. You can either use their API or download the whole +database at http://ergast.com/downloads/f1db.sql.gz. Once you’ve done that load the +database in MySQL:

+
$ mysql -u root
+> create database f1db;
+> source f1db.sql
+
+
+

Now let’s migrate this database into PostgreSQL in a single command line:

+
$ createdb f1db
+$ pgloader mysql://root@localhost/f1db pgsql:///f1db
+
+
+

Done! All with schema, table definitions, constraints, indexes, primary +keys, auto_increment columns turned into bigserial , foreign keys, +comments, and if you had some MySQL default values such as ON UPDATE +CURRENT_TIMESTAMP they would have been translated to a PostgreSQL before +update trigger +automatically.

+
$ pgloader mysql://root@localhost/f1db pgsql:///f1db
+2017-06-16T08:56:14.064000+02:00 LOG Main logs in '/private/tmp/pgloader/pgloader.log'
+2017-06-16T08:56:14.068000+02:00 LOG Data errors in '/private/tmp/pgloader/'
+2017-06-16T08:56:19.542000+02:00 LOG report summary reset
+               table name       read   imported     errors      total time
+-------------------------  ---------  ---------  ---------  --------------
+          fetch meta data         33         33          0          0.365s
+           Create Schemas          0          0          0          0.007s
+         Create SQL Types          0          0          0          0.006s
+            Create tables         26         26          0          0.068s
+           Set Table OIDs         13         13          0          0.012s
+-------------------------  ---------  ---------  ---------  --------------
+  f1db.constructorresults      11011      11011          0          0.205s
+            f1db.circuits         73         73          0          0.150s
+        f1db.constructors        208        208          0          0.059s
+f1db.constructorstandings      11766      11766          0          0.365s
+             f1db.drivers        841        841          0          0.268s
+            f1db.laptimes     413578     413578          0          2.892s
+     f1db.driverstandings      31420      31420          0          0.583s
+            f1db.pitstops       5796       5796          0          2.154s
+               f1db.races        976        976          0          0.227s
+          f1db.qualifying       7257       7257          0          0.228s
+             f1db.seasons         68         68          0          0.527s
+             f1db.results      23514      23514          0          0.658s
+              f1db.status        133        133          0          0.130s
+-------------------------  ---------  ---------  ---------  --------------
+  COPY Threads Completion         39         39          0          4.303s
+           Create Indexes         20         20          0          1.497s
+   Index Build Completion         20         20          0          0.214s
+          Reset Sequences          0         10          0          0.058s
+             Primary Keys         13         13          0          0.012s
+      Create Foreign Keys          0          0          0          0.000s
+          Create Triggers          0          0          0          0.001s
+         Install Comments          0          0          0          0.000s
+-------------------------  ---------  ---------  ---------  --------------
+        Total import time     506641     506641          0          5.547s
+
+
+

You may need to have special cases to take care of tho, or views that you +want to materialize while doing the migration. In advanced case you can use +the pgloader command.

+
+
+

The Command

+

To load data with pgloader you need to define in a command the operations +in some details. Here’s our example for loading the MySQL Sakila Sample +Database.

+

Here’s our command:

+
load database
+     from      mysql://root@localhost/sakila
+     into postgresql:///sakila
+
+ WITH include drop, create tables, no truncate,
+      create indexes, reset sequences, foreign keys
+
+  SET maintenance_work_mem to '128MB', work_mem to '12MB', search_path to 'sakila'
+
+ CAST type datetime to timestamptz
+                drop default drop not null using zero-dates-to-null,
+      type date drop not null drop default using zero-dates-to-null
+
+ MATERIALIZE VIEWS film_list, staff_list
+
+ -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'
+ -- EXCLUDING TABLE NAMES MATCHING ~<ory>
+
+ BEFORE LOAD DO
+ $$ create schema if not exists sakila; $$;
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the MySQL database to create a PostgreSQL database capable of hosting the +data as described, then load the data.

+

In particular, some specific casting rules are given here, to cope with +date values such as 0000-00-00 that MySQL allows and PostgreSQL rejects +for not existing in our calendar. It’s possible to add per-column casting +rules too, which is useful is some of your tinyint are in fact smallint +while some others are in fact boolean values.

+

Finaly note that we are using the MATERIALIZE VIEWS clause of pgloader: +the selected views here will be migrated over to PostgreSQL with their +contents.

+

It’s possible to use the MATERIALIZE VIEWS clause and give both the name +and the SQL (in MySQL dialect) definition of view, then pgloader creates the +view before loading the data, then drops it again at the end.

+

## Loading the data

+

Let’s start the pgloader command with our sakila.load command file:

+
$ pgloader sakila.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sakila.load"
+   <WARNING: table "xxx" does not exists have been edited away>
+
+            table name       read   imported     errors            time
+----------------------  ---------  ---------  ---------  --------------
+           before load          1          1          0          0.007s
+       fetch meta data         45         45          0          0.402s
+          create, drop          0         36          0          0.208s
+----------------------  ---------  ---------  ---------  --------------
+                 actor        200        200          0          0.071s
+               address        603        603          0          0.035s
+              category         16         16          0          0.018s
+                  city        600        600          0          0.037s
+               country        109        109          0          0.023s
+              customer        599        599          0          0.073s
+                  film       1000       1000          0          0.135s
+            film_actor       5462       5462          0          0.236s
+         film_category       1000       1000          0          0.070s
+             film_text       1000       1000          0          0.080s
+             inventory       4581       4581          0          0.136s
+              language          6          6          0          0.036s
+               payment      16049      16049          0          0.539s
+                rental      16044      16044          0          0.648s
+                 staff          2          2          0          0.041s
+                 store          2          2          0          0.036s
+             film_list        997        997          0          0.247s
+            staff_list          2          2          0          0.135s
+Index Build Completion          0          0          0          0.000s
+----------------------  ---------  ---------  ---------  --------------
+        Create Indexes         41         41          0          0.964s
+       Reset Sequences          0          1          0          0.035s
+          Foreign Keys         22         22          0          0.254s
+----------------------  ---------  ---------  ---------  --------------
+     Total import time      48272      48272          0          3.502s
+
+
+

The WARNING messages we see here are expected as the PostgreSQL database +is empty when running the command, and pgloader is using the SQL commands +DROP TABLE IF EXISTS when the given command uses the include drop +option.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/quickstart.html b/docs/_build/html/tutorial/quickstart.html new file mode 100644 index 0000000..3608181 --- /dev/null +++ b/docs/_build/html/tutorial/quickstart.html @@ -0,0 +1,218 @@ + + + + + + + PgLoader Quick Start — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

PgLoader Quick Start

+

In simple cases, pgloader is very easy to use.

+
+

CSV

+

Load data from a CSV file into a pre-existing table in your database:

+
pgloader --type csv                                   \
+         --field id --field field                     \
+         --with truncate                              \
+         --with "fields terminated by ','"            \
+         ./test/data/matching-1.csv                   \
+         postgres:///pgloader?tablename=matching
+
+
+

In that example the whole loading is driven from the command line, bypassing +the need for writing a command in the pgloader command syntax entirely. As +there’s no command though, the extra information needed must be provided on +the command line using the –type and –field and –with switches.

+

For documentation about the available syntaxes for the –field and +–with switches, please refer to the CSV section later in the man page.

+

Note also that the PostgreSQL URI includes the target tablename.

+
+
+

Reading from STDIN

+

File based pgloader sources can be loaded from the standard input, as in the +following example:

+
pgloader --type csv                                         \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                          \
+         --with "fields terminated by '\t'"                \
+         -                                                 \
+         postgresql:///pgloader?districts_longlat          \
+         < test/data/2013_Gaz_113CDs_national.txt
+
+
+

The dash (-) character as a source is used to mean standard input, as +usual in Unix command lines. It’s possible to stream compressed content to +pgloader with this technique, using the Unix pipe:

+
gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo
+
+
+
+
+

Loading from CSV available through HTTP

+

The same command as just above can also be run if the CSV file happens to be +found on a remote HTTP location:

+
pgloader --type csv                                                     \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                                       \
+         --with "fields terminated by '\t'"                             \
+         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \
+         postgresql:///pgloader?districts_longlat
+
+
+

Some more options have to be used in that case, as the file contains a +one-line header (most commonly that’s column names, could be a copyright +notice). Also, in that case, we specify all the fields right into a single +–field option argument.

+

Again, the PostgreSQL target connection string must contain the tablename +option and you have to ensure that the target table exists and may fit the +data. Here’s the SQL command used in that example in case you want to try it +yourself:

+
create table districts_longlat
+(
+         usps        text,
+         geoid       text,
+         aland       bigint,
+         awater      bigint,
+         aland_sqmi  double precision,
+         awater_sqmi double precision,
+         intptlat    double precision,
+         intptlong   double precision
+);
+
+
+

Also notice that the same command will work against an archived version of +the same data.

+
+
+

Streaming CSV data from an HTTP compressed file

+

Finally, it’s important to note that pgloader first fetches the content from +the HTTP URL it to a local file, then expand the archive when it’s +recognized to be one, and only then processes the locally expanded file.

+

In some cases, either because pgloader has no direct support for your +archive format or maybe because expanding the archive is not feasible in +your environment, you might want to stream the content straight from its +remote location into PostgreSQL. Here’s how to do that, using the old battle +tested Unix Pipes trick:

+
curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \
+| gunzip -c                                                        \
+| pgloader --type csv                                              \
+           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong"
+           --with "skip header = 1"                                \
+           --with "fields terminated by '\t'"                      \
+           -                                                       \
+           postgresql:///pgloader?districts_longlat
+
+
+

Now the OS will take care of the streaming and buffering between the network +and the commands and pgloader will take care of streaming the data down to +PostgreSQL.

+
+
+

Migrating from SQLite

+

The following command will open the SQLite database, discover its tables +definitions including indexes and foreign keys, migrate those definitions +while casting the data type specifications to their PostgreSQL equivalent +and then migrate the data over:

+
createdb newdb
+pgloader ./test/sqlite/sqlite.db postgresql:///newdb
+
+
+
+
+

Migrating from MySQL

+

Just create a database where to host the MySQL data and definitions and have +pgloader do the migration for you in a single command line:

+
createdb pagila
+pgloader mysql://user@localhost/sakila postgresql:///pagila
+
+
+
+
+

Fetching an archived DBF file from a HTTP remote location

+

It’s possible for pgloader to download a file from HTTP, unarchive it, and +only then open it to discover the schema then load the data:

+
createdb foo
+pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo
+
+
+

Here it’s not possible for pgloader to guess the kind of data source it’s +being given, so it’s necessary to use the –type command line switch.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/sqlite.html b/docs/_build/html/tutorial/sqlite.html new file mode 100644 index 0000000..7bcc290 --- /dev/null +++ b/docs/_build/html/tutorial/sqlite.html @@ -0,0 +1,208 @@ + + + + + + + Loading SQLite files with pgloader — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Loading SQLite files with pgloader

+

The SQLite database is a respected solution to manage your data with. Its +embeded nature makes it a source of migrations when a projects now needs to +handle more concurrency, which [PostgreSQL](http://www.postgresql.org/) is +very good at. pgloader can help you there.

+
+

In a Single Command Line

+

You can

+
$ createdb chinook
+$ pgloader https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite pgsql:///chinook
+
+
+

Done! All with the schema, data, constraints, primary keys and foreign keys, +etc. We also see an error with the Chinook schema that contains several +primary key definitions against the same table, which is not accepted by +PostgreSQL:

+
2017-06-20T16:18:59.019000+02:00 LOG Data errors in '/private/tmp/pgloader/'
+2017-06-20T16:18:59.236000+02:00 LOG Fetching 'https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite'
+2017-06-20T16:19:00.664000+02:00 ERROR Database error 42P16: multiple primary keys for table "playlisttrack" are not allowed
+QUERY: ALTER TABLE playlisttrack ADD PRIMARY KEY USING INDEX idx_66873_sqlite_autoindex_playlisttrack_1;
+2017-06-20T16:19:00.665000+02:00 LOG report summary reset
+             table name       read   imported     errors      total time
+-----------------------  ---------  ---------  ---------  --------------
+                  fetch          0          0          0          0.877s
+        fetch meta data         33         33          0          0.033s
+         Create Schemas          0          0          0          0.003s
+       Create SQL Types          0          0          0          0.006s
+          Create tables         22         22          0          0.043s
+         Set Table OIDs         11         11          0          0.012s
+-----------------------  ---------  ---------  ---------  --------------
+                  album        347        347          0          0.023s
+                 artist        275        275          0          0.023s
+               customer         59         59          0          0.021s
+               employee          8          8          0          0.018s
+                invoice        412        412          0          0.031s
+                  genre         25         25          0          0.021s
+            invoiceline       2240       2240          0          0.034s
+              mediatype          5          5          0          0.025s
+          playlisttrack       8715       8715          0          0.040s
+               playlist         18         18          0          0.016s
+                  track       3503       3503          0          0.111s
+-----------------------  ---------  ---------  ---------  --------------
+COPY Threads Completion         33         33          0          0.313s
+         Create Indexes         22         22          0          0.160s
+ Index Build Completion         22         22          0          0.027s
+        Reset Sequences          0          0          0          0.017s
+           Primary Keys         12          0          1          0.013s
+    Create Foreign Keys         11         11          0          0.040s
+        Create Triggers          0          0          0          0.000s
+       Install Comments          0          0          0          0.000s
+-----------------------  ---------  ---------  ---------  --------------
+      Total import time      15607      15607          0          1.669s
+
+
+

You may need to have special cases to take care of tho. In advanced case you +can use the pgloader command.

+
+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our command:

+
load database
+     from 'sqlite/Chinook_Sqlite_AutoIncrementPKs.sqlite'
+     into postgresql:///pgloader
+
+ with include drop, create tables, create indexes, reset sequences
+
+  set work_mem to '16MB', maintenance_work_mem to '512 MB';
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the SQLite file to create a PostgreSQL database capable of hosting the data +as described, then load the data.

+
+
+

Loading the data

+

Let’s start the pgloader command with our sqlite.load command file:

+
$ pgloader sqlite.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sqlite.load"
+... WARNING Postgres warning: table "album" does not exist, skipping
+... WARNING Postgres warning: table "artist" does not exist, skipping
+... WARNING Postgres warning: table "customer" does not exist, skipping
+... WARNING Postgres warning: table "employee" does not exist, skipping
+... WARNING Postgres warning: table "genre" does not exist, skipping
+... WARNING Postgres warning: table "invoice" does not exist, skipping
+... WARNING Postgres warning: table "invoiceline" does not exist, skipping
+... WARNING Postgres warning: table "mediatype" does not exist, skipping
+... WARNING Postgres warning: table "playlist" does not exist, skipping
+... WARNING Postgres warning: table "playlisttrack" does not exist, skipping
+... WARNING Postgres warning: table "track" does not exist, skipping
+            table name       read   imported     errors            time
+----------------------  ---------  ---------  ---------  --------------
+      create, truncate          0          0          0          0.052s
+                 Album        347        347          0          0.070s
+                Artist        275        275          0          0.014s
+              Customer         59         59          0          0.014s
+              Employee          8          8          0          0.012s
+                 Genre         25         25          0          0.018s
+               Invoice        412        412          0          0.032s
+           InvoiceLine       2240       2240          0          0.077s
+             MediaType          5          5          0          0.012s
+              Playlist         18         18          0          0.008s
+         PlaylistTrack       8715       8715          0          0.071s
+                 Track       3503       3503          0          0.105s
+index build completion          0          0          0          0.000s
+----------------------  ---------  ---------  ---------  --------------
+        Create Indexes         20         20          0          0.279s
+       reset sequences          0          0          0          0.043s
+----------------------  ---------  ---------  ---------  --------------
+  Total streaming time      15607      15607          0          0.476s
+
+
+

We can see that pgloader did download the file from +its HTTP URL location then unziped it before loading it.

+

Also, the WARNING messages we see here are expected as the PostgreSQL +database is empty when running the command, and pgloader is using the SQL +commands DROP TABLE IF EXISTS when the given command uses the include +drop option.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/tutorial/tutorial.html b/docs/_build/html/tutorial/tutorial.html new file mode 100644 index 0000000..844d134 --- /dev/null +++ b/docs/_build/html/tutorial/tutorial.html @@ -0,0 +1,893 @@ + + + + + + + PgLoader Tutorial — pgloader 3.4.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

PgLoader Tutorial

+
+

PgLoader Quick Start

+

In simple cases, pgloader is very easy to use.

+
+

CSV

+

Load data from a CSV file into a pre-existing table in your database:

+
pgloader --type csv                                   \
+         --field id --field field                     \
+         --with truncate                              \
+         --with "fields terminated by ','"            \
+         ./test/data/matching-1.csv                   \
+         postgres:///pgloader?tablename=matching
+
+
+

In that example the whole loading is driven from the command line, bypassing +the need for writing a command in the pgloader command syntax entirely. As +there’s no command though, the extra information needed must be provided on +the command line using the –type and –field and –with switches.

+

For documentation about the available syntaxes for the –field and +–with switches, please refer to the CSV section later in the man page.

+

Note also that the PostgreSQL URI includes the target tablename.

+
+
+

Reading from STDIN

+

File based pgloader sources can be loaded from the standard input, as in the +following example:

+
pgloader --type csv                                         \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                          \
+         --with "fields terminated by '\t'"                \
+         -                                                 \
+         postgresql:///pgloader?districts_longlat          \
+         < test/data/2013_Gaz_113CDs_national.txt
+
+
+

The dash (-) character as a source is used to mean standard input, as +usual in Unix command lines. It’s possible to stream compressed content to +pgloader with this technique, using the Unix pipe:

+
gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo
+
+
+
+
+

Loading from CSV available through HTTP

+

The same command as just above can also be run if the CSV file happens to be +found on a remote HTTP location:

+
pgloader --type csv                                                     \
+         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \
+         --with "skip header = 1"                                       \
+         --with "fields terminated by '\t'"                             \
+         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \
+         postgresql:///pgloader?districts_longlat
+
+
+

Some more options have to be used in that case, as the file contains a +one-line header (most commonly that’s column names, could be a copyright +notice). Also, in that case, we specify all the fields right into a single +–field option argument.

+

Again, the PostgreSQL target connection string must contain the tablename +option and you have to ensure that the target table exists and may fit the +data. Here’s the SQL command used in that example in case you want to try it +yourself:

+
create table districts_longlat
+(
+         usps        text,
+         geoid       text,
+         aland       bigint,
+         awater      bigint,
+         aland_sqmi  double precision,
+         awater_sqmi double precision,
+         intptlat    double precision,
+         intptlong   double precision
+);
+
+
+

Also notice that the same command will work against an archived version of +the same data.

+
+
+

Streaming CSV data from an HTTP compressed file

+

Finally, it’s important to note that pgloader first fetches the content from +the HTTP URL it to a local file, then expand the archive when it’s +recognized to be one, and only then processes the locally expanded file.

+

In some cases, either because pgloader has no direct support for your +archive format or maybe because expanding the archive is not feasible in +your environment, you might want to stream the content straight from its +remote location into PostgreSQL. Here’s how to do that, using the old battle +tested Unix Pipes trick:

+
curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \
+| gunzip -c                                                        \
+| pgloader --type csv                                              \
+           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong"
+           --with "skip header = 1"                                \
+           --with "fields terminated by '\t'"                      \
+           -                                                       \
+           postgresql:///pgloader?districts_longlat
+
+
+

Now the OS will take care of the streaming and buffering between the network +and the commands and pgloader will take care of streaming the data down to +PostgreSQL.

+
+
+

Migrating from SQLite

+

The following command will open the SQLite database, discover its tables +definitions including indexes and foreign keys, migrate those definitions +while casting the data type specifications to their PostgreSQL equivalent +and then migrate the data over:

+
createdb newdb
+pgloader ./test/sqlite/sqlite.db postgresql:///newdb
+
+
+
+
+

Migrating from MySQL

+

Just create a database where to host the MySQL data and definitions and have +pgloader do the migration for you in a single command line:

+
createdb pagila
+pgloader mysql://user@localhost/sakila postgresql:///pagila
+
+
+
+
+

Fetching an archived DBF file from a HTTP remote location

+

It’s possible for pgloader to download a file from HTTP, unarchive it, and +only then open it to discover the schema then load the data:

+
createdb foo
+pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo
+
+
+

Here it’s not possible for pgloader to guess the kind of data source it’s +being given, so it’s necessary to use the –type command line switch.

+
+
+
+

Loading CSV Data with pgloader

+

CSV means comma separated values and is often found with quite varying +specifications. pgloader allows you to describe those specs in its command.

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading CSV +data:

+
LOAD CSV
+     FROM 'path/to/file.csv' (x, y, a, b, c, d)
+     INTO postgresql:///pgloader?csv (a, b, d, c)
+
+     WITH truncate,
+          skip header = 1,
+          fields optionally enclosed by '"',
+          fields escaped by double-quote,
+          fields terminated by ','
+
+      SET client_encoding to 'latin1',
+          work_mem to '12MB',
+          standard_conforming_strings to 'on'
+
+   BEFORE LOAD DO
+    $$ drop table if exists csv; $$,
+    $$ create table csv (
+        a bigint,
+        b bigint,
+        c char(2),
+        d text
+       );
+  $$;
+
+
+
+
+

The Data

+

This command allows loading the following CSV file content:

+
Header, with a © sign
+"2.6.190.56","2.6.190.63","33996344","33996351","GB","United Kingdom"
+"3.0.0.0","4.17.135.31","50331648","68257567","US","United States"
+"4.17.135.32","4.17.135.63","68257568","68257599","CA","Canada"
+"4.17.135.64","4.17.142.255","68257600","68259583","US","United States"
+"4.17.143.0","4.17.143.15","68259584","68259599","CA","Canada"
+"4.17.143.16","4.18.32.71","68259600","68296775","US","United States"
+
+
+
+
+

Loading the data

+

Here’s how to start loading the data. Note that the ouput here has been +edited so as to facilitate its browsing online:

+
$ pgloader csv.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/csv.load"
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+      before load          2          2          0          0.039s
+-----------------  ---------  ---------  ---------  --------------
+              csv          6          6          0          0.019s
+-----------------  ---------  ---------  ---------  --------------
+Total import time          6          6          0          0.058s
+
+
+
+
+

The result

+

As you can see, the command described above is filtering the input and only +importing some of the columns from the example data file. Here’s what gets +loaded in the PostgreSQL database:

+
pgloader# table csv;
+    a     |    b     | c  |       d
+----------+----------+----+----------------
+ 33996344 | 33996351 | GB | United Kingdom
+ 50331648 | 68257567 | US | United States
+ 68257568 | 68257599 | CA | Canada
+ 68257600 | 68259583 | US | United States
+ 68259584 | 68259599 | CA | Canada
+ 68259600 | 68296775 | US | United States
+(6 rows)
+
+
+
+
+
+

Loading Fixed Width Data File with pgloader

+

Some data providers still use a format where each column is specified with a +starting index position and a given length. Usually the columns are +blank-padded when the data is shorter than the full reserved range.

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading +Fixed Width Data, using a file provided by the US census.

+

You can find more files from them at the +[Census 2000 Gazetteer Files](http://www.census.gov/geo/maps-data/data/gazetteer2000.html).

+

Here’s our command:

+
LOAD ARCHIVE
+   FROM http://www.census.gov/geo/maps-data/data/docs/gazetteer/places2k.zip
+   INTO postgresql:///pgloader
+
+   BEFORE LOAD DO
+     $$ drop table if exists places; $$,
+     $$ create table places
+       (
+          usps      char(2)  not null,
+          fips      char(2)  not null,
+          fips_code char(5),
+          loc_name  varchar(64)
+       );
+     $$
+
+   LOAD FIXED
+        FROM FILENAME MATCHING ~/places2k.txt/
+             WITH ENCODING latin1
+             (
+                usps           from   0 for  2,
+                fips           from   2 for  2,
+                fips_code      from   4 for  5,
+                "LocationName" from   9 for 64 [trim right whitespace],
+                p              from  73 for  9,
+                h              from  82 for  9,
+                land           from  91 for 14,
+                water          from 105 for 14,
+                ldm            from 119 for 14,
+                wtm            from 131 for 14,
+                lat            from 143 for 10,
+                long           from 153 for 11
+             )
+        INTO postgresql:///pgloader?places
+             (
+            usps, fips, fips_code, "LocationName"
+             );
+
+
+
+
+

The Data

+

This command allows loading the following file content, where we are only +showing the first couple of lines:

+
AL0100124Abbeville city                                                       2987     1353      40301945        120383   15.560669    0.046480 31.566367 -85.251300
+AL0100460Adamsville city                                                      4965     2042      50779330         14126   19.606010    0.005454 33.590411 -86.949166
+AL0100484Addison town                                                          723      339       9101325             0    3.514041    0.000000 34.200042 -87.177851
+AL0100676Akron town                                                            521      239       1436797             0    0.554750    0.000000 32.876425 -87.740978
+AL0100820Alabaster city                                                      22619     8594      53023800        141711   20.472605    0.054715 33.231162 -86.823829
+AL0100988Albertville city                                                    17247     7090      67212867        258738   25.951034    0.099899 34.265362 -86.211261
+AL0101132Alexander City city                                                 15008     6855     100534344        433413   38.816529    0.167342 32.933157 -85.936008
+
+
+
+
+

Loading the data

+

Let’s start the pgloader command with our census-places.load command file:

+
$ pgloader census-places.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/census-places.load"
+... LOG Fetching 'http://www.census.gov/geo/maps-data/data/docs/gazetteer/places2k.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//places2k.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0          1.494s
+          extract          0          0          0          1.013s
+      before load          2          2          0          0.013s
+-----------------  ---------  ---------  ---------  --------------
+           places      25375      25375          0          0.499s
+-----------------  ---------  ---------  ---------  --------------
+Total import time      25375      25375          0          3.019s
+
+
+

We can see that pgloader did download the file from its HTTP URL location +then unziped it before the loading itself.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+
+

Loading MaxMind Geolite Data with pgloader

+

MaxMind provides a free dataset for +geolocation, which is quite popular. Using pgloader you can download the +lastest version of it, extract the CSV files from the archive and load their +content into your database directly.

+
+

The Command

+

To load data with pgloader you need to define in a command the operations +in some details. Here’s our example for loading the Geolite data:

+
/*
+ * Loading from a ZIP archive containing CSV files. The full test can be
+ * done with using the archive found at
+ * http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip
+ *
+ * And a very light version of this data set is found at
+ * http://pgsql.tapoueh.org/temp/foo.zip for quick testing.
+ */
+
+LOAD ARCHIVE
+   FROM http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip
+   INTO postgresql:///ip4r
+
+   BEFORE LOAD DO
+     $$ create extension if not exists ip4r; $$,
+     $$ create schema if not exists geolite; $$,
+     $$ create table if not exists geolite.location
+       (
+          locid      integer primary key,
+          country    text,
+          region     text,
+          city       text,
+          postalcode text,
+          location   point,
+          metrocode  text,
+          areacode   text
+       );
+     $$,
+     $$ create table if not exists geolite.blocks
+       (
+          iprange    ip4r,
+          locid      integer
+       );
+     $$,
+     $$ drop index if exists geolite.blocks_ip4r_idx; $$,
+     $$ truncate table geolite.blocks, geolite.location cascade; $$
+
+   LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/
+             WITH ENCODING iso-8859-1
+             (
+                locId,
+                country,
+                region     null if blanks,
+                city       null if blanks,
+                postalCode null if blanks,
+                latitude,
+                longitude,
+                metroCode  null if blanks,
+                areaCode   null if blanks
+             )
+        INTO postgresql:///ip4r?geolite.location
+             (
+                locid,country,region,city,postalCode,
+                location point using (format nil "(~a,~a)" longitude latitude),
+                metroCode,areaCode
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+  AND LOAD CSV
+        FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/
+             WITH ENCODING iso-8859-1
+             (
+                startIpNum, endIpNum, locId
+             )
+        INTO postgresql:///ip4r?geolite.blocks
+             (
+                iprange ip4r using (ip-range startIpNum endIpNum),
+                locId
+             )
+        WITH skip header = 2,
+             fields optionally enclosed by '"',
+             fields escaped by double-quote,
+             fields terminated by ','
+
+   FINALLY DO
+     $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$;
+
+
+

Note that while the Geolite data is using a pair of integers (start, +end) to represent ipv4 data, we use the very poweful ip4r PostgreSQL Extension instead.

+

The transformation from a pair of integers into an IP is done dynamically by +the pgloader process.

+

Also, the location is given as a pair of float columns for the longitude +and the latitude where PostgreSQL offers the +point +datatype, so the pgloader command here will actually transform the data on +the fly to use the appropriate data type and its input representation.

+
+
+

Loading the data

+

Here’s how to start loading the data. Note that the ouput here has been +edited so as to facilitate its browsing online:

+
$ pgloader archive.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/archive.load"
+... LOG Fetching 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//GeoLiteCity-latest.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0         11.592s
+          extract          0          0          0          1.012s
+      before load          6          6          0          0.019s
+-----------------  ---------  ---------  ---------  --------------
+ geolite.location     470387     470387          0          7.743s
+   geolite.blocks    1903155    1903155          0         16.332s
+-----------------  ---------  ---------  ---------  --------------
+          finally          1          1          0         31.692s
+-----------------  ---------  ---------  ---------  --------------
+Total import time    2373542    2373542          0        1m8.390s
+
+
+

The timing of course includes the transformation of the 1.9 million pairs +of integer into a single ipv4 range each. The finally step consists of +creating the GiST specialized index as given in the main command:

+
CREATE INDEX blocks_ip4r_idx ON geolite.blocks USING gist(iprange);
+
+
+

That index will then be used to speed up queries wanting to find which +recorded geolocation contains a specific IP address:

+
ip4r> select *
+        from      geolite.location l
+             join geolite.blocks b using(locid)
+       where iprange >>= '8.8.8.8';
+
+-[ RECORD 1 ]------------------
+locid      | 223
+country    | US
+region     |
+city       |
+postalcode |
+location   | (-97,38)
+metrocode  |
+areacode   |
+iprange    | 8.8.8.8-8.8.37.255
+
+Time: 0.747 ms
+
+
+
+
+
+

Loading dBase files with pgloader

+

The dBase format is still in use in some places as modern tools such as +Filemaker and Excel offer some level of support for it. Speaking of +support in modern tools, pgloader is right there on the list too!

+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our example for loading a +dBase file, using a file provided by the french administration.

+

You can find more files from them at the Insee +website.

+

Here’s our command:

+
LOAD DBF
+    FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip
+    INTO postgresql:///pgloader
+    WITH truncate, create table
+     SET client_encoding TO 'latin1';
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the dBase file to create a PostgreSQL table capable of hosting the data as +described, then load the data.

+
+
+

Loading the data

+

Let’s start the pgloader command with our dbf-zip.load command file:

+
$ pgloader dbf-zip.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/dbf-zip.load"
+... LOG Fetching 'http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip'
+... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//historiq2013.zip'
+
+       table name       read   imported     errors            time
+-----------------  ---------  ---------  ---------  --------------
+         download          0          0          0          0.167s
+          extract          0          0          0          1.010s
+ create, truncate          0          0          0          0.071s
+-----------------  ---------  ---------  ---------  --------------
+     historiq2013       9181       9181          0          0.658s
+-----------------  ---------  ---------  ---------  --------------
+Total import time       9181       9181          0          1.906s
+
+
+

We can see that pgloader did download the file from +its HTTP URL location then unziped it before the loading itself.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+
+

Loading SQLite files with pgloader

+

The SQLite database is a respected solution to manage your data with. Its +embeded nature makes it a source of migrations when a projects now needs to +handle more concurrency, which [PostgreSQL](http://www.postgresql.org/) is +very good at. pgloader can help you there.

+
+

In a Single Command Line

+

You can

+
$ createdb chinook
+$ pgloader https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite pgsql:///chinook
+
+
+

Done! All with the schema, data, constraints, primary keys and foreign keys, +etc. We also see an error with the Chinook schema that contains several +primary key definitions against the same table, which is not accepted by +PostgreSQL:

+
2017-06-20T16:18:59.019000+02:00 LOG Data errors in '/private/tmp/pgloader/'
+2017-06-20T16:18:59.236000+02:00 LOG Fetching 'https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite'
+2017-06-20T16:19:00.664000+02:00 ERROR Database error 42P16: multiple primary keys for table "playlisttrack" are not allowed
+QUERY: ALTER TABLE playlisttrack ADD PRIMARY KEY USING INDEX idx_66873_sqlite_autoindex_playlisttrack_1;
+2017-06-20T16:19:00.665000+02:00 LOG report summary reset
+             table name       read   imported     errors      total time
+-----------------------  ---------  ---------  ---------  --------------
+                  fetch          0          0          0          0.877s
+        fetch meta data         33         33          0          0.033s
+         Create Schemas          0          0          0          0.003s
+       Create SQL Types          0          0          0          0.006s
+          Create tables         22         22          0          0.043s
+         Set Table OIDs         11         11          0          0.012s
+-----------------------  ---------  ---------  ---------  --------------
+                  album        347        347          0          0.023s
+                 artist        275        275          0          0.023s
+               customer         59         59          0          0.021s
+               employee          8          8          0          0.018s
+                invoice        412        412          0          0.031s
+                  genre         25         25          0          0.021s
+            invoiceline       2240       2240          0          0.034s
+              mediatype          5          5          0          0.025s
+          playlisttrack       8715       8715          0          0.040s
+               playlist         18         18          0          0.016s
+                  track       3503       3503          0          0.111s
+-----------------------  ---------  ---------  ---------  --------------
+COPY Threads Completion         33         33          0          0.313s
+         Create Indexes         22         22          0          0.160s
+ Index Build Completion         22         22          0          0.027s
+        Reset Sequences          0          0          0          0.017s
+           Primary Keys         12          0          1          0.013s
+    Create Foreign Keys         11         11          0          0.040s
+        Create Triggers          0          0          0          0.000s
+       Install Comments          0          0          0          0.000s
+-----------------------  ---------  ---------  ---------  --------------
+      Total import time      15607      15607          0          1.669s
+
+
+

You may need to have special cases to take care of tho. In advanced case you +can use the pgloader command.

+
+
+

The Command

+

To load data with [pgloader](http://pgloader.io/) you need to define in a +command the operations in some details. Here’s our command:

+
load database
+     from 'sqlite/Chinook_Sqlite_AutoIncrementPKs.sqlite'
+     into postgresql:///pgloader
+
+ with include drop, create tables, create indexes, reset sequences
+
+  set work_mem to '16MB', maintenance_work_mem to '512 MB';
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the SQLite file to create a PostgreSQL database capable of hosting the data +as described, then load the data.

+
+
+

Loading the data

+

Let’s start the pgloader command with our sqlite.load command file:

+
$ pgloader sqlite.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sqlite.load"
+... WARNING Postgres warning: table "album" does not exist, skipping
+... WARNING Postgres warning: table "artist" does not exist, skipping
+... WARNING Postgres warning: table "customer" does not exist, skipping
+... WARNING Postgres warning: table "employee" does not exist, skipping
+... WARNING Postgres warning: table "genre" does not exist, skipping
+... WARNING Postgres warning: table "invoice" does not exist, skipping
+... WARNING Postgres warning: table "invoiceline" does not exist, skipping
+... WARNING Postgres warning: table "mediatype" does not exist, skipping
+... WARNING Postgres warning: table "playlist" does not exist, skipping
+... WARNING Postgres warning: table "playlisttrack" does not exist, skipping
+... WARNING Postgres warning: table "track" does not exist, skipping
+            table name       read   imported     errors            time
+----------------------  ---------  ---------  ---------  --------------
+      create, truncate          0          0          0          0.052s
+                 Album        347        347          0          0.070s
+                Artist        275        275          0          0.014s
+              Customer         59         59          0          0.014s
+              Employee          8          8          0          0.012s
+                 Genre         25         25          0          0.018s
+               Invoice        412        412          0          0.032s
+           InvoiceLine       2240       2240          0          0.077s
+             MediaType          5          5          0          0.012s
+              Playlist         18         18          0          0.008s
+         PlaylistTrack       8715       8715          0          0.071s
+                 Track       3503       3503          0          0.105s
+index build completion          0          0          0          0.000s
+----------------------  ---------  ---------  ---------  --------------
+        Create Indexes         20         20          0          0.279s
+       reset sequences          0          0          0          0.043s
+----------------------  ---------  ---------  ---------  --------------
+  Total streaming time      15607      15607          0          0.476s
+
+
+

We can see that pgloader did download the file from +its HTTP URL location then unziped it before loading it.

+

Also, the WARNING messages we see here are expected as the PostgreSQL +database is empty when running the command, and pgloader is using the SQL +commands DROP TABLE IF EXISTS when the given command uses the include +drop option.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+
+

Migrating from MySQL to PostgreSQL

+

If you want to migrate your data over to PostgreSQL from MySQL then pgloader is the tool of +choice!

+

Most tools around are skipping the main problem with migrating from MySQL, +which is to do with the type casting and data sanitizing that needs to be +done. pgloader will not leave you alone on those topics.

+
+

In a Single Command Line

+

As an example, we will use the f1db database from <http://ergast.com/mrd/> +which which provides a historical record of motor racing data for +non-commercial purposes. You can either use their API or download the whole +database at http://ergast.com/downloads/f1db.sql.gz. Once you’ve done that load the +database in MySQL:

+
$ mysql -u root
+> create database f1db;
+> source f1db.sql
+
+
+

Now let’s migrate this database into PostgreSQL in a single command line:

+
$ createdb f1db
+$ pgloader mysql://root@localhost/f1db pgsql:///f1db
+
+
+

Done! All with schema, table definitions, constraints, indexes, primary +keys, auto_increment columns turned into bigserial , foreign keys, +comments, and if you had some MySQL default values such as ON UPDATE +CURRENT_TIMESTAMP they would have been translated to a PostgreSQL before +update trigger +automatically.

+
$ pgloader mysql://root@localhost/f1db pgsql:///f1db
+2017-06-16T08:56:14.064000+02:00 LOG Main logs in '/private/tmp/pgloader/pgloader.log'
+2017-06-16T08:56:14.068000+02:00 LOG Data errors in '/private/tmp/pgloader/'
+2017-06-16T08:56:19.542000+02:00 LOG report summary reset
+               table name       read   imported     errors      total time
+-------------------------  ---------  ---------  ---------  --------------
+          fetch meta data         33         33          0          0.365s
+           Create Schemas          0          0          0          0.007s
+         Create SQL Types          0          0          0          0.006s
+            Create tables         26         26          0          0.068s
+           Set Table OIDs         13         13          0          0.012s
+-------------------------  ---------  ---------  ---------  --------------
+  f1db.constructorresults      11011      11011          0          0.205s
+            f1db.circuits         73         73          0          0.150s
+        f1db.constructors        208        208          0          0.059s
+f1db.constructorstandings      11766      11766          0          0.365s
+             f1db.drivers        841        841          0          0.268s
+            f1db.laptimes     413578     413578          0          2.892s
+     f1db.driverstandings      31420      31420          0          0.583s
+            f1db.pitstops       5796       5796          0          2.154s
+               f1db.races        976        976          0          0.227s
+          f1db.qualifying       7257       7257          0          0.228s
+             f1db.seasons         68         68          0          0.527s
+             f1db.results      23514      23514          0          0.658s
+              f1db.status        133        133          0          0.130s
+-------------------------  ---------  ---------  ---------  --------------
+  COPY Threads Completion         39         39          0          4.303s
+           Create Indexes         20         20          0          1.497s
+   Index Build Completion         20         20          0          0.214s
+          Reset Sequences          0         10          0          0.058s
+             Primary Keys         13         13          0          0.012s
+      Create Foreign Keys          0          0          0          0.000s
+          Create Triggers          0          0          0          0.001s
+         Install Comments          0          0          0          0.000s
+-------------------------  ---------  ---------  ---------  --------------
+        Total import time     506641     506641          0          5.547s
+
+
+

You may need to have special cases to take care of tho, or views that you +want to materialize while doing the migration. In advanced case you can use +the pgloader command.

+
+
+

The Command

+

To load data with pgloader you need to define in a command the operations +in some details. Here’s our example for loading the MySQL Sakila Sample +Database.

+

Here’s our command:

+
load database
+     from      mysql://root@localhost/sakila
+     into postgresql:///sakila
+
+ WITH include drop, create tables, no truncate,
+      create indexes, reset sequences, foreign keys
+
+  SET maintenance_work_mem to '128MB', work_mem to '12MB', search_path to 'sakila'
+
+ CAST type datetime to timestamptz
+                drop default drop not null using zero-dates-to-null,
+      type date drop not null drop default using zero-dates-to-null
+
+ MATERIALIZE VIEWS film_list, staff_list
+
+ -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'
+ -- EXCLUDING TABLE NAMES MATCHING ~<ory>
+
+ BEFORE LOAD DO
+ $$ create schema if not exists sakila; $$;
+
+
+

Note that here pgloader will benefit from the meta-data information found in +the MySQL database to create a PostgreSQL database capable of hosting the +data as described, then load the data.

+

In particular, some specific casting rules are given here, to cope with +date values such as 0000-00-00 that MySQL allows and PostgreSQL rejects +for not existing in our calendar. It’s possible to add per-column casting +rules too, which is useful is some of your tinyint are in fact smallint +while some others are in fact boolean values.

+

Finaly note that we are using the MATERIALIZE VIEWS clause of pgloader: +the selected views here will be migrated over to PostgreSQL with their +contents.

+

It’s possible to use the MATERIALIZE VIEWS clause and give both the name +and the SQL (in MySQL dialect) definition of view, then pgloader creates the +view before loading the data, then drops it again at the end.

+

## Loading the data

+

Let’s start the pgloader command with our sakila.load command file:

+
$ pgloader sakila.load
+... LOG Starting pgloader, log system is ready.
+... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sakila.load"
+   <WARNING: table "xxx" does not exists have been edited away>
+
+            table name       read   imported     errors            time
+----------------------  ---------  ---------  ---------  --------------
+           before load          1          1          0          0.007s
+       fetch meta data         45         45          0          0.402s
+          create, drop          0         36          0          0.208s
+----------------------  ---------  ---------  ---------  --------------
+                 actor        200        200          0          0.071s
+               address        603        603          0          0.035s
+              category         16         16          0          0.018s
+                  city        600        600          0          0.037s
+               country        109        109          0          0.023s
+              customer        599        599          0          0.073s
+                  film       1000       1000          0          0.135s
+            film_actor       5462       5462          0          0.236s
+         film_category       1000       1000          0          0.070s
+             film_text       1000       1000          0          0.080s
+             inventory       4581       4581          0          0.136s
+              language          6          6          0          0.036s
+               payment      16049      16049          0          0.539s
+                rental      16044      16044          0          0.648s
+                 staff          2          2          0          0.041s
+                 store          2          2          0          0.036s
+             film_list        997        997          0          0.247s
+            staff_list          2          2          0          0.135s
+Index Build Completion          0          0          0          0.000s
+----------------------  ---------  ---------  ---------  --------------
+        Create Indexes         41         41          0          0.964s
+       Reset Sequences          0          1          0          0.035s
+          Foreign Keys         22         22          0          0.254s
+----------------------  ---------  ---------  ---------  --------------
+     Total import time      48272      48272          0          3.502s
+
+
+

The WARNING messages we see here are expected as the PostgreSQL database +is empty when running the command, and pgloader is using the SQL commands +DROP TABLE IF EXISTS when the given command uses the include drop +option.

+

Note that the output of the command has been edited to facilitate its +browsing online.

+
+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/bugreport.rst b/docs/bugreport.rst new file mode 100644 index 0000000..84726b5 --- /dev/null +++ b/docs/bugreport.rst @@ -0,0 +1,49 @@ +Reporting Bugs +============== + +pgloader is a software and as such contains bugs. Most bugs are easy to +solve and taken care of in a short delay. For this to be possible though, +bug reports need to follow those recommandations: + + - include pgloader version, + - include problematic input and output, + - include a description of the output you expected, + - explain the difference between the ouput you have and the one you expected, + - include a self-reproducing test-case + +Test Cases to Reproduce Bugs +---------------------------- + +Use the *inline* source type to help reproduce a bug, as in the pgloader tests:: + + LOAD CSV + FROM INLINE + INTO postgresql://dim@localhost/pgloader?public."HS" + + WITH truncate, + fields terminated by '\t', + fields not enclosed, + fields escaped by backslash-quote, + quote identifiers + + SET work_mem to '128MB', + standard_conforming_strings to 'on', + application_name to 'my app name' + + BEFORE LOAD DO + $$ create extension if not exists hstore; $$, + $$ drop table if exists "HS"; $$, + $$ CREATE TABLE "HS" + ( + id serial primary key, + kv hstore + ) + $$; + + + 1 email=>foo@example.com,a=>b + 2 test=>value + 3 a=>b,c=>"quoted hstore value",d=>other + 4 baddata + + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..7464272 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pgloader documentation build configuration file, created by +# sphinx-quickstart on Tue Dec 5 19:23:32 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.githubpages'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = '.rst' +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pgloader' +copyright = '2017, Dimitri Fontaine' +author = 'Dimitri Fontaine' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3.4' +# The full version, including alpha/beta/rc tags. +release = '3.4.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} +html_theme_options = { + 'github_user': 'dimitri', + 'github_repo': 'pgloader', + 'description': 'your migration companion', + 'travis_button': True, + 'show_related': True, + 'sidebar_collapse': False, +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pgloaderdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'pgloader.tex', 'pgloader Documentation', + 'Dimitri Fontaine', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pgloader', 'pgloader Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pgloader', 'pgloader Documentation', + author, 'pgloader', 'One line description of project.', + 'Miscellaneous'), +] + + + diff --git a/docs/dist/carousel.css b/docs/dist/carousel.css deleted file mode 100644 index 094662c..0000000 --- a/docs/dist/carousel.css +++ /dev/null @@ -1,164 +0,0 @@ -/* GLOBAL STYLES --------------------------------------------------- */ -/* Padding below the footer and lighter body text */ - -body { - padding-bottom: 40px; - color: #5a5a5a; -} - - - -/* CUSTOMIZE THE NAVBAR --------------------------------------------------- */ - -/* Special class on .container surrounding .navbar, used for positioning it into place. */ -.navbar-wrapper { - position: absolute; - top: 0; - left: 0; - right: 0; - z-index: 20; -} - -/* Flip around the padding for proper display in narrow viewports */ -.navbar-wrapper .container { - padding-left: 0; - padding-right: 0; -} -.navbar-wrapper .navbar { - padding-left: 15px; - padding-right: 15px; -} - - -/* CUSTOMIZE THE CAROUSEL --------------------------------------------------- */ - -/* Carousel base class */ -.carousel { - height: 350px; - margin-bottom: 60px; -} -/* Since positioning the image, we need to help out the caption */ -.carousel-caption { - z-index: 10; -} -.carousel-caption h1 { - color: orange; -} -.carousel-caption p { - text-align: justify; -} - -/* Declare heights because of positioning of img element */ -.carousel .item { - height: 350px; - background-color: #777; -} -.carousel-inner > .item > img { - position: absolute; - top: 0; - left: 0; - min-width: 100%; - height: 350px; -} - - - -/* MARKETING CONTENT --------------------------------------------------- */ - -/* Pad the edges of the mobile views a bit */ -.marketing { - padding-left: 15px; - padding-right: 15px; -} - -/* Center align the text within the three columns below the carousel */ -.marketing .col-lg-4 { - text-align: center; - margin-bottom: 20px; -} -.marketing h2 { - font-weight: normal; -} -.marketing .col-lg-4 p { - margin-left: 10px; - margin-right: 10px; -} - - -/* Featurettes -------------------------- */ - -.featurette-divider { - margin: 80px 0; /* Space out the Bootstrap
more */ -} - -/* Thin out the marketing headings */ -.featurette-heading { - font-weight: 300; - line-height: 1; - letter-spacing: -1px; -} - - - -/* RESPONSIVE CSS --------------------------------------------------- */ - -@media (min-width: 768px) { - - /* Remove the edge padding needed for mobile */ - .marketing { - padding-left: 0; - padding-right: 0; - } - - /* Navbar positioning foo */ - .navbar-wrapper { - margin-top: 20px; - } - .navbar-wrapper .container { - padding-left: 15px; - padding-right: 15px; - } - .navbar-wrapper .navbar { - padding-left: 0; - padding-right: 0; - } - - /* The navbar becomes detached from the top, so we round the corners */ - .navbar-wrapper .navbar { - border-radius: 4px; - } - - /* Bump up size of carousel content */ - .carousel-caption p { - margin-bottom: 20px; - font-size: 21px; - line-height: 1.4; - } - - .featurette-heading { - font-size: 50px; - } - -} - -/* @media (min-width: 992px) { */ -/* .featurette-heading { */ -/* margin-top: 120px; */ -/* } */ -/* } */ - -pre { - overflow: auto; - word-wrap: normal; - white-space: pre; -} - -pre code { - white-space: pre; -} \ No newline at end of file diff --git a/docs/dist/css/bootstrap-theme.css b/docs/dist/css/bootstrap-theme.css deleted file mode 100644 index df2d3d9..0000000 --- a/docs/dist/css/bootstrap-theme.css +++ /dev/null @@ -1,397 +0,0 @@ -/*! - * Bootstrap v3.0.3 (http://getbootstrap.com) - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - */ - -.btn-default, -.btn-primary, -.btn-success, -.btn-info, -.btn-warning, -.btn-danger { - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.btn-default:active, -.btn-primary:active, -.btn-success:active, -.btn-info:active, -.btn-warning:active, -.btn-danger:active, -.btn-default.active, -.btn-primary.active, -.btn-success.active, -.btn-info.active, -.btn-warning.active, -.btn-danger.active { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} - -.btn:active, -.btn.active { - background-image: none; -} - -.btn-default { - text-shadow: 0 1px 0 #fff; - background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); - background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); - background-repeat: repeat-x; - border-color: #dbdbdb; - border-color: #ccc; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-default:hover, -.btn-default:focus { - background-color: #e0e0e0; - background-position: 0 -15px; -} - -.btn-default:active, -.btn-default.active { - background-color: #e0e0e0; - border-color: #dbdbdb; -} - -.btn-primary { - background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); - background-repeat: repeat-x; - border-color: #2b669a; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-primary:hover, -.btn-primary:focus { - background-color: #2d6ca2; - background-position: 0 -15px; -} - -.btn-primary:active, -.btn-primary.active { - background-color: #2d6ca2; - border-color: #2b669a; -} - -.btn-success { - background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); - background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); - background-repeat: repeat-x; - border-color: #3e8f3e; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-success:hover, -.btn-success:focus { - background-color: #419641; - background-position: 0 -15px; -} - -.btn-success:active, -.btn-success.active { - background-color: #419641; - border-color: #3e8f3e; -} - -.btn-warning { - background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); - background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); - background-repeat: repeat-x; - border-color: #e38d13; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-warning:hover, -.btn-warning:focus { - background-color: #eb9316; - background-position: 0 -15px; -} - -.btn-warning:active, -.btn-warning.active { - background-color: #eb9316; - border-color: #e38d13; -} - -.btn-danger { - background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); - background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); - background-repeat: repeat-x; - border-color: #b92c28; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-danger:hover, -.btn-danger:focus { - background-color: #c12e2a; - background-position: 0 -15px; -} - -.btn-danger:active, -.btn-danger.active { - background-color: #c12e2a; - border-color: #b92c28; -} - -.btn-info { - background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); - background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); - background-repeat: repeat-x; - border-color: #28a4c9; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-info:hover, -.btn-info:focus { - background-color: #2aabd2; - background-position: 0 -15px; -} - -.btn-info:active, -.btn-info.active { - background-color: #2aabd2; - border-color: #28a4c9; -} - -.thumbnail, -.img-thumbnail { - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); -} - -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - background-color: #e8e8e8; - background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); -} - -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - background-color: #357ebd; - background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); -} - -.navbar-default { - background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); - background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); - background-repeat: repeat-x; - border-radius: 4px; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); -} - -.navbar-default .navbar-nav > .active > a { - background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); - background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); - -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); -} - -.navbar-brand, -.navbar-nav > li > a { - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); -} - -.navbar-inverse { - background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); - background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.navbar-inverse .navbar-nav > .active > a { - background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); - background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); - -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); - box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); -} - -.navbar-inverse .navbar-brand, -.navbar-inverse .navbar-nav > li > a { - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} - -.navbar-static-top, -.navbar-fixed-top, -.navbar-fixed-bottom { - border-radius: 0; -} - -.alert { - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.alert-success { - background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); - background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); - background-repeat: repeat-x; - border-color: #b2dba1; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); -} - -.alert-info { - background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); - background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); - background-repeat: repeat-x; - border-color: #9acfea; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); -} - -.alert-warning { - background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); - background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); - background-repeat: repeat-x; - border-color: #f5e79e; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); -} - -.alert-danger { - background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); - background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); - background-repeat: repeat-x; - border-color: #dca7a7; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); -} - -.progress { - background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); - background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); -} - -.progress-bar { - background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); -} - -.progress-bar-success { - background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); - background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); -} - -.progress-bar-info { - background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); - background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); -} - -.progress-bar-warning { - background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); - background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); -} - -.progress-bar-danger { - background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); - background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); -} - -.list-group { - border-radius: 4px; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); -} - -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - text-shadow: 0 -1px 0 #3071a9; - background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); - background-repeat: repeat-x; - border-color: #3278b3; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); -} - -.panel { - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.panel-default > .panel-heading { - background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); -} - -.panel-primary > .panel-heading { - background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); -} - -.panel-success > .panel-heading { - background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); - background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); -} - -.panel-info > .panel-heading { - background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); - background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); -} - -.panel-warning > .panel-heading { - background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); - background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); -} - -.panel-danger > .panel-heading { - background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); - background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); -} - -.well { - background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); - background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); - background-repeat: repeat-x; - border-color: #dcdcdc; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); -} \ No newline at end of file diff --git a/docs/dist/css/bootstrap-theme.min.css b/docs/dist/css/bootstrap-theme.min.css deleted file mode 100644 index c7b6d39..0000000 --- a/docs/dist/css/bootstrap-theme.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.0.3 (http://getbootstrap.com) - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - */ - -.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/docs/dist/css/bootstrap.css b/docs/dist/css/bootstrap.css deleted file mode 100644 index 377dff3..0000000 --- a/docs/dist/css/bootstrap.css +++ /dev/null @@ -1,7118 +0,0 @@ -/*! - * Bootstrap v3.0.3 (http://getbootstrap.com) - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - */ - -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -nav, -section, -summary { - display: block; -} - -audio, -canvas, -video { - display: inline-block; -} - -audio:not([controls]) { - display: none; - height: 0; -} - -[hidden], -template { - display: none; -} - -html { - font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - margin: 0; -} - -a { - background: transparent; -} - -a:focus { - outline: thin dotted; -} - -a:active, -a:hover { - outline: 0; -} - -h1 { - margin: 0.67em 0; - font-size: 2em; -} - -abbr[title] { - border-bottom: 1px dotted; -} - -b, -strong { - font-weight: bold; -} - -dfn { - font-style: italic; -} - -hr { - height: 0; - -moz-box-sizing: content-box; - box-sizing: content-box; -} - -mark { - color: #000; - background: #ff0; -} - -code, -kbd, -pre, -samp { - font-family: monospace, serif; - font-size: 1em; -} - -pre { - white-space: pre-wrap; -} - -q { - quotes: "\201C" "\201D" "\2018" "\2019"; -} - -small { - font-size: 80%; -} - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -img { - border: 0; -} - -svg:not(:root) { - overflow: hidden; -} - -figure { - margin: 0; -} - -fieldset { - padding: 0.35em 0.625em 0.75em; - margin: 0 2px; - border: 1px solid #c0c0c0; -} - -legend { - padding: 0; - border: 0; -} - -button, -input, -select, -textarea { - margin: 0; - font-family: inherit; - font-size: 100%; -} - -button, -input { - line-height: normal; -} - -button, -select { - text-transform: none; -} - -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; -} - -button[disabled], -html input[disabled] { - cursor: default; -} - -input[type="checkbox"], -input[type="radio"] { - padding: 0; - box-sizing: border-box; -} - -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -button::-moz-focus-inner, -input::-moz-focus-inner { - padding: 0; - border: 0; -} - -textarea { - overflow: auto; - vertical-align: top; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -@media print { - * { - color: #000 !important; - text-shadow: none !important; - background: transparent !important; - box-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - @page { - margin: 2cm .5cm; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - select { - background: #fff !important; - } - .navbar { - display: none; - } - .table td, - .table th { - background-color: #fff !important; - } - .btn > .caret, - .dropup > .btn > .caret { - border-top-color: #000 !important; - } - .label { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #ddd !important; - } -} - -*, -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -html { - font-size: 62.5%; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.428571429; - color: #333333; - background-color: #ffffff; -} - -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -a { - color: #428bca; - text-decoration: none; -} - -a:hover, -a:focus { - color: #2a6496; - text-decoration: underline; -} - -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -img { - vertical-align: middle; -} - -.img-responsive { - display: block; - height: auto; - max-width: 100%; -} - -.img-rounded { - border-radius: 6px; -} - -.img-thumbnail { - display: inline-block; - height: auto; - max-width: 100%; - padding: 4px; - line-height: 1.428571429; - background-color: #ffffff; - border: 1px solid #dddddd; - border-radius: 4px; - -webkit-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} - -.img-circle { - border-radius: 50%; -} - -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eeeeee; -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} - -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: 500; - line-height: 1.1; - color: inherit; -} - -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #999999; -} - -h1, -h2, -h3 { - margin-top: 20px; - margin-bottom: 10px; -} - -h1 small, -h2 small, -h3 small, -h1 .small, -h2 .small, -h3 .small { - font-size: 65%; -} - -h4, -h5, -h6 { - margin-top: 10px; - margin-bottom: 10px; -} - -h4 small, -h5 small, -h6 small, -h4 .small, -h5 .small, -h6 .small { - font-size: 75%; -} - -h1, -.h1 { - font-size: 36px; -} - -h2, -.h2 { - font-size: 30px; -} - -h3, -.h3 { - font-size: 24px; -} - -h4, -.h4 { - font-size: 18px; -} - -h5, -.h5 { - font-size: 14px; -} - -h6, -.h6 { - font-size: 12px; -} - -p { - margin: 0 0 10px; -} - -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 200; - line-height: 1.4; -} - -@media (min-width: 768px) { - .lead { - font-size: 21px; - } -} - -small, -.small { - font-size: 85%; -} - -cite { - font-style: normal; -} - -.text-muted { - color: #999999; -} - -.text-primary { - color: #428bca; -} - -.text-primary:hover { - color: #3071a9; -} - -.text-warning { - color: #8a6d3b; -} - -.text-warning:hover { - color: #66512c; -} - -.text-danger { - color: #a94442; -} - -.text-danger:hover { - color: #843534; -} - -.text-success { - color: #3c763d; -} - -.text-success:hover { - color: #2b542c; -} - -.text-info { - color: #31708f; -} - -.text-info:hover { - color: #245269; -} - -.text-left { - text-align: left; -} - -.text-right { - text-align: right; -} - -.text-center { - text-align: center; -} - -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eeeeee; -} - -ul, -ol { - margin-top: 0; - margin-bottom: 10px; -} - -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} - -.list-unstyled { - padding-left: 0; - list-style: none; -} - -.list-inline { - padding-left: 0; - list-style: none; -} - -.list-inline > li { - display: inline-block; - padding-right: 5px; - padding-left: 5px; -} - -.list-inline > li:first-child { - padding-left: 0; -} - -dl { - margin-top: 0; - margin-bottom: 20px; -} - -dt, -dd { - line-height: 1.428571429; -} - -dt { - font-weight: bold; -} - -dd { - margin-left: 0; -} - -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } - .dl-horizontal dd:before, - .dl-horizontal dd:after { - display: table; - content: " "; - } - .dl-horizontal dd:after { - clear: both; - } - .dl-horizontal dd:before, - .dl-horizontal dd:after { - display: table; - content: " "; - } - .dl-horizontal dd:after { - clear: both; - } -} - -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #999999; -} - -.initialism { - font-size: 90%; - text-transform: uppercase; -} - -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - border-left: 5px solid #eeeeee; -} - -blockquote p { - font-size: 17.5px; - font-weight: 300; - line-height: 1.25; -} - -blockquote p:last-child { - margin-bottom: 0; -} - -blockquote small, -blockquote .small { - display: block; - line-height: 1.428571429; - color: #999999; -} - -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} - -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #eeeeee; - border-left: 0; -} - -blockquote.pull-right p, -blockquote.pull-right small, -blockquote.pull-right .small { - text-align: right; -} - -blockquote.pull-right small:before, -blockquote.pull-right .small:before { - content: ''; -} - -blockquote.pull-right small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} - -blockquote:before, -blockquote:after { - content: ""; -} - -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.428571429; -} - -code, -kbd, -pre, -samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} - -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - white-space: nowrap; - background-color: #f9f2f4; - border-radius: 4px; -} - -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.428571429; - color: #333333; - word-break: break-all; - word-wrap: break-word; - background-color: #f5f5f5; - border: 1px solid #cccccc; - border-radius: 4px; -} - -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0; -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} - -.container { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} - -.container:before, -.container:after { - display: table; - content: " "; -} - -.container:after { - clear: both; -} - -.container:before, -.container:after { - display: table; - content: " "; -} - -.container:after { - clear: both; -} - -@media (min-width: 768px) { - .container { - width: 750px; - } -} - -@media (min-width: 992px) { - .container { - width: 970px; - } -} - -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} - -.row { - margin-right: -15px; - margin-left: -15px; -} - -.row:before, -.row:after { - display: table; - content: " "; -} - -.row:after { - clear: both; -} - -.row:before, -.row:after { - display: table; - content: " "; -} - -.row:after { - clear: both; -} - -.col-xs-1, -.col-sm-1, -.col-md-1, -.col-lg-1, -.col-xs-2, -.col-sm-2, -.col-md-2, -.col-lg-2, -.col-xs-3, -.col-sm-3, -.col-md-3, -.col-lg-3, -.col-xs-4, -.col-sm-4, -.col-md-4, -.col-lg-4, -.col-xs-5, -.col-sm-5, -.col-md-5, -.col-lg-5, -.col-xs-6, -.col-sm-6, -.col-md-6, -.col-lg-6, -.col-xs-7, -.col-sm-7, -.col-md-7, -.col-lg-7, -.col-xs-8, -.col-sm-8, -.col-md-8, -.col-lg-8, -.col-xs-9, -.col-sm-9, -.col-md-9, -.col-lg-9, -.col-xs-10, -.col-sm-10, -.col-md-10, -.col-lg-10, -.col-xs-11, -.col-sm-11, -.col-md-11, -.col-lg-11, -.col-xs-12, -.col-sm-12, -.col-md-12, -.col-lg-12 { - position: relative; - min-height: 1px; - padding-right: 15px; - padding-left: 15px; -} - -.col-xs-1, -.col-xs-2, -.col-xs-3, -.col-xs-4, -.col-xs-5, -.col-xs-6, -.col-xs-7, -.col-xs-8, -.col-xs-9, -.col-xs-10, -.col-xs-11, -.col-xs-12 { - float: left; -} - -.col-xs-12 { - width: 100%; -} - -.col-xs-11 { - width: 91.66666666666666%; -} - -.col-xs-10 { - width: 83.33333333333334%; -} - -.col-xs-9 { - width: 75%; -} - -.col-xs-8 { - width: 66.66666666666666%; -} - -.col-xs-7 { - width: 58.333333333333336%; -} - -.col-xs-6 { - width: 50%; -} - -.col-xs-5 { - width: 41.66666666666667%; -} - -.col-xs-4 { - width: 33.33333333333333%; -} - -.col-xs-3 { - width: 25%; -} - -.col-xs-2 { - width: 16.666666666666664%; -} - -.col-xs-1 { - width: 8.333333333333332%; -} - -.col-xs-pull-12 { - right: 100%; -} - -.col-xs-pull-11 { - right: 91.66666666666666%; -} - -.col-xs-pull-10 { - right: 83.33333333333334%; -} - -.col-xs-pull-9 { - right: 75%; -} - -.col-xs-pull-8 { - right: 66.66666666666666%; -} - -.col-xs-pull-7 { - right: 58.333333333333336%; -} - -.col-xs-pull-6 { - right: 50%; -} - -.col-xs-pull-5 { - right: 41.66666666666667%; -} - -.col-xs-pull-4 { - right: 33.33333333333333%; -} - -.col-xs-pull-3 { - right: 25%; -} - -.col-xs-pull-2 { - right: 16.666666666666664%; -} - -.col-xs-pull-1 { - right: 8.333333333333332%; -} - -.col-xs-pull-0 { - right: 0; -} - -.col-xs-push-12 { - left: 100%; -} - -.col-xs-push-11 { - left: 91.66666666666666%; -} - -.col-xs-push-10 { - left: 83.33333333333334%; -} - -.col-xs-push-9 { - left: 75%; -} - -.col-xs-push-8 { - left: 66.66666666666666%; -} - -.col-xs-push-7 { - left: 58.333333333333336%; -} - -.col-xs-push-6 { - left: 50%; -} - -.col-xs-push-5 { - left: 41.66666666666667%; -} - -.col-xs-push-4 { - left: 33.33333333333333%; -} - -.col-xs-push-3 { - left: 25%; -} - -.col-xs-push-2 { - left: 16.666666666666664%; -} - -.col-xs-push-1 { - left: 8.333333333333332%; -} - -.col-xs-push-0 { - left: 0; -} - -.col-xs-offset-12 { - margin-left: 100%; -} - -.col-xs-offset-11 { - margin-left: 91.66666666666666%; -} - -.col-xs-offset-10 { - margin-left: 83.33333333333334%; -} - -.col-xs-offset-9 { - margin-left: 75%; -} - -.col-xs-offset-8 { - margin-left: 66.66666666666666%; -} - -.col-xs-offset-7 { - margin-left: 58.333333333333336%; -} - -.col-xs-offset-6 { - margin-left: 50%; -} - -.col-xs-offset-5 { - margin-left: 41.66666666666667%; -} - -.col-xs-offset-4 { - margin-left: 33.33333333333333%; -} - -.col-xs-offset-3 { - margin-left: 25%; -} - -.col-xs-offset-2 { - margin-left: 16.666666666666664%; -} - -.col-xs-offset-1 { - margin-left: 8.333333333333332%; -} - -.col-xs-offset-0 { - margin-left: 0; -} - -@media (min-width: 768px) { - .col-sm-1, - .col-sm-2, - .col-sm-3, - .col-sm-4, - .col-sm-5, - .col-sm-6, - .col-sm-7, - .col-sm-8, - .col-sm-9, - .col-sm-10, - .col-sm-11, - .col-sm-12 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666666666666%; - } - .col-sm-10 { - width: 83.33333333333334%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666666666666%; - } - .col-sm-7 { - width: 58.333333333333336%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666666666667%; - } - .col-sm-4 { - width: 33.33333333333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.666666666666664%; - } - .col-sm-1 { - width: 8.333333333333332%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666666666666%; - } - .col-sm-pull-10 { - right: 83.33333333333334%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666666666666%; - } - .col-sm-pull-7 { - right: 58.333333333333336%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666666666667%; - } - .col-sm-pull-4 { - right: 33.33333333333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.666666666666664%; - } - .col-sm-pull-1 { - right: 8.333333333333332%; - } - .col-sm-pull-0 { - right: 0; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666666666666%; - } - .col-sm-push-10 { - left: 83.33333333333334%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666666666666%; - } - .col-sm-push-7 { - left: 58.333333333333336%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666666666667%; - } - .col-sm-push-4 { - left: 33.33333333333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.666666666666664%; - } - .col-sm-push-1 { - left: 8.333333333333332%; - } - .col-sm-push-0 { - left: 0; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666666666666%; - } - .col-sm-offset-10 { - margin-left: 83.33333333333334%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666666666666%; - } - .col-sm-offset-7 { - margin-left: 58.333333333333336%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666666666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.666666666666664%; - } - .col-sm-offset-1 { - margin-left: 8.333333333333332%; - } - .col-sm-offset-0 { - margin-left: 0; - } -} - -@media (min-width: 992px) { - .col-md-1, - .col-md-2, - .col-md-3, - .col-md-4, - .col-md-5, - .col-md-6, - .col-md-7, - .col-md-8, - .col-md-9, - .col-md-10, - .col-md-11, - .col-md-12 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666666666666%; - } - .col-md-10 { - width: 83.33333333333334%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666666666666%; - } - .col-md-7 { - width: 58.333333333333336%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666666666667%; - } - .col-md-4 { - width: 33.33333333333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.666666666666664%; - } - .col-md-1 { - width: 8.333333333333332%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666666666666%; - } - .col-md-pull-10 { - right: 83.33333333333334%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666666666666%; - } - .col-md-pull-7 { - right: 58.333333333333336%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666666666667%; - } - .col-md-pull-4 { - right: 33.33333333333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.666666666666664%; - } - .col-md-pull-1 { - right: 8.333333333333332%; - } - .col-md-pull-0 { - right: 0; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666666666666%; - } - .col-md-push-10 { - left: 83.33333333333334%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666666666666%; - } - .col-md-push-7 { - left: 58.333333333333336%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666666666667%; - } - .col-md-push-4 { - left: 33.33333333333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.666666666666664%; - } - .col-md-push-1 { - left: 8.333333333333332%; - } - .col-md-push-0 { - left: 0; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666666666666%; - } - .col-md-offset-10 { - margin-left: 83.33333333333334%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666666666666%; - } - .col-md-offset-7 { - margin-left: 58.333333333333336%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666666666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.666666666666664%; - } - .col-md-offset-1 { - margin-left: 8.333333333333332%; - } - .col-md-offset-0 { - margin-left: 0; - } -} - -@media (min-width: 1200px) { - .col-lg-1, - .col-lg-2, - .col-lg-3, - .col-lg-4, - .col-lg-5, - .col-lg-6, - .col-lg-7, - .col-lg-8, - .col-lg-9, - .col-lg-10, - .col-lg-11, - .col-lg-12 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666666666666%; - } - .col-lg-10 { - width: 83.33333333333334%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666666666666%; - } - .col-lg-7 { - width: 58.333333333333336%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666666666667%; - } - .col-lg-4 { - width: 33.33333333333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.666666666666664%; - } - .col-lg-1 { - width: 8.333333333333332%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666666666666%; - } - .col-lg-pull-10 { - right: 83.33333333333334%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666666666666%; - } - .col-lg-pull-7 { - right: 58.333333333333336%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666666666667%; - } - .col-lg-pull-4 { - right: 33.33333333333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.666666666666664%; - } - .col-lg-pull-1 { - right: 8.333333333333332%; - } - .col-lg-pull-0 { - right: 0; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666666666666%; - } - .col-lg-push-10 { - left: 83.33333333333334%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666666666666%; - } - .col-lg-push-7 { - left: 58.333333333333336%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666666666667%; - } - .col-lg-push-4 { - left: 33.33333333333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.666666666666664%; - } - .col-lg-push-1 { - left: 8.333333333333332%; - } - .col-lg-push-0 { - left: 0; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666666666666%; - } - .col-lg-offset-10 { - margin-left: 83.33333333333334%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666666666666%; - } - .col-lg-offset-7 { - margin-left: 58.333333333333336%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666666666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.666666666666664%; - } - .col-lg-offset-1 { - margin-left: 8.333333333333332%; - } - .col-lg-offset-0 { - margin-left: 0; - } -} - -table { - max-width: 100%; - background-color: transparent; -} - -th { - text-align: left; -} - -.table { - width: 100%; - margin-bottom: 20px; -} - -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 8px; - line-height: 1.428571429; - vertical-align: top; - border-top: 1px solid #dddddd; -} - -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #dddddd; -} - -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} - -.table > tbody + tbody { - border-top: 2px solid #dddddd; -} - -.table .table { - background-color: #ffffff; -} - -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 5px; -} - -.table-bordered { - border: 1px solid #dddddd; -} - -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #dddddd; -} - -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} - -.table-striped > tbody > tr:nth-child(odd) > td, -.table-striped > tbody > tr:nth-child(odd) > th { - background-color: #f9f9f9; -} - -.table-hover > tbody > tr:hover > td, -.table-hover > tbody > tr:hover > th { - background-color: #f5f5f5; -} - -table col[class*="col-"] { - position: static; - display: table-column; - float: none; -} - -table td[class*="col-"], -table th[class*="col-"] { - display: table-cell; - float: none; -} - -.table > thead > tr > .active, -.table > tbody > tr > .active, -.table > tfoot > tr > .active, -.table > thead > .active > td, -.table > tbody > .active > td, -.table > tfoot > .active > td, -.table > thead > .active > th, -.table > tbody > .active > th, -.table > tfoot > .active > th { - background-color: #f5f5f5; -} - -.table-hover > tbody > tr > .active:hover, -.table-hover > tbody > .active:hover > td, -.table-hover > tbody > .active:hover > th { - background-color: #e8e8e8; -} - -.table > thead > tr > .success, -.table > tbody > tr > .success, -.table > tfoot > tr > .success, -.table > thead > .success > td, -.table > tbody > .success > td, -.table > tfoot > .success > td, -.table > thead > .success > th, -.table > tbody > .success > th, -.table > tfoot > .success > th { - background-color: #dff0d8; -} - -.table-hover > tbody > tr > .success:hover, -.table-hover > tbody > .success:hover > td, -.table-hover > tbody > .success:hover > th { - background-color: #d0e9c6; -} - -.table > thead > tr > .danger, -.table > tbody > tr > .danger, -.table > tfoot > tr > .danger, -.table > thead > .danger > td, -.table > tbody > .danger > td, -.table > tfoot > .danger > td, -.table > thead > .danger > th, -.table > tbody > .danger > th, -.table > tfoot > .danger > th { - background-color: #f2dede; -} - -.table-hover > tbody > tr > .danger:hover, -.table-hover > tbody > .danger:hover > td, -.table-hover > tbody > .danger:hover > th { - background-color: #ebcccc; -} - -.table > thead > tr > .warning, -.table > tbody > tr > .warning, -.table > tfoot > tr > .warning, -.table > thead > .warning > td, -.table > tbody > .warning > td, -.table > tfoot > .warning > td, -.table > thead > .warning > th, -.table > tbody > .warning > th, -.table > tfoot > .warning > th { - background-color: #fcf8e3; -} - -.table-hover > tbody > tr > .warning:hover, -.table-hover > tbody > .warning:hover > td, -.table-hover > tbody > .warning:hover > th { - background-color: #faf2cc; -} - -@media (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-x: scroll; - overflow-y: hidden; - border: 1px solid #dddddd; - -ms-overflow-style: -ms-autohiding-scrollbar; - -webkit-overflow-scrolling: touch; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} - -fieldset { - padding: 0; - margin: 0; - border: 0; -} - -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333333; - border: 0; - border-bottom: 1px solid #e5e5e5; -} - -label { - display: inline-block; - margin-bottom: 5px; - font-weight: bold; -} - -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - /* IE8-9 */ - - line-height: normal; -} - -input[type="file"] { - display: block; -} - -select[multiple], -select[size] { - height: auto; -} - -select optgroup { - font-family: inherit; - font-size: inherit; - font-style: inherit; -} - -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -input[type="number"]::-webkit-outer-spin-button, -input[type="number"]::-webkit-inner-spin-button { - height: auto; -} - -output { - display: block; - padding-top: 7px; - font-size: 14px; - line-height: 1.428571429; - color: #555555; - vertical-align: middle; -} - -.form-control { - display: block; - width: 100%; - height: 34px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.428571429; - color: #555555; - vertical-align: middle; - background-color: #ffffff; - background-image: none; - border: 1px solid #cccccc; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; - transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; -} - -.form-control:focus { - border-color: #66afe9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); -} - -.form-control:-moz-placeholder { - color: #999999; -} - -.form-control::-moz-placeholder { - color: #999999; - opacity: 1; -} - -.form-control:-ms-input-placeholder { - color: #999999; -} - -.form-control::-webkit-input-placeholder { - color: #999999; -} - -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - cursor: not-allowed; - background-color: #eeeeee; -} - -textarea.form-control { - height: auto; -} - -.form-group { - margin-bottom: 15px; -} - -.radio, -.checkbox { - display: block; - min-height: 20px; - padding-left: 20px; - margin-top: 10px; - margin-bottom: 10px; - vertical-align: middle; -} - -.radio label, -.checkbox label { - display: inline; - margin-bottom: 0; - font-weight: normal; - cursor: pointer; -} - -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { - float: left; - margin-left: -20px; -} - -.radio + .radio, -.checkbox + .checkbox { - margin-top: -5px; -} - -.radio-inline, -.checkbox-inline { - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - vertical-align: middle; - cursor: pointer; -} - -.radio-inline + .radio-inline, -.checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 10px; -} - -input[type="radio"][disabled], -input[type="checkbox"][disabled], -.radio[disabled], -.radio-inline[disabled], -.checkbox[disabled], -.checkbox-inline[disabled], -fieldset[disabled] input[type="radio"], -fieldset[disabled] input[type="checkbox"], -fieldset[disabled] .radio, -fieldset[disabled] .radio-inline, -fieldset[disabled] .checkbox, -fieldset[disabled] .checkbox-inline { - cursor: not-allowed; -} - -.input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -select.input-sm { - height: 30px; - line-height: 30px; -} - -textarea.input-sm { - height: auto; -} - -.input-lg { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} - -select.input-lg { - height: 46px; - line-height: 46px; -} - -textarea.input-lg { - height: auto; -} - -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline { - color: #8a6d3b; -} - -.has-warning .form-control { - border-color: #8a6d3b; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.has-warning .form-control:focus { - border-color: #66512c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; -} - -.has-warning .input-group-addon { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #8a6d3b; -} - -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline { - color: #a94442; -} - -.has-error .form-control { - border-color: #a94442; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.has-error .form-control:focus { - border-color: #843534; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; -} - -.has-error .input-group-addon { - color: #a94442; - background-color: #f2dede; - border-color: #a94442; -} - -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline { - color: #3c763d; -} - -.has-success .form-control { - border-color: #3c763d; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.has-success .form-control:focus { - border-color: #2b542c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; -} - -.has-success .input-group-addon { - color: #3c763d; - background-color: #dff0d8; - border-color: #3c763d; -} - -.form-control-static { - margin-bottom: 0; -} - -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #737373; -} - -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .form-control { - display: inline-block; - } - .form-inline select.form-control { - width: auto; - } - .form-inline .radio, - .form-inline .checkbox { - display: inline-block; - padding-left: 0; - margin-top: 0; - margin-bottom: 0; - } - .form-inline .radio input[type="radio"], - .form-inline .checkbox input[type="checkbox"] { - float: none; - margin-left: 0; - } -} - -.form-horizontal .control-label, -.form-horizontal .radio, -.form-horizontal .checkbox, -.form-horizontal .radio-inline, -.form-horizontal .checkbox-inline { - padding-top: 7px; - margin-top: 0; - margin-bottom: 0; -} - -.form-horizontal .radio, -.form-horizontal .checkbox { - min-height: 27px; -} - -.form-horizontal .form-group { - margin-right: -15px; - margin-left: -15px; -} - -.form-horizontal .form-group:before, -.form-horizontal .form-group:after { - display: table; - content: " "; -} - -.form-horizontal .form-group:after { - clear: both; -} - -.form-horizontal .form-group:before, -.form-horizontal .form-group:after { - display: table; - content: " "; -} - -.form-horizontal .form-group:after { - clear: both; -} - -.form-horizontal .form-control-static { - padding-top: 7px; -} - -@media (min-width: 768px) { - .form-horizontal .control-label { - text-align: right; - } -} - -.btn { - display: inline-block; - padding: 6px 12px; - margin-bottom: 0; - font-size: 14px; - font-weight: normal; - line-height: 1.428571429; - text-align: center; - white-space: nowrap; - vertical-align: middle; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; -} - -.btn:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -.btn:hover, -.btn:focus { - color: #333333; - text-decoration: none; -} - -.btn:active, -.btn.active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} - -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - pointer-events: none; - cursor: not-allowed; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; -} - -.btn-default { - color: #333333; - background-color: #ffffff; - border-color: #cccccc; -} - -.btn-default:hover, -.btn-default:focus, -.btn-default:active, -.btn-default.active, -.open .dropdown-toggle.btn-default { - color: #333333; - background-color: #ebebeb; - border-color: #adadad; -} - -.btn-default:active, -.btn-default.active, -.open .dropdown-toggle.btn-default { - background-image: none; -} - -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #ffffff; - border-color: #cccccc; -} - -.btn-default .badge { - color: #ffffff; - background-color: #fff; -} - -.btn-primary { - color: #ffffff; - background-color: #428bca; - border-color: #357ebd; -} - -.btn-primary:hover, -.btn-primary:focus, -.btn-primary:active, -.btn-primary.active, -.open .dropdown-toggle.btn-primary { - color: #ffffff; - background-color: #3276b1; - border-color: #285e8e; -} - -.btn-primary:active, -.btn-primary.active, -.open .dropdown-toggle.btn-primary { - background-image: none; -} - -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #428bca; - border-color: #357ebd; -} - -.btn-primary .badge { - color: #428bca; - background-color: #fff; -} - -.btn-warning { - color: #ffffff; - background-color: #f0ad4e; - border-color: #eea236; -} - -.btn-warning:hover, -.btn-warning:focus, -.btn-warning:active, -.btn-warning.active, -.open .dropdown-toggle.btn-warning { - color: #ffffff; - background-color: #ed9c28; - border-color: #d58512; -} - -.btn-warning:active, -.btn-warning.active, -.open .dropdown-toggle.btn-warning { - background-image: none; -} - -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #f0ad4e; - border-color: #eea236; -} - -.btn-warning .badge { - color: #f0ad4e; - background-color: #fff; -} - -.btn-danger { - color: #ffffff; - background-color: #d9534f; - border-color: #d43f3a; -} - -.btn-danger:hover, -.btn-danger:focus, -.btn-danger:active, -.btn-danger.active, -.open .dropdown-toggle.btn-danger { - color: #ffffff; - background-color: #d2322d; - border-color: #ac2925; -} - -.btn-danger:active, -.btn-danger.active, -.open .dropdown-toggle.btn-danger { - background-image: none; -} - -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #d9534f; - border-color: #d43f3a; -} - -.btn-danger .badge { - color: #d9534f; - background-color: #fff; -} - -.btn-success { - color: #ffffff; - background-color: #5cb85c; - border-color: #4cae4c; -} - -.btn-success:hover, -.btn-success:focus, -.btn-success:active, -.btn-success.active, -.open .dropdown-toggle.btn-success { - color: #ffffff; - background-color: #47a447; - border-color: #398439; -} - -.btn-success:active, -.btn-success.active, -.open .dropdown-toggle.btn-success { - background-image: none; -} - -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #5cb85c; - border-color: #4cae4c; -} - -.btn-success .badge { - color: #5cb85c; - background-color: #fff; -} - -.btn-info { - color: #ffffff; - background-color: #5bc0de; - border-color: #46b8da; -} - -.btn-info:hover, -.btn-info:focus, -.btn-info:active, -.btn-info.active, -.open .dropdown-toggle.btn-info { - color: #ffffff; - background-color: #39b3d7; - border-color: #269abc; -} - -.btn-info:active, -.btn-info.active, -.open .dropdown-toggle.btn-info { - background-image: none; -} - -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #5bc0de; - border-color: #46b8da; -} - -.btn-info .badge { - color: #5bc0de; - background-color: #fff; -} - -.btn-link { - font-weight: normal; - color: #428bca; - cursor: pointer; - border-radius: 0; -} - -.btn-link, -.btn-link:active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} - -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} - -.btn-link:hover, -.btn-link:focus { - color: #2a6496; - text-decoration: underline; - background-color: transparent; -} - -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #999999; - text-decoration: none; -} - -.btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} - -.btn-sm { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -.btn-xs { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -.btn-block { - display: block; - width: 100%; - padding-right: 0; - padding-left: 0; -} - -.btn-block + .btn-block { - margin-top: 5px; -} - -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} - -.fade { - opacity: 0; - -webkit-transition: opacity 0.15s linear; - transition: opacity 0.15s linear; -} - -.fade.in { - opacity: 1; -} - -.collapse { - display: none; -} - -.collapse.in { - display: block; -} - -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition: height 0.35s ease; - transition: height 0.35s ease; -} - -@font-face { - font-family: 'Glyphicons Halflings'; - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg'); -} - -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - -webkit-font-smoothing: antialiased; - font-style: normal; - font-weight: normal; - line-height: 1; - -moz-osx-font-smoothing: grayscale; -} - -.glyphicon:empty { - width: 1em; -} - -.glyphicon-asterisk:before { - content: "\2a"; -} - -.glyphicon-plus:before { - content: "\2b"; -} - -.glyphicon-euro:before { - content: "\20ac"; -} - -.glyphicon-minus:before { - content: "\2212"; -} - -.glyphicon-cloud:before { - content: "\2601"; -} - -.glyphicon-envelope:before { - content: "\2709"; -} - -.glyphicon-pencil:before { - content: "\270f"; -} - -.glyphicon-glass:before { - content: "\e001"; -} - -.glyphicon-music:before { - content: "\e002"; -} - -.glyphicon-search:before { - content: "\e003"; -} - -.glyphicon-heart:before { - content: "\e005"; -} - -.glyphicon-star:before { - content: "\e006"; -} - -.glyphicon-star-empty:before { - content: "\e007"; -} - -.glyphicon-user:before { - content: "\e008"; -} - -.glyphicon-film:before { - content: "\e009"; -} - -.glyphicon-th-large:before { - content: "\e010"; -} - -.glyphicon-th:before { - content: "\e011"; -} - -.glyphicon-th-list:before { - content: "\e012"; -} - -.glyphicon-ok:before { - content: "\e013"; -} - -.glyphicon-remove:before { - content: "\e014"; -} - -.glyphicon-zoom-in:before { - content: "\e015"; -} - -.glyphicon-zoom-out:before { - content: "\e016"; -} - -.glyphicon-off:before { - content: "\e017"; -} - -.glyphicon-signal:before { - content: "\e018"; -} - -.glyphicon-cog:before { - content: "\e019"; -} - -.glyphicon-trash:before { - content: "\e020"; -} - -.glyphicon-home:before { - content: "\e021"; -} - -.glyphicon-file:before { - content: "\e022"; -} - -.glyphicon-time:before { - content: "\e023"; -} - -.glyphicon-road:before { - content: "\e024"; -} - -.glyphicon-download-alt:before { - content: "\e025"; -} - -.glyphicon-download:before { - content: "\e026"; -} - -.glyphicon-upload:before { - content: "\e027"; -} - -.glyphicon-inbox:before { - content: "\e028"; -} - -.glyphicon-play-circle:before { - content: "\e029"; -} - -.glyphicon-repeat:before { - content: "\e030"; -} - -.glyphicon-refresh:before { - content: "\e031"; -} - -.glyphicon-list-alt:before { - content: "\e032"; -} - -.glyphicon-lock:before { - content: "\e033"; -} - -.glyphicon-flag:before { - content: "\e034"; -} - -.glyphicon-headphones:before { - content: "\e035"; -} - -.glyphicon-volume-off:before { - content: "\e036"; -} - -.glyphicon-volume-down:before { - content: "\e037"; -} - -.glyphicon-volume-up:before { - content: "\e038"; -} - -.glyphicon-qrcode:before { - content: "\e039"; -} - -.glyphicon-barcode:before { - content: "\e040"; -} - -.glyphicon-tag:before { - content: "\e041"; -} - -.glyphicon-tags:before { - content: "\e042"; -} - -.glyphicon-book:before { - content: "\e043"; -} - -.glyphicon-bookmark:before { - content: "\e044"; -} - -.glyphicon-print:before { - content: "\e045"; -} - -.glyphicon-camera:before { - content: "\e046"; -} - -.glyphicon-font:before { - content: "\e047"; -} - -.glyphicon-bold:before { - content: "\e048"; -} - -.glyphicon-italic:before { - content: "\e049"; -} - -.glyphicon-text-height:before { - content: "\e050"; -} - -.glyphicon-text-width:before { - content: "\e051"; -} - -.glyphicon-align-left:before { - content: "\e052"; -} - -.glyphicon-align-center:before { - content: "\e053"; -} - -.glyphicon-align-right:before { - content: "\e054"; -} - -.glyphicon-align-justify:before { - content: "\e055"; -} - -.glyphicon-list:before { - content: "\e056"; -} - -.glyphicon-indent-left:before { - content: "\e057"; -} - -.glyphicon-indent-right:before { - content: "\e058"; -} - -.glyphicon-facetime-video:before { - content: "\e059"; -} - -.glyphicon-picture:before { - content: "\e060"; -} - -.glyphicon-map-marker:before { - content: "\e062"; -} - -.glyphicon-adjust:before { - content: "\e063"; -} - -.glyphicon-tint:before { - content: "\e064"; -} - -.glyphicon-edit:before { - content: "\e065"; -} - -.glyphicon-share:before { - content: "\e066"; -} - -.glyphicon-check:before { - content: "\e067"; -} - -.glyphicon-move:before { - content: "\e068"; -} - -.glyphicon-step-backward:before { - content: "\e069"; -} - -.glyphicon-fast-backward:before { - content: "\e070"; -} - -.glyphicon-backward:before { - content: "\e071"; -} - -.glyphicon-play:before { - content: "\e072"; -} - -.glyphicon-pause:before { - content: "\e073"; -} - -.glyphicon-stop:before { - content: "\e074"; -} - -.glyphicon-forward:before { - content: "\e075"; -} - -.glyphicon-fast-forward:before { - content: "\e076"; -} - -.glyphicon-step-forward:before { - content: "\e077"; -} - -.glyphicon-eject:before { - content: "\e078"; -} - -.glyphicon-chevron-left:before { - content: "\e079"; -} - -.glyphicon-chevron-right:before { - content: "\e080"; -} - -.glyphicon-plus-sign:before { - content: "\e081"; -} - -.glyphicon-minus-sign:before { - content: "\e082"; -} - -.glyphicon-remove-sign:before { - content: "\e083"; -} - -.glyphicon-ok-sign:before { - content: "\e084"; -} - -.glyphicon-question-sign:before { - content: "\e085"; -} - -.glyphicon-info-sign:before { - content: "\e086"; -} - -.glyphicon-screenshot:before { - content: "\e087"; -} - -.glyphicon-remove-circle:before { - content: "\e088"; -} - -.glyphicon-ok-circle:before { - content: "\e089"; -} - -.glyphicon-ban-circle:before { - content: "\e090"; -} - -.glyphicon-arrow-left:before { - content: "\e091"; -} - -.glyphicon-arrow-right:before { - content: "\e092"; -} - -.glyphicon-arrow-up:before { - content: "\e093"; -} - -.glyphicon-arrow-down:before { - content: "\e094"; -} - -.glyphicon-share-alt:before { - content: "\e095"; -} - -.glyphicon-resize-full:before { - content: "\e096"; -} - -.glyphicon-resize-small:before { - content: "\e097"; -} - -.glyphicon-exclamation-sign:before { - content: "\e101"; -} - -.glyphicon-gift:before { - content: "\e102"; -} - -.glyphicon-leaf:before { - content: "\e103"; -} - -.glyphicon-fire:before { - content: "\e104"; -} - -.glyphicon-eye-open:before { - content: "\e105"; -} - -.glyphicon-eye-close:before { - content: "\e106"; -} - -.glyphicon-warning-sign:before { - content: "\e107"; -} - -.glyphicon-plane:before { - content: "\e108"; -} - -.glyphicon-calendar:before { - content: "\e109"; -} - -.glyphicon-random:before { - content: "\e110"; -} - -.glyphicon-comment:before { - content: "\e111"; -} - -.glyphicon-magnet:before { - content: "\e112"; -} - -.glyphicon-chevron-up:before { - content: "\e113"; -} - -.glyphicon-chevron-down:before { - content: "\e114"; -} - -.glyphicon-retweet:before { - content: "\e115"; -} - -.glyphicon-shopping-cart:before { - content: "\e116"; -} - -.glyphicon-folder-close:before { - content: "\e117"; -} - -.glyphicon-folder-open:before { - content: "\e118"; -} - -.glyphicon-resize-vertical:before { - content: "\e119"; -} - -.glyphicon-resize-horizontal:before { - content: "\e120"; -} - -.glyphicon-hdd:before { - content: "\e121"; -} - -.glyphicon-bullhorn:before { - content: "\e122"; -} - -.glyphicon-bell:before { - content: "\e123"; -} - -.glyphicon-certificate:before { - content: "\e124"; -} - -.glyphicon-thumbs-up:before { - content: "\e125"; -} - -.glyphicon-thumbs-down:before { - content: "\e126"; -} - -.glyphicon-hand-right:before { - content: "\e127"; -} - -.glyphicon-hand-left:before { - content: "\e128"; -} - -.glyphicon-hand-up:before { - content: "\e129"; -} - -.glyphicon-hand-down:before { - content: "\e130"; -} - -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} - -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} - -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} - -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} - -.glyphicon-globe:before { - content: "\e135"; -} - -.glyphicon-wrench:before { - content: "\e136"; -} - -.glyphicon-tasks:before { - content: "\e137"; -} - -.glyphicon-filter:before { - content: "\e138"; -} - -.glyphicon-briefcase:before { - content: "\e139"; -} - -.glyphicon-fullscreen:before { - content: "\e140"; -} - -.glyphicon-dashboard:before { - content: "\e141"; -} - -.glyphicon-paperclip:before { - content: "\e142"; -} - -.glyphicon-heart-empty:before { - content: "\e143"; -} - -.glyphicon-link:before { - content: "\e144"; -} - -.glyphicon-phone:before { - content: "\e145"; -} - -.glyphicon-pushpin:before { - content: "\e146"; -} - -.glyphicon-usd:before { - content: "\e148"; -} - -.glyphicon-gbp:before { - content: "\e149"; -} - -.glyphicon-sort:before { - content: "\e150"; -} - -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} - -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} - -.glyphicon-sort-by-order:before { - content: "\e153"; -} - -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} - -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} - -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} - -.glyphicon-unchecked:before { - content: "\e157"; -} - -.glyphicon-expand:before { - content: "\e158"; -} - -.glyphicon-collapse-down:before { - content: "\e159"; -} - -.glyphicon-collapse-up:before { - content: "\e160"; -} - -.glyphicon-log-in:before { - content: "\e161"; -} - -.glyphicon-flash:before { - content: "\e162"; -} - -.glyphicon-log-out:before { - content: "\e163"; -} - -.glyphicon-new-window:before { - content: "\e164"; -} - -.glyphicon-record:before { - content: "\e165"; -} - -.glyphicon-save:before { - content: "\e166"; -} - -.glyphicon-open:before { - content: "\e167"; -} - -.glyphicon-saved:before { - content: "\e168"; -} - -.glyphicon-import:before { - content: "\e169"; -} - -.glyphicon-export:before { - content: "\e170"; -} - -.glyphicon-send:before { - content: "\e171"; -} - -.glyphicon-floppy-disk:before { - content: "\e172"; -} - -.glyphicon-floppy-saved:before { - content: "\e173"; -} - -.glyphicon-floppy-remove:before { - content: "\e174"; -} - -.glyphicon-floppy-save:before { - content: "\e175"; -} - -.glyphicon-floppy-open:before { - content: "\e176"; -} - -.glyphicon-credit-card:before { - content: "\e177"; -} - -.glyphicon-transfer:before { - content: "\e178"; -} - -.glyphicon-cutlery:before { - content: "\e179"; -} - -.glyphicon-header:before { - content: "\e180"; -} - -.glyphicon-compressed:before { - content: "\e181"; -} - -.glyphicon-earphone:before { - content: "\e182"; -} - -.glyphicon-phone-alt:before { - content: "\e183"; -} - -.glyphicon-tower:before { - content: "\e184"; -} - -.glyphicon-stats:before { - content: "\e185"; -} - -.glyphicon-sd-video:before { - content: "\e186"; -} - -.glyphicon-hd-video:before { - content: "\e187"; -} - -.glyphicon-subtitles:before { - content: "\e188"; -} - -.glyphicon-sound-stereo:before { - content: "\e189"; -} - -.glyphicon-sound-dolby:before { - content: "\e190"; -} - -.glyphicon-sound-5-1:before { - content: "\e191"; -} - -.glyphicon-sound-6-1:before { - content: "\e192"; -} - -.glyphicon-sound-7-1:before { - content: "\e193"; -} - -.glyphicon-copyright-mark:before { - content: "\e194"; -} - -.glyphicon-registration-mark:before { - content: "\e195"; -} - -.glyphicon-cloud-download:before { - content: "\e197"; -} - -.glyphicon-cloud-upload:before { - content: "\e198"; -} - -.glyphicon-tree-conifer:before { - content: "\e199"; -} - -.glyphicon-tree-deciduous:before { - content: "\e200"; -} - -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px solid; - border-right: 4px solid transparent; - border-left: 4px solid transparent; -} - -.dropdown { - position: relative; -} - -.dropdown-toggle:focus { - outline: 0; -} - -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - list-style: none; - background-color: #ffffff; - border: 1px solid #cccccc; - border: 1px solid rgba(0, 0, 0, 0.15); - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - background-clip: padding-box; -} - -.dropdown-menu.pull-right { - right: 0; - left: auto; -} - -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} - -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 1.428571429; - color: #333333; - white-space: nowrap; -} - -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - color: #262626; - text-decoration: none; - background-color: #f5f5f5; -} - -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: #ffffff; - text-decoration: none; - background-color: #428bca; - outline: 0; -} - -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: #999999; -} - -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - cursor: not-allowed; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.open > .dropdown-menu { - display: block; -} - -.open > a { - outline: 0; -} - -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.428571429; - color: #999999; -} - -.dropdown-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 990; -} - -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} - -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - border-top: 0; - border-bottom: 4px solid; - content: ""; -} - -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 1px; -} - -@media (min-width: 768px) { - .navbar-right .dropdown-menu { - right: 0; - left: auto; - } -} - -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle; -} - -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - float: left; -} - -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover, -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus, -.btn-group > .btn:active, -.btn-group-vertical > .btn:active, -.btn-group > .btn.active, -.btn-group-vertical > .btn.active { - z-index: 2; -} - -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus { - outline: none; -} - -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group { - margin-left: -1px; -} - -.btn-toolbar:before, -.btn-toolbar:after { - display: table; - content: " "; -} - -.btn-toolbar:after { - clear: both; -} - -.btn-toolbar:before, -.btn-toolbar:after { - display: table; - content: " "; -} - -.btn-toolbar:after { - clear: both; -} - -.btn-toolbar .btn-group { - float: left; -} - -.btn-toolbar > .btn + .btn, -.btn-toolbar > .btn-group + .btn, -.btn-toolbar > .btn + .btn-group, -.btn-toolbar > .btn-group + .btn-group { - margin-left: 5px; -} - -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0; -} - -.btn-group > .btn:first-child { - margin-left: 0; -} - -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.btn-group > .btn:last-child:not(:first-child), -.btn-group > .dropdown-toggle:not(:first-child) { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} - -.btn-group > .btn-group { - float: left; -} - -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} - -.btn-group > .btn-group:first-child > .btn:last-child, -.btn-group > .btn-group:first-child > .dropdown-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.btn-group > .btn-group:last-child > .btn:first-child { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} - -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} - -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -.btn-group-lg > .btn { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} - -.btn-group > .btn + .dropdown-toggle { - padding-right: 8px; - padding-left: 8px; -} - -.btn-group > .btn-lg + .dropdown-toggle { - padding-right: 12px; - padding-left: 12px; -} - -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} - -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none; -} - -.btn .caret { - margin-left: 0; -} - -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0; -} - -.dropup .btn-lg .caret { - border-width: 0 5px 5px; -} - -.btn-group-vertical > .btn, -.btn-group-vertical > .btn-group, -.btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100%; -} - -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after { - display: table; - content: " "; -} - -.btn-group-vertical > .btn-group:after { - clear: both; -} - -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after { - display: table; - content: " "; -} - -.btn-group-vertical > .btn-group:after { - clear: both; -} - -.btn-group-vertical > .btn-group > .btn { - float: none; -} - -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} - -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0; -} - -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-top-right-radius: 0; - border-bottom-left-radius: 4px; - border-top-left-radius: 0; -} - -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} - -.btn-group-vertical > .btn-group:first-child > .btn:last-child, -.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.btn-group-vertical > .btn-group:last-child > .btn:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} - -.btn-group-justified { - display: table; - width: 100%; - border-collapse: separate; - table-layout: fixed; -} - -.btn-group-justified > .btn, -.btn-group-justified > .btn-group { - display: table-cell; - float: none; - width: 1%; -} - -.btn-group-justified > .btn-group .btn { - width: 100%; -} - -[data-toggle="buttons"] > .btn > input[type="radio"], -[data-toggle="buttons"] > .btn > input[type="checkbox"] { - display: none; -} - -.input-group { - position: relative; - display: table; - border-collapse: separate; -} - -.input-group[class*="col-"] { - float: none; - padding-right: 0; - padding-left: 0; -} - -.input-group .form-control { - width: 100%; - margin-bottom: 0; -} - -.input-group-lg > .form-control, -.input-group-lg > .input-group-addon, -.input-group-lg > .input-group-btn > .btn { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} - -select.input-group-lg > .form-control, -select.input-group-lg > .input-group-addon, -select.input-group-lg > .input-group-btn > .btn { - height: 46px; - line-height: 46px; -} - -textarea.input-group-lg > .form-control, -textarea.input-group-lg > .input-group-addon, -textarea.input-group-lg > .input-group-btn > .btn { - height: auto; -} - -.input-group-sm > .form-control, -.input-group-sm > .input-group-addon, -.input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} - -select.input-group-sm > .form-control, -select.input-group-sm > .input-group-addon, -select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px; -} - -textarea.input-group-sm > .form-control, -textarea.input-group-sm > .input-group-addon, -textarea.input-group-sm > .input-group-btn > .btn { - height: auto; -} - -.input-group-addon, -.input-group-btn, -.input-group .form-control { - display: table-cell; -} - -.input-group-addon:not(:first-child):not(:last-child), -.input-group-btn:not(:first-child):not(:last-child), -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} - -.input-group-addon, -.input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle; -} - -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: normal; - line-height: 1; - color: #555555; - text-align: center; - background-color: #eeeeee; - border: 1px solid #cccccc; - border-radius: 4px; -} - -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px; -} - -.input-group-addon.input-lg { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px; -} - -.input-group-addon input[type="radio"], -.input-group-addon input[type="checkbox"] { - margin-top: 0; -} - -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.input-group-addon:first-child { - border-right: 0; -} - -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child) { - border-bottom-left-radius: 0; - border-top-left-radius: 0; -} - -.input-group-addon:last-child { - border-left: 0; -} - -.input-group-btn { - position: relative; - white-space: nowrap; -} - -.input-group-btn:first-child > .btn { - margin-right: -1px; -} - -.input-group-btn:last-child > .btn { - margin-left: -1px; -} - -.input-group-btn > .btn { - position: relative; -} - -.input-group-btn > .btn + .btn { - margin-left: -4px; -} - -.input-group-btn > .btn:hover, -.input-group-btn > .btn:active { - z-index: 2; -} - -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none; -} - -.nav:before, -.nav:after { - display: table; - content: " "; -} - -.nav:after { - clear: both; -} - -.nav:before, -.nav:after { - display: table; - content: " "; -} - -.nav:after { - clear: both; -} - -.nav > li { - position: relative; - display: block; -} - -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px; -} - -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #eeeeee; -} - -.nav > li.disabled > a { - color: #999999; -} - -.nav > li.disabled > a:hover, -.nav > li.disabled > a:focus { - color: #999999; - text-decoration: none; - cursor: not-allowed; - background-color: transparent; -} - -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - background-color: #eeeeee; - border-color: #428bca; -} - -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} - -.nav > li > a > img { - max-width: none; -} - -.nav-tabs { - border-bottom: 1px solid #dddddd; -} - -.nav-tabs > li { - float: left; - margin-bottom: -1px; -} - -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.428571429; - border: 1px solid transparent; - border-radius: 4px 4px 0 0; -} - -.nav-tabs > li > a:hover { - border-color: #eeeeee #eeeeee #dddddd; -} - -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - color: #555555; - cursor: default; - background-color: #ffffff; - border: 1px solid #dddddd; - border-bottom-color: transparent; -} - -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0; -} - -.nav-tabs.nav-justified > li { - float: none; -} - -.nav-tabs.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} - -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} - -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-tabs.nav-justified > li > a { - margin-bottom: 0; - } -} - -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px; -} - -.nav-tabs.nav-justified > .active > a, -.nav-tabs.nav-justified > .active > a:hover, -.nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #dddddd; -} - -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #dddddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs.nav-justified > .active > a, - .nav-tabs.nav-justified > .active > a:hover, - .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #ffffff; - } -} - -.nav-pills > li { - float: left; -} - -.nav-pills > li > a { - border-radius: 4px; -} - -.nav-pills > li + li { - margin-left: 2px; -} - -.nav-pills > li.active > a, -.nav-pills > li.active > a:hover, -.nav-pills > li.active > a:focus { - color: #ffffff; - background-color: #428bca; -} - -.nav-stacked > li { - float: none; -} - -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0; -} - -.nav-justified { - width: 100%; -} - -.nav-justified > li { - float: none; -} - -.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} - -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} - -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-justified > li > a { - margin-bottom: 0; - } -} - -.nav-tabs-justified { - border-bottom: 0; -} - -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 4px; -} - -.nav-tabs-justified > .active > a, -.nav-tabs-justified > .active > a:hover, -.nav-tabs-justified > .active > a:focus { - border: 1px solid #dddddd; -} - -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #dddddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs-justified > .active > a, - .nav-tabs-justified > .active > a:hover, - .nav-tabs-justified > .active > a:focus { - border-bottom-color: #ffffff; - } -} - -.tab-content > .tab-pane { - display: none; -} - -.tab-content > .active { - display: block; -} - -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-right-radius: 0; - border-top-left-radius: 0; -} - -.navbar { - position: relative; - min-height: 50px; - margin-bottom: 20px; - border: 1px solid transparent; -} - -.navbar:before, -.navbar:after { - display: table; - content: " "; -} - -.navbar:after { - clear: both; -} - -.navbar:before, -.navbar:after { - display: table; - content: " "; -} - -.navbar:after { - clear: both; -} - -@media (min-width: 768px) { - .navbar { - border-radius: 4px; - } -} - -.navbar-header:before, -.navbar-header:after { - display: table; - content: " "; -} - -.navbar-header:after { - clear: both; -} - -.navbar-header:before, -.navbar-header:after { - display: table; - content: " "; -} - -.navbar-header:after { - clear: both; -} - -@media (min-width: 768px) { - .navbar-header { - float: left; - } -} - -.navbar-collapse { - max-height: 340px; - padding-right: 15px; - padding-left: 15px; - overflow-x: visible; - border-top: 1px solid transparent; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); - -webkit-overflow-scrolling: touch; -} - -.navbar-collapse:before, -.navbar-collapse:after { - display: table; - content: " "; -} - -.navbar-collapse:after { - clear: both; -} - -.navbar-collapse:before, -.navbar-collapse:after { - display: table; - content: " "; -} - -.navbar-collapse:after { - clear: both; -} - -.navbar-collapse.in { - overflow-y: auto; -} - -@media (min-width: 768px) { - .navbar-collapse { - width: auto; - border-top: 0; - box-shadow: none; - } - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important; - } - .navbar-collapse.in { - overflow-y: visible; - } - .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - padding-right: 0; - padding-left: 0; - } -} - -.container > .navbar-header, -.container > .navbar-collapse { - margin-right: -15px; - margin-left: -15px; -} - -@media (min-width: 768px) { - .container > .navbar-header, - .container > .navbar-collapse { - margin-right: 0; - margin-left: 0; - } -} - -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px; -} - -@media (min-width: 768px) { - .navbar-static-top { - border-radius: 0; - } -} - -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} - -@media (min-width: 768px) { - .navbar-fixed-top, - .navbar-fixed-bottom { - border-radius: 0; - } -} - -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px; -} - -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0; -} - -.navbar-brand { - float: left; - padding: 15px 15px; - font-size: 18px; - line-height: 20px; -} - -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none; -} - -@media (min-width: 768px) { - .navbar > .container .navbar-brand { - margin-left: -15px; - } -} - -.navbar-toggle { - position: relative; - float: right; - padding: 9px 10px; - margin-top: 8px; - margin-right: 15px; - margin-bottom: 8px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} - -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px; -} - -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px; -} - -@media (min-width: 768px) { - .navbar-toggle { - display: none; - } -} - -.navbar-nav { - margin: 7.5px -15px; -} - -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px; -} - -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - box-shadow: none; - } - .navbar-nav .open .dropdown-menu > li > a, - .navbar-nav .open .dropdown-menu .dropdown-header { - padding: 5px 15px 5px 25px; - } - .navbar-nav .open .dropdown-menu > li > a { - line-height: 20px; - } - .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-nav .open .dropdown-menu > li > a:focus { - background-image: none; - } -} - -@media (min-width: 768px) { - .navbar-nav { - float: left; - margin: 0; - } - .navbar-nav > li { - float: left; - } - .navbar-nav > li > a { - padding-top: 15px; - padding-bottom: 15px; - } - .navbar-nav.navbar-right:last-child { - margin-right: -15px; - } -} - -@media (min-width: 768px) { - .navbar-left { - float: left !important; - } - .navbar-right { - float: right !important; - } -} - -.navbar-form { - padding: 10px 15px; - margin-top: 8px; - margin-right: -15px; - margin-bottom: 8px; - margin-left: -15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); -} - -@media (min-width: 768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .form-control { - display: inline-block; - } - .navbar-form select.form-control { - width: auto; - } - .navbar-form .radio, - .navbar-form .checkbox { - display: inline-block; - padding-left: 0; - margin-top: 0; - margin-bottom: 0; - } - .navbar-form .radio input[type="radio"], - .navbar-form .checkbox input[type="checkbox"] { - float: none; - margin-left: 0; - } -} - -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px; - } -} - -@media (min-width: 768px) { - .navbar-form { - width: auto; - padding-top: 0; - padding-bottom: 0; - margin-right: 0; - margin-left: 0; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-form.navbar-right:last-child { - margin-right: -15px; - } -} - -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-right-radius: 0; - border-top-left-radius: 0; -} - -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.navbar-nav.pull-right > li > .dropdown-menu, -.navbar-nav > li > .dropdown-menu.pull-right { - right: 0; - left: auto; -} - -.navbar-btn { - margin-top: 8px; - margin-bottom: 8px; -} - -.navbar-btn.btn-sm { - margin-top: 10px; - margin-bottom: 10px; -} - -.navbar-btn.btn-xs { - margin-top: 14px; - margin-bottom: 14px; -} - -.navbar-text { - margin-top: 15px; - margin-bottom: 15px; -} - -@media (min-width: 768px) { - .navbar-text { - float: left; - margin-right: 15px; - margin-left: 15px; - } - .navbar-text.navbar-right:last-child { - margin-right: 0; - } -} - -.navbar-default { - background-color: #f8f8f8; - border-color: #e7e7e7; -} - -.navbar-default .navbar-brand { - color: #777777; -} - -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #5e5e5e; - background-color: transparent; -} - -.navbar-default .navbar-text { - color: #777777; -} - -.navbar-default .navbar-nav > li > a { - color: #777777; -} - -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #333333; - background-color: transparent; -} - -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #555555; - background-color: #e7e7e7; -} - -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #cccccc; - background-color: transparent; -} - -.navbar-default .navbar-toggle { - border-color: #dddddd; -} - -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #dddddd; -} - -.navbar-default .navbar-toggle .icon-bar { - background-color: #cccccc; -} - -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: #e7e7e7; -} - -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - color: #555555; - background-color: #e7e7e7; -} - -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #777777; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #333333; - background-color: transparent; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #555555; - background-color: #e7e7e7; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #cccccc; - background-color: transparent; - } -} - -.navbar-default .navbar-link { - color: #777777; -} - -.navbar-default .navbar-link:hover { - color: #333333; -} - -.navbar-inverse { - background-color: #222222; - border-color: #080808; -} - -.navbar-inverse .navbar-brand { - color: #999999; -} - -.navbar-inverse .navbar-brand:hover, -.navbar-inverse .navbar-brand:focus { - color: #ffffff; - background-color: transparent; -} - -.navbar-inverse .navbar-text { - color: #999999; -} - -.navbar-inverse .navbar-nav > li > a { - color: #999999; -} - -.navbar-inverse .navbar-nav > li > a:hover, -.navbar-inverse .navbar-nav > li > a:focus { - color: #ffffff; - background-color: transparent; -} - -.navbar-inverse .navbar-nav > .active > a, -.navbar-inverse .navbar-nav > .active > a:hover, -.navbar-inverse .navbar-nav > .active > a:focus { - color: #ffffff; - background-color: #080808; -} - -.navbar-inverse .navbar-nav > .disabled > a, -.navbar-inverse .navbar-nav > .disabled > a:hover, -.navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444444; - background-color: transparent; -} - -.navbar-inverse .navbar-toggle { - border-color: #333333; -} - -.navbar-inverse .navbar-toggle:hover, -.navbar-inverse .navbar-toggle:focus { - background-color: #333333; -} - -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #ffffff; -} - -.navbar-inverse .navbar-collapse, -.navbar-inverse .navbar-form { - border-color: #101010; -} - -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .open > a:hover, -.navbar-inverse .navbar-nav > .open > a:focus { - color: #ffffff; - background-color: #080808; -} - -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #999999; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #ffffff; - background-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #ffffff; - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444444; - background-color: transparent; - } -} - -.navbar-inverse .navbar-link { - color: #999999; -} - -.navbar-inverse .navbar-link:hover { - color: #ffffff; -} - -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #f5f5f5; - border-radius: 4px; -} - -.breadcrumb > li { - display: inline-block; -} - -.breadcrumb > li + li:before { - padding: 0 5px; - color: #cccccc; - content: "/\00a0"; -} - -.breadcrumb > .active { - color: #999999; -} - -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px; -} - -.pagination > li { - display: inline; -} - -.pagination > li > a, -.pagination > li > span { - position: relative; - float: left; - padding: 6px 12px; - margin-left: -1px; - line-height: 1.428571429; - text-decoration: none; - background-color: #ffffff; - border: 1px solid #dddddd; -} - -.pagination > li:first-child > a, -.pagination > li:first-child > span { - margin-left: 0; - border-bottom-left-radius: 4px; - border-top-left-radius: 4px; -} - -.pagination > li:last-child > a, -.pagination > li:last-child > span { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} - -.pagination > li > a:hover, -.pagination > li > span:hover, -.pagination > li > a:focus, -.pagination > li > span:focus { - background-color: #eeeeee; -} - -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - z-index: 2; - color: #ffffff; - cursor: default; - background-color: #428bca; - border-color: #428bca; -} - -.pagination > .disabled > span, -.pagination > .disabled > span:hover, -.pagination > .disabled > span:focus, -.pagination > .disabled > a, -.pagination > .disabled > a:hover, -.pagination > .disabled > a:focus { - color: #999999; - cursor: not-allowed; - background-color: #ffffff; - border-color: #dddddd; -} - -.pagination-lg > li > a, -.pagination-lg > li > span { - padding: 10px 16px; - font-size: 18px; -} - -.pagination-lg > li:first-child > a, -.pagination-lg > li:first-child > span { - border-bottom-left-radius: 6px; - border-top-left-radius: 6px; -} - -.pagination-lg > li:last-child > a, -.pagination-lg > li:last-child > span { - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; -} - -.pagination-sm > li > a, -.pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; -} - -.pagination-sm > li:first-child > a, -.pagination-sm > li:first-child > span { - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; -} - -.pagination-sm > li:last-child > a, -.pagination-sm > li:last-child > span { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} - -.pager { - padding-left: 0; - margin: 20px 0; - text-align: center; - list-style: none; -} - -.pager:before, -.pager:after { - display: table; - content: " "; -} - -.pager:after { - clear: both; -} - -.pager:before, -.pager:after { - display: table; - content: " "; -} - -.pager:after { - clear: both; -} - -.pager li { - display: inline; -} - -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #ffffff; - border: 1px solid #dddddd; - border-radius: 15px; -} - -.pager li > a:hover, -.pager li > a:focus { - text-decoration: none; - background-color: #eeeeee; -} - -.pager .next > a, -.pager .next > span { - float: right; -} - -.pager .previous > a, -.pager .previous > span { - float: left; -} - -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #999999; - cursor: not-allowed; - background-color: #ffffff; -} - -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #ffffff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} - -.label[href]:hover, -.label[href]:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -.label:empty { - display: none; -} - -.btn .label { - position: relative; - top: -1px; -} - -.label-default { - background-color: #999999; -} - -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #808080; -} - -.label-primary { - background-color: #428bca; -} - -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #3071a9; -} - -.label-success { - background-color: #5cb85c; -} - -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #449d44; -} - -.label-info { - background-color: #5bc0de; -} - -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #31b0d5; -} - -.label-warning { - background-color: #f0ad4e; -} - -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ec971f; -} - -.label-danger { - background-color: #d9534f; -} - -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} - -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: bold; - line-height: 1; - color: #ffffff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - background-color: #999999; - border-radius: 10px; -} - -.badge:empty { - display: none; -} - -.btn .badge { - position: relative; - top: -1px; -} - -a.badge:hover, -a.badge:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -a.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #428bca; - background-color: #ffffff; -} - -.nav-pills > li > a > .badge { - margin-left: 3px; -} - -.jumbotron { - padding: 30px; - margin-bottom: 30px; - font-size: 21px; - font-weight: 200; - line-height: 2.1428571435; - color: inherit; - background-color: #eeeeee; -} - -.jumbotron h1, -.jumbotron .h1 { - line-height: 1; - color: inherit; -} - -.jumbotron p { - line-height: 1.4; -} - -.container .jumbotron { - border-radius: 6px; -} - -.jumbotron .container { - max-width: 100%; -} - -@media screen and (min-width: 768px) { - .jumbotron { - padding-top: 48px; - padding-bottom: 48px; - } - .container .jumbotron { - padding-right: 60px; - padding-left: 60px; - } - .jumbotron h1, - .jumbotron .h1 { - font-size: 63px; - } -} - -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.428571429; - background-color: #ffffff; - border: 1px solid #dddddd; - border-radius: 4px; - -webkit-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} - -.thumbnail > img, -.thumbnail a > img { - display: block; - height: auto; - max-width: 100%; - margin-right: auto; - margin-left: auto; -} - -a.thumbnail:hover, -a.thumbnail:focus, -a.thumbnail.active { - border-color: #428bca; -} - -.thumbnail .caption { - padding: 9px; - color: #333333; -} - -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} - -.alert h4 { - margin-top: 0; - color: inherit; -} - -.alert .alert-link { - font-weight: bold; -} - -.alert > p, -.alert > ul { - margin-bottom: 0; -} - -.alert > p + p { - margin-top: 5px; -} - -.alert-dismissable { - padding-right: 35px; -} - -.alert-dismissable .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} - -.alert-success { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} - -.alert-success hr { - border-top-color: #c9e2b3; -} - -.alert-success .alert-link { - color: #2b542c; -} - -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} - -.alert-info hr { - border-top-color: #a6e1ec; -} - -.alert-info .alert-link { - color: #245269; -} - -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} - -.alert-warning hr { - border-top-color: #f7e1b5; -} - -.alert-warning .alert-link { - color: #66512c; -} - -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} - -.alert-danger hr { - border-top-color: #e4b9c0; -} - -.alert-danger .alert-link { - color: #843534; -} - -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #f5f5f5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.progress-bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #ffffff; - text-align: center; - background-color: #428bca; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -webkit-transition: width 0.6s ease; - transition: width 0.6s ease; -} - -.progress-striped .progress-bar { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-size: 40px 40px; -} - -.progress.active .progress-bar { - -webkit-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} - -.progress-bar-success { - background-color: #5cb85c; -} - -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-bar-info { - background-color: #5bc0de; -} - -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-bar-warning { - background-color: #f0ad4e; -} - -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-bar-danger { - background-color: #d9534f; -} - -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.media, -.media-body { - overflow: hidden; - zoom: 1; -} - -.media, -.media .media { - margin-top: 15px; -} - -.media:first-child { - margin-top: 0; -} - -.media-object { - display: block; -} - -.media-heading { - margin: 0 0 5px; -} - -.media > .pull-left { - margin-right: 10px; -} - -.media > .pull-right { - margin-left: 10px; -} - -.media-list { - padding-left: 0; - list-style: none; -} - -.list-group { - padding-left: 0; - margin-bottom: 20px; -} - -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #ffffff; - border: 1px solid #dddddd; -} - -.list-group-item:first-child { - border-top-right-radius: 4px; - border-top-left-radius: 4px; -} - -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; -} - -.list-group-item > .badge { - float: right; -} - -.list-group-item > .badge + .badge { - margin-right: 5px; -} - -a.list-group-item { - color: #555555; -} - -a.list-group-item .list-group-item-heading { - color: #333333; -} - -a.list-group-item:hover, -a.list-group-item:focus { - text-decoration: none; - background-color: #f5f5f5; -} - -a.list-group-item.active, -a.list-group-item.active:hover, -a.list-group-item.active:focus { - z-index: 2; - color: #ffffff; - background-color: #428bca; - border-color: #428bca; -} - -a.list-group-item.active .list-group-item-heading, -a.list-group-item.active:hover .list-group-item-heading, -a.list-group-item.active:focus .list-group-item-heading { - color: inherit; -} - -a.list-group-item.active .list-group-item-text, -a.list-group-item.active:hover .list-group-item-text, -a.list-group-item.active:focus .list-group-item-text { - color: #e1edf7; -} - -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px; -} - -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3; -} - -.panel { - margin-bottom: 20px; - background-color: #ffffff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); -} - -.panel-body { - padding: 15px; -} - -.panel-body:before, -.panel-body:after { - display: table; - content: " "; -} - -.panel-body:after { - clear: both; -} - -.panel-body:before, -.panel-body:after { - display: table; - content: " "; -} - -.panel-body:after { - clear: both; -} - -.panel > .list-group { - margin-bottom: 0; -} - -.panel > .list-group .list-group-item { - border-width: 1px 0; -} - -.panel > .list-group .list-group-item:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0; -} - -.panel > .list-group .list-group-item:last-child { - border-bottom: 0; -} - -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} - -.panel > .table, -.panel > .table-responsive > .table { - margin-bottom: 0; -} - -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive { - border-top: 1px solid #dddddd; -} - -.panel > .table > tbody:first-child th, -.panel > .table > tbody:first-child td { - border-top: 0; -} - -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} - -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} - -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} - -.panel > .table-bordered > thead > tr:last-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-bordered > thead > tr:last-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; -} - -.panel > .table-responsive { - margin-bottom: 0; - border: 0; -} - -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} - -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} - -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} - -.panel-title > a { - color: inherit; -} - -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #dddddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} - -.panel-group .panel { - margin-bottom: 0; - overflow: hidden; - border-radius: 4px; -} - -.panel-group .panel + .panel { - margin-top: 5px; -} - -.panel-group .panel-heading { - border-bottom: 0; -} - -.panel-group .panel-heading + .panel-collapse .panel-body { - border-top: 1px solid #dddddd; -} - -.panel-group .panel-footer { - border-top: 0; -} - -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #dddddd; -} - -.panel-default { - border-color: #dddddd; -} - -.panel-default > .panel-heading { - color: #333333; - background-color: #f5f5f5; - border-color: #dddddd; -} - -.panel-default > .panel-heading + .panel-collapse .panel-body { - border-top-color: #dddddd; -} - -.panel-default > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #dddddd; -} - -.panel-primary { - border-color: #428bca; -} - -.panel-primary > .panel-heading { - color: #ffffff; - background-color: #428bca; - border-color: #428bca; -} - -.panel-primary > .panel-heading + .panel-collapse .panel-body { - border-top-color: #428bca; -} - -.panel-primary > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #428bca; -} - -.panel-success { - border-color: #d6e9c6; -} - -.panel-success > .panel-heading { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} - -.panel-success > .panel-heading + .panel-collapse .panel-body { - border-top-color: #d6e9c6; -} - -.panel-success > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #d6e9c6; -} - -.panel-warning { - border-color: #faebcc; -} - -.panel-warning > .panel-heading { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} - -.panel-warning > .panel-heading + .panel-collapse .panel-body { - border-top-color: #faebcc; -} - -.panel-warning > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #faebcc; -} - -.panel-danger { - border-color: #ebccd1; -} - -.panel-danger > .panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} - -.panel-danger > .panel-heading + .panel-collapse .panel-body { - border-top-color: #ebccd1; -} - -.panel-danger > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #ebccd1; -} - -.panel-info { - border-color: #bce8f1; -} - -.panel-info > .panel-heading { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} - -.panel-info > .panel-heading + .panel-collapse .panel-body { - border-top-color: #bce8f1; -} - -.panel-info > .panel-footer + .panel-collapse .panel-body { - border-bottom-color: #bce8f1; -} - -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} - -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} - -.well-lg { - padding: 24px; - border-radius: 6px; -} - -.well-sm { - padding: 9px; - border-radius: 3px; -} - -.close { - float: right; - font-size: 21px; - font-weight: bold; - line-height: 1; - color: #000000; - text-shadow: 0 1px 0 #ffffff; - opacity: 0.2; - filter: alpha(opacity=20); -} - -.close:hover, -.close:focus { - color: #000000; - text-decoration: none; - cursor: pointer; - opacity: 0.5; - filter: alpha(opacity=50); -} - -button.close { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} - -.modal-open { - overflow: hidden; -} - -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - display: none; - overflow: auto; - overflow-y: scroll; -} - -.modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - transform: translate(0, -25%); - -webkit-transition: -webkit-transform 0.3s ease-out; - -moz-transition: -moz-transform 0.3s ease-out; - -o-transition: -o-transform 0.3s ease-out; - transition: transform 0.3s ease-out; -} - -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); -} - -.modal-dialog { - position: relative; - z-index: 1050; - width: auto; - margin: 10px; -} - -.modal-content { - position: relative; - background-color: #ffffff; - border: 1px solid #999999; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 6px; - outline: none; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - background-clip: padding-box; -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1030; - background-color: #000000; -} - -.modal-backdrop.fade { - opacity: 0; - filter: alpha(opacity=0); -} - -.modal-backdrop.in { - opacity: 0.5; - filter: alpha(opacity=50); -} - -.modal-header { - min-height: 16.428571429px; - padding: 15px; - border-bottom: 1px solid #e5e5e5; -} - -.modal-header .close { - margin-top: -2px; -} - -.modal-title { - margin: 0; - line-height: 1.428571429; -} - -.modal-body { - position: relative; - padding: 20px; -} - -.modal-footer { - padding: 19px 20px 20px; - margin-top: 15px; - text-align: right; - border-top: 1px solid #e5e5e5; -} - -.modal-footer:before, -.modal-footer:after { - display: table; - content: " "; -} - -.modal-footer:after { - clear: both; -} - -.modal-footer:before, -.modal-footer:after { - display: table; - content: " "; -} - -.modal-footer:after { - clear: both; -} - -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px; -} - -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} - -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} - -@media screen and (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - } -} - -.tooltip { - position: absolute; - z-index: 1030; - display: block; - font-size: 12px; - line-height: 1.4; - opacity: 0; - filter: alpha(opacity=0); - visibility: visible; -} - -.tooltip.in { - opacity: 0.9; - filter: alpha(opacity=90); -} - -.tooltip.top { - padding: 5px 0; - margin-top: -3px; -} - -.tooltip.right { - padding: 0 5px; - margin-left: 3px; -} - -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px; -} - -.tooltip.left { - padding: 0 5px; - margin-left: -3px; -} - -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - border-radius: 4px; -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-top-color: #000000; - border-width: 5px 5px 0; -} - -.tooltip.top-left .tooltip-arrow { - bottom: 0; - left: 5px; - border-top-color: #000000; - border-width: 5px 5px 0; -} - -.tooltip.top-right .tooltip-arrow { - right: 5px; - bottom: 0; - border-top-color: #000000; - border-width: 5px 5px 0; -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-right-color: #000000; - border-width: 5px 5px 5px 0; -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-left-color: #000000; - border-width: 5px 0 5px 5px; -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-bottom-color: #000000; - border-width: 0 5px 5px; -} - -.tooltip.bottom-left .tooltip-arrow { - top: 0; - left: 5px; - border-bottom-color: #000000; - border-width: 0 5px 5px; -} - -.tooltip.bottom-right .tooltip-arrow { - top: 0; - right: 5px; - border-bottom-color: #000000; - border-width: 0 5px 5px; -} - -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1010; - display: none; - max-width: 276px; - padding: 1px; - text-align: left; - white-space: normal; - background-color: #ffffff; - border: 1px solid #cccccc; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - background-clip: padding-box; -} - -.popover.top { - margin-top: -10px; -} - -.popover.right { - margin-left: 10px; -} - -.popover.bottom { - margin-top: 10px; -} - -.popover.left { - margin-left: -10px; -} - -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - font-weight: normal; - line-height: 18px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0; -} - -.popover-content { - padding: 9px 14px; -} - -.popover .arrow, -.popover .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} - -.popover .arrow { - border-width: 11px; -} - -.popover .arrow:after { - border-width: 10px; - content: ""; -} - -.popover.top .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999999; - border-top-color: rgba(0, 0, 0, 0.25); - border-bottom-width: 0; -} - -.popover.top .arrow:after { - bottom: 1px; - margin-left: -10px; - border-top-color: #ffffff; - border-bottom-width: 0; - content: " "; -} - -.popover.right .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999999; - border-right-color: rgba(0, 0, 0, 0.25); - border-left-width: 0; -} - -.popover.right .arrow:after { - bottom: -10px; - left: 1px; - border-right-color: #ffffff; - border-left-width: 0; - content: " "; -} - -.popover.bottom .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-bottom-color: #999999; - border-bottom-color: rgba(0, 0, 0, 0.25); - border-top-width: 0; -} - -.popover.bottom .arrow:after { - top: 1px; - margin-left: -10px; - border-bottom-color: #ffffff; - border-top-width: 0; - content: " "; -} - -.popover.left .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-left-color: #999999; - border-left-color: rgba(0, 0, 0, 0.25); - border-right-width: 0; -} - -.popover.left .arrow:after { - right: 1px; - bottom: -10px; - border-left-color: #ffffff; - border-right-width: 0; - content: " "; -} - -.carousel { - position: relative; -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; -} - -.carousel-inner > .item { - position: relative; - display: none; - -webkit-transition: 0.6s ease-in-out left; - transition: 0.6s ease-in-out left; -} - -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - display: block; - height: auto; - max-width: 100%; - line-height: 1; -} - -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} - -.carousel-inner > .active { - left: 0; -} - -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} - -.carousel-inner > .next { - left: 100%; -} - -.carousel-inner > .prev { - left: -100%; -} - -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} - -.carousel-inner > .active.left { - left: -100%; -} - -.carousel-inner > .active.right { - left: 100%; -} - -.carousel-control { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 15%; - font-size: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); - opacity: 0.5; - filter: alpha(opacity=50); -} - -.carousel-control.left { - background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); -} - -.carousel-control.right { - right: 0; - left: auto; - background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); - background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); -} - -.carousel-control:hover, -.carousel-control:focus { - color: #ffffff; - text-decoration: none; - outline: none; - opacity: 0.9; - filter: alpha(opacity=90); -} - -.carousel-control .icon-prev, -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-left, -.carousel-control .glyphicon-chevron-right { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block; -} - -.carousel-control .icon-prev, -.carousel-control .glyphicon-chevron-left { - left: 50%; -} - -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-right { - right: 50%; -} - -.carousel-control .icon-prev, -.carousel-control .icon-next { - width: 20px; - height: 20px; - margin-top: -10px; - margin-left: -10px; - font-family: serif; -} - -.carousel-control .icon-prev:before { - content: '\2039'; -} - -.carousel-control .icon-next:before { - content: '\203a'; -} - -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - padding-left: 0; - margin-left: -30%; - text-align: center; - list-style: none; -} - -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); - border: 1px solid #ffffff; - border-radius: 10px; -} - -.carousel-indicators .active { - width: 12px; - height: 12px; - margin: 0; - background-color: #ffffff; -} - -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #ffffff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); -} - -.carousel-caption .btn { - text-shadow: none; -} - -@media screen and (min-width: 768px) { - .carousel-control .glyphicons-chevron-left, - .carousel-control .glyphicons-chevron-right, - .carousel-control .icon-prev, - .carousel-control .icon-next { - width: 30px; - height: 30px; - margin-top: -15px; - margin-left: -15px; - font-size: 30px; - } - .carousel-caption { - right: 20%; - left: 20%; - padding-bottom: 30px; - } - .carousel-indicators { - bottom: 20px; - } -} - -.clearfix:before, -.clearfix:after { - display: table; - content: " "; -} - -.clearfix:after { - clear: both; -} - -.center-block { - display: block; - margin-right: auto; - margin-left: auto; -} - -.pull-right { - float: right !important; -} - -.pull-left { - float: left !important; -} - -.hide { - display: none !important; -} - -.show { - display: block !important; -} - -.invisible { - visibility: hidden; -} - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - -.hidden { - display: none !important; - visibility: hidden !important; -} - -.affix { - position: fixed; -} - -@-ms-viewport { - width: device-width; -} - -.visible-xs, -tr.visible-xs, -th.visible-xs, -td.visible-xs { - display: none !important; -} - -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-xs.visible-sm { - display: block !important; - } - table.visible-xs.visible-sm { - display: table; - } - tr.visible-xs.visible-sm { - display: table-row !important; - } - th.visible-xs.visible-sm, - td.visible-xs.visible-sm { - display: table-cell !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-xs.visible-md { - display: block !important; - } - table.visible-xs.visible-md { - display: table; - } - tr.visible-xs.visible-md { - display: table-row !important; - } - th.visible-xs.visible-md, - td.visible-xs.visible-md { - display: table-cell !important; - } -} - -@media (min-width: 1200px) { - .visible-xs.visible-lg { - display: block !important; - } - table.visible-xs.visible-lg { - display: table; - } - tr.visible-xs.visible-lg { - display: table-row !important; - } - th.visible-xs.visible-lg, - td.visible-xs.visible-lg { - display: table-cell !important; - } -} - -.visible-sm, -tr.visible-sm, -th.visible-sm, -td.visible-sm { - display: none !important; -} - -@media (max-width: 767px) { - .visible-sm.visible-xs { - display: block !important; - } - table.visible-sm.visible-xs { - display: table; - } - tr.visible-sm.visible-xs { - display: table-row !important; - } - th.visible-sm.visible-xs, - td.visible-sm.visible-xs { - display: table-cell !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-sm.visible-md { - display: block !important; - } - table.visible-sm.visible-md { - display: table; - } - tr.visible-sm.visible-md { - display: table-row !important; - } - th.visible-sm.visible-md, - td.visible-sm.visible-md { - display: table-cell !important; - } -} - -@media (min-width: 1200px) { - .visible-sm.visible-lg { - display: block !important; - } - table.visible-sm.visible-lg { - display: table; - } - tr.visible-sm.visible-lg { - display: table-row !important; - } - th.visible-sm.visible-lg, - td.visible-sm.visible-lg { - display: table-cell !important; - } -} - -.visible-md, -tr.visible-md, -th.visible-md, -td.visible-md { - display: none !important; -} - -@media (max-width: 767px) { - .visible-md.visible-xs { - display: block !important; - } - table.visible-md.visible-xs { - display: table; - } - tr.visible-md.visible-xs { - display: table-row !important; - } - th.visible-md.visible-xs, - td.visible-md.visible-xs { - display: table-cell !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-md.visible-sm { - display: block !important; - } - table.visible-md.visible-sm { - display: table; - } - tr.visible-md.visible-sm { - display: table-row !important; - } - th.visible-md.visible-sm, - td.visible-md.visible-sm { - display: table-cell !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} - -@media (min-width: 1200px) { - .visible-md.visible-lg { - display: block !important; - } - table.visible-md.visible-lg { - display: table; - } - tr.visible-md.visible-lg { - display: table-row !important; - } - th.visible-md.visible-lg, - td.visible-md.visible-lg { - display: table-cell !important; - } -} - -.visible-lg, -tr.visible-lg, -th.visible-lg, -td.visible-lg { - display: none !important; -} - -@media (max-width: 767px) { - .visible-lg.visible-xs { - display: block !important; - } - table.visible-lg.visible-xs { - display: table; - } - tr.visible-lg.visible-xs { - display: table-row !important; - } - th.visible-lg.visible-xs, - td.visible-lg.visible-xs { - display: table-cell !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-lg.visible-sm { - display: block !important; - } - table.visible-lg.visible-sm { - display: table; - } - tr.visible-lg.visible-sm { - display: table-row !important; - } - th.visible-lg.visible-sm, - td.visible-lg.visible-sm { - display: table-cell !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-lg.visible-md { - display: block !important; - } - table.visible-lg.visible-md { - display: table; - } - tr.visible-lg.visible-md { - display: table-row !important; - } - th.visible-lg.visible-md, - td.visible-lg.visible-md { - display: table-cell !important; - } -} - -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} - -.hidden-xs { - display: block !important; -} - -table.hidden-xs { - display: table; -} - -tr.hidden-xs { - display: table-row !important; -} - -th.hidden-xs, -td.hidden-xs { - display: table-cell !important; -} - -@media (max-width: 767px) { - .hidden-xs, - tr.hidden-xs, - th.hidden-xs, - td.hidden-xs { - display: none !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-xs.hidden-sm, - tr.hidden-xs.hidden-sm, - th.hidden-xs.hidden-sm, - td.hidden-xs.hidden-sm { - display: none !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-xs.hidden-md, - tr.hidden-xs.hidden-md, - th.hidden-xs.hidden-md, - td.hidden-xs.hidden-md { - display: none !important; - } -} - -@media (min-width: 1200px) { - .hidden-xs.hidden-lg, - tr.hidden-xs.hidden-lg, - th.hidden-xs.hidden-lg, - td.hidden-xs.hidden-lg { - display: none !important; - } -} - -.hidden-sm { - display: block !important; -} - -table.hidden-sm { - display: table; -} - -tr.hidden-sm { - display: table-row !important; -} - -th.hidden-sm, -td.hidden-sm { - display: table-cell !important; -} - -@media (max-width: 767px) { - .hidden-sm.hidden-xs, - tr.hidden-sm.hidden-xs, - th.hidden-sm.hidden-xs, - td.hidden-sm.hidden-xs { - display: none !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm, - tr.hidden-sm, - th.hidden-sm, - td.hidden-sm { - display: none !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-sm.hidden-md, - tr.hidden-sm.hidden-md, - th.hidden-sm.hidden-md, - td.hidden-sm.hidden-md { - display: none !important; - } -} - -@media (min-width: 1200px) { - .hidden-sm.hidden-lg, - tr.hidden-sm.hidden-lg, - th.hidden-sm.hidden-lg, - td.hidden-sm.hidden-lg { - display: none !important; - } -} - -.hidden-md { - display: block !important; -} - -table.hidden-md { - display: table; -} - -tr.hidden-md { - display: table-row !important; -} - -th.hidden-md, -td.hidden-md { - display: table-cell !important; -} - -@media (max-width: 767px) { - .hidden-md.hidden-xs, - tr.hidden-md.hidden-xs, - th.hidden-md.hidden-xs, - td.hidden-md.hidden-xs { - display: none !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-md.hidden-sm, - tr.hidden-md.hidden-sm, - th.hidden-md.hidden-sm, - td.hidden-md.hidden-sm { - display: none !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md, - tr.hidden-md, - th.hidden-md, - td.hidden-md { - display: none !important; - } -} - -@media (min-width: 1200px) { - .hidden-md.hidden-lg, - tr.hidden-md.hidden-lg, - th.hidden-md.hidden-lg, - td.hidden-md.hidden-lg { - display: none !important; - } -} - -.hidden-lg { - display: block !important; -} - -table.hidden-lg { - display: table; -} - -tr.hidden-lg { - display: table-row !important; -} - -th.hidden-lg, -td.hidden-lg { - display: table-cell !important; -} - -@media (max-width: 767px) { - .hidden-lg.hidden-xs, - tr.hidden-lg.hidden-xs, - th.hidden-lg.hidden-xs, - td.hidden-lg.hidden-xs { - display: none !important; - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-lg.hidden-sm, - tr.hidden-lg.hidden-sm, - th.hidden-lg.hidden-sm, - td.hidden-lg.hidden-sm { - display: none !important; - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-lg.hidden-md, - tr.hidden-lg.hidden-md, - th.hidden-lg.hidden-md, - td.hidden-lg.hidden-md { - display: none !important; - } -} - -@media (min-width: 1200px) { - .hidden-lg, - tr.hidden-lg, - th.hidden-lg, - td.hidden-lg { - display: none !important; - } -} - -.visible-print, -tr.visible-print, -th.visible-print, -td.visible-print { - display: none !important; -} - -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } - .hidden-print, - tr.hidden-print, - th.hidden-print, - td.hidden-print { - display: none !important; - } -} \ No newline at end of file diff --git a/docs/dist/css/bootstrap.min.css b/docs/dist/css/bootstrap.min.css deleted file mode 100644 index c547283..0000000 --- a/docs/dist/css/bootstrap.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.0.3 (http://getbootstrap.com) - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - */ - -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#8a6d3b}.text-warning:hover{color:#66512c}.text-danger{color:#a94442}.text-danger:hover{color:#843534}.text-success{color:#3c763d}.text-success:hover{color:#2b542c}.text-info{color:#31708f}.text-info:hover{color:#245269}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>.active,.table>tbody>tr>.active,.table>tfoot>tr>.active,.table>thead>.active>td,.table>tbody>.active>td,.table>tfoot>.active>td,.table>thead>.active>th,.table>tbody>.active>th,.table>tfoot>.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>.active:hover,.table-hover>tbody>.active:hover>td,.table-hover>tbody>.active:hover>th{background-color:#e8e8e8}.table>thead>tr>.success,.table>tbody>tr>.success,.table>tfoot>tr>.success,.table>thead>.success>td,.table>tbody>.success>td,.table>tfoot>.success>td,.table>thead>.success>th,.table>tbody>.success>th,.table>tfoot>.success>th{background-color:#dff0d8}.table-hover>tbody>tr>.success:hover,.table-hover>tbody>.success:hover>td,.table-hover>tbody>.success:hover>th{background-color:#d0e9c6}.table>thead>tr>.danger,.table>tbody>tr>.danger,.table>tfoot>tr>.danger,.table>thead>.danger>td,.table>tbody>.danger>td,.table>tfoot>.danger>td,.table>thead>.danger>th,.table>tbody>.danger>th,.table>tfoot>.danger>th{background-color:#f2dede}.table-hover>tbody>tr>.danger:hover,.table-hover>tbody>.danger:hover>td,.table-hover>tbody>.danger:hover>th{background-color:#ebcccc}.table>thead>tr>.warning,.table>tbody>tr>.warning,.table>tfoot>tr>.warning,.table>thead>.warning>td,.table>tbody>.warning>td,.table>tfoot>.warning>td,.table>thead>.warning>th,.table>tbody>.warning>th,.table>tfoot>.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>.warning:hover,.table-hover>tbody>.warning:hover>td,.table-hover>tbody>.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline select.form-control{width:auto}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#fff}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form select.form-control{width:auto}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child th,.panel>.table>tbody:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}table.hidden-xs{display:table}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}table.hidden-sm{display:table}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}table.hidden-md{display:table}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}table.hidden-lg{display:table}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/docs/dist/fonts/glyphicons-halflings-regular.eot b/docs/dist/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index 423bd5d..0000000 Binary files a/docs/dist/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/docs/dist/fonts/glyphicons-halflings-regular.svg b/docs/dist/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 4469488..0000000 --- a/docs/dist/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/dist/fonts/glyphicons-halflings-regular.ttf b/docs/dist/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index a498ef4..0000000 Binary files a/docs/dist/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/docs/dist/fonts/glyphicons-halflings-regular.woff b/docs/dist/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index d83c539..0000000 Binary files a/docs/dist/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/docs/dist/js/bootstrap.js b/docs/dist/js/bootstrap.js deleted file mode 100644 index 850e6e5..0000000 --- a/docs/dist/js/bootstrap.js +++ /dev/null @@ -1,2006 +0,0 @@ -/*! - * Bootstrap v3.0.3 (http://getbootstrap.com) - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - */ - -if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") } - -/* ======================================================================== - * Bootstrap: transition.js v3.0.3 - * http://getbootstrap.com/javascript/#transitions - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) - // ============================================================ - - function transitionEnd() { - var el = document.createElement('bootstrap') - - var transEndEventNames = { - 'WebkitTransition' : 'webkitTransitionEnd' - , 'MozTransition' : 'transitionend' - , 'OTransition' : 'oTransitionEnd otransitionend' - , 'transition' : 'transitionend' - } - - for (var name in transEndEventNames) { - if (el.style[name] !== undefined) { - return { end: transEndEventNames[name] } - } - } - } - - // http://blog.alexmaccaw.com/css-transitions - $.fn.emulateTransitionEnd = function (duration) { - var called = false, $el = this - $(this).one($.support.transition.end, function () { called = true }) - var callback = function () { if (!called) $($el).trigger($.support.transition.end) } - setTimeout(callback, duration) - return this - } - - $(function () { - $.support.transition = transitionEnd() - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: alert.js v3.0.3 - * http://getbootstrap.com/javascript/#alerts - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // ALERT CLASS DEFINITION - // ====================== - - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = $(selector) - - if (e) e.preventDefault() - - if (!$parent.length) { - $parent = $this.hasClass('alert') ? $this : $this.parent() - } - - $parent.trigger(e = $.Event('close.bs.alert')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - $parent.trigger('closed.bs.alert').remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent - .one($.support.transition.end, removeElement) - .emulateTransitionEnd(150) : - removeElement() - } - - - // ALERT PLUGIN DEFINITION - // ======================= - - var old = $.fn.alert - - $.fn.alert = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.alert.Constructor = Alert - - - // ALERT NO CONFLICT - // ================= - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - // ALERT DATA-API - // ============== - - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: button.js v3.0.3 - * http://getbootstrap.com/javascript/#buttons - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - } - - Button.DEFAULTS = { - loadingText: 'loading...' - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state = state + 'Text' - - if (!data.resetText) $el.data('resetText', $el[val]()) - - $el[val](data[state] || this.options[state]) - - // push to event loop to allow forms to submit - setTimeout(function () { - state == 'loadingText' ? - $el.addClass(d).attr(d, d) : - $el.removeClass(d).removeAttr(d); - }, 0) - } - - Button.prototype.toggle = function () { - var $parent = this.$element.closest('[data-toggle="buttons"]') - var changed = true - - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') === 'radio') { - // see if clicking on current one - if ($input.prop('checked') && this.$element.hasClass('active')) - changed = false - else - $parent.find('.active').removeClass('active') - } - if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') - } - - if (changed) this.$element.toggleClass('active') - } - - - // BUTTON PLUGIN DEFINITION - // ======================== - - var old = $.fn.button - - $.fn.button = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.button', (data = new Button(this, options))) - - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - $.fn.button.Constructor = Button - - - // BUTTON NO CONFLICT - // ================== - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - // BUTTON DATA-API - // =============== - - $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - e.preventDefault() - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: carousel.js v3.0.3 - * http://getbootstrap.com/javascript/#carousel - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // CAROUSEL CLASS DEFINITION - // ========================= - - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.paused = - this.sliding = - this.interval = - this.$active = - this.$items = null - - this.options.pause == 'hover' && this.$element - .on('mouseenter', $.proxy(this.pause, this)) - .on('mouseleave', $.proxy(this.cycle, this)) - } - - Carousel.DEFAULTS = { - interval: 5000 - , pause: 'hover' - , wrap: true - } - - Carousel.prototype.cycle = function (e) { - e || (this.paused = false) - - this.interval && clearInterval(this.interval) - - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - - return this - } - - Carousel.prototype.getActiveIndex = function () { - this.$active = this.$element.find('.item.active') - this.$items = this.$active.parent().children() - - return this.$items.index(this.$active) - } - - Carousel.prototype.to = function (pos) { - var that = this - var activeIndex = this.getActiveIndex() - - if (pos > (this.$items.length - 1) || pos < 0) return - - if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) - if (activeIndex == pos) return this.pause().cycle() - - return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) - } - - Carousel.prototype.pause = function (e) { - e || (this.paused = true) - - if (this.$element.find('.next, .prev').length && $.support.transition.end) { - this.$element.trigger($.support.transition.end) - this.cycle(true) - } - - this.interval = clearInterval(this.interval) - - return this - } - - Carousel.prototype.next = function () { - if (this.sliding) return - return this.slide('next') - } - - Carousel.prototype.prev = function () { - if (this.sliding) return - return this.slide('prev') - } - - Carousel.prototype.slide = function (type, next) { - var $active = this.$element.find('.item.active') - var $next = next || $active[type]() - var isCycling = this.interval - var direction = type == 'next' ? 'left' : 'right' - var fallback = type == 'next' ? 'first' : 'last' - var that = this - - if (!$next.length) { - if (!this.options.wrap) return - $next = this.$element.find('.item')[fallback]() - } - - this.sliding = true - - isCycling && this.pause() - - var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) - - if ($next.hasClass('active')) return - - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - this.$element.one('slid.bs.carousel', function () { - var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) - $nextIndicator && $nextIndicator.addClass('active') - }) - } - - if ($.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - $active - .one($.support.transition.end, function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) - }) - .emulateTransitionEnd(600) - } else { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid.bs.carousel') - } - - isCycling && this.cycle() - - return this - } - - - // CAROUSEL PLUGIN DEFINITION - // ========================== - - var old = $.fn.carousel - - $.fn.carousel = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.carousel') - var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) - var action = typeof option == 'string' ? option : options.slide - - if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() - }) - } - - $.fn.carousel.Constructor = Carousel - - - // CAROUSEL NO CONFLICT - // ==================== - - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } - - - // CAROUSEL DATA-API - // ================= - - $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { - var $this = $(this), href - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - var options = $.extend({}, $target.data(), $this.data()) - var slideIndex = $this.attr('data-slide-to') - if (slideIndex) options.interval = false - - $target.carousel(options) - - if (slideIndex = $this.attr('data-slide-to')) { - $target.data('bs.carousel').to(slideIndex) - } - - e.preventDefault() - }) - - $(window).on('load', function () { - $('[data-ride="carousel"]').each(function () { - var $carousel = $(this) - $carousel.carousel($carousel.data()) - }) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: collapse.js v3.0.3 - * http://getbootstrap.com/javascript/#collapse - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // COLLAPSE PUBLIC CLASS DEFINITION - // ================================ - - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Collapse.DEFAULTS, options) - this.transitioning = null - - if (this.options.parent) this.$parent = $(this.options.parent) - if (this.options.toggle) this.toggle() - } - - Collapse.DEFAULTS = { - toggle: true - } - - Collapse.prototype.dimension = function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - Collapse.prototype.show = function () { - if (this.transitioning || this.$element.hasClass('in')) return - - var startEvent = $.Event('show.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - var actives = this.$parent && this.$parent.find('> .panel > .in') - - if (actives && actives.length) { - var hasData = actives.data('bs.collapse') - if (hasData && hasData.transitioning) return - actives.collapse('hide') - hasData || actives.data('bs.collapse', null) - } - - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - .addClass('collapsing') - [dimension](0) - - this.transitioning = 1 - - var complete = function () { - this.$element - .removeClass('collapsing') - .addClass('in') - [dimension]('auto') - this.transitioning = 0 - this.$element.trigger('shown.bs.collapse') - } - - if (!$.support.transition) return complete.call(this) - - var scrollSize = $.camelCase(['scroll', dimension].join('-')) - - this.$element - .one($.support.transition.end, $.proxy(complete, this)) - .emulateTransitionEnd(350) - [dimension](this.$element[0][scrollSize]) - } - - Collapse.prototype.hide = function () { - if (this.transitioning || !this.$element.hasClass('in')) return - - var startEvent = $.Event('hide.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - var dimension = this.dimension() - - this.$element - [dimension](this.$element[dimension]()) - [0].offsetHeight - - this.$element - .addClass('collapsing') - .removeClass('collapse') - .removeClass('in') - - this.transitioning = 1 - - var complete = function () { - this.transitioning = 0 - this.$element - .trigger('hidden.bs.collapse') - .removeClass('collapsing') - .addClass('collapse') - } - - if (!$.support.transition) return complete.call(this) - - this.$element - [dimension](0) - .one($.support.transition.end, $.proxy(complete, this)) - .emulateTransitionEnd(350) - } - - Collapse.prototype.toggle = function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - - // COLLAPSE PLUGIN DEFINITION - // ========================== - - var old = $.fn.collapse - - $.fn.collapse = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.collapse') - var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) - - if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.collapse.Constructor = Collapse - - - // COLLAPSE NO CONFLICT - // ==================== - - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } - - - // COLLAPSE DATA-API - // ================= - - $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { - var $this = $(this), href - var target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - var $target = $(target) - var data = $target.data('bs.collapse') - var option = data ? 'toggle' : $this.data() - var parent = $this.attr('data-parent') - var $parent = parent && $(parent) - - if (!data || !data.transitioning) { - if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') - $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') - } - - $target.collapse(option) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: dropdown.js v3.0.3 - * http://getbootstrap.com/javascript/#dropdowns - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // DROPDOWN CLASS DEFINITION - // ========================= - - var backdrop = '.dropdown-backdrop' - var toggle = '[data-toggle=dropdown]' - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle) - } - - Dropdown.prototype.toggle = function (e) { - var $this = $(this) - - if ($this.is('.disabled, :disabled')) return - - var $parent = getParent($this) - var isActive = $parent.hasClass('open') - - clearMenus() - - if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $(' - - - - - - - - - - - - - - - - diff --git a/docs/howto/geolite.html b/docs/howto/geolite.html deleted file mode 100644 index c39b954..0000000 --- a/docs/howto/geolite.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
-

Loading MaxMind Geolite Data with pgloader

The MaxMind provides a free dataset for geolocation, which is quite popular. Using pgloader you can download the lastest version of it, extract the CSV files from the archive and load their content into your database directly.

The Command

To load data with pgloader you need to define in a command the operations in some details. Here's our example for loading the Geolite data:

/*  
- * Loading from a ZIP archive containing CSV files. The full test can be  
- * done with using the archive found at  
- * http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip  
- *  
- * And a very light version of this data set is found at  
- * http://pgsql.tapoueh.org/temp/foo.zip for quick testing.  
- */  
- 
-LOAD ARCHIVE  
-   FROM http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip  
-   INTO postgresql:///ip4r  
- 
-   BEFORE LOAD DO  
-     $$ create extension if not exists ip4r; $$,  
-     $$ create schema if not exists geolite; $$,  
-     $$ create table if not exists geolite.location  
-       (  
-          locid      integer primary key,  
-          country    text,  
-          region     text,  
-          city       text,  
-          postalcode text,  
-          location   point,  
-          metrocode  text,  
-          areacode   text  
-       );  
-     $$,  
-     $$ create table if not exists geolite.blocks  
-       (  
-          iprange    ip4r,  
-          locid      integer  
-       );  
-     $$,  
-     $$ drop index if exists geolite.blocks_ip4r_idx; $$,  
-     $$ truncate table geolite.blocks, geolite.location cascade; $$  
- 
-   LOAD CSV  
-        FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/  
-             WITH ENCODING iso-8859-1  
-             (  
-                locId,  
-                country,  
-                region     null if blanks,  
-                city       null if blanks,  
-                postalCode null if blanks,  
-                latitude,  
-                longitude,  
-                metroCode  null if blanks,  
-                areaCode   null if blanks  
-             )  
-        INTO postgresql:///ip4r?geolite.location  
-             (  
-                locid,country,region,city,postalCode,  
-                location point using (format nil "(~a,~a)" longitude latitude),  
-                metroCode,areaCode  
-             )  
-        WITH skip header = 2,  
-             fields optionally enclosed by '"',  
-             fields escaped by double-quote,  
-             fields terminated by ','  
- 
-  AND LOAD CSV  
-        FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/  
-             WITH ENCODING iso-8859-1  
-             (  
-                startIpNum, endIpNum, locId  
-             )  
-        INTO postgresql:///ip4r?geolite.blocks  
-             (  
-                iprange ip4r using (ip-range startIpNum endIpNum),  
-                locId  
-             )  
-        WITH skip header = 2,  
-             fields optionally enclosed by '"',  
-             fields escaped by double-quote,  
-             fields terminated by ','  
- 
-   FINALLY DO  
-     $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$; 

You can see the full list of options in the pgloader reference manual, with a complete description of the options you see here.

Note that while the Geolite data is using a pair of integers (start, end) to represent ipv4 data, we use the very poweful ip4r PostgreSQL Extension instead.

The transformation from a pair of integers into an IP is done dynamically by the pgloader process.

Also, the location is given as a pair of float columns for the longitude and the latitude where PostgreSQL offers the point datatype, so the pgloader command here will actually transform the data on the fly to use the appropriate data type and its input representation.

Loading the data

Here's how to start loading the data. Note that the ouput here has been edited so as to facilitate its browsing online.

$ pgloader archive.load  
-... LOG Starting pgloader, log system is ready.  
-... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/archive.load"  
-... LOG Fetching 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity_CSV/GeoLiteCity-latest.zip'  
-... LOG Extracting files from archive '//private/var/folders/w7/9n8v8pw54t1gngfff0lj16040000gn/T/pgloader//GeoLiteCity-latest.zip'  
- 
-       table name       read   imported     errors            time  
------------------  ---------  ---------  ---------  --------------  
-         download          0          0          0         11.592s  
-          extract          0          0          0          1.012s  
-      before load          6          6          0          0.019s  
------------------  ---------  ---------  ---------  --------------  
- geolite.location     470387     470387          0          7.743s  
-   geolite.blocks    1903155    1903155          0         16.332s  
------------------  ---------  ---------  ---------  --------------  
-          finally          1          1          0         31.692s  
------------------  ---------  ---------  ---------  --------------  
-Total import time    2373542    2373542          0        1m8.390s 

The timing of course includes the transformation of the 1.9 million pairs of integer into a single ipv4 range each. The finally step consists of creating the GiST specialized index as given in the main command:

CREATE INDEX blocks_ip4r_idx ON geolite.blocks USING gist(iprange); 

That index will then be used to speed up queries wanting to find which recorded geolocation contains a specific IP address:

ip4r> select *  
-        from      geolite.location l  
-             join geolite.blocks b using(locid)  
-       where iprange >>= '8.8.8.8';  
- 
--[ RECORD 1 ]------------------  
-locid      | 223  
-country    | US  
-region     |  
-city       |  
-postalcode |  
-location   | (-97,38)  
-metrocode  |  
-areacode   |  
-iprange    | 8.8.8.8-8.8.37.255  
- 
-Time: 0.747 ms 
-
-
- - - - -
- - - - - - - - - - - diff --git a/docs/howto/header.html b/docs/howto/header.html deleted file mode 100644 index 2ba4094..0000000 --- a/docs/howto/header.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
diff --git a/docs/howto/mysql.html b/docs/howto/mysql.html deleted file mode 100644 index dcaea15..0000000 --- a/docs/howto/mysql.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
-

Migrating from MySQL to PostgreSQL

If you want to migrate your data over to PostgreSQL from MySQL then pgloader is the tool of choice!

Most tools around are skipping the main problem with migrating from MySQL, which is to do with the type casting and data sanitizing that needs to be done. pgloader will not leave you alone on those topics.

In a Single Command Line

As an example, we will use the f1db database from which which provides a historical record of motor racing data for non-commercial purposes. You can either use their API or download the whole database at http://ergast.com/downloads/f1db.sql.gz. Once you've done that load the database in MySQL:

$ mysql -u root  
-> create database f1db;  
-> source f1db.sql 

Now let's migrate this database into PostgreSQL in a single command line:

$ createdb f1db  
-$ pgloader mysql://root@localhost/f1db pgsql:///f1db 

Done! All with schema, table definitions, constraints, indexes, primary keys, auto_increment columns turned into bigserial , foreign keys, comments, and if you had some MySQL default values such as ON UPDATE CURRENT_TIMESTAMP they would have been translated to a PostgreSQL before update trigger automatically.

$ pgloader mysql://root@localhost/f1db pgsql:///f1db  
-2017-06-16T08:56:14.064000+02:00 LOG Main logs in '/private/tmp/pgloader/pgloader.log'  
-2017-06-16T08:56:14.068000+02:00 LOG Data errors in '/private/tmp/pgloader/'  
-2017-06-16T08:56:19.542000+02:00 LOG report summary reset  
-               table name       read   imported     errors      total time  
--------------------------  ---------  ---------  ---------  --------------  
-          fetch meta data         33         33          0          0.365s  
-           Create Schemas          0          0          0          0.007s  
-         Create SQL Types          0          0          0          0.006s  
-            Create tables         26         26          0          0.068s  
-           Set Table OIDs         13         13          0          0.012s  
--------------------------  ---------  ---------  ---------  --------------  
-  f1db.constructorresults      11011      11011          0          0.205s  
-            f1db.circuits         73         73          0          0.150s  
-        f1db.constructors        208        208          0          0.059s  
-f1db.constructorstandings      11766      11766          0          0.365s  
-             f1db.drivers        841        841          0          0.268s  
-            f1db.laptimes     413578     413578          0          2.892s  
-     f1db.driverstandings      31420      31420          0          0.583s  
-            f1db.pitstops       5796       5796          0          2.154s  
-               f1db.races        976        976          0          0.227s  
-          f1db.qualifying       7257       7257          0          0.228s  
-             f1db.seasons         68         68          0          0.527s  
-             f1db.results      23514      23514          0          0.658s  
-              f1db.status        133        133          0          0.130s  
--------------------------  ---------  ---------  ---------  --------------  
-  COPY Threads Completion         39         39          0          4.303s  
-           Create Indexes         20         20          0          1.497s  
-   Index Build Completion         20         20          0          0.214s  
-          Reset Sequences          0         10          0          0.058s  
-             Primary Keys         13         13          0          0.012s  
-      Create Foreign Keys          0          0          0          0.000s  
-          Create Triggers          0          0          0          0.001s  
-         Install Comments          0          0          0          0.000s  
--------------------------  ---------  ---------  ---------  --------------  
-        Total import time     506641     506641          0          5.547s 

You may need to have special cases to take care of tho, or views that you want to materialize while doing the migration. In advanced case you can use the pgloader command.

The Command

To load data with pgloader you need to define in a command the operations in some details. Here's our example for loading the MySQL Sakila Sample Database:

Here's our command:

load database  
-     from      mysql://root@localhost/sakila  
-     into postgresql:///sakila  
- 
- WITH include drop, create tables, no truncate,  
-      create indexes, reset sequences, foreign keys  
- 
-  SET maintenance_work_mem to '128MB', work_mem to '12MB', search_path to 'sakila'  
- 
- CAST type datetime to timestamptz  
-                drop default drop not null using zero-dates-to-null,  
-      type date drop not null drop default using zero-dates-to-null  
- 
- MATERIALIZE VIEWS film_list, staff_list  
- 
- -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'  
- -- EXCLUDING TABLE NAMES MATCHING ~<ory>  
- 
- BEFORE LOAD DO  
- $$ create schema if not exists sakila; $$; 

You can see the full list of options in the pgloader reference manual, with a complete description of the options you see here.

Note that here pgloader will benefit from the meta-data information found in the MySQL database to create a PostgreSQL database capable of hosting the data as described, then load the data.

In particular, some specific casting rules are given here, to cope with date values such as 0000-00-00 that MySQL allows and PostgreSQL rejects for not existing in our calendar. It's possible to add per-column casting rules too, which is useful is some of your tinyint are in fact smallint while some others are in fact boolean values.

Finaly note that we are using the MATERIALIZE VIEWS clause of pgloader: the selected views here will be migrated over to PostgreSQL with their contents.

It's possible to use the MATERIALIZE VIEWS clause and give both the name and the SQL (in MySQL dialect) definition of view, then pgloader creates the view before loading the data, then drops it again at the end.

Loading the data

Let's start the pgloader command with our sakila.load command file:

$ pgloader sakila.load  
-... LOG Starting pgloader, log system is ready.  
-... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sakila.load"  
-   <WARNING: table "xxx" does not exists have been edited away>  
- 
-            table name       read   imported     errors            time  
-----------------------  ---------  ---------  ---------  --------------  
-           before load          1          1          0          0.007s  
-       fetch meta data         45         45          0          0.402s  
-          create, drop          0         36          0          0.208s  
-----------------------  ---------  ---------  ---------  --------------  
-                 actor        200        200          0          0.071s  
-               address        603        603          0          0.035s  
-              category         16         16          0          0.018s  
-                  city        600        600          0          0.037s  
-               country        109        109          0          0.023s  
-              customer        599        599          0          0.073s  
-                  film       1000       1000          0          0.135s  
-            film_actor       5462       5462          0          0.236s  
-         film_category       1000       1000          0          0.070s  
-             film_text       1000       1000          0          0.080s  
-             inventory       4581       4581          0          0.136s  
-              language          6          6          0          0.036s  
-               payment      16049      16049          0          0.539s  
-                rental      16044      16044          0          0.648s  
-                 staff          2          2          0          0.041s  
-                 store          2          2          0          0.036s  
-             film_list        997        997          0          0.247s  
-            staff_list          2          2          0          0.135s  
-Index Build Completion          0          0          0          0.000s  
-----------------------  ---------  ---------  ---------  --------------  
-        Create Indexes         41         41          0          0.964s  
-       Reset Sequences          0          1          0          0.035s  
-          Foreign Keys         22         22          0          0.254s  
-----------------------  ---------  ---------  ---------  --------------  
-     Total import time      48272      48272          0          3.502s 

The WARNING messages we see here are expected as the PostgreSQL database is empty when running the command, and pgloader is using the SQL commands DROP TABLE IF EXISTS when the given command uses the include drop option.

Note that the output of the command has been edited to facilitate its browsing online.

-
-
- - - - -
- - - - - - - - - - - diff --git a/docs/howto/pgloader.1.html b/docs/howto/pgloader.1.html deleted file mode 100644 index a4cfc21..0000000 --- a/docs/howto/pgloader.1.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
-

pgloader(1) -- PostgreSQL data loader

SYNOPSIS

pgloader [<options>] [<command-file>]...  
-pgloader [<options>] SOURCE TARGET 

DESCRIPTION

pgloader loads data from various sources into PostgreSQL. It can transform the data it reads on the fly and submit raw SQL before and after the loading. It uses the COPY PostgreSQL protocol to stream the data into the server, and manages errors by filling a pair of reject.dat and reject.log files.

pgloader operates either using commands which are read from files:

pgloader commands.load 

or by using arguments and options all provided on the command line:

pgloader SOURCE TARGET 

ARGUMENTS

The pgloader arguments can be as many load files as needed, or a couple of connection strings to a specific input file.

SOURCE CONNECTION STRING

The source connection string format is as follows:

format:///absolute/path/to/file.ext  
-format://./relative/path/to/file.ext 

Where format might be one of csv, fixed, copy, dbf, db3 or ixf.

db://user:pass@host:port/dbname 

Where db might be of sqlite, mysql or mssql.

When using a file based source format, pgloader also support natively fetching the file from an http location and decompressing an archive if needed. In that case it's necessary to use the --type option to specify the expected format of the file. See the examples below.

Also note that some file formats require describing some implementation details such as columns to be read and delimiters and quoting when loading from csv.

For more complex loading scenarios, you will need to write a full fledge load command in the syntax described later in this document.

TARGET CONNECTION STRING

The target connection string format is described in details later in this document, see Section Connection String.

OPTIONS

INQUIRY OPTIONS

Use these options when you want to know more about how to use pgloader, as those options will cause pgloader not to load any data.

  • -h, --help: Show command usage summary and exit.

  • -V, --version: Show pgloader version string and exit.

  • -E, --list-encodings: List known encodings in this version of pgloader.

  • -U, --upgrade-config: Parse given files in the command line as pgloader.conf files with the INI syntax that was in use in pgloader versions 2.x, and output the new command syntax for pgloader on standard output.

GENERAL OPTIONS

Those options are meant to tweak pgloader behavior when loading data.

  • -v, --verbose: Be verbose.

  • -q, --quiet: Be quiet.

  • -d, --debug: Show debug level information messages.

  • -D, --root-dir: Set the root working directory (default to "/tmp/pgloader").

  • -L, --logfile: Set the pgloader log file (default to "/tmp/pgloader.log").

  • --log-min-messages: Minimum level of verbosity needed for log message to make it to the logfile. One of critical, log, error, warning, notice, info or debug.

  • --client-min-messages: Minimum level of verbosity needed for log message to make it to the console. One of critical, log, error, warning, notice, info or debug.

  • -S, --summary: A filename where to copy the summary output. When relative, the filename is expanded into *root-dir*.

  • The format of the filename defaults to being human readable. It is possible to have the output in machine friendly formats such as CSV, COPY (PostgreSQL's own COPY format) or JSON by specifying a filename with the extension resp. .csv, .copy or .json.

  • -l <file>, --load-lisp-file <file>: Specify a lisp to compile and load into the pgloader image before reading the commands, allowing to define extra transformation function. Those functions should be defined in the pgloader.transforms package. This option can appear more than once in the command line.

  • --dry-run:

    Allow testing a .load file without actually trying to load any data. It's useful to debug it until it's ok, in particular to fix connection strings.

  • --on-error-stop

    Alter pgloader behavior: rather than trying to be smart about error handling and continue loading good data, separating away the bad one, just stop as soon as PostgreSQL refuses anything sent to it. Useful to debug data processing, transformation function and specific type casting.

  • --self-upgrade <directory>:

    Specify a where to find pgloader sources so that one of the very first things it does is dynamically loading-in (and compiling to machine code) another version of itself, usually a newer one like a very recent git checkout.

COMMAND LINE ONLY OPERATIONS

Those options are meant to be used when using pgloader from the command line only, rather than using a command file and the rich command clauses and parser. In simple cases, it can be much easier to use the SOURCE and TARGET directly on the command line, then tweak the loading with those options:

  • --with "option":

    Allows setting options from the command line. You can use that option as many times as you want. The option arguments must follow the WITH clause for the source type of the SOURCE specification, as described later in this document.

  • --set "guc_name='value'"

    Allows setting PostgreSQL configuration from the command line. Note that the option parsing is the same as when used from the SET command clause, in particular you must enclose the guc value with single-quotes.

  • --field "..."

    Allows setting a source field definition. Fields are accumulated in the order given on the command line. It's possible to either use a --field option per field in the source file, or to separate field definitions by a comma, as you would do in the HAVING FIELDS clause.

  • --cast "..."

    Allows setting a specific casting rule for loading the data.

  • --type csv|fixed|db3|ixf|sqlite|mysql|mssql

    Allows forcing the source type, in case when the SOURCE parsing isn't satisfying.

  • --encoding <encoding>

    Set the encoding of the source file to load data from.

  • --before <filename>

    Parse given filename for SQL queries and run them against the target database before loading the data from the source. The queries are parsed by pgloader itself: they need to be terminated by a semi-colon (;) and the file may include \i or \ir commands to include another file.

  • --after <filename>

    Parse given filename for SQL queries and run them against the target database after having loaded the data from the source. The queries are parsed in the same way as with the --before option, see above.

MORE DEBUG INFORMATION

To get the maximum amount of debug information, you can use both the --verbose and the --debug switches at the same time, which is equivalent to saying --client-min-messages data. Then the log messages will show the data being processed, in the cases where the code has explicit support for it.

USAGE EXAMPLES

Review the command line options and pgloader's version:

pgloader --help  
-pgloader --version 

Loading from a complex command

Use the command file as the pgloader command argument, pgloader will parse that file and execute the commands found in it:

pgloader --verbose ./test/csv-districts.load 

CSV

Load data from a CSV file into a pre-existing table in your database, having pgloader guess the CSV properties (separator, quote and escape character):

pgloader ./test/data/matching-1.csv pgsql:///pgloader?tablename=matching 

Load data from a CSV file into a pre-existing table in your database, with expanded options:

pgloader --type csv                                   \  
-         --field id --field field                     \  
-         --with truncate                              \  
-         --with "fields terminated by ','"            \  
-         ./test/data/matching-1.csv                   \  
-         postgres:///pgloader?tablename=matching 

In that example the whole loading is driven from the command line, bypassing the need for writing a command in the pgloader command syntax entirely. As there's no command though, the extra inforamtion needed must be provided on the command line using the --type and --field and --with switches.

For documentation about the available syntaxes for the --field and --with switches, please refer to the CSV section later in the man page.

Note also that the PostgreSQL URI includes the target tablename.

Reading from STDIN

File based pgloader sources can be loaded from the standard input, as in the following example:

pgloader --type csv                                         \  
-         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \  
-         --with "skip header = 1"                          \  
-         --with "fields terminated by '\t'"                \  
-         -                                                 \  
-         postgresql:///pgloader?districts_longlat          \  
-         < test/data/2013_Gaz_113CDs_national.txt 

The dash (-) character as a source is used to mean standard input, as usual in Unix command lines. It's possible to stream compressed content to pgloader with this technique, using the Unix pipe:

gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo 

Loading from CSV available through HTTP

The same command as just above can also be run if the CSV file happens to be found on a remote HTTP location:

pgloader --type csv                                                     \  
-         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \  
-         --with "skip header = 1"                                       \  
-         --with "fields terminated by '\t'"                             \  
-         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \  
-         postgresql:///pgloader?districts_longlat 

Some more options have to be used in that case, as the file contains a one-line header (most commonly that's column names, could be a copyright notice). Also, in that case, we specify all the fields right into a single --field option argument.

Again, the PostgreSQL target connection string must contain the tablename option and you have to ensure that the target table exists and may fit the data. Here's the SQL command used in that example in case you want to try it yourself:

create table districts_longlat  
-(  
-         usps        text,  
-         geoid       text,  
-         aland       bigint,  
-         awater      bigint,  
-         aland_sqmi  double precision,  
-         awater_sqmi double precision,  
-         intptlat    double precision,  
-         intptlong   double precision  
-); 

Also notice that the same command will work against an archived version of the same data, e.g. http://pgsql.tapoueh.org/temp/2013Gaz113CDs_national.txt.gz.

Finally, it's important to note that pgloader first fetches the content from the HTTP URL it to a local file, then expand the archive when it's recognized to be one, and only then processes the locally expanded file.

In some cases, either because pgloader has no direct support for your archive format or maybe because expanding the archive is not feasible in your environment, you might want to stream the content straight from its remote location into PostgreSQL. Here's how to do that, using the old battle tested Unix Pipes trick:

curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \  
-| gunzip -c                                                        \  
-| pgloader --type csv                                              \  
-           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong"  
-           --with "skip header = 1"                                \  
-           --with "fields terminated by '\t'"                      \  
-           -                                                       \  
-           postgresql:///pgloader?districts_longlat 

Now the OS will take care of the streaming and buffering between the network and the commands and pgloader will take care of streaming the data down to PostgreSQL.

Migrating from SQLite

The following command will open the SQLite database, discover its tables definitions including indexes and foreign keys, migrate those definitions while casting the data type specifications to their PostgreSQL equivalent and then migrate the data over:

createdb newdb  
-pgloader ./test/sqlite/sqlite.db postgresql:///newdb 

Migrating from MySQL

Just create a database where to host the MySQL data and definitions and have pgloader do the migration for you in a single command line:

createdb pagila  
-pgloader mysql://user@localhost/sakila postgresql:///pagila 

Fetching an archived DBF file from a HTTP remote location

It's possible for pgloader to download a file from HTTP, unarchive it, and only then open it to discover the schema then load the data:

createdb foo  
-pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo 

Here it's not possible for pgloader to guess the kind of data source it's being given, so it's necessary to use the --type command line switch.

BATCHES AND RETRY BEHAVIOUR

To load data to PostgreSQL, pgloader uses the COPY streaming protocol. While this is the faster way to load data, COPY has an important drawback: as soon as PostgreSQL emits an error with any bit of data sent to it, whatever the problem is, the whole data set is rejected by PostgreSQL.

To work around that, pgloader cuts the data into batches of 25000 rows each, so that when a problem occurs it's only impacting that many rows of data. Each batch is kept in memory while the COPY streaming happens, in order to be able to handle errors should some happen.

When PostgreSQL rejects the whole batch, pgloader logs the error message then isolates the bad row(s) from the accepted ones by retrying the batched rows in smaller batches. To do that, pgloader parses the CONTEXT error message from the failed COPY, as the message contains the line number where the error was found in the batch, as in the following example:

CONTEXT: COPY errors, line 3, column b: "2006-13-11" 

Using that information, pgloader will reload all rows in the batch before the erroneous one, log the erroneous one as rejected, then try loading the remaining of the batch in a single attempt, which may or may not contain other erroneous data.

At the end of a load containing rejected rows, you will find two files in the root-dir location, under a directory named the same as the target database of your setup. The filenames are the target table, and their extensions are .dat for the rejected data and .log for the file containing the full PostgreSQL client side logs about the rejected data.

The .dat file is formatted in PostgreSQL the text COPY format as documented in http://www.postgresql.org/docs/9.2/static/sql-copy.html#AEN66609.

A NOTE ABOUT PERFORMANCE

pgloader has been developed with performance in mind, to be able to cope with ever growing needs in loading large amounts of data into PostgreSQL.

The basic architecture it uses is the old Unix pipe model, where a thread is responsible for loading the data (reading a CSV file, querying MySQL, etc) and fills pre-processed data into a queue. Another threads feeds from the queue, apply some more transformations to the input data and stream the end result to PostgreSQL using the COPY protocol.

When given a file that the PostgreSQL COPY command knows how to parse, and if the file contains no erroneous data, then pgloader will never be as fast as just using the PostgreSQL COPY command.

Note that while the COPY command is restricted to read either from its standard input or from a local file on the server's file system, the command line tool psql implements a \copy command that knows how to stream a file local to the client over the network and into the PostgreSQL server, using the same protocol as pgloader uses.

A NOTE ABOUT PARALLELISM

pgloader uses several concurrent tasks to process the data being loaded:

  • a reader task reads the data in and pushes it to a queue,

  • at last one write task feeds from the queue and formats the raw into the PostgreSQL COPY format in batches (so that it's possible to then retry a failed batch without reading the data from source again), and then sends the data to PostgreSQL using the COPY protocol.

The parameter workers allows to control how many worker threads are allowed to be active at any time (that's the parallelism level); and the parameter concurrency allows to control how many tasks are started to handle the data (they may not all run at the same time, depending on the workers setting).

We allow workers simultaneous workers to be active at the same time in the context of a single table. A single unit of work consist of several kinds of workers:

  • a reader getting raw data from the source,
  • N writers preparing and sending the data down to PostgreSQL.

The N here is setup to the concurrency parameter: with a CONCURRENCY of 2, we start (+ 1 2) = 3 concurrent tasks, with a concurrency of 4 we start (+ 1 4) = 9 concurrent tasks, of which only workers may be active simultaneously.

The defaults are workers = 4, concurrency = 1 when loading from a database source, and workers = 8, concurrency = 2 when loading from something else (currently, a file). Those defaults are arbitrary and waiting for feedback from users, so please consider providing feedback if you play with the settings.

As the CREATE INDEX threads started by pgloader are only waiting until PostgreSQL is done with the real work, those threads are NOT counted into the concurrency levels as detailed here.

By default, as many CREATE INDEX threads as the maximum number of indexes per table are found in your source schema. It is possible to set the max parallel create index WITH option to another number in case there's just too many of them to create.

SOURCE FORMATS

pgloader supports the following input formats:

  • csv, which includes also tsv and other common variants where you can change the separator and the quoting rules and how to escape the quotes themselves;

  • fixed columns file, where pgloader is flexible enough to accomodate with source files missing columns (ragged fixed length column files do exist);

  • PostgreSLQ COPY formatted files, following the COPY TEXT documentation of PostgreSQL, such as the reject files prepared by pgloader;

  • dbase files known as db3 or dbf file;

  • ixf formated files, ixf being a binary storage format from IBM;

  • sqlite databases with fully automated discovery of the schema and advanced cast rules;

  • mysql databases with fully automated discovery of the schema and advanced cast rules;

  • MS SQL databases with fully automated discovery of the schema and advanced cast rules.

PGLOADER COMMANDS SYNTAX

pgloader implements a Domain Specific Language allowing to setup complex data loading scripts handling computed columns and on-the-fly sanitization of the input data. For more complex data loading scenarios, you will be required to learn that DSL's syntax. It's meant to look familiar to DBA by being inspired by SQL where it makes sense, which is not that much after all.

The pgloader commands follow the same global grammar rules. Each of them might support only a subset of the general options and provide specific options.

LOAD <source-type>  
-     FROM <source-url>     [ HAVING FIELDS <source-level-options> ]  
-	 INTO <postgresql-url> [ TARGET COLUMNS <columns-and-options> ]  
- 
-[ WITH <load-options> ]  
- 
-[ SET <postgresql-settings> ]  
- 
-[ BEFORE LOAD [ DO <sql statements> | EXECUTE <sql file> ] ... ]  
-[  AFTER LOAD [ DO <sql statements> | EXECUTE <sql file> ] ... ]  
-; 

The main clauses are the LOAD, FROM, INTO and WITH clauses that each command implements. Some command then implement the SET command, or some specific clauses such as the CAST clause.

COMMON CLAUSES

Some clauses are common to all commands:

  • FROM

    The FROM clause specifies where to read the data from, and each command introduces its own variant of sources. For instance, the CSV source supports inline, stdin, a filename, a quoted filename, and a FILENAME MATCHING clause (see above); whereas the MySQL source only supports a MySQL database URI specification.

  • In all cases, the FROM clause is able to read its value from an environment variable when using the form GETENV 'varname'.

  • INTO
  • The PostgreSQL connection URI must contains the name of the target table where to load the data into. That table must have already been created in PostgreSQL, and the name might be schema qualified.

    The INTO target database connection URI can be parsed from the value of an environment variable when using the form GETENV 'varname'.

    Then INTO option also supports an optional comma separated list of target columns, which are either the name of an input field or the white space separated list of the target column name, its PostgreSQL data type and a USING expression.

    The USING expression can be any valid Common Lisp form and will be read with the current package set to pgloader.transforms, so that you can use functions defined in that package, such as functions loaded dynamically with the --load command line parameter.

    Each USING expression is compiled at runtime to native code.

    This feature allows pgloader to load any number of fields in a CSV file into a possibly different number of columns in the database, using custom code for that projection.

  • WITH

    Set of options to apply to the command, using a global syntax of either:

    • key = value
    • use option
    • do not use option
  • See each specific command for details.

    All data sources specific commands support the following options:

    • on error stop
    • batch rows = R
    • batch size = ... MB
    • prefetch rows = ...

    See the section BATCH BEHAVIOUR OPTIONS for more details.

    In addition, the following settings are available:

    • workers = W
    • concurrency = C
    • max parallel create index = I

    See section A NOTE ABOUT PARALLELISM for more details.

  • SET

    This clause allows to specify session parameters to be set for all the sessions opened by pgloader. It expects a list of parameter name, the equal sign, then the single-quoted value as a comma separated list.

  • The names and values of the parameters are not validated by pgloader, they are given as-is to PostgreSQL.

  • BEFORE LOAD DO
  • You can run SQL queries against the database before loading the data from the CSV file. Most common SQL queries are CREATE TABLE IF NOT EXISTS so that the data can be loaded.

    Each command must be dollar-quoted: it must begin and end with a double dollar sign, $$. Dollar-quoted queries are then comma separated. No extra punctuation is expected after the last SQL query.

  • BEFORE LOAD EXECUTE

    Same behaviour as in the BEFORE LOAD DO clause. Allows you to read the SQL queries from a SQL file. Implements support for PostgreSQL dollar-quoting and the \i and \ir include facilities as in psql batch mode (where they are the same thing).

  • AFTER LOAD DO

    Same format as BEFORE LOAD DO, the dollar-quoted queries found in that section are executed once the load is done. That's the right time to create indexes and constraints, or re-enable triggers.

  • AFTER LOAD EXECUTE

    Same behaviour as in the AFTER LOAD DO clause. Allows you to read the SQL queries from a SQL file. Implements support for PostgreSQL dollar-quoting and the \i and \ir include facilities as in psql batch mode (where they are the same thing).

Connection String

The <postgresql-url> parameter is expected to be given as a Connection URI as documented in the PostgreSQL documentation at http://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNSTRING.

postgresql://[user[:password]@][netloc][:port][/dbname][?option=value&...] 

Where:

  • user

    Can contain any character, including colon (:) which must then be doubled (::) and at-sign (@) which must then be doubled (@@).

  • When omitted, the user name defaults to the value of the PGUSER environment variable, and if it is unset, the value of the USER environment variable.

  • password
  • Can contain any character, including the at sign (@) which must then be doubled (@@). To leave the password empty, when the user name ends with at at sign, you then have to use the syntax user:@.

    When omitted, the password defaults to the value of the PGPASSWORD environment variable if it is set, otherwise the password is left unset.

  • netloc

    Can be either a hostname in dotted notation, or an ipv4, or an Unix domain socket path. Empty is the default network location, under a system providing unix domain socket that method is preferred, otherwise the netloc default to localhost.

  • It's possible to force the unix domain socket path by using the syntax unix:/path/to/where/the/socket/file/is, so to force a non default socket path and a non default port, you would have:

    postgresql://unix:/tmp:54321/dbname 

    The netloc defaults to the value of the PGHOST environment variable, and if it is unset, to either the default unix socket path when running on a Unix system, and localhost otherwise.

  • dbname
  • Should be a proper identifier (letter followed by a mix of letters, digits and the punctuation signs comma (,), dash (-) and underscore (_).

    When omitted, the dbname defaults to the value of the environment variable PGDATABASE, and if that is unset, to the user value as determined above.

  • options

    The optional parameters must be supplied with the form name=value, and you may use several parameters by separating them away using an ampersand (&) character.

  • Only some options are supported here, tablename (which might be qualified with a schema name) sslmode, host, port, dbname, user and password.

    The sslmode parameter values can be one of disable, allow, prefer or require.

    For backward compatibility reasons, it's possible to specify the tablename option directly, without spelling out the tablename= parts.

    The options override the main URI components when both are given, and using the percent-encoded option parameters allow using passwords starting with a colon and bypassing other URI components parsing limitations.

Regular Expressions

Several clauses listed in the following accept regular expressions with the following input rules:

  • A regular expression begins with a tilde sign (~),

  • is then followed with an opening sign,

  • then any character is allowed and considered part of the regular expression, except for the closing sign,

  • then a closing sign is expected.

The opening and closing sign are allowed by pair, here's the complete list of allowed delimiters:

~//  
-~[]  
-~{}  
-~()  
-~<>  
-~""  
-~''  
-~||  
-~## 

Pick the set of delimiters that don't collide with the regular expression you're trying to input. If your expression is such that none of the solutions allow you to enter it, the places where such expressions are allowed should allow for a list of expressions.

Comments

Any command may contain comments, following those input rules:

  • the -- delimiter begins a comment that ends with the end of the current line,

  • the delimiters /* and */ respectively start and end a comment, which can be found in the middle of a command or span several lines.

Any place where you could enter a whitespace will accept a comment too.

Batch behaviour options

All pgloader commands have support for a WITH clause that allows for specifying options. Some options are generic and accepted by all commands, such as the batch behaviour options, and some options are specific to a data source kind, such as the CSV skip header option.

The global batch behaviour options are:

  • batch rows

    Takes a numeric value as argument, used as the maximum number of rows allowed in a batch. The default is 25 000 and can be changed to try having better performance characteristics or to control pgloader memory usage;

  • batch size

    Takes a memory unit as argument, such as 20 MB, its default value. Accepted multipliers are kB, MB, GB, TB and PB. The case is important so as not to be confused about bits versus bytes, we're only talking bytes here.

  • prefetch rows

    Takes a numeric value as argument, defaults to 100000. That's the number of rows that pgloader is allowed to read in memory in each reader thread. See the workers setting for how many reader threads are allowed to run at the same time.

Other options are specific to each input source, please refer to specific parts of the documentation for their listing and covering.

A batch is then closed as soon as either the batch rows or the batch size threshold is crossed, whichever comes first. In cases when a batch has to be closed because of the batch size setting, a debug level log message is printed with how many rows did fit in the oversized batch.

LOAD CSV

This command instructs pgloader to load data from a CSV file. Here's an example:

LOAD CSV  
-   FROM 'GeoLiteCity-Blocks.csv' WITH ENCODING iso-646-us  
-        HAVING FIELDS  
-        (  
-           startIpNum, endIpNum, locId  
-        )  
-   INTO postgresql://user@localhost:54393/dbname?geolite.blocks  
-        TARGET COLUMNS  
-        (  
-           iprange ip4r using (ip-range startIpNum endIpNum),  
-           locId  
-        )  
-   WITH truncate,  
-        skip header = 2,  
-        fields optionally enclosed by '"',  
-        fields escaped by backslash-quote,  
-        fields terminated by '\t'  
- 
-    SET work_mem to '32 MB', maintenance_work_mem to '64 MB'; 

The csv format command accepts the following clauses and options:

  • FROM

    Filename where to load the data from. Accepts an ENCODING option. Use the --list-encodings option to know which encoding names are supported.

  • The filename may be enclosed by single quotes, and could be one of the following special values:

    • inline

      The data is found after the end of the parsed commands. Any number of empty lines between the end of the commands and the beginning of the data is accepted.

    • stdin

      Reads the data from the standard input stream.

    • FILENAMES MATCHING

      The whole matching clause must follow the following rule:

      [ ALL FILENAMES | [ FIRST ] FILENAME ]  
      -MATCHING regexp  
      -[ IN DIRECTORY '...' ] 
    • The matching clause applies given regular expression (see above for exact syntax, several options can be used here) to filenames. It's then possible to load data from only the first match of all of them.

      The optional IN DIRECTORY clause allows specifying which directory to walk for finding the data files, and can be either relative to where the command file is read from, or absolute. The given directory must exists.

    The FROM option also supports an optional comma separated list of field names describing what is expected in the CSV data file, optionally introduced by the clause HAVING FIELDS.

    Each field name can be either only one name or a name following with specific reader options for that field, enclosed in square brackets and comma-separated. Supported per-field reader options are:

    • terminated by

      See the description of field terminated by below.

    • The processing of this option is not currently implemented.

    • date format
    • When the field is expected of the date type, then this option allows to specify the date format used in the file.

      Date format string are template strings modeled against the PostgreSQL to_char template strings support, limited to the following patterns:

      • YYYY, YYY, YY for the year part
      • MM for the numeric month part
      • DD for the numeric day part
      • HH, HH12, HH24 for the hour part
      • am, AM, a.m., A.M.
      • pm, PM, p.m., P.M.
      • MI for the minutes part
      • SS for the seconds part
      • MS for the milliseconds part (4 digits)
      • US for the microseconds part (6 digits)
      • unparsed punctuation signs: - . * # @ T / \ and space

      Here's an example of a date format specification:

      column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] 
    • null if

      This option takes an argument which is either the keyword blanks or a double-quoted string.

    • When blanks is used and the field value that is read contains only space characters, then it's automatically converted to an SQL NULL value.

      When a double-quoted string is used and that string is read as the field value, then the field value is automatically converted to an SQL NULL value.

    • trim both whitespace, trim left whitespace, trim right whitespace

      This option allows to trim whitespaces in the read data, either from both sides of the data, or only the whitespace characters found on the left of the streaing, or only those on the right of the string.

  • WITH

    When loading from a CSV file, the following options are supported:

    • truncate

      When this option is listed, pgloader issues a TRUNCATE command against the PostgreSQL target table before reading the data file.

    • drop indexes

      When this option is listed, pgloader issues DROP INDEX commands against all the indexes defined on the target table before copying the data, then CREATE INDEX commands once the COPY is done.

    • In order to get the best performance possible, all the indexes are created in parallel and when done the primary keys are built again from the unique indexes just created. This two step process allows creating the primary key index in parallel with the other indexes, as only the ALTER TABLE command needs an access exclusive lock on the target table.

    • disable triggers
    • When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

      This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • skip header

      Takes a numeric value as argument. Instruct pgloader to skip that many lines at the beginning of the input file.

    • csv header

      Use the first line read after skip header as the list of csv field names to be found in the CSV file, using the same CSV parameters as for the CSV data.

    • trim unquoted blanks

      When reading unquoted values in the CSV file, remove the blanks found in between the separator and the value. That behaviour is the default.

    • keep unquoted blanks

      When reading unquoted values in the CSV file, keep blanks found in between the separator and the value.

    • fields optionally enclosed by

      Takes a single character as argument, which must be found inside single quotes, and might be given as the printable character itself, the special value \t to denote a tabulation character, or 0x then an hexadecimal value read as the ASCII code for the character.

    • This character is used as the quoting character in the CSV file, and defaults to double-quote.

    • fields not enclosed
    • By default, pgloader will use the double-quote character as the enclosing character. If you have a CSV file where fields are not enclosed and are using double-quote as an expected ordinary character, then use the option fields not enclosed for the CSV parser to accept those values.

    • fields escaped by
    • Takes either the special value backslash-quote or double-quote, or any value supported by the fields terminated by option (see below). This value is used to recognize escaped field separators when they are to be found within the data fields themselves. Defaults to double-quote.

    • csv escape mode
    • Takes either the special value quote (the default) or following and allows the CSV parser to parse either only escaped field separator or any character (including CSV data) when using the following value.

    • fields terminated by
    • Takes a single character as argument, which must be found inside single quotes, and might be given as the printable character itself, the special value \t to denote a tabulation character, or 0x then an hexadecimal value read as the ASCII code for the character.

      This character is used as the field separator when reading the CSV data.

    • lines terminated by

      Takes a single character as argument, which must be found inside single quotes, and might be given as the printable character itself, the special value \t to denote a tabulation character, or 0x then an hexadecimal value read as the ASCII code for the character.

    • This character is used to recognize end-of-line condition when reading the CSV data.

LOAD FIXED COLS

This command instructs pgloader to load data from a text file containing columns arranged in a fixed size manner. Here's an example:

LOAD FIXED  
-     FROM inline  
-          (  
-           a from  0 for 10,  
-           b from 10 for  8,  
-           c from 18 for  8,  
-           d from 26 for 17 [null if blanks, trim right whitespace]  
-          )  
-     INTO postgresql:///pgloader?fixed  
-          (  
-             a, b,  
-             c time using (time-with-no-separator c),  
-             d  
-          )  
- 
-     WITH truncate  
- 
-      SET work_mem to '14MB',  
-          standard_conforming_strings to 'on'  
- 
-BEFORE LOAD DO  
-     $$ drop table if exists fixed; $$,  
-     $$ create table fixed (  
-         a integer,  
-         b date,  
-         c time,  
-         d text  
-        );  
-     $$;  
- 
- 01234567892008052011431250firstline  
-    01234562008052115182300left blank-padded  
- 12345678902008052208231560another line  
-  2345609872014092914371500                  
-  2345678902014092914371520 

The fixed format command accepts the following clauses and options:

  • FROM

    Filename where to load the data from. Accepts an ENCODING option. Use the --list-encodings option to know which encoding names are supported.

  • The filename may be enclosed by single quotes, and could be one of the following special values:

    • inline

      The data is found after the end of the parsed commands. Any number of empty lines between the end of the commands and the beginning of the data is accepted.

    • stdin

      Reads the data from the standard input stream.

    • FILENAMES MATCHING

      The whole matching clause must follow the following rule:

      [ ALL FILENAMES | [ FIRST ] FILENAME ]  
      -MATCHING regexp  
      -[ IN DIRECTORY '...' ] 
    • The matching clause applies given regular expression (see above for exact syntax, several options can be used here) to filenames. It's then possible to load data from only the first match of all of them.

      The optional IN DIRECTORY clause allows specifying which directory to walk for finding the data files, and can be either relative to where the command file is read from, or absolute. The given directory must exists.

    The FROM option also supports an optional comma separated list of field names describing what is expected in the FIXED data file.

    Each field name is composed of the field name followed with specific reader options for that field. Supported per-field reader options are the following, where only start and length are required.

    • start

      Position in the line where to start reading that field's value. Can be entered with decimal digits or 0x then hexadecimal digits.

    • length

      How many bytes to read from the start position to read that field's value. Same format as start.

    Those optional parameters must be enclosed in square brackets and comma-separated:

    • terminated by

      See the description of field terminated by below.

    • The processing of this option is not currently implemented.

    • date format
    • When the field is expected of the date type, then this option allows to specify the date format used in the file.

      Date format string are template strings modeled against the PostgreSQL to_char template strings support, limited to the following patterns:

      • YYYY, YYY, YY for the year part
      • MM for the numeric month part
      • DD for the numeric day part
      • HH, HH12, HH24 for the hour part
      • am, AM, a.m., A.M.
      • pm, PM, p.m., P.M.
      • MI for the minutes part
      • SS for the seconds part
      • MS for the milliseconds part (4 digits)
      • US for the microseconds part (6 digits)
      • unparsed punctuation signs: - . * # @ T / \ and space

      Here's an example of a date format specification:

      column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] 
    • null if

      This option takes an argument which is either the keyword blanks or a double-quoted string.

    • When blanks is used and the field value that is read contains only space characters, then it's automatically converted to an SQL NULL value.

      When a double-quoted string is used and that string is read as the field value, then the field value is automatically converted to an SQL NULL value.

    • trim both whitespace, trim left whitespace, trim right whitespace

      This option allows to trim whitespaces in the read data, either from both sides of the data, or only the whitespace characters found on the left of the streaing, or only those on the right of the string.

  • WITH

    When loading from a FIXED file, the following options are supported:

    • truncate

      When this option is listed, pgloader issues a TRUNCATE command against the PostgreSQL target table before reading the data file.

    • disable triggers

      When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

    • This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • skip header
    • Takes a numeric value as argument. Instruct pgloader to skip that many lines at the beginning of the input file.

LOAD COPY FORMATTED FILES

This commands instructs pgloader to load from a file containing COPY TEXT data as described in the PostgreSQL documentation. Here's an example:

LOAD COPY  
-     FROM copy://./data/track.copy  
-          (  
-            trackid, track, album, media, genre, composer,  
-            milliseconds, bytes, unitprice  
-          )  
-     INTO postgresql:///pgloader?track_full  
- 
-     WITH truncate  
- 
-      SET work_mem to '14MB',  
-          standard_conforming_strings to 'on'  
- 
-BEFORE LOAD DO  
-     $$ drop table if exists track_full; $$,  
-     $$ create table track_full (  
-          trackid      bigserial,  
-          track        text,  
-          album        text,  
-          media        text,  
-          genre        text,  
-          composer     text,  
-          milliseconds bigint,  
-          bytes        bigint,  
-          unitprice    numeric  
-        );  
-     $$; 

The COPY format command accepts the following clauses and options:

  • FROM

    Filename where to load the data from. This support local files, HTTP URLs and zip files containing a single dbf file of the same name. Fetch such a zip file from an HTTP address is of course supported.

    • inline

      The data is found after the end of the parsed commands. Any number of empty lines between the end of the commands and the beginning of the data is accepted.

    • stdin

      Reads the data from the standard input stream.

    • FILENAMES MATCHING

      The whole matching clause must follow the following rule:

      [ ALL FILENAMES | [ FIRST ] FILENAME ]  
      -MATCHING regexp  
      -[ IN DIRECTORY '...' ] 
    • The matching clause applies given regular expression (see above for exact syntax, several options can be used here) to filenames. It's then possible to load data from only the first match of all of them.

      The optional IN DIRECTORY clause allows specifying which directory to walk for finding the data files, and can be either relative to where the command file is read from, or absolute. The given directory must exists.

  • WITH

    When loading from a COPY file, the following options are supported:

    • delimiter

      Takes a single character as argument, which must be found inside single quotes, and might be given as the printable character itself, the special value \t to denote a tabulation character, or 0x then an hexadecimal value read as the ASCII code for the character.

    • This character is used as the delimiter when reading the data, in a similar way to the PostgreSQL COPY option.

    • null
    • Takes a quoted string as an argument (quotes can be either double quotes or single quotes) and uses that string as the NULL representation in the data.

      This is similar to the null COPY option in PostgreSQL.

    • truncate

      When this option is listed, pgloader issues a TRUNCATE command against the PostgreSQL target table before reading the data file.

    • disable triggers

      When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

    • This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • skip header
    • Takes a numeric value as argument. Instruct pgloader to skip that many lines at the beginning of the input file.

LOAD DBF

This command instructs pgloader to load data from a DBF file. Here's an example:

LOAD DBF  
-    FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/reg2013.dbf  
-    INTO postgresql://user@localhost/dbname  
-    WITH truncate, create table; 

The dbf format command accepts the following clauses and options:

  • FROM

    Filename where to load the data from. This support local files, HTTP URLs and zip files containing a single dbf file of the same name. Fetch such a zip file from an HTTP address is of course supported.

  • WITH

    When loading from a DBF file, the following options are supported:

    • truncate

      When this option is listed, pgloader issues a TRUNCATE command against the PostgreSQL target table before reading the data file.

    • disable triggers

      When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

    • This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • create table
    • When this option is listed, pgloader creates the table using the meta data found in the DBF file, which must contain a list of fields with their data type. A standard data type conversion from DBF to PostgreSQL is done.

    • table name
    • This options expects as its value the possibly qualified name of the table to create.

LOAD IXF

This command instructs pgloader to load data from an IBM IXF file. Here's an example:

LOAD IXF  
-    FROM data/nsitra.test1.ixf  
-    INTO postgresql:///pgloader?nsitra.test1  
-    WITH truncate, create table, timezone UTC  
- 
-  BEFORE LOAD DO  
-   $$ create schema if not exists nsitra; $$,  
-   $$ drop table if exists nsitra.test1; $$; 

The ixf format command accepts the following clauses and options:

  • FROM

    Filename where to load the data from. This support local files, HTTP URLs and zip files containing a single ixf file of the same name. Fetch such a zip file from an HTTP address is of course supported.

  • WITH

    When loading from a IXF file, the following options are supported:

    • truncate

      When this option is listed, pgloader issues a TRUNCATE command against the PostgreSQL target table before reading the data file.

    • disable triggers

      When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

    • This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • create table
    • When this option is listed, pgloader creates the table using the meta data found in the DBF file, which must contain a list of fields with their data type. A standard data type conversion from DBF to PostgreSQL is done.

    • table name
    • This options expects as its value the possibly qualified name of the table to create.

    • timezone
    • This options allows to specify which timezone is used when parsing timestamps from an IXF file, and defaults to UTC. Expected values are either UTC, GMT or a single quoted location name such as 'Universal' or 'Europe/Paris'.

LOAD ARCHIVE

This command instructs pgloader to load data from one or more files contained in an archive. Currently the only supported archive format is ZIP, and the archive might be downloaded from an HTTP URL.

Here's an example:

LOAD ARCHIVE  
-   FROM /Users/dim/Downloads/GeoLiteCity-latest.zip  
-   INTO postgresql:///ip4r  
- 
-   BEFORE LOAD  
-     DO $$ create extension if not exists ip4r; $$,  
-        $$ create schema if not exists geolite; $$,  
- 
-     EXECUTE 'geolite.sql'  
- 
-   LOAD CSV  
-        FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/  
-             WITH ENCODING iso-8859-1  
-             (  
-                locId,  
-                country,  
-                region     null if blanks,  
-                city       null if blanks,  
-                postalCode null if blanks,  
-                latitude,  
-                longitude,  
-                metroCode  null if blanks,  
-                areaCode   null if blanks  
-             )  
-        INTO postgresql:///ip4r?geolite.location  
-             (  
-                locid,country,region,city,postalCode,  
-                location point using (format nil "(~a,~a)" longitude latitude),  
-                metroCode,areaCode  
-             )  
-        WITH skip header = 2,  
-             fields optionally enclosed by '"',  
-             fields escaped by double-quote,  
-             fields terminated by ','  
- 
-  AND LOAD CSV  
-        FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/  
-             WITH ENCODING iso-8859-1  
-             (  
-                startIpNum, endIpNum, locId  
-             )  
-        INTO postgresql:///ip4r?geolite.blocks  
-             (  
-                iprange ip4r using (ip-range startIpNum endIpNum),  
-                locId  
-             )  
-        WITH skip header = 2,  
-             fields optionally enclosed by '"',  
-             fields escaped by double-quote,  
-             fields terminated by ','  
- 
-   FINALLY DO  
-     $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$; 

The archive command accepts the following clauses and options:

  • FROM

    Filename or HTTP URI where to load the data from. When given an HTTP URL the linked file will get downloaded locally before processing.

  • If the file is a zip file, the command line utility unzip is used to expand the archive into files in $TMPDIR, or /tmp if $TMPDIR is unset or set to a non-existing directory.

    Then the following commands are used from the top level directory where the archive has been expanded.

  • command [ AND command ... ]

    A series of commands against the contents of the archive, at the moment only CSV,'FIXED and DBF commands are supported.

  • Note that commands are supporting the clause FROM FILENAME MATCHING which allows the pgloader command not to depend on the exact names of the archive directories.

    The same clause can also be applied to several files with using the spelling FROM ALL FILENAMES MATCHING and a regular expression.

    The whole matching clause must follow the following rule:

     FROM [ ALL FILENAMES | [ FIRST ] FILENAME ] MATCHING 
  • FINALLY DO

    SQL Queries to run once the data is loaded, such as CREATE INDEX.

LOAD MYSQL DATABASE

This command instructs pgloader to load data from a database connection. The only supported database source is currently MySQL, and pgloader supports dynamically converting the schema of the source database and the indexes building.

A default set of casting rules are provided and might be overloaded and appended to by the command.

Here's an example using as many options as possible, some of them even being defaults. Chances are you don't need that complex a setup, don't copy and paste it, use it only as a reference!

LOAD DATABASE  
-     FROM      mysql://root@localhost/sakila  
-     INTO postgresql://localhost:54393/sakila  
- 
- WITH include drop, create tables, create indexes, reset sequences,  
-      workers = 8, concurrency = 1,  
-      multiple readers per thread, rows per range = 50000  
- 
-  SET PostgreSQL PARAMETERS  
-      maintenance_work_mem to '128MB',  
-      work_mem to '12MB',  
-      search_path to 'sakila, public, "$user"'  
- 
-  SET MySQL PARAMETERS  
-      net_read_timeout  = '120',  
-      net_write_timeout = '120'  
- 
- CAST type bigint when (= precision 20) to bigserial drop typemod,  
-      type date drop not null drop default using zero-dates-to-null,  
-      -- type tinyint to boolean using tinyint-to-boolean,  
-      type year to integer  
- 
- MATERIALIZE VIEWS film_list, staff_list  
- 
- -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'  
- -- EXCLUDING TABLE NAMES MATCHING ~<ory>  
- -- DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8  
- -- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'  
- -- ALTER TABLE NAMES MATCHING ~/_list$/ SET SCHEMA 'mv'  
- 
- ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/  
-  SET SCHEMA 'mv'  
- 
- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'  
- ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40')  
- 
- ALTER SCHEMA 'sakila' RENAME TO 'pagila'  
- 
- BEFORE LOAD DO  
-   $$ create schema if not exists pagila; $$,  
-   $$ create schema if not exists mv;     $$,  
-   $$ alter database sakila set search_path to pagila, mv, public; $$;  
-

The database command accepts the following clauses and options:

  • FROM

    Must be a connection URL pointing to a MySQL database.

  • If the connection URI contains a table name, then only this table is migrated from MySQL to PostgreSQL.

    See the SOURCE CONNECTION STRING section above for details on how to write the connection string. Environment variables described in can be used as default values too. If the user is not provided, then it defaults to USER environment variable value. The password can be provided with the environment variable MYSQL_PWD. The host can be provided with the environment variable MYSQL_HOST and otherwise defaults to localhost. The port can be provided with the environment variable MYSQL_TCP_PORT and otherwise defaults to 3306.

  • WITH

    When loading from a MySQL database, the following options are supported, and the default WITH clause is: no truncate, create schema, create tables, include drop, create indexes, reset sequences, foreign keys, downcase identifiers, uniquify index names.

  • WITH options:

    • include drop

      When this option is listed, pgloader drops all the tables in the target PostgreSQL database whose names appear in the MySQL database. This option allows for using the same command several times in a row until you figure out all the options, starting automatically from a clean environment. Please note that CASCADE is used to ensure that tables are dropped even if there are foreign keys pointing to them. This is precisely what include drop is intended to do: drop all target tables and recreate them.

    • Great care needs to be taken when using include drop, as it will cascade to all objects referencing the target tables, possibly including other tables that are not being loaded from the source DB.

    • include no drop
    • When this option is listed, pgloader will not include any DROP statement when loading the data.

    • truncate
    • When this option is listed, pgloader issue the TRUNCATE command against each PostgreSQL table just before loading data into it.

    • no truncate
    • When this option is listed, pgloader issues no TRUNCATE command.

    • disable triggers
    • When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

      This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • create tables

      When this option is listed, pgloader creates the table using the meta data found in the MySQL file, which must contain a list of fields with their data type. A standard data type conversion from DBF to PostgreSQL is done.

    • create no tables

      When this option is listed, pgloader skips the creation of table before loading data, target tables must then already exist.

    • Also, when using create no tables pgloader fetches the metadata from the current target database and checks type casting, then will remove constraints and indexes prior to loading the data and install them back again once the loading is done.

    • create indexes
    • When this option is listed, pgloader gets the definitions of all the indexes found in the MySQL database and create the same set of index definitions against the PostgreSQL database.

    • create no indexes
    • When this option is listed, pgloader skips the creating indexes.

    • drop indexes
    • When this option is listed, pgloader drops the indexes in the target database before loading the data, and creates them again at the end of the data copy.

    • uniquify index names, preserve index names
    • MySQL index names are unique per-table whereas in PostgreSQL index names have to be unique per-schema. The default for pgloader is to change the index name by prefixing it with idx_OID where OID is the internal numeric identifier of the table the index is built against.

      In somes cases like when the DDL are entirely left to a framework it might be sensible for pgloader to refrain from handling index unique names, that is achieved by using the preserve index names option.

      The default is to uniquify index names.

      Even when using the option preserve index names, MySQL primary key indexes named "PRIMARY" will get their names uniquified. Failing to do so would prevent the primary keys to be created again in PostgreSQL where the index names must be unique per schema.

    • drop schema

      When this option is listed, pgloader drops the target schema in the target PostgreSQL database before creating it again and all the objects it contains. The default behavior doesn't drop the target schemas.

    • foreign keys

      When this option is listed, pgloader gets the definitions of all the foreign keys found in the MySQL database and create the same set of foreign key definitions against the PostgreSQL database.

    • no foreign keys

      When this option is listed, pgloader skips creating foreign keys.

    • reset sequences

      When this option is listed, at the end of the data loading and after the indexes have all been created, pgloader resets all the PostgreSQL sequences created to the current maximum value of the column they are attached to.

    • The options schema only and data only have no effects on this option.

    • reset no sequences
    • When this option is listed, pgloader skips resetting sequences after the load.

      The options schema only and data only have no effects on this option.

    • downcase identifiers

      When this option is listed, pgloader converts all MySQL identifiers (table names, index names, column names) to downcase, except for PostgreSQL reserved keywords.

    • The PostgreSQL reserved keywords are determined dynamically by using the system function pg_get_keywords().

    • quote identifiers
    • When this option is listed, pgloader quotes all MySQL identifiers so that their case is respected. Note that you will then have to do the same thing in your application code queries.

    • schema only
    • When this option is listed pgloader refrains from migrating the data over. Note that the schema in this context includes the indexes when the option create indexes has been listed.

    • data only
    • When this option is listed pgloader only issues the COPY statements, without doing any other processing.

    • single reader per thread, multiple readers per thread
    • The default is single reader per thread and it means that each MySQL table is read by a single thread as a whole, with a single SELECT statement using no WHERE clause.

      When using multiple readers per thread pgloader may be able to divide the reading work into several threads, as many as the concurrency setting, which needs to be greater than 1 for this option to kick be activated.

      For each source table, pgloader searches for a primary key over a single numeric column, or a multiple-column primary key index for which the first column is of a numeric data type (one of integer or bigint). When such an index exists, pgloader runs a query to find the min and max values on this column, and then split that range into many ranges containing a maximum of rows per range.

      When the range list we then obtain contains at least as many ranges than our concurrency setting, then we distribute those ranges to each reader thread.

      So when all the conditions are met, pgloader then starts as many reader thread as the concurrency setting, and each reader thread issues several queries with a WHERE id >= x AND id < y, where y - x = rows per range or less (for the last range, depending on the max value just obtained.

    • rows per range

      How many rows are fetched per SELECT query when using multiple readers per thread, see above for details.

  • SET MySQL PARAMETERS

    The SET MySQL PARAMETERS allows setting MySQL parameters using the MySQL SET command each time pgloader connects to it.

  • CAST

    The cast clause allows to specify custom casting rules, either to overload the default casting rules or to amend them with special cases.

  • A casting rule is expected to follow one of the forms:

    type <mysql-type-name> [ <guard> ... ] to <pgsql-type-name> [ <option> ... ]  
    -column <table-name>.<column-name> [ <guards> ] to ... 

    It's possible for a casting rule to either match against a MySQL data type or against a given column name in a given table name. That flexibility allows to cope with cases where the type tinyint might have been used as a boolean in some cases but as a smallint in others.

    The casting rules are applied in order, the first match prevents following rules to be applied, and user defined rules are evaluated first.

    The supported guards are:

    • when default 'value'

      The casting rule is only applied against MySQL columns of the source type that have given value, which must be a single-quoted or a double-quoted string.

    • when typemod expression

      The casting rule is only applied against MySQL columns of the source type that have a typemod value matching the given typemod expression. The typemod is separated into its precision and scale components.

    • Example of a cast rule using a typemod guard:

      type char when (= precision 1) to char keep typemod 

      This expression casts MySQL char(1) column to a PostgreSQL column of type char(1) while allowing for the general case char(N) will be converted by the default cast rule into a PostgreSQL type varchar(N).

    • with extra auto_increment
    • The casting rule is only applied against MySQL columns having the extra column auto_increment option set, so that it's possible to target e.g. serial rather than integer.

      The default matching behavior, when this option isn't set, is to match both columns with the extra definition and without.

      This means that if you want to implement a casting rule that target either serial or integer from a smallint definition depending on the auto_increment extra bit of information from MySQL, then you need to spell out two casting rules as following:

      type smallint  with extra auto_increment  
      -  to serial drop typemod keep default keep not null,  
      -type smallint  
      -  to integer drop typemod keep default keep not null 

    The supported casting options are:

    • drop default, keep default

      When the option drop default is listed, pgloader drops any existing default expression in the MySQL database for columns of the source type from the CREATE TABLE statement it generates.

    • The spelling keep default explicitly prevents that behaviour and can be used to overload the default casting rules.

    • drop not null, keep not null, set not null
    • When the option drop not null is listed, pgloader drops any existing NOT NULL constraint associated with the given source MySQL datatype when it creates the tables in the PostgreSQL database.

      The spelling keep not null explicitly prevents that behaviour and can be used to overload the default casting rules.

      When the option set not null is listed, pgloader sets a NOT NULL constraint on the target column regardless whether it has been set in the source MySQL column.

    • drop typemod, keep typemod

      When the option drop typemod is listed, pgloader drops any existing typemod definition (e.g. precision and scale) from the datatype definition found in the MySQL columns of the source type when it created the tables in the PostgreSQL database.

    • The spelling keep typemod explicitly prevents that behaviour and can be used to overload the default casting rules.

    • using
    • This option takes as its single argument the name of a function to be found in the pgloader.transforms Common Lisp package. See above for details.

      It's possible to augment a default cast rule (such as one that applies against ENUM data type for example) with a transformation function by omitting entirely the type parts of the casting rule, as in the following example:

      column enumerate.foo using empty-string-to-null 
  • MATERIALIZE VIEWS

    This clause allows you to implement custom data processing at the data source by providing a view definition against which pgloader will query the data. It's not possible to just allow for plain SQL because we want to know a lot about the exact data types of each column involved in the query output.

  • This clause expect a comma separated list of view definitions, each one being either the name of an existing view in your database or the following expression:

    name AS $$ sql query $$

    The name and the sql query will be used in a CREATE VIEW statement at the beginning of the data loading, and the resulting view will then be dropped at the end of the data loading.

  • MATERIALIZE ALL VIEWS

    Same behaviour as MATERIALIZE VIEWS using the dynamic list of views as returned by MySQL rather than asking the user to specify the list.

  • INCLUDING ONLY TABLE NAMES MATCHING

    Introduce a comma separated list of table names or regular expression used to limit the tables to migrate to a sublist.

  • Example:

    INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor' 
  • EXCLUDING TABLE NAMES MATCHING

    Introduce a comma separated list of table names or regular expression used to exclude table names from the migration. This filter only applies to the result of the INCLUDING filter.

    EXCLUDING TABLE NAMES MATCHING ~<ory> 
  • DECODING TABLE NAMES MATCHING

    Introduce a comma separated list of table names or regular expressions used to force the encoding to use when processing data from MySQL. If the data encoding known to you is different from MySQL's idea about it, this is the option to use.

    DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8 
  • You can use as many such rules as you need, all with possibly different encodings.

  • ALTER TABLE NAMES MATCHING
  • Introduce a comma separated list of table names or regular expressions that you want to target in the pgloader ALTER TABLE command. The only two available actions are SET SCHEMA and RENAME TO, both take a quoted string as parameter:

    ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/  
    - SET SCHEMA 'mv'  
    - 
    -ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'  
    - 
    -ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40') 

    You can use as many such rules as you need. The list of tables to be migrated is searched in pgloader memory against the ALTER TABLE matching rules, and for each command pgloader stops at the first matching criteria (regexp or string).

    No ALTER TABLE command is sent to PostgreSQL, the modification happens at the level of the pgloader in-memory representation of your source database schema. In case of a name change, the mapping is kept and reused in the foreign key and index support.

    The SET () action takes effect as a WITH clause for the CREATE TABLE command that pgloader will run when it has to create a table.

LIMITATIONS

The database command currently only supports MySQL source database and has the following limitations:

  • Views are not migrated,

    Supporting views might require implementing a full SQL parser for the MySQL dialect with a porting engine to rewrite the SQL against PostgreSQL, including renaming functions and changing some constructs.

  • While it's not theoretically impossible, don't hold your breath.

  • Triggers are not migrated
  • The difficulty of doing so is not yet assessed.

  • ON UPDATE CURRENT_TIMESTAMP is currently not migrated
  • It's simple enough to implement, just not on the priority list yet.

  • Of the geometric datatypes, only the POINT database has been covered. The other ones should be easy enough to implement now, it's just not done yet.

DEFAULT MySQL CASTING RULES

When migrating from MySQL the following Casting Rules are provided:

Numbers:

  • type int with extra auto_increment to serial when (< precision 10)
  • type int with extra auto_increment to bigserial when (<= 10 precision)
  • type int to int when (< precision 10)
  • type int to bigint when (<= 10 precision)
  • type tinyint with extra auto_increment to serial
  • type smallint with extra auto_increment to serial
  • type mediumint with extra auto_increment to serial
  • type bigint with extra auto_increment to bigserial

  • type tinyint to boolean when (= 1 precision) using tinyint-to-boolean

  • type tinyint to smallint drop typemod

  • type smallint to smallint drop typemod
  • type mediumint to integer drop typemod
  • type integer to integer drop typemod
  • type float to float drop typemod
  • type bigint to bigint drop typemod
  • type double to double precision drop typemod

  • type numeric to numeric keep typemod

  • type decimal to decimal keep typemod

Texts:

  • type char to char keep typemod using remove-null-characters
  • type varchar to varchar keep typemod using remove-null-characters
  • type tinytext to text using remove-null-characters
  • type text to text using remove-null-characters
  • type mediumtext to text using remove-null-characters
  • type longtext to text using remove-null-characters

Binary:

  • type binary to bytea
  • type varbinary to bytea
  • type tinyblob to bytea
  • type blob to bytea
  • type mediumblob to bytea
  • type longblob to bytea

Date:

  • type datetime when default "0000-00-00 00:00:00" and not null to timestamptz drop not null drop default using zero-dates-to-null

  • type datetime when default "0000-00-00 00:00:00" to timestamptz drop default using zero-dates-to-null

  • type timestamp when default "0000-00-00 00:00:00" and not null to timestamptz drop not null drop default using zero-dates-to-null

  • type timestamp when default "0000-00-00 00:00:00" to timestamptz drop default using zero-dates-to-null

  • type date when default "0000-00-00" to date drop default using zero-dates-to-null

  • type date to date

  • type datetime to timestamptz
  • type timestamp to timestamptz
  • type year to integer drop typemod

Geometric:

  • type point to point using pgloader.transforms::convert-mysql-point

Enum types are declared inline in MySQL and separately with a CREATE TYPE command in PostgreSQL, so each column of Enum Type is converted to a type named after the table and column names defined with the same labels in the same order.

When the source type definition is not matched in the default casting rules nor in the casting rules provided in the command, then the type name with the typemod is used.

LOAD SQLite DATABASE

This command instructs pgloader to load data from a SQLite file. Automatic discovery of the schema is supported, including build of the indexes.

Here's an example:

load database  
-     from sqlite:///Users/dim/Downloads/lastfm_tags.db  
-     into postgresql:///tags  
- 
- with include drop, create tables, create indexes, reset sequences  
- 
-  set work_mem to '16MB', maintenance_work_mem to '512 MB'; 

The sqlite command accepts the following clauses and options:

  • FROM

    Path or HTTP URL to a SQLite file, might be a .zip file.

  • WITH

    When loading from a SQLite database, the following options are supported:

  • When loading from a SQLite database, the following options are supported, and the default WITH clause is: no truncate, create tables, include drop, create indexes, reset sequences, downcase identifiers, encoding 'utf-8'.

    • include drop

      When this option is listed, pgloader drops all the tables in the target PostgreSQL database whose names appear in the SQLite database. This option allows for using the same command several times in a row until you figure out all the options, starting automatically from a clean environment. Please note that CASCADE is used to ensure that tables are dropped even if there are foreign keys pointing to them. This is precisely what include drop is intended to do: drop all target tables and recreate them.

    • Great care needs to be taken when using include drop, as it will cascade to all objects referencing the target tables, possibly including other tables that are not being loaded from the source DB.

    • include no drop
    • When this option is listed, pgloader will not include any DROP statement when loading the data.

    • truncate
    • When this option is listed, pgloader issue the TRUNCATE command against each PostgreSQL table just before loading data into it.

    • no truncate
    • When this option is listed, pgloader issues no TRUNCATE command.

    • disable triggers
    • When this option is listed, pgloader issues an ALTER TABLE ... DISABLE TRIGGER ALL command against the PostgreSQL target table before copying the data, then the command ALTER TABLE ... ENABLE TRIGGER ALL once the COPY is done.

      This option allows loading data into a pre-existing table ignoring the foreign key constraints and user defined triggers and may result in invalid foreign key constraints once the data is loaded. Use with care.

    • create tables

      When this option is listed, pgloader creates the table using the meta data found in the SQLite file, which must contain a list of fields with their data type. A standard data type conversion from DBF to PostgreSQL is done.

    • create no tables

      When this option is listed, pgloader skips the creation of table before loading data, target tables must then already exist.

    • Also, when using create no tables pgloader fetches the metadata from the current target database and checks type casting, then will remove constraints and indexes prior to loading the data and install them back again once the loading is done.

    • create indexes
    • When this option is listed, pgloader gets the definitions of all the indexes found in the SQLite database and create the same set of index definitions against the PostgreSQL database.

    • create no indexes
    • When this option is listed, pgloader skips the creating indexes.

    • drop indexes
    • When this option is listed, pgloader drops the indexes in the target database before loading the data, and creates them again at the end of the data copy.

    • reset sequences
    • When this option is listed, at the end of the data loading and after the indexes have all been created, pgloader resets all the PostgreSQL sequences created to the current maximum value of the column they are attached to.

    • reset no sequences
    • When this option is listed, pgloader skips resetting sequences after the load.

      The options schema only and data only have no effects on this option.

    • schema only

      When this option is listed pgloader will refrain from migrating the data over. Note that the schema in this context includes the indexes when the option create indexes has been listed.

    • data only

      When this option is listed pgloader only issues the COPY statements, without doing any other processing.

    • encoding

      This option allows to control which encoding to parse the SQLite text data with. Defaults to UTF-8.

  • CAST

    The cast clause allows to specify custom casting rules, either to overload the default casting rules or to amend them with special cases.

  • Please refer to the MySQL CAST clause for details.

  • INCLUDING ONLY TABLE NAMES LIKE
  • Introduce a comma separated list of table name patterns used to limit the tables to migrate to a sublist.

    Example:

    INCLUDING ONLY TABLE NAMES LIKE 'Invoice%' 
  • EXCLUDING TABLE NAMES LIKE

    Introduce a comma separated list of table name patterns used to exclude table names from the migration. This filter only applies to the result of the INCLUDING filter.

    EXCLUDING TABLE NAMES LIKE 'appointments' 

DEFAULT SQLite CASTING RULES

When migrating from SQLite the following Casting Rules are provided:

Numbers:

  • type tinyint to smallint using integer-to-string
  • type integer to bigint using integer-to-string

  • type float to float using float-to-string

  • type real to real using float-to-string
  • type double to double precision using float-to-string
  • type numeric to numeric using float-to-string

Texts:

  • type character to text drop typemod
  • type varchar to text drop typemod
  • type nvarchar to text drop typemod
  • type char to text drop typemod
  • type nchar to text drop typemod
  • type nvarchar to text drop typemod
  • type clob to text drop typemod

Binary:

  • type blob to bytea

Date:

  • type datetime to timestamptz using sqlite-timestamp-to-timestamp
  • type timestamp to timestamptz using sqlite-timestamp-to-timestamp
  • type timestamptz to timestamptz using sqlite-timestamp-to-timestamp

LOAD MS SQL DATABASE

This command instructs pgloader to load data from a MS SQL database. Automatic discovery of the schema is supported, including build of the indexes, primary and foreign keys constraints.

Here's an example:

load database  
-     from mssql://user@host/dbname  
-     into postgresql:///dbname  
- 
-including only table names like 'GlobalAccount' in schema 'dbo'  
- 
-set work_mem to '16MB', maintenance_work_mem to '512 MB'  
- 
-before load do $$ drop schema if exists dbo cascade; $$; 

The mssql command accepts the following clauses and options:

  • FROM

    Connection string to an existing MS SQL database server that listens and welcome external TCP/IP connection. As pgloader currently piggybacks on the FreeTDS driver, to change the port of the server please export the TDSPORT environment variable.

  • WITH

    When loading from a MS SQL database, the same options as when loading a MySQL database are supported. Please refer to the MySQL section. The following options are added:

    • create schemas

      When this option is listed, pgloader creates the same schemas as found on the MS SQL instance. This is the default.

    • create no schemas

      When this option is listed, pgloader refrains from creating any schemas at all, you must then ensure that the target schema do exist.

  • CAST

    The cast clause allows to specify custom casting rules, either to overload the default casting rules or to amend them with special cases.

  • Please refer to the MySQL CAST clause for details.

  • INCLUDING ONLY TABLE NAMES LIKE '...' [, '...'] IN SCHEMA '...'
  • Introduce a comma separated list of table name patterns used to limit the tables to migrate to a sublist. More than one such clause may be used, they will be accumulated together.

    Example:

    including only table names lile 'GlobalAccount' in schema 'dbo' 
  • EXCLUDING TABLE NAMES LIKE '...' [, '...'] IN SCHEMA '...'

    Introduce a comma separated list of table name patterns used to exclude table names from the migration. This filter only applies to the result of the INCLUDING filter.

    EXCLUDING TABLE NAMES MATCHING 'LocalAccount' in schema 'dbo' 
  • ALTER SCHEMA '...' RENAME TO '...'

    Allows to rename a schema on the flight, so that for instance the tables found in the schema 'dbo' in your source database will get migrated into the schema 'public' in the target database with this command:

    ALTER SCHEMA 'dbo' RENAME TO 'public' 
  • ALTER TABLE NAMES MATCHING ... IN SCHEMA '...'

    See the MySQL explanation for this clause above. It works the same in the context of migrating from MS SQL, only with the added option to specify the name of the schema where to find the definition of the target tables.

  • The matching is done in pgloader itself, with a Common Lisp regular expression lib, so doesn't depend on the LIKE implementation of MS SQL, nor on the lack of support for regular expressions in the engine.

Driver setup and encoding

pgloader is using the FreeTDS driver, and internally expects the data to be sent in utf-8. To achieve that, you can configure the FreeTDS driver with those defaults, in the file ~/.freetds.conf:

[global]  
-	tds version = 7.4  
-	client charset = UTF-8 

DEFAULT MS SQL CASTING RULES

When migrating from MS SQL the following Casting Rules are provided:

Numbers:

  • type tinyint to smallint

  • type float to float using float-to-string

  • type real to real using float-to-string
  • type double to double precision using float-to-string
  • type numeric to numeric using float-to-string
  • type decimal to numeric using float-to-string
  • type money to numeric using float-to-string
  • type smallmoney to numeric using float-to-string

Texts:

  • type char to text drop typemod
  • type nchat to text drop typemod
  • type varchar to text drop typemod
  • type nvarchar to text drop typemod
  • type xml to text drop typemod

Binary:

  • type binary to bytea using byte-vector-to-bytea
  • type varbinary to bytea using byte-vector-to-bytea

Date:

  • type datetime to timestamptz
  • type datetime2 to timestamptz

Others:

  • type bit to boolean
  • type hierarchyid to bytea
  • type geography to bytea
  • type uniqueidentifier to uuid using sql-server-uniqueidentifier-to-uuid

TRANSFORMATION FUNCTIONS

Some data types are implemented in a different enough way that a transformation function is necessary. This function must be written in Common lisp and is searched in the pgloader.transforms package.

Some default transformation function are provided with pgloader, and you can use the --load command line option to load and compile your own lisp file into pgloader at runtime. For your functions to be found, remember to begin your lisp file with the following form:

(in-package #:pgloader.transforms) 

The provided transformation functions are:

  • zero-dates-to-null

    When the input date is all zeroes, return nil, which gets loaded as a PostgreSQL NULL value.

  • date-with-no-separator

    Applies zero-dates-to-null then transform the given date into a format that PostgreSQL will actually process:

    In:  "20041002152952"  
    -Out: "2004-10-02 15:29:52" 
  • time-with-no-separator

    Transform the given time into a format that PostgreSQL will actually process:

    In:  "08231560"  
    -Out: "08:23:15.60" 
  • tinyint-to-boolean

    As MySQL lacks a proper boolean type, tinyint is often used to implement that. This function transforms 0 to 'false' and anything else to 'true'.

  • bits-to-boolean

    As MySQL lacks a proper boolean type, BIT is often used to implement that. This function transforms 1-bit bit vectors from 0 to f and any other value to t..

  • int-to-ip

    Convert an integer into a dotted representation of an ip4.

    In:  18435761  
    -Out: "1.25.78.177" 
  • ip-range

    Converts a couple of integers given as strings into a range of ip4.

    In:  "16825344" "16825599"  
    -Out: "1.0.188.0-1.0.188.255" 
  • convert-mysql-point

    Converts from the astext representation of points in MySQL to the PostgreSQL representation.

    In:  "POINT(48.5513589 7.6926827)"  
    -Out: "(48.5513589,7.6926827)" 
  • integer-to-string

    Converts a integer string or a Common Lisp integer into a string suitable for a PostgreSQL integer. Takes care of quoted integers.

    In:  "\"0\""  
    -Out: "0" 
  • float-to-string

    Converts a Common Lisp float into a string suitable for a PostgreSQL float:

    In:  100.0d0  
    -Out: "100.0" 
  • set-to-enum-array

    Converts a string representing a MySQL SET into a PostgreSQL Array of Enum values from the set.

    In: "foo,bar"  
    -Out: "{foo,bar}" 
  • empty-string-to-null

    Convert an empty string to a null.

  • right-trim

    Remove whitespace at end of string.

  • remove-null-characters

    Remove NUL characters (0x0) from given strings.

  • byte-vector-to-bytea

    Transform a simple array of unsigned bytes to the PostgreSQL bytea Hex Format representation as documented at http://www.postgresql.org/docs/9.3/interactive/datatype-binary.html

  • sqlite-timestamp-to-timestamp

    SQLite type system is quite interesting, so cope with it here to produce timestamp literals as expected by PostgreSQL. That covers year only on 4 digits, 0 dates to null, and proper date strings.

  • sql-server-uniqueidentifier-to-uuid

    The SQL Server driver receives data fo type uniqueidentifier as byte vector that we then need to convert to an UUID string for PostgreSQL COPY input format to process.

  • unix-timestamp-to-timestamptz

    Converts a unix timestamp (number of seconds elapsed since beginning of 1970) into a proper PostgreSQL timestamp format.

  • varbinary-to-string

    Converts binary encoded string (such as a MySQL varbinary entry) to a decoded text, using the table's encoding that may be overloaded with the DECODING TABLE NAMES MATCHING clause.

LOAD MESSAGES

This command is still experimental and allows receiving messages via UDP using a syslog like format, and, depending on rule matching, loads named portions of the data stream into a destination table.

LOAD MESSAGES  
-    FROM syslog://localhost:10514/  
- 
- WHEN MATCHES rsyslog-msg IN apache  
-  REGISTERING timestamp, ip, rest  
-         INTO postgresql://localhost/db?logs.apache  
-          SET guc_1 = 'value', guc_2 = 'other value'  
- 
- WHEN MATCHES rsyslog-msg IN others  
-  REGISTERING timestamp, app-name, data  
-         INTO postgresql://localhost/db?logs.others  
-          SET guc_1 = 'value', guc_2 = 'other value'  
- 
-    WITH apache = rsyslog  
-         DATA   = IP REST  
-         IP     = 1*3DIGIT "." 1*3DIGIT "."1*3DIGIT "."1*3DIGIT  
-         REST   = ~/.*/  
- 
-    WITH others = rsyslog; 

As the command is still experimental the options might be changed in the future and the details are not documented.

AUTHOR

Dimitri Fontaine

SEE ALSO

PostgreSQL COPY documentation at .

The pgloader source code, binary packages, documentation and examples may be downloaded from .

-
-
- - - - -
- - - - - - - - - - - diff --git a/docs/howto/quickstart.html b/docs/howto/quickstart.html deleted file mode 100644 index 0508f8b..0000000 --- a/docs/howto/quickstart.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
-

pgloader: a quickstart

In simple cases, pgloader is very easy to use.

CSV

Load data from a CSV file into a pre-existing table in your database:

pgloader --type csv                                   \  
-         --field id --field field                     \  
-         --with truncate                              \  
-         --with "fields terminated by ','"            \  
-         ./test/data/matching-1.csv                   \  
-         postgres:///pgloader?tablename=matching 

In that example the whole loading is driven from the command line, bypassing the need for writing a command in the pgloader command syntax entirely. As there's no command though, the extra information needed must be provided on the command line using the --type and --field and --with switches.

For documentation about the available syntaxes for the --field and --with switches, please refer to the CSV section later in the man page.

Note also that the PostgreSQL URI includes the target tablename.

Reading from STDIN

File based pgloader sources can be loaded from the standard input, as in the following example:

pgloader --type csv                                         \  
-         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \  
-         --with "skip header = 1"                          \  
-         --with "fields terminated by '\t'"                \  
-         -                                                 \  
-         postgresql:///pgloader?districts_longlat          \  
-         < test/data/2013_Gaz_113CDs_national.txt 

The dash (-) character as a source is used to mean standard input, as usual in Unix command lines. It's possible to stream compressed content to pgloader with this technique, using the Unix pipe:

gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo 

Loading from CSV available through HTTP

The same command as just above can also be run if the CSV file happens to be found on a remote HTTP location:

pgloader --type csv                                                     \  
-         --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \  
-         --with "skip header = 1"                                       \  
-         --with "fields terminated by '\t'"                             \  
-         http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt     \  
-         postgresql:///pgloader?districts_longlat 

Some more options have to be used in that case, as the file contains a one-line header (most commonly that's column names, could be a copyright notice). Also, in that case, we specify all the fields right into a single --field option argument.

Again, the PostgreSQL target connection string must contain the tablename option and you have to ensure that the target table exists and may fit the data. Here's the SQL command used in that example in case you want to try it yourself:

create table districts_longlat  
-(  
-         usps        text,  
-         geoid       text,  
-         aland       bigint,  
-         awater      bigint,  
-         aland_sqmi  double precision,  
-         awater_sqmi double precision,  
-         intptlat    double precision,  
-         intptlong   double precision  
-); 

Also notice that the same command will work against an archived version of the same data.

Streaming CSV data from an HTTP compressed file

Finally, it's important to note that pgloader first fetches the content from the HTTP URL it to a local file, then expand the archive when it's recognized to be one, and only then processes the locally expanded file.

In some cases, either because pgloader has no direct support for your archive format or maybe because expanding the archive is not feasible in your environment, you might want to stream the content straight from its remote location into PostgreSQL. Here's how to do that, using the old battle tested Unix Pipes trick:

curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \  
-| gunzip -c                                                        \  
-| pgloader --type csv                                              \  
-           --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong"  
-           --with "skip header = 1"                                \  
-           --with "fields terminated by '\t'"                      \  
-           -                                                       \  
-           postgresql:///pgloader?districts_longlat 

Now the OS will take care of the streaming and buffering between the network and the commands and pgloader will take care of streaming the data down to PostgreSQL.

Migrating from SQLite

The following command will open the SQLite database, discover its tables definitions including indexes and foreign keys, migrate those definitions while casting the data type specifications to their PostgreSQL equivalent and then migrate the data over:

createdb newdb  
-pgloader ./test/sqlite/sqlite.db postgresql:///newdb 

Migrating from MySQL

Just create a database where to host the MySQL data and definitions and have pgloader do the migration for you in a single command line:

createdb pagila  
-pgloader mysql://user@localhost/sakila postgresql:///pagila 

Fetching an archived DBF file from a HTTP remote location

It's possible for pgloader to download a file from HTTP, unarchive it, and only then open it to discover the schema then load the data:

createdb foo  
-pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo 

Here it's not possible for pgloader to guess the kind of data source it's being given, so it's necessary to use the --type command line switch.

-
-
- - - - -
- - - - - - - - - - - diff --git a/docs/howto/sqlite.html b/docs/howto/sqlite.html deleted file mode 100644 index e9ec1a9..0000000 --- a/docs/howto/sqlite.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - pgloader - - - - - - - - - - - - - - -
-
-
-
-

Loading SQLite files with pgloader

The SQLite database is a respected solution to manage your data with. Its embeded nature makes it a source of migrations when a projects now needs to handle more concurrency, which PostgreSQL is very good at. pgloader can help you there.

In a Single Command Line

You can

$ createdb chinook  
-$ pgloader https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite pgsql:///chinook 

Done! All with the schema, data, constraints, primary keys and foreign keys, etc. We also see an error with the Chinook schema that contains several primary key definitions against the same table, which is not accepted by PostgreSQL:

2017-06-20T16:18:59.019000+02:00 LOG Data errors in '/private/tmp/pgloader/'  
-2017-06-20T16:18:59.236000+02:00 LOG Fetching 'https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite_AutoIncrementPKs.sqlite'  
-2017-06-20T16:19:00.664000+02:00 ERROR Database error 42P16: multiple primary keys for table "playlisttrack" are not allowed  
-QUERY: ALTER TABLE playlisttrack ADD PRIMARY KEY USING INDEX idx_66873_sqlite_autoindex_playlisttrack_1;  
-2017-06-20T16:19:00.665000+02:00 LOG report summary reset  
-             table name       read   imported     errors      total time  
------------------------  ---------  ---------  ---------  --------------  
-                  fetch          0          0          0          0.877s  
-        fetch meta data         33         33          0          0.033s  
-         Create Schemas          0          0          0          0.003s  
-       Create SQL Types          0          0          0          0.006s  
-          Create tables         22         22          0          0.043s  
-         Set Table OIDs         11         11          0          0.012s  
------------------------  ---------  ---------  ---------  --------------  
-                  album        347        347          0          0.023s  
-                 artist        275        275          0          0.023s  
-               customer         59         59          0          0.021s  
-               employee          8          8          0          0.018s  
-                invoice        412        412          0          0.031s  
-                  genre         25         25          0          0.021s  
-            invoiceline       2240       2240          0          0.034s  
-              mediatype          5          5          0          0.025s  
-          playlisttrack       8715       8715          0          0.040s  
-               playlist         18         18          0          0.016s  
-                  track       3503       3503          0          0.111s  
------------------------  ---------  ---------  ---------  --------------  
-COPY Threads Completion         33         33          0          0.313s  
-         Create Indexes         22         22          0          0.160s  
- Index Build Completion         22         22          0          0.027s  
-        Reset Sequences          0          0          0          0.017s  
-           Primary Keys         12          0          1          0.013s  
-    Create Foreign Keys         11         11          0          0.040s  
-        Create Triggers          0          0          0          0.000s  
-       Install Comments          0          0          0          0.000s  
------------------------  ---------  ---------  ---------  --------------  
-      Total import time      15607      15607          0          1.669s 

You may need to have special cases to take care of tho. In advanced case you can use the pgloader command.

The Command

To load data with pgloader you need to define in a command the operations in some details. Here's our command:

load database  
-     from 'sqlite/Chinook_Sqlite_AutoIncrementPKs.sqlite'  
-     into postgresql:///pgloader  
- 
- with include drop, create tables, create indexes, reset sequences  
- 
-  set work_mem to '16MB', maintenance_work_mem to '512 MB'; 

You can see the full list of options in the pgloader reference manual, with a complete description of the options you see here.

Note that here pgloader will benefit from the meta-data information found in the SQLite file to create a PostgreSQL database capable of hosting the data as described, then load the data.

Loading the data

Let's start the pgloader command with our sqlite.load command file:

$ pgloader sqlite.load  
-... LOG Starting pgloader, log system is ready.  
-... LOG Parsing commands from file "/Users/dim/dev/pgloader/test/sqlite.load"  
-... WARNING Postgres warning: table "album" does not exist, skipping  
-... WARNING Postgres warning: table "artist" does not exist, skipping  
-... WARNING Postgres warning: table "customer" does not exist, skipping  
-... WARNING Postgres warning: table "employee" does not exist, skipping  
-... WARNING Postgres warning: table "genre" does not exist, skipping  
-... WARNING Postgres warning: table "invoice" does not exist, skipping  
-... WARNING Postgres warning: table "invoiceline" does not exist, skipping  
-... WARNING Postgres warning: table "mediatype" does not exist, skipping  
-... WARNING Postgres warning: table "playlist" does not exist, skipping  
-... WARNING Postgres warning: table "playlisttrack" does not exist, skipping  
-... WARNING Postgres warning: table "track" does not exist, skipping  
-            table name       read   imported     errors            time  
-----------------------  ---------  ---------  ---------  --------------  
-      create, truncate          0          0          0          0.052s  
-                 Album        347        347          0          0.070s  
-                Artist        275        275          0          0.014s  
-              Customer         59         59          0          0.014s  
-              Employee          8          8          0          0.012s  
-                 Genre         25         25          0          0.018s  
-               Invoice        412        412          0          0.032s  
-           InvoiceLine       2240       2240          0          0.077s  
-             MediaType          5          5          0          0.012s  
-              Playlist         18         18          0          0.008s  
-         PlaylistTrack       8715       8715          0          0.071s  
-                 Track       3503       3503          0          0.105s  
-index build completion          0          0          0          0.000s  
-----------------------  ---------  ---------  ---------  --------------  
-        Create Indexes         20         20          0          0.279s  
-       reset sequences          0          0          0          0.043s  
-----------------------  ---------  ---------  ---------  --------------  
-  Total streaming time      15607      15607          0          0.476s 

We can see that http://pgloader.io did download the file from its HTTP URL location then unziped it before loading it.

Also, the WARNING messages we see here are expected as the PostgreSQL database is empty when running the command, and pgloader is using the SQL commands DROP TABLE IF EXISTS when the given command uses the include drop option.

Note that the output of the command has been edited to facilitate its browsing online.

-
-
- - - - -
- - - - - - - - - - - diff --git a/docs/img/2ndquadrant_logo_full_color.640.jpg b/docs/img/2ndquadrant_logo_full_color.640.jpg deleted file mode 100644 index f9157e2..0000000 Binary files a/docs/img/2ndquadrant_logo_full_color.640.jpg and /dev/null differ diff --git a/docs/img/2ndquadrant_logo_full_color.800.jpg b/docs/img/2ndquadrant_logo_full_color.800.jpg deleted file mode 100644 index 86f4c6b..0000000 Binary files a/docs/img/2ndquadrant_logo_full_color.800.jpg and /dev/null differ diff --git a/docs/img/2ndquadrant_logo_full_color.jpg b/docs/img/2ndquadrant_logo_full_color.jpg deleted file mode 100644 index 4d938c5..0000000 Binary files a/docs/img/2ndquadrant_logo_full_color.jpg and /dev/null differ diff --git a/docs/img/bsd.svg b/docs/img/bsd.svg deleted file mode 100644 index e47ce6d..0000000 --- a/docs/img/bsd.svg +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/img/csv_text.png b/docs/img/csv_text.png deleted file mode 100644 index cd30e93..0000000 Binary files a/docs/img/csv_text.png and /dev/null differ diff --git a/docs/img/enterprise-metasearch-sources.jpg b/docs/img/enterprise-metasearch-sources.jpg deleted file mode 100644 index 896ab72..0000000 Binary files a/docs/img/enterprise-metasearch-sources.jpg and /dev/null differ diff --git a/docs/img/fb-logo-4d-1000x168.COLOR.png b/docs/img/fb-logo-4d-1000x168.COLOR.png deleted file mode 100644 index 4bf3bdb..0000000 Binary files a/docs/img/fb-logo-4d-1000x168.COLOR.png and /dev/null differ diff --git a/docs/img/huge-full-outer-join.gif b/docs/img/huge-full-outer-join.gif deleted file mode 100644 index 3ce0a36..0000000 Binary files a/docs/img/huge-full-outer-join.gif and /dev/null differ diff --git a/docs/img/iwoca.png b/docs/img/iwoca.png deleted file mode 100644 index c25034a..0000000 Binary files a/docs/img/iwoca.png and /dev/null differ diff --git a/docs/img/redpill-linpro.jpg b/docs/img/redpill-linpro.jpg deleted file mode 100644 index 1999203..0000000 Binary files a/docs/img/redpill-linpro.jpg and /dev/null differ diff --git a/docs/img/sqlite.gif b/docs/img/sqlite.gif deleted file mode 100644 index c63fdc4..0000000 Binary files a/docs/img/sqlite.gif and /dev/null differ diff --git a/docs/img/toy-loader.140.jpg b/docs/img/toy-loader.140.jpg deleted file mode 100644 index f861db6..0000000 Binary files a/docs/img/toy-loader.140.jpg and /dev/null differ diff --git a/docs/img/toy-loader.320.jpg b/docs/img/toy-loader.320.jpg deleted file mode 100644 index a9ddf65..0000000 Binary files a/docs/img/toy-loader.320.jpg and /dev/null differ diff --git a/docs/img/toy-loader.640.jpg b/docs/img/toy-loader.640.jpg deleted file mode 100644 index 8d50159..0000000 Binary files a/docs/img/toy-loader.640.jpg and /dev/null differ diff --git a/docs/img/type-casting-machine.320.jpg b/docs/img/type-casting-machine.320.jpg deleted file mode 100644 index 0ab7ff7..0000000 Binary files a/docs/img/type-casting-machine.320.jpg and /dev/null differ diff --git a/docs/img/type-casting-machine.500.jpg b/docs/img/type-casting-machine.500.jpg deleted file mode 100644 index 37288bf..0000000 Binary files a/docs/img/type-casting-machine.500.jpg and /dev/null differ diff --git a/docs/img/type-casting-machine.640.jpg b/docs/img/type-casting-machine.640.jpg deleted file mode 100644 index 56331d5..0000000 Binary files a/docs/img/type-casting-machine.640.jpg and /dev/null differ diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 5cd7b96..0000000 --- a/docs/index.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - pgloader - - - - - - - - - - - - - - - - - - -
-
-
-

Why did pgloader get so much faster?

- -
-
- -
- - - - - -
-
-

Migrate from MySQL to PostgreSQL. In one command.

-

Given a MySQL connection string, pgloader query - the catalogs to list your tables, constraints and indexes and know - how to transform this schema into a PostgreSQL equivalent, - applying advanced casting rules that you can edit in the - command.

-

Migrate some tinyint to boolean and some others - to smallint all from the same tool!

-

View details »

-
-
- MySQL to PostgreSQL with Custom Type Casting -
-
- -
- -
-
- CSV data format -
-
-

Load any CSV file. Real quick.

-

The current version of pgloader is up to ten - times faster than the previous one. The new command syntax - is really powerful, and as it's different enough from the previous - version, pgloader includes a command line switch to upgrade your - setup for you.

-

View details »

-
-
- -
- -
-
-

Transform your data. While streaming.

-

pgloader includes reformating modules allowing you - to reformat your data, such as transforming a couple of integer - columns into a single ip address, or a couple of floats - into a single point. Of course, you can add any - transformation you like and easily get to use it with - pgloader loading your code!

-

View details »

-
-
- Transform Data -
-
- -
- - - - - - - -
- - - - - - - - - - - - diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..d69915e --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,33 @@ +.. pgloader documentation master file, created by + sphinx-quickstart on Tue Dec 5 19:23:32 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to pgloader's documentation! +==================================== + +.. toctree:: + :maxdepth: 2 + :caption: Table Of Contents: + + intro + tutorial/tutorial + pgloader + ref/csv + ref/fixed + ref/copy + ref/dbf + ref/ixf + ref/archive + ref/mysql + ref/sqlite + ref/mssql + ref/transforms + bugreport + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 0000000..0dc75e2 --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,63 @@ +Introduction +============ + +pgloader loads data from various sources into PostgreSQL. It can +transform the data it reads on the fly and submit raw SQL before and +after the loading. It uses the `COPY` PostgreSQL protocol to stream +the data into the server, and manages errors by filling a pair of +*reject.dat* and *reject.log* files. + +pgloader knows how to read data from different kind of sources: + + * Files + * CSV + * Fixed Format + * DBF + * Databases + * SQLite + * MySQL + * MS SQL Server + +The level of automation provided by pgloader depends on the data source +type. In the case of CSV and Fixed Format files, a full description of the +expected input properties must be given to pgloader. In the case of a +database, pgloader connects to the live service and knows how to fetch the +metadata it needs directly from it. + +Continuous Migration +-------------------- + +pgloader is meant to migrate a whole database in a single command line and +without any manual intervention. The goal is to be able to setup a +*Continuous Integration* environment as described in the `Project +Methodology `_ document of the `MySQL to +PostgreSQL `_ webpage. + + 1. Setup your target PostgreSQL Architecture + 2. Fork a Continuous Integration environment that uses PostgreSQL + 3. Migrate the data over and over again every night, from production + 4. As soon as the CI is all green using PostgreSQL, schedule the D-Day + 5. Migrate without suprise and enjoy! + +In order to be able to follow this great methodology, you need tooling to +implement the third step in a fully automated way. That's pgloader. + +Commands +-------- + +pgloader implements its own *Command Language*, a DSL that allows to specify +every aspect of the data load and migration to implement. Some of the +features provided in the language are only available for a specific source +type. + +Command Line +------------ + +The pgloader command line accepts those two variants:: + + pgloader [] []... + pgloader [] SOURCE TARGET + +Either you have a *command-file* containing migration specifications in the +pgloader *Command Language*, or you can give a *Source* for the data and a +PostgreSQL database connection *Target* where to load the data into. diff --git a/docs/pgloader-moral-license.html b/docs/pgloader-moral-license.html deleted file mode 100644 index 3416f27..0000000 --- a/docs/pgloader-moral-license.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - - - - pgloader - - - - - - - - - - - - - - - -
-
-
-

- pgloader Moral License -

-

- The pgloader project is fully Open Source and released - under The - PostgreSQL License so that anyone can easily contribute to - the project. The whole project management (issue tracking, - feature proposals, etc) happens on - the pgloader - github page, in public. -

- - BSD - -
-

- Software development may be open, and the result shared with an - Open Source Software licence, but the actual hours of - programming are not gratis. -

-

- Just like everybody else, I need money for mortgage, kids and - food, money I make by doing things with computers, for people - who are willing to pay for that. - - One of the things I do for money, is develop pgloader, and the - pgloader Moral License is a good vehicle available for - the paperwork. I shamelessly stole the whole idea - from The Varnish Moral - License. See - the Varnish - Moral License FAQ and How To to see how PHK does it. -

-

Buy your license here:

-
-
- - - - -
-
-

- If you have very custom needs and require more paperwork, of - course that is still possible too, just get in touch - at dim@tapoueh.org! -

- - -
- - - - - - - - - - - - diff --git a/docs/pgloader-usage-examples.rst b/docs/pgloader-usage-examples.rst new file mode 100644 index 0000000..72223b9 --- /dev/null +++ b/docs/pgloader-usage-examples.rst @@ -0,0 +1,163 @@ +Pgloader Usage Examples +======================= + +Currently not included, because redundant with the tutorial. + +Usage Examples +-------------- + +Review the command line options and pgloader's version:: + + pgloader --help + pgloader --version + +Loading from a complex command +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use the command file as the pgloader command argument, pgloader will parse +that file and execute the commands found in it:: + + pgloader --verbose ./test/csv-districts.load + +CSV +^^^ + +Load data from a CSV file into a pre-existing table in your database, having +pgloader guess the CSV properties (separator, quote and escape character):: + + pgloader ./test/data/matching-1.csv pgsql:///pgloader?tablename=matching + +Load data from a CSV file into a pre-existing table in your database, with +expanded options:: + + pgloader --type csv \ + --field id --field field \ + --with truncate \ + --with "fields terminated by ','" \ + ./test/data/matching-1.csv \ + postgres:///pgloader?tablename=matching + +In that example the whole loading is driven from the command line, bypassing +the need for writing a command in the pgloader command syntax entirely. As +there's no command though, the extra inforamtion needed must be provided on +the command line using the `--type` and `--field` and `--with` switches. + +For documentation about the available syntaxes for the `--field` and +`--with` switches, please refer to the CSV section later in the man page. + +Note also that the PostgreSQL URI includes the target *tablename*. + +Reading from STDIN +^^^^^^^^^^^^^^^^^^ + +File based pgloader sources can be loaded from the standard input, as in the +following example:: + + pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \ + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + - \ + postgresql:///pgloader?districts_longlat \ + < test/data/2013_Gaz_113CDs_national.txt + +The dash (`-`) character as a source is used to mean *standard input*, as +usual in Unix command lines. It's possible to stream compressed content to +pgloader with this technique, using the Unix pipe: + + gunzip -c source.gz | pgloader --type csv ... - pgsql:///target?foo + +Loading from CSV available through HTTP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The same command as just above can also be run if the CSV file happens to be +found on a remote HTTP location:: + + pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" \ + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt \ + postgresql:///pgloader?districts_longlat + +Some more options have to be used in that case, as the file contains a +one-line header (most commonly that's column names, could be a copyright +notice). Also, in that case, we specify all the fields right into a single +`--field` option argument. + +Again, the PostgreSQL target connection string must contain the *tablename* +option and you have to ensure that the target table exists and may fit the +data. Here's the SQL command used in that example in case you want to try it +yourself:: + + create table districts_longlat + ( + usps text, + geoid text, + aland bigint, + awater bigint, + aland_sqmi double precision, + awater_sqmi double precision, + intptlat double precision, + intptlong double precision + ); + +Also notice that the same command will work against an archived version of +the same data, e.g. +http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz. + +Finally, it's important to note that pgloader first fetches the content from +the HTTP URL it to a local file, then expand the archive when it's +recognized to be one, and only then processes the locally expanded file. + +In some cases, either because pgloader has no direct support for your +archive format or maybe because expanding the archive is not feasible in +your environment, you might want to *stream* the content straight from its +remote location into PostgreSQL. Here's how to do that, using the old battle +tested Unix Pipes trick:: + + curl http://pgsql.tapoueh.org/temp/2013_Gaz_113CDs_national.txt.gz \ + | gunzip -c \ + | pgloader --type csv \ + --field "usps,geoid,aland,awater,aland_sqmi,awater_sqmi,intptlat,intptlong" + --with "skip header = 1" \ + --with "fields terminated by '\t'" \ + - \ + postgresql:///pgloader?districts_longlat + +Now the OS will take care of the streaming and buffering between the network +and the commands and pgloader will take care of streaming the data down to +PostgreSQL. + +Migrating from SQLite +^^^^^^^^^^^^^^^^^^^^^ + +The following command will open the SQLite database, discover its tables +definitions including indexes and foreign keys, migrate those definitions +while *casting* the data type specifications to their PostgreSQL equivalent +and then migrate the data over:: + + createdb newdb + pgloader ./test/sqlite/sqlite.db postgresql:///newdb + +Migrating from MySQL +^^^^^^^^^^^^^^^^^^^^ + +Just create a database where to host the MySQL data and definitions and have +pgloader do the migration for you in a single command line:: + + createdb pagila + pgloader mysql://user@localhost/sakila postgresql:///pagila + +Fetching an archived DBF file from a HTTP remote location +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's possible for pgloader to download a file from HTTP, unarchive it, and +only then open it to discover the schema then load the data:: + + createdb foo + pgloader --type dbf http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/historiq2013.zip postgresql:///foo + +Here it's not possible for pgloader to guess the kind of data source it's +being given, so it's necessary to use the `--type` command line switch. + diff --git a/docs/pgloader.rst b/docs/pgloader.rst new file mode 100644 index 0000000..fb51bdf --- /dev/null +++ b/docs/pgloader.rst @@ -0,0 +1,713 @@ +PgLoader Reference Manual +========================= + +pgloader loads data from various sources into PostgreSQL. It can +transform the data it reads on the fly and submit raw SQL before and +after the loading. It uses the `COPY` PostgreSQL protocol to stream +the data into the server, and manages errors by filling a pair of +*reject.dat* and *reject.log* files. + +pgloader operates either using commands which are read from files:: + + pgloader commands.load + +or by using arguments and options all provided on the command line:: + + pgloader SOURCE TARGET + +Arguments +--------- + +The pgloader arguments can be as many load files as needed, or a couple of +connection strings to a specific input file. + +Source Connection String +^^^^^^^^^^^^^^^^^^^^^^^^ + +The source connection string format is as follows:: + + format:///absolute/path/to/file.ext + format://./relative/path/to/file.ext + +Where format might be one of `csv`, `fixed`, `copy`, `dbf`, `db3` or `ixf`.:: + + db://user:pass@host:port/dbname + +Where db might be of `sqlite`, `mysql` or `mssql`. + +When using a file based source format, pgloader also support natively +fetching the file from an http location and decompressing an archive if +needed. In that case it's necessary to use the `--type` option to specify +the expected format of the file. See the examples below. + +Also note that some file formats require describing some implementation +details such as columns to be read and delimiters and quoting when loading +from csv. + +For more complex loading scenarios, you will need to write a full fledge +load command in the syntax described later in this document. + +Target Connection String +^^^^^^^^^^^^^^^^^^^^^^^^ + +The target connection string format is described in details later in this +document, see Section Connection String. + +Options +------- + +Inquiry Options +^^^^^^^^^^^^^^^ + +Use these options when you want to know more about how to use `pgloader`, as +those options will cause `pgloader` not to load any data. + + * `-h`, `--help` + + Show command usage summary and exit. + + * `-V`, `--version` + + Show pgloader version string and exit. + + * `-E`, `--list-encodings` + + List known encodings in this version of pgloader. + + * `-U`, `--upgrade-config` + + Parse given files in the command line as `pgloader.conf` files with the + `INI` syntax that was in use in pgloader versions 2.x, and output the + new command syntax for pgloader on standard output. + + +General Options +^^^^^^^^^^^^^^^ + +Those options are meant to tweak `pgloader` behavior when loading data. + + * `-v`, `--verbose` + + Be verbose. + + * `-q`, `--quiet` + + Be quiet. + + * `-d`, `--debug` + + Show debug level information messages. + + * `-D`, `--root-dir` + + Set the root working directory (default to "/tmp/pgloader"). + + * `-L`, `--logfile` + + Set the pgloader log file (default to "/tmp/pgloader.log"). + + * `--log-min-messages` + + Minimum level of verbosity needed for log message to make it to the + logfile. One of critical, log, error, warning, notice, info or debug. + + * `--client-min-messages` + + Minimum level of verbosity needed for log message to make it to the + console. One of critical, log, error, warning, notice, info or debug. + + * `-S`, `--summary` + + A filename where to copy the summary output. When relative, the filename + is expanded into `*root-dir*`. + + The format of the filename defaults to being *human readable*. It is + possible to have the output in machine friendly formats such as *CSV*, + *COPY* (PostgreSQL's own COPY format) or *JSON* by specifying a filename + with the extension resp. `.csv`, `.copy` or `.json`. + + * `-l `, `--load-lisp-file ` + + Specify a lisp to compile and load into the pgloader image before + reading the commands, allowing to define extra transformation function. + Those functions should be defined in the `pgloader.transforms` package. + This option can appear more than once in the command line. + + * `--dry-run` + + Allow testing a `.load` file without actually trying to load any data. + It's useful to debug it until it's ok, in particular to fix connection + strings. + + * `--on-error-stop` + + Alter pgloader behavior: rather than trying to be smart about error + handling and continue loading good data, separating away the bad one, + just stop as soon as PostgreSQL refuses anything sent to it. Useful to + debug data processing, transformation function and specific type + casting. + + * `--self-upgrade ` + + Specify a where to find pgloader sources so that one of the + very first things it does is dynamically loading-in (and compiling to + machine code) another version of itself, usually a newer one like a very + recent git checkout. + +Command Line Only Operations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Those options are meant to be used when using `pgloader` from the command +line only, rather than using a command file and the rich command clauses and +parser. In simple cases, it can be much easier to use the *SOURCE* and +*TARGET* directly on the command line, then tweak the loading with those +options: + + * `--with "option"` + + Allows setting options from the command line. You can use that option as + many times as you want. The option arguments must follow the *WITH* + clause for the source type of the `SOURCE` specification, as described + later in this document. + + * `--set "guc_name='value'"` + + Allows setting PostgreSQL configuration from the command line. Note that + the option parsing is the same as when used from the *SET* command + clause, in particular you must enclose the guc value with single-quotes. + + * `--field "..."` + + Allows setting a source field definition. Fields are accumulated in the + order given on the command line. It's possible to either use a `--field` + option per field in the source file, or to separate field definitions by + a comma, as you would do in the *HAVING FIELDS* clause. + + * `--cast "..."` + + Allows setting a specific casting rule for loading the data. + + * `--type csv|fixed|db3|ixf|sqlite|mysql|mssql` + + Allows forcing the source type, in case when the *SOURCE* parsing isn't + satisfying. + + * `--encoding ` + + Set the encoding of the source file to load data from. + + * `--before ` + + Parse given filename for SQL queries and run them against the target + database before loading the data from the source. The queries are parsed + by pgloader itself: they need to be terminated by a semi-colon (;) and + the file may include `\i` or `\ir` commands to *include* another file. + + * `--after ` + + Parse given filename for SQL queries and run them against the target + database after having loaded the data from the source. The queries are + parsed in the same way as with the `--before` option, see above. + +More Debug Information +^^^^^^^^^^^^^^^^^^^^^^ + +To get the maximum amount of debug information, you can use both the +`--verbose` and the `--debug` switches at the same time, which is equivalent +to saying `--client-min-messages data`. Then the log messages will show the +data being processed, in the cases where the code has explicit support for +it. + +Batches And Retry Behaviour +--------------------------- + +To load data to PostgreSQL, pgloader uses the `COPY` streaming protocol. +While this is the faster way to load data, `COPY` has an important drawback: +as soon as PostgreSQL emits an error with any bit of data sent to it, +whatever the problem is, the whole data set is rejected by PostgreSQL. + +To work around that, pgloader cuts the data into *batches* of 25000 rows +each, so that when a problem occurs it's only impacting that many rows of +data. Each batch is kept in memory while the `COPY` streaming happens, in +order to be able to handle errors should some happen. + +When PostgreSQL rejects the whole batch, pgloader logs the error message +then isolates the bad row(s) from the accepted ones by retrying the batched +rows in smaller batches. To do that, pgloader parses the *CONTEXT* error +message from the failed COPY, as the message contains the line number where +the error was found in the batch, as in the following example:: + + CONTEXT: COPY errors, line 3, column b: "2006-13-11" + +Using that information, pgloader will reload all rows in the batch before +the erroneous one, log the erroneous one as rejected, then try loading the +remaining of the batch in a single attempt, which may or may not contain +other erroneous data. + +At the end of a load containing rejected rows, you will find two files in +the *root-dir* location, under a directory named the same as the target +database of your setup. The filenames are the target table, and their +extensions are `.dat` for the rejected data and `.log` for the file +containing the full PostgreSQL client side logs about the rejected data. + +The `.dat` file is formatted in PostgreSQL the text COPY format as documented +in `http://www.postgresql.org/docs/9.2/static/sql-copy.html#AEN66609`. + +A Note About Performance +------------------------ + +pgloader has been developed with performance in mind, to be able to cope +with ever growing needs in loading large amounts of data into PostgreSQL. + +The basic architecture it uses is the old Unix pipe model, where a thread is +responsible for loading the data (reading a CSV file, querying MySQL, etc) +and fills pre-processed data into a queue. Another threads feeds from the +queue, apply some more *transformations* to the input data and stream the +end result to PostgreSQL using the COPY protocol. + +When given a file that the PostgreSQL `COPY` command knows how to parse, and +if the file contains no erroneous data, then pgloader will never be as fast +as just using the PostgreSQL `COPY` command. + +Note that while the `COPY` command is restricted to read either from its +standard input or from a local file on the server's file system, the command +line tool `psql` implements a `\copy` command that knows how to stream a +file local to the client over the network and into the PostgreSQL server, +using the same protocol as pgloader uses. + +A Note About Parallelism +------------------------ + +pgloader uses several concurrent tasks to process the data being loaded: + + - a reader task reads the data in and pushes it to a queue, + + - at last one write task feeds from the queue and formats the raw into the + PostgreSQL COPY format in batches (so that it's possible to then retry a + failed batch without reading the data from source again), and then sends + the data to PostgreSQL using the COPY protocol. + +The parameter *workers* allows to control how many worker threads are +allowed to be active at any time (that's the parallelism level); and the +parameter *concurrency* allows to control how many tasks are started to +handle the data (they may not all run at the same time, depending on the +*workers* setting). + +We allow *workers* simultaneous workers to be active at the same time in the +context of a single table. A single unit of work consist of several kinds of +workers: + + - a reader getting raw data from the source, + - N writers preparing and sending the data down to PostgreSQL. + +The N here is setup to the *concurrency* parameter: with a *CONCURRENCY* of +2, we start (+ 1 2) = 3 concurrent tasks, with a *concurrency* of 4 we start +(+ 1 4) = 9 concurrent tasks, of which only *workers* may be active +simultaneously. + +The defaults are `workers = 4, concurrency = 1` when loading from a database +source, and `workers = 8, concurrency = 2` when loading from something else +(currently, a file). Those defaults are arbitrary and waiting for feedback +from users, so please consider providing feedback if you play with the +settings. + +As the `CREATE INDEX` threads started by pgloader are only waiting until +PostgreSQL is done with the real work, those threads are *NOT* counted into +the concurrency levels as detailed here. + +By default, as many `CREATE INDEX` threads as the maximum number of indexes +per table are found in your source schema. It is possible to set the `max +parallel create index` *WITH* option to another number in case there's just +too many of them to create. + +Source Formats +-------------- + +pgloader supports the following input formats: + + - csv, which includes also tsv and other common variants where you can + change the *separator* and the *quoting* rules and how to *escape* the + *quotes* themselves; + + - fixed columns file, where pgloader is flexible enough to accomodate with + source files missing columns (*ragged fixed length column files* do + exist); + + - PostgreSLQ COPY formatted files, following the COPY TEXT documentation + of PostgreSQL, such as the reject files prepared by pgloader; + + - dbase files known as db3 or dbf file; + + - ixf formated files, ixf being a binary storage format from IBM; + + - sqlite databases with fully automated discovery of the schema and + advanced cast rules; + + - mysql databases with fully automated discovery of the schema and + advanced cast rules; + + - MS SQL databases with fully automated discovery of the schema and + advanced cast rules. + +Pgloader Commands Syntax +------------------------ + +pgloader implements a Domain Specific Language allowing to setup complex +data loading scripts handling computed columns and on-the-fly sanitization +of the input data. For more complex data loading scenarios, you will be +required to learn that DSL's syntax. It's meant to look familiar to DBA by +being inspired by SQL where it makes sense, which is not that much after +all. + +The pgloader commands follow the same global grammar rules. Each of them +might support only a subset of the general options and provide specific +options. + +:: + + LOAD + FROM + [ HAVING FIELDS ] + INTO + [ TARGET TABLE [ "" ]."" ] + [ TARGET COLUMNS ] + + [ WITH ] + + [ SET ] + + [ BEFORE LOAD [ DO | EXECUTE ] ... ] + [ AFTER LOAD [ DO | EXECUTE ] ... ] + ; + +The main clauses are the `LOAD`, `FROM`, `INTO` and `WITH` clauses that each +command implements. Some command then implement the `SET` command, or some +specific clauses such as the `CAST` clause. + +Templating with Mustache +------------------------ + +pgloader implements the https://mustache.github.io/ templating system so +that you may have dynamic parts of your commands. See the documentation for +this template system online. + +A specific feature of pgloader is the ability to fetch a variable from the +OS environment of the pgloader process, making it possible to run pgloader +as in the following example:: + + $ DBPATH=sqlite/sqlite.db pgloader ./test/sqlite-env.load + +or in several steps:: + + $ export DBPATH=sqlite/sqlite.db + $ pgloader ./test/sqlite-env.load + +The variable can then be used in a typical mustache fashion:: + + load database + from '{{DBPATH}}' + into postgresql:///pgloader; + +It's also possible to prepare a INI file such as the following:: + + [pgloader] + + DBPATH = sqlite/sqlite.db + +And run the following command, feeding the INI values as a *context* for +pgloader templating system:: + + $ pgloader --context ./test/sqlite.ini ./test/sqlite-ini.load + +The mustache templates implementation with OS environment support replaces +former `GETENV` implementation, which didn't work anyway. + +Common Clauses +-------------- + +Some clauses are common to all commands: + +FROM +^^^^ + +The *FROM* clause specifies where to read the data from, and each command +introduces its own variant of sources. For instance, the *CSV* source +supports `inline`, `stdin`, a filename, a quoted filename, and a *FILENAME +MATCHING* clause (see above); whereas the *MySQL* source only supports a +MySQL database URI specification. + +INTO +^^^^ + +The PostgreSQL connection URI must contains the name of the target table +where to load the data into. That table must have already been created in +PostgreSQL, and the name might be schema qualified. + +Then *INTO* option also supports an optional comma separated list of target +columns, which are either the name of an input *field* or the white space +separated list of the target column name, its PostgreSQL data type and a +*USING* expression. + +The *USING* expression can be any valid Common Lisp form and will be read +with the current package set to `pgloader.transforms`, so that you can use +functions defined in that package, such as functions loaded dynamically with +the `--load` command line parameter. + +Each *USING* expression is compiled at runtime to native code. + +This feature allows pgloader to load any number of fields in a CSV file into +a possibly different number of columns in the database, using custom code +for that projection. + +WITH +^^^^ + +Set of options to apply to the command, using a global syntax of either: + + - *key = value* + - *use option* + - *do not use option* + +See each specific command for details. + +All data sources specific commands support the following options: + + - *on error stop* + - *batch rows = R* + - *batch size = ... MB* + - *prefetch rows = ...* + +See the section BATCH BEHAVIOUR OPTIONS for more details. + +In addition, the following settings are available: + + - *workers = W* + - *concurrency = C* + - *max parallel create index = I* + +See section A NOTE ABOUT PARALLELISM for more details. + +SET +^^^ + +This clause allows to specify session parameters to be set for all the +sessions opened by pgloader. It expects a list of parameter name, the equal +sign, then the single-quoted value as a comma separated list. + +The names and values of the parameters are not validated by pgloader, they +are given as-is to PostgreSQL. + +BEFORE LOAD DO +^^^^^^^^^^^^^^ + +You can run SQL queries against the database before loading the data from +the `CSV` file. Most common SQL queries are `CREATE TABLE IF NOT EXISTS` so +that the data can be loaded. + +Each command must be *dollar-quoted*: it must begin and end with a double +dollar sign, `$$`. Dollar-quoted queries are then comma separated. No extra +punctuation is expected after the last SQL query. + +BEFORE LOAD EXECUTE +^^^^^^^^^^^^^^^^^^^ + +Same behaviour as in the *BEFORE LOAD DO* clause. Allows you to read the SQL +queries from a SQL file. Implements support for PostgreSQL dollar-quoting +and the `\i` and `\ir` include facilities as in `psql` batch mode (where +they are the same thing). + +AFTER LOAD DO +^^^^^^^^^^^^^ + +Same format as *BEFORE LOAD DO*, the dollar-quoted queries found in that +section are executed once the load is done. That's the right time to create +indexes and constraints, or re-enable triggers. + +AFTER LOAD EXECUTE +^^^^^^^^^^^^^^^^^^ + +Same behaviour as in the *AFTER LOAD DO* clause. Allows you to read the SQL +queries from a SQL file. Implements support for PostgreSQL dollar-quoting +and the `\i` and `\ir` include facilities as in `psql` batch mode (where +they are the same thing). + +Connection String +^^^^^^^^^^^^^^^^^ + +The `` parameter is expected to be given as a *Connection URI* +as documented in the PostgreSQL documentation at +http://www.postgresql.org/docs/9.3/static/libpq-connect.html#LIBPQ-CONNSTRING. + +:: + + postgresql://[user[:password]@][netloc][:port][/dbname][?option=value&...] + +Where: + + - *user* + + Can contain any character, including colon (`:`) which must then be + doubled (`::`) and at-sign (`@`) which must then be doubled (`@@`). + + When omitted, the *user* name defaults to the value of the `PGUSER` + environment variable, and if it is unset, the value of the `USER` + environment variable. + + - *password* + + Can contain any character, including the at sign (`@`) which must then + be doubled (`@@`). To leave the password empty, when the *user* name + ends with at at sign, you then have to use the syntax user:@. + + When omitted, the *password* defaults to the value of the `PGPASSWORD` + environment variable if it is set, otherwise the password is left + unset. + + When no *password* is found either in the connection URI nor in the + environment, then pgloader looks for a `.pgpass` file as documented at + https://www.postgresql.org/docs/current/static/libpq-pgpass.html. The + implementation is not that of `libpq` though. As with `libpq` you can + set the environment variable `PGPASSFILE` to point to a `.pgpass` file, + and pgloader defaults to `~/.pgpass` on unix like systems and + `%APPDATA%\postgresql\pgpass.conf` on windows. Matching rules and syntax + are the same as with `libpq`, refer to its documentation. + + - *netloc* + + Can be either a hostname in dotted notation, or an ipv4, or an Unix + domain socket path. Empty is the default network location, under a + system providing *unix domain socket* that method is preferred, otherwise + the *netloc* default to `localhost`. + + It's possible to force the *unix domain socket* path by using the syntax + `unix:/path/to/where/the/socket/file/is`, so to force a non default + socket path and a non default port, you would have: + + postgresql://unix:/tmp:54321/dbname + + The *netloc* defaults to the value of the `PGHOST` environment + variable, and if it is unset, to either the default `unix` socket path + when running on a Unix system, and `localhost` otherwise. + + Socket path containing colons are supported by doubling the colons + within the path, as in the following example: + + postgresql://unix:/tmp/project::region::instance:5432/dbname + + - *dbname* + + Should be a proper identifier (letter followed by a mix of letters, + digits and the punctuation signs comma (`,`), dash (`-`) and underscore + (`_`). + + When omitted, the *dbname* defaults to the value of the environment + variable `PGDATABASE`, and if that is unset, to the *user* value as + determined above. + + - *options* + + The optional parameters must be supplied with the form `name=value`, and + you may use several parameters by separating them away using an + ampersand (`&`) character. + + Only some options are supported here, *tablename* (which might be + qualified with a schema name) *sslmode*, *host*, *port*, *dbname*, + *user* and *password*. + + The *sslmode* parameter values can be one of `disable`, `allow`, + `prefer` or `require`. + + For backward compatibility reasons, it's possible to specify the + *tablename* option directly, without spelling out the `tablename=` + parts. + + The options override the main URI components when both are given, and + using the percent-encoded option parameters allow using passwords + starting with a colon and bypassing other URI components parsing + limitations. + +Regular Expressions +^^^^^^^^^^^^^^^^^^^ + +Several clauses listed in the following accept *regular expressions* with +the following input rules: + + - A regular expression begins with a tilde sign (`~`), + + - is then followed with an opening sign, + + - then any character is allowed and considered part of the regular + expression, except for the closing sign, + + - then a closing sign is expected. + +The opening and closing sign are allowed by pair, here's the complete list +of allowed delimiters:: + + ~// + ~[] + ~{} + ~() + ~<> + ~"" + ~'' + ~|| + ~## + +Pick the set of delimiters that don't collide with the *regular expression* +you're trying to input. If your expression is such that none of the +solutions allow you to enter it, the places where such expressions are +allowed should allow for a list of expressions. + +Comments +^^^^^^^^ + +Any command may contain comments, following those input rules: + + - the `--` delimiter begins a comment that ends with the end of the + current line, + + - the delimiters `/*` and `*/` respectively start and end a comment, which + can be found in the middle of a command or span several lines. + +Any place where you could enter a *whitespace* will accept a comment too. + +Batch behaviour options +^^^^^^^^^^^^^^^^^^^^^^^ + +All pgloader commands have support for a *WITH* clause that allows for +specifying options. Some options are generic and accepted by all commands, +such as the *batch behaviour options*, and some options are specific to a +data source kind, such as the CSV *skip header* option. + +The global batch behaviour options are: + + - *batch rows* + + Takes a numeric value as argument, used as the maximum number of rows + allowed in a batch. The default is `25 000` and can be changed to try + having better performance characteristics or to control pgloader memory + usage; + + - *batch size* + + Takes a memory unit as argument, such as *20 MB*, its default value. + Accepted multipliers are *kB*, *MB*, *GB*, *TB* and *PB*. The case is + important so as not to be confused about bits versus bytes, we're only + talking bytes here. + + - *prefetch rows* + + Takes a numeric value as argument, defaults to `100000`. That's the + number of rows that pgloader is allowed to read in memory in each reader + thread. See the *workers* setting for how many reader threads are + allowed to run at the same time. + +Other options are specific to each input source, please refer to specific +parts of the documentation for their listing and covering. + +A batch is then closed as soon as either the *batch rows* or the *batch +size* threshold is crossed, whichever comes first. In cases when a batch has +to be closed because of the *batch size* setting, a *debug* level log +message is printed with how many rows did fit in the *oversized* batch. + diff --git a/docs/ref/archive.rst b/docs/ref/archive.rst new file mode 100644 index 0000000..1cb95c2 --- /dev/null +++ b/docs/ref/archive.rst @@ -0,0 +1,104 @@ +Loading From an Archive +======================= + +This command instructs pgloader to load data from one or more files contained +in an archive. Currently the only supported archive format is *ZIP*, and the +archive might be downloaded from an *HTTP* URL. + +Here's an example:: + + LOAD ARCHIVE + FROM /Users/dim/Downloads/GeoLiteCity-latest.zip + INTO postgresql:///ip4r + + BEFORE LOAD + DO $$ create extension if not exists ip4r; $$, + $$ create schema if not exists geolite; $$, + + EXECUTE 'geolite.sql' + + LOAD CSV + FROM FILENAME MATCHING ~/GeoLiteCity-Location.csv/ + WITH ENCODING iso-8859-1 + ( + locId, + country, + region null if blanks, + city null if blanks, + postalCode null if blanks, + latitude, + longitude, + metroCode null if blanks, + areaCode null if blanks + ) + INTO postgresql:///ip4r?geolite.location + ( + locid,country,region,city,postalCode, + location point using (format nil "(~a,~a)" longitude latitude), + metroCode,areaCode + ) + WITH skip header = 2, + fields optionally enclosed by '"', + fields escaped by double-quote, + fields terminated by ',' + + AND LOAD CSV + FROM FILENAME MATCHING ~/GeoLiteCity-Blocks.csv/ + WITH ENCODING iso-8859-1 + ( + startIpNum, endIpNum, locId + ) + INTO postgresql:///ip4r?geolite.blocks + ( + iprange ip4r using (ip-range startIpNum endIpNum), + locId + ) + WITH skip header = 2, + fields optionally enclosed by '"', + fields escaped by double-quote, + fields terminated by ',' + + FINALLY DO + $$ create index blocks_ip4r_idx on geolite.blocks using gist(iprange); $$; + +The `archive` command accepts the following clauses and options. + +Archive Source Specification: FROM +---------------------------------- + +Filename or HTTP URI where to load the data from. When given an HTTP URL the +linked file will get downloaded locally before processing. + +If the file is a `zip` file, the command line utility `unzip` is used to +expand the archive into files in `$TMPDIR`, or `/tmp` if `$TMPDIR` is unset +or set to a non-existing directory. + +Then the following commands are used from the top level directory where the +archive has been expanded. + +Archive Sub Commands +-------------------- + + - command [ *AND* command ... ] + + A series of commands against the contents of the archive, at the moment + only `CSV`,`'FIXED` and `DBF` commands are supported. + + Note that commands are supporting the clause *FROM FILENAME MATCHING* + which allows the pgloader command not to depend on the exact names of + the archive directories. + + The same clause can also be applied to several files with using the + spelling *FROM ALL FILENAMES MATCHING* and a regular expression. + + The whole *matching* clause must follow the following rule:: + + FROM [ ALL FILENAMES | [ FIRST ] FILENAME ] MATCHING + +Archive Final SQL Commands +-------------------------- + + - *FINALLY DO* + + SQL Queries to run once the data is loaded, such as `CREATE INDEX`. + diff --git a/docs/ref/copy.rst b/docs/ref/copy.rst new file mode 100644 index 0000000..e8b156d --- /dev/null +++ b/docs/ref/copy.rst @@ -0,0 +1,115 @@ +Loading COPY Formatted Files +============================ + +This commands instructs pgloader to load from a file containing COPY TEXT +data as described in the PostgreSQL documentation. Here's an example:: + + LOAD COPY + FROM copy://./data/track.copy + ( + trackid, track, album, media, genre, composer, + milliseconds, bytes, unitprice + ) + INTO postgresql:///pgloader + TARGET TABLE track_full + + WITH truncate + + SET work_mem to '14MB', + standard_conforming_strings to 'on' + + BEFORE LOAD DO + $$ drop table if exists track_full; $$, + $$ create table track_full ( + trackid bigserial, + track text, + album text, + media text, + genre text, + composer text, + milliseconds bigint, + bytes bigint, + unitprice numeric + ); + $$; + +The `COPY` format command accepts the following clauses and options. + +COPY Formatted Files Source Specification: FROM +----------------------------------------------- + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + + - *inline* + + The data is found after the end of the parsed commands. Any number of + empty lines between the end of the commands and the beginning of the + data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above for + exact syntax, several options can be used here) to filenames. It's then + possible to load data from only the first match of all of them. + + The optional *IN DIRECTORY* clause allows specifying which directory to + walk for finding the data files, and can be either relative to where the + command file is read from, or absolute. The given directory must exists. + +COPY Formatted File Options: WITH +--------------------------------- + + +When loading from a `COPY` file, the following options are supported: + + - *delimiter* + + Takes a single character as argument, which must be found inside single + quotes, and might be given as the printable character itself, the + special value \t to denote a tabulation character, or `0x` then an + hexadecimal value read as the ASCII code for the character. + + This character is used as the *delimiter* when reading the data, in a + similar way to the PostgreSQL `COPY` option. + + - *null* + + Takes a quoted string as an argument (quotes can be either double quotes + or single quotes) and uses that string as the `NULL` representation in + the data. + + This is similar to the *null* `COPY` option in PostgreSQL. + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that many + lines at the beginning of the input file. diff --git a/docs/ref/csv.rst b/docs/ref/csv.rst new file mode 100644 index 0000000..243e8e6 --- /dev/null +++ b/docs/ref/csv.rst @@ -0,0 +1,237 @@ +Loading CSV data +================ + +This command instructs pgloader to load data from a `CSV` file. Here's an +example:: + + LOAD CSV + FROM 'GeoLiteCity-Blocks.csv' WITH ENCODING iso-646-us + HAVING FIELDS + ( + startIpNum, endIpNum, locId + ) + INTO postgresql://user@localhost:54393/dbname + TARGET TABLE geolite.blocks + TARGET COLUMNS + ( + iprange ip4r using (ip-range startIpNum endIpNum), + locId + ) + WITH truncate, + skip header = 2, + fields optionally enclosed by '"', + fields escaped by backslash-quote, + fields terminated by '\t' + + SET work_mem to '32 MB', maintenance_work_mem to '64 MB'; + +The `csv` format command accepts the following clauses and options. + +CSV Source Specification: FROM +------------------------------ + +Filename where to load the data from. Accepts an *ENCODING* option. Use the +`--list-encodings` option to know which encoding names are supported. + +The filename may be enclosed by single quotes, and could be one of the +following special values: + + - *inline* + + The data is found after the end of the parsed commands. Any number + of empty lines between the end of the commands and the beginning of + the data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above + for exact syntax, several options can be used here) to filenames. + It's then possible to load data from only the first match of all of + them. + + The optional *IN DIRECTORY* clause allows specifying which directory + to walk for finding the data files, and can be either relative to + where the command file is read from, or absolute. The given + directory must exists. + +Fields Specifications +--------------------- + +The *FROM* option also supports an optional comma separated list of *field* +names describing what is expected in the `CSV` data file, optionally +introduced by the clause `HAVING FIELDS`. + +Each field name can be either only one name or a name following with +specific reader options for that field, enclosed in square brackets and +comma-separated. Supported per-field reader options are: + + - *terminated by* + + See the description of *field terminated by* below. + + The processing of this option is not currently implemented. + + - *date format* + + When the field is expected of the date type, then this option allows + to specify the date format used in the file. + + Date format string are template strings modeled against the + PostgreSQL `to_char` template strings support, limited to the + following patterns: + + - YYYY, YYY, YY for the year part + - MM for the numeric month part + - DD for the numeric day part + - HH, HH12, HH24 for the hour part + - am, AM, a.m., A.M. + - pm, PM, p.m., P.M. + - MI for the minutes part + - SS for the seconds part + - MS for the milliseconds part (4 digits) + - US for the microseconds part (6 digits) + - unparsed punctuation signs: - . * # @ T / \ and space + + Here's an example of a *date format* specification:: + + column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] + + - *null if* + + This option takes an argument which is either the keyword *blanks* + or a double-quoted string. + + When *blanks* is used and the field value that is read contains + only space characters, then it's automatically converted to an SQL + `NULL` value. + + When a double-quoted string is used and that string is read as the + field value, then the field value is automatically converted to an + SQL `NULL` value. + + - *trim both whitespace*, *trim left whitespace*, *trim right whitespace* + + This option allows to trim whitespaces in the read data, either from + both sides of the data, or only the whitespace characters found on + the left of the streaing, or only those on the right of the string. + +CSV Loading Options: WITH +------------------------- + +When loading from a `CSV` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command + against the PostgreSQL target table before reading the data file. + + - *drop indexes* + + When this option is listed, pgloader issues `DROP INDEX` commands + against all the indexes defined on the target table before copying + the data, then `CREATE INDEX` commands once the `COPY` is done. + + In order to get the best performance possible, all the indexes are + created in parallel and when done the primary keys are built again + from the unique indexes just created. This two step process allows + creating the primary key index in parallel with the other indexes, + as only the `ALTER TABLE` command needs an *access exclusive lock* + on the target table. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... + DISABLE TRIGGER ALL` command against the PostgreSQL target table + before copying the data, then the command `ALTER TABLE ... ENABLE + TRIGGER ALL` once the `COPY` is done. + + This option allows loading data into a pre-existing table ignoring + the *foreign key constraints* and user defined triggers and may + result in invalid *foreign key constraints* once the data is loaded. + Use with care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that + many lines at the beginning of the input file. + + - *csv header* + + Use the first line read after *skip header* as the list of csv field + names to be found in the CSV file, using the same CSV parameters as + for the CSV data. + + - *trim unquoted blanks* + + When reading unquoted values in the `CSV` file, remove the blanks + found in between the separator and the value. That behaviour is the + default. + + - *keep unquoted blanks* + + When reading unquoted values in the `CSV` file, keep blanks found in + between the separator and the value. + + - *fields optionally enclosed by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used as the quoting character in the `CSV` file, + and defaults to double-quote. + + - *fields not enclosed* + + By default, pgloader will use the double-quote character as the + enclosing character. If you have a CSV file where fields are not + enclosed and are using double-quote as an expected ordinary + character, then use the option *fields not enclosed* for the CSV + parser to accept those values. + + - *fields escaped by* + + Takes either the special value *backslash-quote* or *double-quote*, + or any value supported by the *fields terminated by* option (see + below). This value is used to recognize escaped field separators + when they are to be found within the data fields themselves. + Defaults to *double-quote*. + + - *csv escape mode* + + Takes either the special value *quote* (the default) or *following* + and allows the CSV parser to parse either only escaped field + separator or any character (including CSV data) when using the + *following* value. + + - *fields terminated by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used as the *field separator* when reading the + `CSV` data. + + - *lines terminated by* + + Takes a single character as argument, which must be found inside + single quotes, and might be given as the printable character itself, + the special value \t to denote a tabulation character, or `0x` then + an hexadecimal value read as the ASCII code for the character. + + This character is used to recognize *end-of-line* condition when + reading the `CSV` data. + diff --git a/docs/ref/dbf.rst b/docs/ref/dbf.rst new file mode 100644 index 0000000..28269f3 --- /dev/null +++ b/docs/ref/dbf.rst @@ -0,0 +1,53 @@ +Loading DBF data +================= + +This command instructs pgloader to load data from a `DBF` file. Here's an +example:: + + LOAD DBF + FROM http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement/2013/dbf/reg2013.dbf + INTO postgresql://user@localhost/dbname + WITH truncate, create table; + +The `dbf` format command accepts the following clauses and options. + +DBF Source Specification: FROM +------------------------------ + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single dbf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + +DBF Loading Options: WITH +------------------------- + +When loading from a `DBF` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create table* + + When this option is listed, pgloader creates the table using the meta + data found in the `DBF` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *table name* + + This options expects as its value the possibly qualified name of the + table to create. diff --git a/docs/ref/fixed.rst b/docs/ref/fixed.rst new file mode 100644 index 0000000..dd567da --- /dev/null +++ b/docs/ref/fixed.rst @@ -0,0 +1,182 @@ +Loading Fixed Cols File Formats +=============================== + +This command instructs pgloader to load data from a text file containing +columns arranged in a *fixed size* manner. Here's an example:: + + LOAD FIXED + FROM inline + ( + a from 0 for 10, + b from 10 for 8, + c from 18 for 8, + d from 26 for 17 [null if blanks, trim right whitespace] + ) + INTO postgresql:///pgloader + TARGET TABLE fixed + ( + a, b, + c time using (time-with-no-separator c), + d + ) + + WITH truncate + + SET work_mem to '14MB', + standard_conforming_strings to 'on' + + BEFORE LOAD DO + $$ drop table if exists fixed; $$, + $$ create table fixed ( + a integer, + b date, + c time, + d text + ); + $$; + + 01234567892008052011431250firstline + 01234562008052115182300left blank-padded + 12345678902008052208231560another line + 2345609872014092914371500 + 2345678902014092914371520 + +The `fixed` format command accepts the following clauses and options. + +Fixed File Format Source Specification: FROM +-------------------------------------------- + +Filename where to load the data from. Accepts an *ENCODING* option. Use the +`--list-encodings` option to know which encoding names are supported. + +The filename may be enclosed by single quotes, and could be one of the +following special values: + + - *inline* + + The data is found after the end of the parsed commands. Any number + of empty lines between the end of the commands and the beginning of + the data is accepted. + + - *stdin* + + Reads the data from the standard input stream. + + - *FILENAMES MATCHING* + + The whole *matching* clause must follow the following rule:: + + [ ALL FILENAMES | [ FIRST ] FILENAME ] + MATCHING regexp + [ IN DIRECTORY '...' ] + + The *matching* clause applies given *regular expression* (see above + for exact syntax, several options can be used here) to filenames. + It's then possible to load data from only the first match of all of + them. + + The optional *IN DIRECTORY* clause allows specifying which directory + to walk for finding the data files, and can be either relative to + where the command file is read from, or absolute. The given + directory must exists. + +Fields Specifications +--------------------- + +The *FROM* option also supports an optional comma separated list of *field* +names describing what is expected in the `FIXED` data file. + +Each field name is composed of the field name followed with specific reader +options for that field. Supported per-field reader options are the +following, where only *start* and *length* are required. + + - *start* + + Position in the line where to start reading that field's value. Can + be entered with decimal digits or `0x` then hexadecimal digits. + + - *length* + + How many bytes to read from the *start* position to read that + field's value. Same format as *start*. + +Those optional parameters must be enclosed in square brackets and +comma-separated: + + - *terminated by* + + See the description of *field terminated by* below. + + The processing of this option is not currently implemented. + + - *date format* + + When the field is expected of the date type, then this option allows + to specify the date format used in the file. + + Date format string are template strings modeled against the + PostgreSQL `to_char` template strings support, limited to the + following patterns: + + - YYYY, YYY, YY for the year part + - MM for the numeric month part + - DD for the numeric day part + - HH, HH12, HH24 for the hour part + - am, AM, a.m., A.M. + - pm, PM, p.m., P.M. + - MI for the minutes part + - SS for the seconds part + - MS for the milliseconds part (4 digits) + - US for the microseconds part (6 digits) + - unparsed punctuation signs: - . * # @ T / \ and space + + Here's an example of a *date format* specification:: + + column-name [date format 'YYYY-MM-DD HH24-MI-SS.US'] + + - *null if* + + This option takes an argument which is either the keyword *blanks* + or a double-quoted string. + + When *blanks* is used and the field value that is read contains only + space characters, then it's automatically converted to an SQL `NULL` + value. + + When a double-quoted string is used and that string is read as the + field value, then the field value is automatically converted to an + SQL `NULL` value. + + - *trim both whitespace*, *trim left whitespace*, *trim right whitespace* + + This option allows to trim whitespaces in the read data, either from + both sides of the data, or only the whitespace characters found on + the left of the streaing, or only those on the right of the string. + +Fixed File Format Loading Options: WITH +--------------------------------------- + +When loading from a `FIXED` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command + against the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... + DISABLE TRIGGER ALL` command against the PostgreSQL target table + before copying the data, then the command `ALTER TABLE ... ENABLE + TRIGGER ALL` once the `COPY` is done. + + This option allows loading data into a pre-existing table ignoring + the *foreign key constraints* and user defined triggers and may + result in invalid *foreign key constraints* once the data is loaded. + Use with care. + + - *skip header* + + Takes a numeric value as argument. Instruct pgloader to skip that + many lines at the beginning of the input file. + diff --git a/docs/ref/ixf.rst b/docs/ref/ixf.rst new file mode 100644 index 0000000..3f698fa --- /dev/null +++ b/docs/ref/ixf.rst @@ -0,0 +1,66 @@ +Loading IXF Data +================ + +This command instructs pgloader to load data from an IBM `IXF` file. Here's +an example:: + + LOAD IXF + FROM data/nsitra.test1.ixf + INTO postgresql:///pgloader + TARGET TABLE nsitra.test1 + WITH truncate, create table, timezone UTC + + BEFORE LOAD DO + $$ create schema if not exists nsitra; $$, + $$ drop table if exists nsitra.test1; $$; + +The `ixf` format command accepts the following clauses and options. + +IXF Source Specification: FROM +------------------------------ + +Filename where to load the data from. This support local files, HTTP URLs +and zip files containing a single ixf file of the same name. Fetch such a +zip file from an HTTP address is of course supported. + +IXF Loading Options: WITH +------------------------- + +When loading from a `IXF` file, the following options are supported: + + - *truncate* + + When this option is listed, pgloader issues a `TRUNCATE` command against + the PostgreSQL target table before reading the data file. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create table* + + When this option is listed, pgloader creates the table using the meta + data found in the `DBF` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *table name* + + This options expects as its value the possibly qualified name of the + table to create. + + - *timezone* + + This options allows to specify which timezone is used when parsing + timestamps from an IXF file, and defaults to *UTC*. Expected values are + either `UTC`, `GMT` or a single quoted location name such as + `'Universal'` or `'Europe/Paris'`. + diff --git a/docs/ref/mssql.rst b/docs/ref/mssql.rst new file mode 100644 index 0000000..89ff6f3 --- /dev/null +++ b/docs/ref/mssql.rst @@ -0,0 +1,159 @@ +Migrating a MS SQL Database to PostgreSQL +========================================= + +This command instructs pgloader to load data from a MS SQL database. +Automatic discovery of the schema is supported, including build of the +indexes, primary and foreign keys constraints. + +Here's an example:: + + load database + from mssql://user@host/dbname + into postgresql:///dbname + + including only table names like 'GlobalAccount' in schema 'dbo' + + set work_mem to '16MB', maintenance_work_mem to '512 MB' + + before load do $$ drop schema if exists dbo cascade; $$; + +The `mssql` command accepts the following clauses and options. + +MS SQL Database Source Specification: FROM +------------------------------------------ + +Connection string to an existing MS SQL database server that listens and +welcome external TCP/IP connection. As pgloader currently piggybacks on the +FreeTDS driver, to change the port of the server please export the `TDSPORT` +environment variable. + +MS SQL Database Migration Options: WITH +--------------------------------------- + +When loading from a `MS SQL` database, the same options as when loading a +`MySQL` database are supported. Please refer to the MySQL section. The +following options are added: + + - *create schemas* + + When this option is listed, pgloader creates the same schemas as found + on the MS SQL instance. This is the default. + + - *create no schemas* + + When this option is listed, pgloader refrains from creating any schemas + at all, you must then ensure that the target schema do exist. + +MS SQL Database Casting Rules +----------------------------- + +CAST +^^^^ + +The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases. + +Please refer to the MySQL CAST clause for details. + +MS SQL Partial Migration +------------------------ + + +INCLUDING ONLY TABLE NAMES LIKE +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Introduce a comma separated list of table name patterns used to limit the +tables to migrate to a sublist. More than one such clause may be used, they +will be accumulated together. + +Example:: + + including only table names lile 'GlobalAccount' in schema 'dbo' + +EXCLUDING TABLE NAMES LIKE +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Introduce a comma separated list of table name patterns used to exclude +table names from the migration. This filter only applies to the result of +the *INCLUDING* filter. + +:: + + excluding table names matching 'LocalAccount' in schema 'dbo' + +MS SQL Schema Transformations +----------------------------- + +ALTER SCHEMA '...' RENAME TO '...' +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Allows to rename a schema on the flight, so that for instance the tables +found in the schema 'dbo' in your source database will get migrated into the +schema 'public' in the target database with this command:: + + alter schema 'dbo' rename to 'public' + +ALTER TABLE NAMES MATCHING ... IN SCHEMA '...' +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +See the MySQL explanation for this clause above. It works the same in the +context of migrating from MS SQL, only with the added option to specify the +name of the schema where to find the definition of the target tables. + +The matching is done in pgloader itself, with a Common Lisp regular +expression lib, so doesn't depend on the *LIKE* implementation of MS SQL, +nor on the lack of support for regular expressions in the engine. + +MS SQL Driver setup and encoding +-------------------------------- + +pgloader is using the `FreeTDS` driver, and internally expects the data to +be sent in utf-8. To achieve that, you can configure the FreeTDS driver with +those defaults, in the file `~/.freetds.conf`:: + + [global] + tds version = 7.4 + client charset = UTF-8 + +Default MS SQL Casting Rules +---------------------------- + +When migrating from MS SQL the following Casting Rules are provided: + +Numbers:: + + type tinyint to smallint + + type float to float using float-to-string + type real to real using float-to-string + type double to double precision using float-to-string + type numeric to numeric using float-to-string + type decimal to numeric using float-to-string + type money to numeric using float-to-string + type smallmoney to numeric using float-to-string + +Texts:: + + type char to text drop typemod + type nchat to text drop typemod + type varchar to text drop typemod + type nvarchar to text drop typemod + type xml to text drop typemod + +Binary:: + + type binary to bytea using byte-vector-to-bytea + type varbinary to bytea using byte-vector-to-bytea + +Date:: + + type datetime to timestamptz + type datetime2 to timestamptz + +Others:: + + type bit to boolean + type hierarchyid to bytea + type geography to bytea + type uniqueidentifier to uuid using sql-server-uniqueidentifier-to-uuid + diff --git a/docs/ref/mysql.rst b/docs/ref/mysql.rst new file mode 100644 index 0000000..b484d5b --- /dev/null +++ b/docs/ref/mysql.rst @@ -0,0 +1,623 @@ +Migrating a MySQL Database to PostgreSQL +======================================== + +This command instructs pgloader to load data from a database connection. The +only supported database source is currently *MySQL*, and pgloader supports +dynamically converting the schema of the source database and the indexes +building. + +A default set of casting rules are provided and might be overloaded and +appended to by the command. + +Here's an example using as many options as possible, some of them even being +defaults. Chances are you don't need that complex a setup, don't copy and +paste it, use it only as a reference! + +:: + + LOAD DATABASE + FROM mysql://root@localhost/sakila + INTO postgresql://localhost:54393/sakila + + WITH include drop, create tables, create indexes, reset sequences, + workers = 8, concurrency = 1, + multiple readers per thread, rows per range = 50000 + + SET PostgreSQL PARAMETERS + maintenance_work_mem to '128MB', + work_mem to '12MB', + search_path to 'sakila, public, "$user"' + + SET MySQL PARAMETERS + net_read_timeout = '120', + net_write_timeout = '120' + + CAST type bigint when (= precision 20) to bigserial drop typemod, + type date drop not null drop default using zero-dates-to-null, + -- type tinyint to boolean using tinyint-to-boolean, + type year to integer + + MATERIALIZE VIEWS film_list, staff_list + + -- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor' + -- EXCLUDING TABLE NAMES MATCHING ~ + -- DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8 + -- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films' + -- ALTER TABLE NAMES MATCHING ~/_list$/ SET SCHEMA 'mv' + + ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/ + SET SCHEMA 'mv' + + ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films' + ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40') + + ALTER SCHEMA 'sakila' RENAME TO 'pagila' + + BEFORE LOAD DO + $$ create schema if not exists pagila; $$, + $$ create schema if not exists mv; $$, + $$ alter database sakila set search_path to pagila, mv, public; $$; + + +The `database` command accepts the following clauses and options. + +MySQL Database Source Specification: FROM +----------------------------------------- + +Must be a connection URL pointing to a MySQL database. + +If the connection URI contains a table name, then only this table is +migrated from MySQL to PostgreSQL. + +See the `SOURCE CONNECTION STRING` section above for details on how to write +the connection string. The MySQL connection string accepts the same +parameter *sslmode* as the PostgreSQL connection string, but the *verify* +mode is not implemented (yet). + +Environment variables described in + can be +used as default values too. If the user is not provided, then it defaults to +`USER` environment variable value. The password can be provided with the +environment variable `MYSQL_PWD`. The host can be provided with the +environment variable `MYSQL_HOST` and otherwise defaults to `localhost`. The +port can be provided with the environment variable `MYSQL_TCP_PORT` and +otherwise defaults to `3306`. + +MySQL Database Migration Options: WITH +-------------------------------------- + +When loading from a `MySQL` database, the following options are supported, +and the default *WITH* clause is: *no truncate*, *create schema*, *create +tables*, *include drop*, *create indexes*, *reset sequences*, *foreign +keys*, *downcase identifiers*, *uniquify index names*. + + - *include drop* + + When this option is listed, pgloader drops all the tables in the target + PostgreSQL database whose names appear in the MySQL database. This + option allows for using the same command several times in a row until + you figure out all the options, starting automatically from a clean + environment. Please note that `CASCADE` is used to ensure that tables + are dropped even if there are foreign keys pointing to them. This is + precisely what `include drop` is intended to do: drop all target tables + and recreate them. + + Great care needs to be taken when using `include drop`, as it will + cascade to *all* objects referencing the target tables, possibly + including other tables that are not being loaded from the source DB. + + - *include no drop* + + When this option is listed, pgloader will not include any `DROP` + statement when loading the data. + + - *truncate* + + When this option is listed, pgloader issue the `TRUNCATE` command + against each PostgreSQL table just before loading data into it. + + - *no truncate* + + When this option is listed, pgloader issues no `TRUNCATE` command. + + - *disable triggers* + + When this option is listed, pgloader issues an `ALTER TABLE ... DISABLE + TRIGGER ALL` command against the PostgreSQL target table before copying + the data, then the command `ALTER TABLE ... ENABLE TRIGGER ALL` once the + `COPY` is done. + + This option allows loading data into a pre-existing table ignoring the + *foreign key constraints* and user defined triggers and may result in + invalid *foreign key constraints* once the data is loaded. Use with + care. + + - *create tables* + + When this option is listed, pgloader creates the table using the meta + data found in the `MySQL` file, which must contain a list of fields with + their data type. A standard data type conversion from DBF to PostgreSQL + is done. + + - *create no tables* + + When this option is listed, pgloader skips the creation of table before + loading data, target tables must then already exist. + + Also, when using *create no tables* pgloader fetches the metadata from + the current target database and checks type casting, then will remove + constraints and indexes prior to loading the data and install them back + again once the loading is done. + + - *create indexes* + + When this option is listed, pgloader gets the definitions of all the + indexes found in the MySQL database and create the same set of index + definitions against the PostgreSQL database. + + - *create no indexes* + + When this option is listed, pgloader skips the creating indexes. + + - *drop indexes* + + When this option is listed, pgloader drops the indexes in the target + database before loading the data, and creates them again at the end + of the data copy. + + - *uniquify index names*, *preserve index names* + + MySQL index names are unique per-table whereas in PostgreSQL index names + have to be unique per-schema. The default for pgloader is to change the + index name by prefixing it with `idx_OID` where `OID` is the internal + numeric identifier of the table the index is built against. + + In somes cases like when the DDL are entirely left to a framework it + might be sensible for pgloader to refrain from handling index unique + names, that is achieved by using the *preserve index names* option. + + The default is to *uniquify index names*. + + Even when using the option *preserve index names*, MySQL primary key + indexes named "PRIMARY" will get their names uniquified. Failing to do + so would prevent the primary keys to be created again in PostgreSQL + where the index names must be unique per schema. + + - *drop schema* + + When this option is listed, pgloader drops the target schema in the + target PostgreSQL database before creating it again and all the objects + it contains. The default behavior doesn't drop the target schemas. + + - *foreign keys* + + When this option is listed, pgloader gets the definitions of all the + foreign keys found in the MySQL database and create the same set of + foreign key definitions against the PostgreSQL database. + + - *no foreign keys* + + When this option is listed, pgloader skips creating foreign keys. + + - *reset sequences* + + When this option is listed, at the end of the data loading and after the + indexes have all been created, pgloader resets all the PostgreSQL + sequences created to the current maximum value of the column they are + attached to. + + The options *schema only* and *data only* have no effects on this + option. + + - *reset no sequences* + + When this option is listed, pgloader skips resetting sequences after the + load. + + The options *schema only* and *data only* have no effects on this + option. + + - *downcase identifiers* + + When this option is listed, pgloader converts all MySQL identifiers + (table names, index names, column names) to *downcase*, except for + PostgreSQL *reserved* keywords. + + The PostgreSQL *reserved* keywords are determined dynamically by using + the system function `pg_get_keywords()`. + + - *quote identifiers* + + When this option is listed, pgloader quotes all MySQL identifiers so + that their case is respected. Note that you will then have to do the + same thing in your application code queries. + + - *schema only* + + When this option is listed pgloader refrains from migrating the data + over. Note that the schema in this context includes the indexes when the + option *create indexes* has been listed. + + - *data only* + + When this option is listed pgloader only issues the `COPY` statements, + without doing any other processing. + + - *single reader per thread*, *multiple readers per thread* + + The default is *single reader per thread* and it means that each + MySQL table is read by a single thread as a whole, with a single + `SELECT` statement using no `WHERE` clause. + + When using *multiple readers per thread* pgloader may be able to + divide the reading work into several threads, as many as the + *concurrency* setting, which needs to be greater than 1 for this + option to kick be activated. + + For each source table, pgloader searches for a primary key over a + single numeric column, or a multiple-column primary key index for + which the first column is of a numeric data type (one of `integer` + or `bigint`). When such an index exists, pgloader runs a query to + find the *min* and *max* values on this column, and then split that + range into many ranges containing a maximum of *rows per range*. + + When the range list we then obtain contains at least as many ranges + than our concurrency setting, then we distribute those ranges to + each reader thread. + + So when all the conditions are met, pgloader then starts as many + reader thread as the *concurrency* setting, and each reader thread + issues several queries with a `WHERE id >= x AND id < y`, where `y - + x = rows per range` or less (for the last range, depending on the + max value just obtained. + + - *rows per range* + + How many rows are fetched per `SELECT` query when using *multiple + readers per thread*, see above for details. + + - *SET MySQL PARAMETERS* + + The *SET MySQL PARAMETERS* allows setting MySQL parameters using the + MySQL `SET` command each time pgloader connects to it. + +MySQL Database Casting Rules +---------------------------- + +The command *CAST* introduces user-defined casting rules. + +The cast clause allows to specify custom casting rules, either to overload +the default casting rules or to amend them with special cases. + +A casting rule is expected to follow one of the forms:: + + type [ ... ] to [