[
  {
    "path": ".github/workflows/dotnet-test.yml",
    "content": "name: .NET\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v2\n      with:\n        dotnet-version: 8.0.x\n    - name: Restore dependencies\n      run: dotnet restore src\n    - name: Build Lib\n      run: dotnet build src/NReco.Data -property:TargetFrameworks=netstandard2.0 --no-restore\n    - name: Build Tests\n      run: dotnet build src/NReco.Data.Tests --no-restore      \n    - name: Test\n      run: dotnet test src/NReco.Data.Tests --no-build --verbosity normal\n"
  },
  {
    "path": ".gitignore",
    "content": "App_Data/\npackages/\nbin/\nobj/\n*.user\n*.suo\n.vs\n*.nuget.targets\n*.lock.json\nexamples/*/northwind.db"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Vitalii Fedorchenko\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# NReco.Data\nLightweight high-performance data access components for generating SQL commands, mapping results to strongly typed POCO models or dictionaries, schema-less CRUD-operations with RecordSet. \n\nNuGet | Windows x64 | Ubuntu\n--- | --- | ---\n[![NuGet Release](https://img.shields.io/nuget/v/NReco.Data.svg)](https://www.nuget.org/packages/NReco.Data/) | [![AppVeyor](https://img.shields.io/appveyor/ci/nreco/data/master.svg)](https://ci.appveyor.com/project/nreco/data) | ![Tests](https://github.com/nreco/data/actions/workflows/dotnet-test.yml/badge.svg) \n\n* very fast: NReco.Data shows almost the same performance as Dapper but offers more features\n* abstract DB-independent [Query structure](https://github.com/nreco/data/wiki/Query): no need to compose raw SQL in the code + query can be constructed dynamically (at run-time)\n* automated CRUD commands generation\n* generate several SQL statements into one IDbCommand (batch inserts, updates, selects for multiple recordsets: *DbBatchCommandBuilder*)\n* supports mapping to annotated POCO models (EF Core entity models), allows customized mapping of query result \n* API for schema-less data access (dictionaries, RecordSet, DataTable)\n* can handle results returned by stored procedure, including multiple record sets\n* application-level data views (for complex SQL queries) that accessed like simple read-only tables (DbDataView)\n* parser for compact string query representation: [relex](https://github.com/nreco/data/wiki/Relex) expressions\n* can be used with any existing ADO.NET data provider (SQL Server, PostgreSql, Sqlite, MySql, Oracle etc)\n* supports .NET Framework 4.5+, .NET Core 2.x / 3.x (netstandard2.0)\n\n## Quick reference\nClass | Dependencies | Purpose\n--- | --- | ---\n`DbFactory` | | incapsulates DB-specific functions and conventions \n`DbCommandBuilder` | *IDbFactory* | composes *IDbCommand* and SQL text for SELECT/UPDATE/DELETE/INSERT, handles app-level dataviews\n`DbDataAdapter` | *IDbCommandBuilder*, *IDbConnection* | CRUD operations for model, dictionary, *DataTable* or *[RecordSet](https://github.com/nreco/data/wiki/RecordSet)*: Insert/Update/Delete/Select. Async versions are supported for all methods.\n`Query` | | Represents abstract query to database; used as parameter in *DbCommandBuilder*, *DbDataAdapter*\n`RelexParser` | | Parsers query string expression ([Relex](https://github.com/nreco/data/wiki/Relex)) into *Query* structure\n`RecordSet` | | [RecordSet model](https://github.com/nreco/data/wiki/RecordSet) represents in-memory data records, this is lightweight and efficient replacement for classic *DataTable*/*DataRow*\n`DataReaderResult` | *IDataReader* | reads data from any data reader implementation and efficiently maps it to models, dictionaries, *DataTable* or *RecordSet*\n\nNReco.Data documentation:\n* [Getting started and HowTos](https://github.com/nreco/data/wiki)\n* [Full API Reference](http://www.nrecosite.com/doc/NReco.Data/)\n* something is still not clear? Feel free to [ask a question on StackOverflow](http://stackoverflow.com/questions/ask?tags=nreco,c%23) \n\n## How to use\nGeneric implementation of `DbFactory` can be used with any ADO.NET connector. \n\n**DbFactory initialization for SqlClient**:\n```\nvar dbFactory = new DbFactory(System.Data.SqlClient.SqlClientFactory.Instance) {\n\tLastInsertIdSelectText = \"SELECT @@IDENTITY\" };\n```\n**DbFactory initialization for Mysql**:\n```\nvar dbFactory = new DbFactory(MySql.Data.MySqlClient.MySqlClientFactory.Instance) {\n\tLastInsertIdSelectText = \"SELECT LAST_INSERT_ID()\" };\n```\n**DbFactory initialization for Postgresql**:\n```\nvar dbFactory = new DbFactory(Npgsql.NpgsqlFactory.Instance) {\n\tLastInsertIdSelectText = \"SELECT lastval()\" };\n```\n**DbFactory initialization for Sqlite**:\n```\nvar dbFactory = new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\" };\n```\n\n**DbCommandBuilder** generates SQL commands by [Query](https://github.com/nreco/data/wiki/Query):\n```\nvar dbCmdBuilder = new DbCommandBuilder(dbFactory);\nvar selectCmd = dbCmdBuilder.GetSelectCommand( \n\tnew Query(\"Employees\", (QField)\"BirthDate\" > new QConst(new DateTime(1960,1,1)) ) );\nvar selectGroupByCmd = dbCmdBuilder.GetSelectCommand( \n\tnew Query(\"Employees\").Select(\"company_id\", new QAggregateField(\"avg_age\", \"AVG\", \"age\") ) );\nvar insertCmd = dbCmdBuilder.GetInsertCommand(\n\t\"Employees\", new { Name = \"John Smith\", BirthDate = new DateTime(1980,1,1) } );\nvar deleteCmd = dbCmdBuilder.GetDeleteCommand(\n\tnew Query(\"Employees\", (QField)\"Name\" == (QConst)\"John Smith\" ) );\n```\n\n**DbDataAdapter** - provides simple API for CRUD-operations:\n```\nvar dbConnection = dbFactory.CreateConnection();\ndbConnection.ConnectionString = \"<db_connection_string>\";\nvar dbAdapter = new DbDataAdapter(dbConnection, dbCmdBuilder);\n// map select results to POCO models\nvar employeeModelsList = dbAdapter.Select( new Query(\"Employees\") ).ToList<Employee>();\n// read select result to dictionary\nvar employeeDictionary = dbAdapter.Select( \n    new Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)newEmployee.EmployeeID ).Select(\"FirstName\",\"LastName\") \n  ).ToDictionary();\n// update by dictionary\ndbAdapter.Update( \n\tnew Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)1001 ),\n\tnew Dictionary<string,object>() {\n\t\t{\"FirstName\", \"Bruce\" },\n\t\t{\"LastName\", \"Wayne\" }\n\t});\n// insert by model\ndbAdapter.Insert( \"Employees\", new { FirstName = \"John\", LastName = \"Smith\" } );  \n```\n**[RecordSet](https://github.com/nreco/data/wiki/RecordSet)** - efficient replacement for DataTable/DataRow with very similar API:\n```\nvar rs = dbAdapter.Select(new Query(\"Employees\")).ToRecordSet();\nrs.SetPrimaryKey(\"EmployeeID\");\nforeach (var row in rs) {\n\tConsole.WriteLine(\"ID={0}\", row[\"EmployeeID\"]);\n\tif (\"Canada\".Equals(row[\"Country\"]))\n\t\trow.Delete();\n}\ndbAdapter.Update(rs);\nvar rsReader = new RecordSetReader(rs); // DbDataReader for in-memory rows\n```\n**[Relex](https://github.com/nreco/data/wiki/Relex)** - compact relational query expressions:\n```\nvar relex = @\"Employees(BirthDate>\"\"1960-01-01\"\":datetime)[Name,BirthDate]\"\nvar relexParser = new NReco.Data.Relex.RelexParser();\nQuery q = relexParser.Parse(relex);\n```\n\n## More examples\n* [Command Builder](https://github.com/nreco/data/tree/master/examples/SqliteDemo.CommandBuilder/Program.cs): illustrates SQL commands generation, command batching (inserts)\n* [Data Adapter](https://github.com/nreco/data/tree/master/examples/SqliteDemo.DataAdapter/Program.cs): CRUD operations with dictionaries, POCO, RecordSet\n* [DataSet GenericDataAdapter](https://github.com/nreco/data/blob/master/examples/DataSetGenericDataAdapter/Program.cs): how to implement generic DataSet DataAdapter (Fill/Update) for any ADO.NET provider \n* [SQL logging](https://github.com/nreco/data/tree/master/examples/SqliteDemo.SqlLogging): how to extend `DbFactory` and add wrapper for `DbCommand` that logs SQL commands produced by `DbDataAdapter`\n* [DB WebApi](https://github.com/nreco/data/tree/master/examples/SqliteDemo.WebApi): configures NReco.Data services in MVC Core app, simple REST API for database tables\n* [MVC Core CRUD](https://github.com/nreco/data/tree/master/examples/SqliteDemo.MVCApplication): full-functional CRUD (list, add/edit forms) that uses NReco.Data as data layer in combination with EF Core\n* [DB Metadata](https://github.com/nreco/data/tree/master/examples/MySqlDemo.DbMetadata): extract database metadata (list of tables, columns) with information_schema queries\n* [GraphQL API for SQL database](https://github.com/nreco/data/tree/master/examples/SqliteDemo.GraphQLApi): provides simple GraphQL API by existing database schema (simple queries only, no mutations yet)\n\n## Who is using this?\nNReco.Data is in production use at [SeekTable.com](https://www.seektable.com/) and [PivotData microservice](https://www.nrecosite.com/pivotdata_service.aspx).\n\n## License\nCopyright 2016-2025 Vitaliy Fedorchenko and contributors\n\nDistributed under the MIT license\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: 1.0.{build}\nos: Visual Studio 2022\nconfiguration: Release\nplatform: Any CPU\n\nbranches:\n  only:\n  - master\n\nskip_tags: true\n\ninstall:\n- cmd: dotnet restore src\\NReco.Data.sln\n\nbuild_script:\n- cmd: dotnet build src\\NReco.Data --configuration Release\n- cmd: dotnet build src\\NReco.Data.Tests --configuration Release\n\ntest_script:\n- cmd: dotnet test src\\NReco.Data.Tests\\NReco.Data.Tests.csproj --configuration Release"
  },
  {
    "path": "examples/DataSetGenericDataAdapter/DataSetGenericDataAdapter.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"MySqlConnector\" Version=\"2.4.0\" />\n  </ItemGroup>  \n  \n\n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>\n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>    \n  \n</Project>\n"
  },
  {
    "path": "examples/DataSetGenericDataAdapter/GenericDataAdapter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Data.Common;\nusing System.Data;\n\nusing NReco.Data;\n\nnamespace DataSetGenericDataAdapter\n{\n\n\t/// <summary>\n\t/// Generic implementation of <see cref=\"IDbDataAdapter\"/>.\n\t/// </summary>\n\t/// <remarks>Note: this implementation ignores tables and columns mapping. You may enhance the code if you need this feature.</remarks>\n    public class GenericDataAdapter : System.Data.Common.DbDataAdapter {\n\n\t\tIDbCommandBuilder CmdBuilder;\n\t\tDbConnection Conn;\n\n\t\tpublic GenericDataAdapter(IDbCommandBuilder cmdBuilder, DbCommand selectCmd) {\n\t\t\tCmdBuilder = cmdBuilder;\n\t\t\tSelectCommand = selectCmd;\n\t\t}\n\n\t\tpublic GenericDataAdapter(IDbCommandBuilder cmdBuilder, DbConnection conn) {\n\t\t\tCmdBuilder = cmdBuilder;\n\t\t\tConn = conn;\n\t\t}\n\n\t\tIEnumerable<KeyValuePair<string,IQueryValue>> GetChangeset(DataTable t) {\n\t\t\tvar res = new List<KeyValuePair<string, IQueryValue>>(t.Columns.Count);\n\t\t\tforeach (DataColumn col in t.Columns)\n\t\t\t\tif (!col.AutoIncrement && !col.ReadOnly) {\n\t\t\t\t\tres.Add(new KeyValuePair<string, IQueryValue>(col.ColumnName, new QVar(col.ColumnName).Set(null) ));\n\t\t\t\t}\n\t\t\treturn res.ToArray();\n\t\t}\n\n\t\tconst string OriginalSuffix = \"__ORIGINAL\";\n\n\t\tvoid InitDbCmd(DbCommand cmd, DataTable t) {\n\t\t\tforeach (DbParameter p in cmd.Parameters) {\n\t\t\t\tif (p.SourceColumn != null) {\n\t\t\t\t\tif (p.SourceColumn.EndsWith(OriginalSuffix)) {\n\t\t\t\t\t\tp.SourceColumn = p.SourceColumn.Substring(0, p.SourceColumn.Length - OriginalSuffix.Length);\n\t\t\t\t\t\tp.SourceVersion = DataRowVersion.Original;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.SourceVersion = DataRowVersion.Current;\n\t\t\t\t\t}\n\t\t\t\t\tvar col = t.Columns[p.SourceColumn];\n\t\t\t\t\t// you may use column metadata to initialize DbParameter in a special way if needed\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (SelectCommand != null && SelectCommand.Connection != null) { \n\t\t\t\tcmd.Connection = SelectCommand.Connection;\n\t\t\t} else {\n\t\t\t\tcmd.Connection = Conn;\n\t\t\t}\n\t\t}\n\n\t\tQNode ComposePkCondition(DataTable t) {\n\t\t\tvar pkCondition = new QGroupNode(QGroupType.And);\n\t\t\tforeach (DataColumn col in t.PrimaryKey) {\n\t\t\t\tpkCondition.Nodes.Add(\n\t\t\t\t\t(QField)col.ColumnName == new QVar(col.ColumnName+OriginalSuffix).Set(null) );\n\t\t\t}\n\t\t\treturn pkCondition;\n\t\t}\n\n\t\tprotected override int Update(DataRow[] dataRows, DataTableMapping tableMapping) {\n\t\t\t// generate commands by first row table schema\n\t\t\tif (dataRows.Length>0) {\n\t\t\t\tvar tbl = dataRows[0].Table;\n\t\t\t\tvar changeset = GetChangeset(tbl);\n\t\t\t\tInsertCommand = (DbCommand)CmdBuilder.GetInsertCommand(tbl.TableName, changeset);\n\t\t\t\tInitDbCmd(InsertCommand, tbl);\n\n\t\t\t\tif (tbl.PrimaryKey!=null && tbl.PrimaryKey.Length>0) {\n\t\t\t\t\tvar pkQuery = new Query(tbl.TableName, ComposePkCondition(tbl) );\n\t\t\t\t\tUpdateCommand = (DbCommand)CmdBuilder.GetUpdateCommand(pkQuery, changeset);\n\t\t\t\t\tInitDbCmd(UpdateCommand, tbl);\n\n\t\t\t\t\tDeleteCommand = (DbCommand)CmdBuilder.GetDeleteCommand(pkQuery);\n\t\t\t\t\tInitDbCmd(DeleteCommand, tbl);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\n\t\t\treturn base.Update(dataRows, tableMapping);\n\t\t}\n\n\n\t}\n\n}\n"
  },
  {
    "path": "examples/DataSetGenericDataAdapter/Program.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Data;\nusing System.Data.Common;\n\nusing NReco.Data;\n\nnamespace DataSetGenericDataAdapter\n{\n\tclass Program {\n\t\tstatic void Main(string[] args) {\n\n\t\t\tGenericDataAdapterForSqlite();\n\n\t\t\tGenericDataAdapterForMySql();\n\t\t}\n\n\t\tstatic void GenericDataAdapterForSqlite() {\n\t\t\tConsole.WriteLine(\"Sqlite database (northwind.db)\");\n\n\t\t\tvar dbFactory = new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\",\n\t\t\t\tIdentifierFormat = \"\\\"{0}\\\"\"\n\t\t\t};\n\t\t\tvar dbCmdBuilder = new NReco.Data.DbCommandBuilder(dbFactory);\n\n\t\t\tvar sqliteDbPath = Path.Combine(Directory.GetCurrentDirectory(), \"northwind.db\");\n\t\t\tvar sqliteConnStr = String.Format(\"Data Source={0}\", sqliteDbPath);\n\n\t\t\tusing (var conn = dbFactory.CreateConnection()) {\n\t\t\t\tconn.ConnectionString = sqliteConnStr;\n\n\t\t\t\tvar selectCmd = dbCmdBuilder.GetSelectCommand(new Query(\"Employees\"));\n\t\t\t\tselectCmd.Connection = conn;\n\n\t\t\t\tvar dsDataAdapter = new GenericDataAdapter(dbCmdBuilder, (DbCommand)selectCmd);\n\t\t\t\tvar ds = new DataSet();\n\t\t\t\tdsDataAdapter.Fill(ds, \"Employees\");\n\n\t\t\t\tConsole.WriteLine(\"Fill: loaded {0} rows\", ds.Tables[\"Employees\"].Rows.Count);\n\n\t\t\t\t// lets set PK\n\t\t\t\tds.Tables[\"Employees\"].PrimaryKey = new[] { ds.Tables[\"Employees\"].Columns[\"EmployeeID\"] };\n\t\t\t\tds.Tables[\"Employees\"].Columns[\"Deleted\"].ReadOnly = true;  // do not insert/update this column\n\n\t\t\t\t// and modify some rows\n\t\t\t\tds.Tables[\"Employees\"].Rows.Find(1)[\"FirstName\"] = \"Nancy1\";\n\t\t\t\tvar newRow = ds.Tables[\"Employees\"].NewRow();\n\t\t\t\tnewRow[\"EmployeeID\"] = 10;\n\t\t\t\tnewRow[\"FirstName\"] = \"John\";\n\t\t\t\tnewRow[\"LastName\"] = \"Smith\";\n\t\t\t\tnewRow[\"ReportsTo\"] = 2;\n\t\t\t\tnewRow[\"Deleted\"] = 1;  // this will be ignored \n\t\t\t\tds.Tables[\"Employees\"].Rows.Add(newRow);\n\n\t\t\t\tConsole.WriteLine(\"Update (insert+update): affected {0} rows\", dsDataAdapter.Update(ds.Tables[\"Employees\"]));\n\n\t\t\t\tds.Tables[\"Employees\"].Rows.Find(10).Delete();\n\t\t\t\tConsole.WriteLine(\"Update (delete): affected {0} rows\", dsDataAdapter.Update(ds.Tables[\"Employees\"]));\n\n\t\t\t}\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tstatic void GenericDataAdapterForMySql() {\n\t\t\tConsole.WriteLine(\"Mysql database (sample server, may respond slowly)\");\n\n\t\t\tvar dbFactory = new DbFactory(MySqlConnector.MySqlConnectorFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT LAST_INSERT_ID()\",\n\t\t\t\tIdentifierFormat = \"`{0}`\"\n\t\t\t};\n\t\t\tvar dbCmdBuilder = new NReco.Data.DbCommandBuilder(dbFactory);\n\n\t\t\tvar mysqlConnStr = \"Server=db4free.net;Database=nreco_sampledb;Uid=nreco_sampledb;Pwd=HRt5UbVD;\";\n\t\t\tusing (var conn = dbFactory.CreateConnection()) {\n\t\t\t\tconn.ConnectionString = mysqlConnStr;\n\n\t\t\t\tvar selectCmd = dbCmdBuilder.GetSelectCommand(new Query(\"orders\"));\n\t\t\t\tselectCmd.Connection = conn;\n\n\t\t\t\tvar dsDataAdapter = new GenericDataAdapter(dbCmdBuilder, (DbCommand)selectCmd);\n\t\t\t\tvar ds = new DataSet();\n\t\t\t\tdsDataAdapter.Fill(ds, \"orders\");\n\n\t\t\t\tConsole.WriteLine(\"Fill: loaded {0} rows\", ds.Tables[\"orders\"].Rows.Count);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/MySqlDemo.DbMetadata/Models/ColumnMetadata.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nnamespace MySqlDemo.DbMetadata.Models {\n\n\tpublic class ColumnMetadata {\n\n\t\t[Column(\"column_name\")]\n\t\tpublic string ColumnName {\n\t\t\tget; set;\n\t\t}\n\n\t\t[Column(\"data_type\")]\n\t\tpublic string DataType {\n\t\t\tget; set;\n\t\t}\n\n\t\t[Column(\"is_nullable\")]\n\t\tpublic string IsNullable {\n\t\t\tget; set;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "examples/MySqlDemo.DbMetadata/Models/TableMetadata.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nnamespace MySqlDemo.DbMetadata.Models {\n\t\n\tpublic class TableMetadata {\n\n\t\t[Column(\"table_name\")]\n\t\tpublic string TableName { get; set; }\n\n\t\t[Column(\"create_time\")]\n\t\tpublic DateTime? CreateTime { get; set; }\n\n\t\tpublic List<ColumnMetadata> Columns { get; set; }\n\n\t}\n}\n"
  },
  {
    "path": "examples/MySqlDemo.DbMetadata/MySqlDemo.DbMetadata.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <AssemblyName>MySqlDemo.DbMetadata</AssemblyName>\n    <OutputType>Exe</OutputType>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MySqlConnector\" Version=\"2.4.0\" />\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"System.Data.SqlClient\" Version=\"4.8.6\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "examples/MySqlDemo.DbMetadata/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.SqlClient;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing MySqlConnector;\n\nusing NReco.Data;\n\nusing MySqlDemo.DbMetadata.Models;\n\nnamespace MySqlDemo.DbMetadata {\n\n\t/// <summary>\n\t/// This example illustrates how to use NReco.Data for getting database metadata (list of tables / table columns)\n\t/// by querying 'information_schema' views (part of SQL-92, https://en.wikipedia.org/wiki/Information_schema).\n\t/// </summary>\n\t/// <remarks>\n\t/// Note that 'information_schema' views are not supported by some databases (like Oracle, SQLite).\n\t/// </remarks>\n\tpublic class Program {\n\n\t\tprivate static DbDataAdapter _dbAdapter;\n\t\tprotected static DbDataAdapter dbAdapter {\n\t\t\tget {\n\t\t\t\tif (_dbAdapter == null) {\n\t\t\t\t\tvar sqlDbPath = \"Server=db4free.net;Database=nreco_sampledb;Uid=nreco_sampledb;Pwd=HRt5UbVD;\";\n\n\t\t\t\t\tvar dbFactory = new DbFactory(MySqlConnector.MySqlConnectorFactory.Instance) {\n\t\t\t\t\t\tLastInsertIdSelectText = \"SELECT LAST_INSERT_ID()\"\n\t\t\t\t\t};\n\t\t\t\t\tvar dbConnection = dbFactory.CreateConnection();\n\t\t\t\t\tdbConnection.ConnectionString = sqlDbPath;\n\n\t\t\t\t\tvar dbCmdBuilder = new DbCommandBuilder(dbFactory);\n\t\t\t\t\t_dbAdapter = new DbDataAdapter(dbConnection, dbCmdBuilder);\n\t\t\t\t}\n\t\t\t\treturn _dbAdapter;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Main(string[] args) {\n\n\t\t\tConsole.WriteLine(\"Fetch 'orders' table columns (database 'nreco_sampledb', may respond slowly):\");\n\t\t\tvar tbl = FetchTableMetaData(\"orders\");\n\t\t\tConsole.Write(\"Table added: {0}\", tbl.CreateTime);\n\t\t\tConsole.WriteLine();\n\t\t\tConsole.WriteLine();\n\t\t\tforeach (var col in tbl.Columns) {\n\t\t\t\tConsole.WriteLine(\"Column name: {0}; Data type: {1}; IsNullable: {2}\", col.ColumnName, col.DataType, col.IsNullable);\n\t\t\t}\n\t\t\tConsole.WriteLine(\"Press any key to continue...\");\n\t\t\tConsole.ReadKey();\n\t\t}\n\n\t\tprotected static TableMetadata FetchTableMetaData(string tableName) {\n\t\t\tvar query = new Query(\n\t\t\t\tnew QTable(\"INFORMATION_SCHEMA.tables\", null),\n\t\t\t\t(QField)\"table_name\" == (QConst)tableName).Select(\"table_name\", \"create_time\"\n\t\t\t);\n\t\t\tvar table = dbAdapter.Select(query).Single<TableMetadata>();\n\t\t\tGetColumnsMetadata(table);\n\t\t\treturn table;\n\t\t}\n\n\t\tprotected static void GetColumnsMetadata(TableMetadata table) {\n\t\t\tvar query = new Query(\n\t\t\t\tnew QTable(\"INFORMATION_SCHEMA.columns\", null),\n\t\t\t\t(QField)\"TABLE_NAME\" == (QConst)table.TableName).Select(\"column_name\", \"data_type\", \"is_nullable\"\n\t\t\t);\n\t\t\tvar tableColumns = dbAdapter.Select(query).ToList<ColumnMetadata>();\n\n\t\t\ttable.Columns = tableColumns;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/NReco.Data.Examples.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26730.16\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.CommandBuilder\", \"SqliteDemo.CommandBuilder\\SqliteDemo.CommandBuilder.csproj\", \"{E138270B-84B3-4A0C-82E6-CE283F9D53EA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.DataAdapter\", \"SqliteDemo.DataAdapter\\SqliteDemo.DataAdapter.csproj\", \"{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.WebApi\", \"SqliteDemo.WebApi\\SqliteDemo.WebApi.csproj\", \"{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.MVCApplication\", \"SqliteDemo.MVCApplication\\SqliteDemo.MVCApplication.csproj\", \"{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"MySqlDemo.DbMetadata\", \"MySqlDemo.DbMetadata\\MySqlDemo.DbMetadata.csproj\", \"{2B8EB4B6-4896-4970-B5EA-6D324824A541}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.GraphQLAPI\", \"SqliteDemo.GraphQLApi\\SqliteDemo.GraphQLAPI.csproj\", \"{F79B488D-8779-4FE9-B27D-617F9A431739}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SqliteDemo.SqlLogging\", \"SqliteDemo.SqlLogging\\SqliteDemo.SqlLogging.csproj\", \"{B9C42268-CBEF-46CF-A44B-ADC01737F67E}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"DataSetGenericDataAdapter\", \"DataSetGenericDataAdapter\\DataSetGenericDataAdapter.csproj\", \"{B48FD072-C587-4387-9625-6F67B328C42E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|x64.Build.0 = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|x86.Build.0 = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|x64.Build.0 = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{424DF75E-B560-41A7-ACEF-ABFDB620F8EA}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B71A1BCB-9BCD-4385-9D12-2710DE030A2C}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C26E59A1-E085-45DF-8AD2-E7C2810AC1D8}.Release|x86.Build.0 = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|x64.Build.0 = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{2B8EB4B6-4896-4970-B5EA-6D324824A541}.Release|x86.Build.0 = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|x64.Build.0 = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{F79B488D-8779-4FE9-B27D-617F9A431739}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B9C42268-CBEF-46CF-A44B-ADC01737F67E}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B48FD072-C587-4387-9625-6F67B328C42E}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {53B4C967-C2C7-4D78-AD74-EF496B12AA94}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "examples/SqliteDemo.CommandBuilder/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.IO;\n\nusing System.Data;\nusing System.Diagnostics;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.CommandBuilder\n{\n\t/// <summary>\n\t/// Example illustrates how to use DbCommandBuilder for generating SQL commands by Query structure.\n\t/// </summary>\n\t/// <remarks>\n\t/// This approach is useful if you really need to have full control over low-level ADO.NET components.\n\t/// In most cases it is much easier to use DbDataAdapter which provides simple interface for CRUD-operations (see SqliteDemo.DataAdapter example).\n\t/// </remarks>\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n\t\t\t// configure ADO.NET and NReco.Data components\n\t\t\tvar dbFactory = new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t};\n\t\t\tvar dbCmdBuilder = new DbCommandBuilder(dbFactory);\n\t\t\tvar sqliteDbPath = Path.Combine( Directory.GetCurrentDirectory(), \"northwind.db\");\n\n\t\t\tusing (var conn = dbFactory.CreateConnection()) {\n\t\t\t\tconn.ConnectionString = String.Format(\"Data Source={0}\", sqliteDbPath);\n\n\t\t\t\t// simple helper class that holds DB context.\n\t\t\t\tvar dbContext = new DbContext() {\n\t\t\t\t\tCommandBuilder = dbCmdBuilder,\n\t\t\t\t\tConnection = conn,\n\t\t\t\t\tDbFactory = dbFactory\n\t\t\t\t};\n\n\t\t\t\tconn.Open();\n\t\t\t\ttry {\n\t\t\t\t\tRunSelect(dbContext);\n\n\t\t\t\t\t// lets run insert / update in transaction\n\t\t\t\t\tusing (var tr = conn.BeginTransaction()) {\n\t\t\t\t\t\tdbContext.Transaction = tr;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tRunInsert(dbContext);\n\t\t\t\t\t\t\tRunUpdate(dbContext);\n\t\t\t\t\t\t\ttr.Commit();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\ttr.Rollback();\n\t\t\t\t\t\t\tthrow;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdbContext.Transaction = null;\n\n\t\t\t\t\t// batch inserts: several SQL statements in one DbCommand\n\t\t\t\t\tRunBatchInserts(dbContext);\n\n\t\t\t\t\tRunDelete(dbContext);\n\n\n\t\t\t\t} finally {\n\t\t\t\t\tconn.Close();\n\t\t\t\t}\n\n\t\t\t\t// multiple result sets example\n\t\t\t\tRunSelectMultipleResultSet(dbContext);\n\t\t\t}\n\n\n        }\n\n\t\tstatic void RunSelect(DbContext dbContext) {\n\t\t\tvar selectCmd = dbContext.CommandBuilder.GetSelectCommand(new Query(\"Employees\", (QField)\"BirthDate\" > new QConst(new DateTime(1960,1,1)) ));\n\t\t\tdbContext.InitCommand(selectCmd);\n\n\t\t\tConsole.WriteLine(\"Selecting 'Employees' with BirthDay > 1960\");\n\t\t\tConsole.WriteLine(\"Generated SQL: {0}\", selectCmd.CommandText);\n\t\t\tusing (var rdr = selectCmd.ExecuteReader()) {\n\t\t\t\twhile (rdr.Read()) {\n\t\t\t\t\tConsole.WriteLine(\"#{0}: {1} {2}\", rdr[\"EmployeeID\"], rdr[\"FirstName\"], rdr[\"LastName\"]);\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tstatic void RunInsert(DbContext dbContext) {\n\t\t\tvar newEmployee = new Dictionary<string,object>() {\n\t\t\t\t{ \"EmployeeID\", 1000 },\n\t\t\t\t{ \"FirstName\", \"John\" },\n\t\t\t\t{ \"LastName\", \"Smith\" },\n\t\t\t\t{ \"BirthDate\", new DateTime(1980, 1, 1) }\n\t\t\t};\n\t\t\tvar insertCmd = dbContext.CommandBuilder.GetInsertCommand(\"Employees\", newEmployee );\n\t\t\tdbContext.InitCommand(insertCmd);\n\n\t\t\tConsole.WriteLine(\"Inserting new record to 'Employees' table\");\n\t\t\tConsole.WriteLine($\"Generated SQL: {insertCmd.CommandText}\");\n\t\t\tvar affected = insertCmd.ExecuteNonQuery();\n\t\t\tConsole.WriteLine($\"Done, affected: {affected}\");\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tstatic void RunUpdate(DbContext dbContext) {\n\t\t\tvar changeset = new Dictionary<string,object>() {\n\t\t\t\t{ \"FirstName\", \"Mike\" }\n\t\t\t};\n\t\t\tvar updateCmd = dbContext.CommandBuilder.GetUpdateCommand(\n\t\t\t\tnew Query(\"Employees\", (QField)\"EmployeeID\" == (QConst)1000 ), changeset );\n\t\t\tdbContext.InitCommand(updateCmd);\n\n\t\t\tConsole.WriteLine(\"Updating just inserted record in 'Employees' table\");\n\t\t\tConsole.WriteLine($\"Generated SQL: {updateCmd.CommandText}\");\n\t\t\tvar affected = updateCmd.ExecuteNonQuery();\n\t\t\tConsole.WriteLine($\"Done, affected: {affected}\");\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tstatic void RunDelete(DbContext dbContext) {\n\t\t\tvar deleteCmd = dbContext.CommandBuilder.GetDeleteCommand(\n\t\t\t\tnew Query(\"Employees\", (QField)\"EmployeeID\" >= (QConst)1000 ) );\n\t\t\tdbContext.InitCommand(deleteCmd);\n\n\t\t\tConsole.WriteLine(\"Deleting all records with EmployeeID >=100 from 'Employees' table\");\n\t\t\tConsole.WriteLine(\"Generated SQL: {0}\", deleteCmd.CommandText);\n\t\t\tvar affected = deleteCmd.ExecuteNonQuery();\n\t\t\tConsole.WriteLine($\"Done, affected: {affected}\");\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tstatic void RunBatchInserts(DbContext dbContext) {\n\t\t\t// about SQL statements batches: https://msdn.microsoft.com/en-us/library/ms712553%28v=vs.85%29.aspx\n\t\t\t// note that depending on database/ADO.NET connector, executing SQL statements in batch may not lead to performance boost\n\t\t\t// (for example, for SQLite)\n\t\t\t// usually batches are efficient for inserting/updating many records in cloud DB \n\t\t\t// (like Azure SQL: https://azure.microsoft.com/en-us/documentation/articles/sql-database-use-batching-to-improve-performance/ )\n\n\t\t\tvar sw = new Stopwatch();\n\t\t\tvar batchCmdBuilder = new DbBatchCommandBuilder(dbContext.DbFactory);\n\n\t\t\t// lets create 10,000 records to insert\n\t\t\tvar insertsCount = 10000;\n\t\t\tvar insertRecords = new List<Dictionary<string,object>>();\n\t\t\tfor (int i=0; i<insertsCount; i++) {\n\t\t\t\tinsertRecords.Add( new Dictionary<string, object>() {\n\t\t\t\t\t{ \"EmployeeID\", 1001+i },\n\t\t\t\t\t{ \"FirstName\", \"First\"+i.ToString() },\n\t\t\t\t\t{ \"LastName\", \"Last\"+i.ToString() }\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tsw.Start();\n\n\t\t\t// insert in batch (10-per-command)\n\t\t\tvar batchSize = 10;\n\t\t\tvar startIdx = 0;\n\n\t\t\tusing (var tr = dbContext.Connection.BeginTransaction()) {\n\n\t\t\t\twhile (startIdx<insertRecords.Count) {\n\t\t\t\t\tbatchCmdBuilder.BeginBatch();\n\t\t\t\t\tfor (var i=0; i<batchSize && (i+startIdx)<insertRecords.Count; i++) {\n\t\t\t\t\t\tbatchCmdBuilder.GetInsertCommand(\"Employees\", insertRecords[startIdx+i] );\n\t\t\t\t\t}\n\t\t\t\t\tvar cmd = batchCmdBuilder.EndBatch();\n\t\t\t\t\tcmd.Connection = dbContext.Connection;\n\t\t\t\t\tcmd.Transaction = tr;\n\t\t\t\t\tcmd.ExecuteNonQuery();\n\t\t\t\t\tstartIdx += batchSize;\n\n\t\t\t\t\tif ( (startIdx%1000)==0 )\n\t\t\t\t\t\tConsole.WriteLine($\"Inserted {startIdx} records...\");\n\t\t\t\t}\n\t\t\t\ttr.Commit();\n\t\t\t}\n\n\t\t\tsw.Stop();\n\n\t\t\tConsole.WriteLine($\"Inserted {insertsCount} records in {sw.Elapsed}\");\n\t\t\t\n\t\t\t// ensure that records are really inserted\n\t\t\tvar employeesCountCmd = dbContext.CommandBuilder.GetSelectCommand(new Query(\"Employees\").Select(QField.Count) );\n\t\t\temployeesCountCmd.Connection = dbContext.Connection;\n\t\t\tConsole.WriteLine(\"Number of records in 'Employees' table: {0}\", employeesCountCmd.ExecuteScalar() );\n\t\t}\n\n\n\t\tpublic static void RunSelectMultipleResultSet(DbContext dbContext) {\n\t\t\t// lets generate several selects in one command\n\t\t\tvar batchCmdBuilder = new DbBatchCommandBuilder(dbContext.DbFactory);\n\n\t\t\tConsole.WriteLine(\"Composing 2 selects in one DbCommand (multiple result sets)\");\n\t\t\tbatchCmdBuilder.BeginBatch();\n\n\t\t\tbatchCmdBuilder.GetSelectCommand(new Query(\"Customers\", (QField)\"Country\" == (QConst)\"Germany\" ));\n\t\t\tbatchCmdBuilder.GetSelectCommand(new Query(\"Orders\",\n\t\t\t\tnew QConditionNode((QField)\"CustomerID\", Conditions.In,\n\t\t\t\t\tnew Query(\"Customers.c\", (QField)\"c.Country\" == (QConst)\"Germany\" ).Select(\"c.CustomerID\")\n\t\t\t\t)\n\t\t\t));\n\n\t\t\tvar multiSelectCmd = batchCmdBuilder.EndBatch();\n\t\t\tmultiSelectCmd.Connection = dbContext.Connection;\n\n\t\t\tRecordSet customerRS = null;\n\t\t\tRecordSet orderRS = null;\n\t\t\tdbContext.Connection.Open();\n\t\t\ttry {\n\t\t\t\tusing (var rdr = multiSelectCmd.ExecuteReader()) {\n\t\t\t\t\tcustomerRS = RecordSet.FromReader(rdr);\n\t\t\t\t\tif (rdr.NextResult())\n\t\t\t\t\t\torderRS = RecordSet.FromReader(rdr);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tdbContext.Connection.Close();\n\t\t\t}\n\n\t\t\tConsole.WriteLine($\"Loaded {customerRS.Count} customers and {orderRS.Count} their orders from one data reader\");\n\t\t}\n\n\n\t\tpublic class DbContext {\n\t\t\tpublic IDbConnection Connection { get; set; }\n\t\t\tpublic IDbCommandBuilder CommandBuilder { get; set; }\n\t\t\tpublic IDbTransaction Transaction { get; set; }\n\t\t\tpublic IDbFactory DbFactory { get; set; }\n\n\t\t\tpublic void InitCommand(IDbCommand cmd) {\n\t\t\t\tcmd.Connection = Connection;\n\t\t\t\tif (Transaction!=null)\n\t\t\t\t\tcmd.Transaction = Transaction;\n\t\t\t}\n\t\t}\n\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.CommandBuilder/SqliteDemo.CommandBuilder.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <AssemblyName>SqliteDemo.CommandBuilder</AssemblyName>\n    <OutputType>Exe</OutputType>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n  </ItemGroup>\n\n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>\n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>    \n  \n</Project>\n"
  },
  {
    "path": "examples/SqliteDemo.DataAdapter/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nusing System.IO;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.DataAdapter\n{\n\t/// <summary>\n\t/// Example illustrates how to use DbDataAdapter for accessing and updating DB in a schema-less way.\n\t/// </summary>\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n\t\t\tvar sqliteDbPath = Path.Combine( Directory.GetCurrentDirectory(), \"northwind.db\");\n\n\t\t\t// configure ADO.NET and NReco.Data components\n\t\t\tvar dbFactory = new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t};\n\t\t\tvar dbConnection = dbFactory.CreateConnection();\n\t\t\tdbConnection.ConnectionString = String.Format(\"Data Source={0}\", sqliteDbPath);\n\n\t\t\tvar dbCmdBuilder = new DbCommandBuilder(dbFactory);\n\t\t\tvar dbAdapter = new DbDataAdapter(dbConnection, dbCmdBuilder);\n\t\t\t\n\t\t\t// note: DbDataAdapter automatically opens (if it is not opened) and closes DB connection\n\t\t\t\n\t\t\t// lets remove all employees with ID>=1000 (cleanup)\n\t\t\tdbAdapter.Delete(new Query(\"Employees\", (QField)\"EmployeeID\">=(QConst)1000 ));\n\n\t\t\t// demo for select queries\n\t\t\tSelectDemo(dbAdapter);\n\n\t\t\t// demo for DbDataAdapter Insert/Update/Delete for one record\n\t\t\tInsertUpdateDeleteForOneRecord(dbAdapter);\n\n\t\t\t// demo for DbDataAdapter mass Update (record set)\n\t\t\tUpdateForRecordSet(dbAdapter);\n\n        }\n\n\t\tpublic static void SelectDemo(DbDataAdapter dbAdapter) {\n\t\t\t// select single value\n\t\t\tConsole.WriteLine(\"Records count in 'Employees' table: {0}\",\n\t\t\t\t\tdbAdapter.Select( new Query(\"Employees\").Select( QField.Count ) ).Single<int>()\n\t\t\t\t);\n\n\t\t\t// select data into POCO models (columns are mapped to object properties)\n\t\t\tConsole.WriteLine(\"All names from 'Employees' table:\");\n\t\t\tforeach (var employee in dbAdapter.Select( new Query(\"Employees\") ).ToList<Employee>() ) {\n\t\t\t\tConsole.WriteLine(\"#{0}: {1} {2}\", employee.EmployeeID, employee.FirstName, employee.LastName);\n\t\t\t}\n\t\t\tConsole.WriteLine();\n\n\t\t\t// select data into dictionaries (illustrates subquery) \n\t\t\tConsole.WriteLine(\"Products from 'Seafood' category:\");\n\t\t\tvar productBySeafoodQuery = new Query(\"Products\", \n\t\t\t\t\tnew QConditionNode( (QField)\"CategoryID\", Conditions.In, \n\t\t\t\t\t\tnew Query(\"Categories\", (QField)\"CategoryName\"==(QConst)\"Seafood\" ).Select(\"CategoryID\")\n\t\t\t\t\t)\n\t\t\t\t).Select(\"ProductName\", \"UnitPrice\");\n\t\t\tforeach (var product in dbAdapter.Select( productBySeafoodQuery ).ToDictionaryList() ) {\n\t\t\t\tConsole.WriteLine(\"{0} for ${1}\", product[\"ProductName\"], product[\"UnitPrice\"]);\n\t\t\t}\n\n\t\t\t// select data into RecordSet\n\t\t\tConsole.WriteLine(\"Customers from USA:\");\n\t\t\tvar customersRS = dbAdapter.Select( \n\t\t\t\t\tnew Query(\"Customers\", (QField)\"Country\"==(QConst)\"USA\").Select(\"CustomerID\",\"CompanyName\",\"ContactName\")\n\t\t\t\t).ToRecordSet();\n\t\t\tforeach (var row in customersRS) {\n\t\t\t\tforeach (var col in customersRS.Columns) {\n\t\t\t\t\tConsole.Write(\"{0}={1} |\", col.Name, row[col]);\n\t\t\t\t}\n\t\t\t\tConsole.WriteLine();\n\t\t\t}\n\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tpublic static void InsertUpdateDeleteForOneRecord(DbDataAdapter dbAdapter) {\n\n\t\t\t// add new employee by POCO model\n\t\t\tvar newEmployee = new Employee() { EmployeeID = 1000, FirstName = \"John\", LastName = \"Smith\" };\n\t\t\tdbAdapter.Insert(\"Employees\", newEmployee );\n\t\t\tConsole.WriteLine(\"Added new employee: John Smith (ID=1000)\");\n\n\t\t\t// add new employee by dictionary\n\t\t\tdbAdapter.Insert(\"Employees\", new Dictionary<string,object>() {\n\t\t\t\t{\"EmployeeID\", 1001},\n\t\t\t\t{\"FirstName\", \"Jim\"},\n\t\t\t\t{\"LastName\", \"Gordon\"}\n\t\t\t});\n\t\t\tConsole.WriteLine(\"Added new employee: Jim Gordon (ID=1001)\");\n\n\t\t\t// update employee by poco model\n\t\t\tnewEmployee.FirstName = \"Bart\";\n\t\t\tvar newEmployeeByIdQuery = new Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)newEmployee.EmployeeID );\n\t\t\tdbAdapter.Update( newEmployeeByIdQuery, newEmployee);\n\n\t\t\tConsole.WriteLine(\"New first name for EmployeeID=1000: {0}\", \n\t\t\t\tdbAdapter.Select( new Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)1000).Select(\"FirstName\") ).Single<string>() );\n\n\t\t\t// update employee by dictionary\n\t\t\tdbAdapter.Update( \n\t\t\t\tnew Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)1001 ),\n\t\t\t\tnew Dictionary<string,object>() {\n\t\t\t\t\t{\"FirstName\", \"Bruce\" },\n\t\t\t\t\t{\"LastName\", \"Wayne\" }\n\t\t\t\t}\n\t\t\t);\n\t\t\tvar employee_1001_data = dbAdapter.Select( new Query(\"Employees\", (QField)\"EmployeeID\"==(QConst)1001 )).ToDictionary();\n\t\t\tConsole.WriteLine(\"New name for EmployeeID=1001: {0} {1}\", employee_1001_data[\"FirstName\"], employee_1001_data[\"LastName\"]);\n\n\t\t\t// update only some fields from model\n\t\t\tnewEmployee.LastName = \"Simpson\";\n\t\t\tnewEmployee.FirstName = \"Homer\";\n\n\t\t\tdbAdapter.Update(newEmployeeByIdQuery, new { LastName = \"LastName\" } );\n\t\t\t\n\t\t\tvar newEmployeeNameFromDb = dbAdapter.Select( new Query(newEmployeeByIdQuery).Select(\"FirstName\",\"LastName\") ).ToDictionary();\n\t\t\tConsole.WriteLine(\"First+Last for EmployeeID=1000 after update: {0} {1}\",\n\t\t\t\tnewEmployeeNameFromDb[\"FirstName\"], newEmployeeNameFromDb[\"LastName\"]);\t\t\t\n\t\t}\n\n\t\tpublic static void UpdateForRecordSet(DbDataAdapter dbAdapter) {\n\t\t\tvar customersRS = dbAdapter.Select( \n\t\t\t\t\tnew Query(\"Customers\").OrderBy(\"CustomerID asc\")\n\t\t\t\t).ToRecordSet();\t\t\t\n\t\t\tConsole.WriteLine(\"Loaded {0} customer records ({1} columns)\", customersRS.Count, customersRS.Columns.Count);\n\n\t\t\t// in most cases primary key should be set explicetly\n\t\t\tcustomersRS.SetPrimaryKey(\"CustomerID\");\n\n\t\t\t// lets change USA,Canada to 'North America'\n\t\t\tint updateRows = 0;\n\t\t\tforeach (var row in customersRS)\n\t\t\t\tif (\"USA\".Equals(row[\"Country\"]) || \"Canada\".Equals(row[\"Country\"])) {\n\t\t\t\t\trow[\"Country\"] = \"North America\";\n\t\t\t\t\tupdateRows++;\n\t\t\t\t}\n\t\t\t// lets delete some customer\n\t\t\tvar deleteRows = 0;\n\t\t\tforeach (var row in customersRS)\n\t\t\t\tif (\"PARIS\".Equals(row[\"CustomerID\"])) {\n\t\t\t\t\trow.Delete();\n\t\t\t\t\tdeleteRows++;\n\t\t\t\t}\n\t\t\t// lets add one customer from Ukraine\n\t\t\tvar uaCustomer = customersRS.Add();\n\t\t\tuaCustomer[\"CompanyName\"] = \"MegaSuperAwsome Inc\";\n\t\t\tuaCustomer[\"CustomerID\"] = \"MEGAUA\";\n\t\t\tuaCustomer[\"Country\"] = \"Ukraine\";\n\t\t\t\n\t\t\tConsole.WriteLine(\"RecordSet rows: update={0} delete={1} insert={2}\", updateRows, deleteRows, 1);\n\n\t\t\tdbAdapter.Connection.Open();\n\t\t\tusing (var tr = dbAdapter.Connection.BeginTransaction()) {\n\t\t\t\tdbAdapter.Transaction = tr; // associate transaction for adapter commands\n\t\t\t\ttry {\n\t\t\t\t\t\n\t\t\t\t\tdbAdapter.Update(\"Customers\", customersRS);\t\t\n\t\t\t\t\t\n\t\t\t\t\tConsole.WriteLine(\"Customers count={0}\", dbAdapter.Select(new Query(\"Customers\").Select(QField.Count) ).Single<int>() );\n\n\t\t\t\t\t// lets throw an exception\n\t\t\t\t\tthrow new Exception(\"Rollback Test!\");\n\n\t\t\t\t\ttr.Commit();\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tConsole.WriteLine(\"Exception is thrown: {0}\", ex.ToString() );\n\t\t\t\t\ttr.Rollback();\n\t\t\t\t} finally {\n\t\t\t\t\tdbAdapter.Transaction = null;\n\t\t\t\t\tdbAdapter.Connection.Close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class Employee {\n\n\t\t\t[Key]\n\t\t\tpublic int EmployeeID { get; set; }\n\t\t\tpublic string FirstName { get; set; }\n\t\t\tpublic string LastName { get; set; }\n\t\t\tpublic DateTime? BirthDate { get; set; }\n\n\t\t\t[NotMapped]\n\t\t\tpublic string FullName {\n\t\t\t\tget { return $\"{FirstName} {LastName}\"; }\n\t\t\t}\n\t\t}\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.DataAdapter/SqliteDemo.DataAdapter.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <AssemblyName>SqliteDemo.DataAdapter</AssemblyName>\n    <OutputType>Exe</OutputType>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n  </ItemGroup>\n\n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>\n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>   \n  \n</Project>\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Controllers/GraphQLController.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Net;\nusing System.Net.Http;\nusing System.Text;\n\nusing Microsoft.AspNetCore.Mvc;\n\nusing SqliteDemo.GraphQLApi.Db.GraphQL;\n\nusing GraphQL;\nusing GraphQL.Http;\nusing GraphQL.Instrumentation;\nusing GraphQL.Execution;\nusing GraphQL.Types;\nusing GraphQL.Validation;\nusing GraphQL.Validation.Complexity;\n\nnamespace SqliteDemo.GraphQLApi.Controllers {\n\t[Route(\"api/[controller]\")]\n\tpublic class GraphQLController : Controller {\n\t\tSchema graphQLSchema;\n\n\t\tpublic GraphQLController(Schema schema) {\n\t\t\tgraphQLSchema = schema;\n\t\t}\n\n\t\t[HttpGet(\"\")]\n\t\tpublic async Task<string> Get(string query) {\n\t\t\t//query = @\"{ Customers(CustomerID: \"\"ALFKI\"\") { CustomerID CompanyName } }\";\n\t\t\t//query = @\"{ Customers_list { CustomerID CompanyName } }\";\n\n\t\t\tvar result = await new DocumentExecuter().ExecuteAsync(\n\t\t\t\tnew ExecutionOptions() {\n\t\t\t\t\tSchema = graphQLSchema,\n\t\t\t\t\tQuery = query\n\t\t\t\t}\n\t\t\t).ConfigureAwait(false);\n\n\t\t\tvar json = new DocumentWriter(indent: true).Write(result.Data);\n\t\t\treturn json;\n\t\t}\n\n\t\t// POST api/values\n\t\t[HttpPost]\n\t\tpublic void Post([FromBody]string value) {\n\t\t}\n\n\t\t// PUT api/values/5\n\t\t[HttpPut(\"{id}\")]\n\t\tpublic void Put(int id, [FromBody]string value) {\n\t\t}\n\n\t\t// DELETE api/values/5\n\t\t[HttpDelete(\"{id}\")]\n\t\tpublic void Delete(int id) {\n\t\t}\n\t}\n}"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Db/GraphQL/GraphQLQuery.cs",
    "content": "using System.Collections.Generic;\n\nusing GraphQL.Types;\n\nusing SqliteDemo.GraphQLApi.Db.Models;\nusing GraphQL.Resolvers;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.GraphQLApi.Db.GraphQL {\n\tpublic class GraphQLQuery : ObjectGraphType<object> {\n\t\tprivate IDatabaseMetadata _dbMetadata;\n\t\tprivate DbDataAdapter _dbAdapter;\n\n\t\tpublic GraphQLQuery(DbDataAdapter data, IDatabaseMetadata dbMetadata) {\n\t\t\t_dbMetadata = dbMetadata;\n\t\t\t_dbAdapter = data;\n\n\t\t\tName = \"Query\";\n\n\t\t\tforeach (var metaTable in _dbMetadata.GetMetadataTables()) {\n\t\t\t\tvar tableType = new TableType(metaTable);\n\t\t\t\tthis.AddField(new FieldType() {\n\t\t\t\t\tName = metaTable.TableName,\n\t\t\t\t\tType = tableType.GetType(),\n\t\t\t\t\tResolvedType = tableType,\n\t\t\t\t\tResolver = new MyFieldResolver(metaTable, _dbAdapter),\n\t\t\t\t\tArguments = new QueryArguments(\n\t\t\t\t\t\ttableType.TableArgs\n\t\t\t\t\t)\n\t\t\t\t});\n\t\t\t\t//lets add key to get list of current table\n\t\t\t\tvar listType = new ListGraphType(tableType);\n\t\t\t\tthis.AddField(new FieldType {\n\t\t\t\t\tName = $\"{metaTable.TableName}_list\",\n\t\t\t\t\tType = listType.GetType(),\n\t\t\t\t\tResolvedType = listType,\n\t\t\t\t\tResolver = new MyFieldResolver(metaTable, _dbAdapter),\n\t\t\t\t\tArguments = new QueryArguments(\n\t\t\t\t\t\ttableType.TableArgs\n\t\t\t\t\t)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic class MyFieldResolver : IFieldResolver {\n\t\tprivate TableMetadata _tableMetadata;\n\t\tprivate DbDataAdapter _dbAdapter;\n\n\t\tpublic MyFieldResolver(TableMetadata tableMetadata, DbDataAdapter data) {\n\t\t\t_tableMetadata = tableMetadata;\n\t\t\t_dbAdapter = data;\n\t\t}\n\n\t\tpublic object Resolve(ResolveFieldContext context) {\n\t\t\tvar query = new Query(\n\t\t\t\t$\"'{_tableMetadata.TableName}'\"\n\t\t\t);\n\t\t\tApplyArguments(query, context.Arguments);\n\t\t\tif (context.FieldName.Contains(\"_list\")) {\n\t\t\t\treturn _dbAdapter.Select(query).ToDictionaryList();\n\t\t\t} else {\n\t\t\t\treturn _dbAdapter.Select(query).ToDictionary();\n\t\t\t}\n\t\t}\n\n\t\tprivate void ApplyArguments(Query q, IDictionary<string, object> args) {\n\t\t\tvar grpAnd = QGroupNode.And();\n\t\t\tvar applyConditions = false;\n\t\t\tforeach (var arg in args) {\n\t\t\t\tif (arg.Value != null) {\n\t\t\t\t\tgrpAnd.Nodes.Add(\n\t\t\t\t\t\t(QField)arg.Key == new QConst(arg.Value)\n\t\t\t\t\t);\n\t\t\t\t\tapplyConditions = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (applyConditions)\n\t\t\t\tq.Condition = grpAnd;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Db/GraphQL/TableType.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing System.Reflection;\n\nusing GraphQL.Types;\nusing SqliteDemo.GraphQLApi.Db.Models;\nusing GraphQL;\nusing GraphQL.Resolvers;\n\nusing Microsoft.Data.Sqlite;\n\nnamespace SqliteDemo.GraphQLApi.Db.GraphQL {\n\tpublic class TableType : ObjectGraphType<IDictionary<string,object>> {\n\n\t\tpublic QueryArguments TableArgs {\n\t\t\tget; set;\n\t\t}\n\n\t\tprivate IDictionary<string, Type> _SqliteTypeToSystemType;\n\t\tprotected IDictionary<string, Type> SqliteTypeToSystemType {\n\t\t\tget {\n\t\t\t\tif (_SqliteTypeToSystemType == null) {\n\t\t\t\t\t_SqliteTypeToSystemType = new Dictionary<string, Type> {\n\t\t\t\t\t\t{ \"char\", typeof(String) },\n\t\t\t\t\t\t{ \"nvarchar\", typeof(String) },\n\t\t\t\t\t\t{ \"int\", typeof(int) },\n\t\t\t\t\t\t{ \"decimal\", typeof(decimal) },\n\t\t\t\t\t\t{ \"bit\", typeof(bool) }\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn _SqliteTypeToSystemType;\n\t\t\t}\n\t\t}\n\n\t\tpublic TableType(TableMetadata tableMetadata) {\n\t\t\tName = tableMetadata.TableName;\n\t\t\tforeach (var tableColumn in tableMetadata.Columns) {\n\t\t\t\tInitGraphTableColumn(tableColumn);\n\t\t\t}\n\t\t}\n\n\t\tprivate void InitGraphTableColumn(ColumnMetadata columnMetadata) {\n\t\t\tvar graphQLType = (ResolveColumnMetaType(columnMetadata.DataType)).GetGraphTypeFromType(true);\n\n\t\t\tvar columnField = this.Field(\n\t\t\t\tgraphQLType, \n\t\t\t\tcolumnMetadata.ColumnName\n\t\t\t);\n\t\t\tcolumnField.Resolver = new DictionaryNameFieldResolver();\n\t\t\tFillArgs(columnMetadata.ColumnName);\n\t\t}\n\n\t\tprivate void FillArgs(string columnName) {\n\t\t\tif (TableArgs == null) {\n\t\t\t\tTableArgs = new QueryArguments(\n\t\t\t\t\tnew QueryArgument<StringGraphType>() {\n\t\t\t\t\t\tName = columnName\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tTableArgs.Add(new QueryArgument<StringGraphType> { Name = columnName });\n\t\t\t}\n\t\t}\n\n\t\tprivate Type ResolveColumnMetaType(string dbType) {\n\t\t\tif (SqliteTypeToSystemType.ContainsKey(dbType))\n\t\t\t\treturn SqliteTypeToSystemType[dbType];\n\n\t\t\treturn typeof(String);\n\t\t}\n\t}\n\n\t/**/\n\n\tpublic class DictionaryNameFieldResolver : IFieldResolver {\n\t\tprivate BindingFlags _flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;\n\n\t\tpublic object Resolve(ResolveFieldContext context) {\n\t\t\tvar source = context.Source;\n\n\t\t\tif (source == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar value = (source as IDictionary<string, object>)[context.FieldAst.Name];\n\n\t\t\tif (value == null) {\n\t\t\t\tthrow new InvalidOperationException($\"Expected to find property {context.FieldAst.Name} on {context.Source.GetType().Name} but it does not exist.\");\n\t\t\t}\n\n\t\t\treturn value;\n\t\t}\n\t}\n\n\n}"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Db/Models/ColumnMetadata.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nnamespace SqliteDemo.GraphQLApi.Db.Models {\n\n\tpublic class ColumnMetadata {\n\n\t\t[Column(\"name\")]\n\t\tpublic string ColumnName {\n\t\t\tget; set;\n\t\t}\n\n\t\t[Column(\"type\")]\n\t\tpublic string DataType {\n\t\t\tget; set;\n\t\t}\n\n\t\t[Column(\"notnull\")]\n\t\tpublic string IsNullable {\n\t\t\tget; set;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Db/Models/DatabaseMetadata.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.GraphQLApi.Db.Models {\n\t\n\tpublic class DatabaseMetadata : IDatabaseMetadata {\n\n\t\tprotected DbDataAdapter _DbNRecoAdapter;\n\n\t\tpublic DatabaseMetadata(DbDataAdapter dbAdapter) {\n\t\t\t_DbNRecoAdapter = dbAdapter;\n\t\t\tDatabaseName = _DbNRecoAdapter.Connection.Database;\n\t\t\tif (Tables == null)\n\t\t\t\tLoadMetaData();\n\t\t}\n\n\t\tpublic string DatabaseName { get; set; }\n\n\t\tpublic List<TableMetadata> Tables { get; set; }\n\n\t\tprivate void LoadMetaData() {\n\t\t\tvar res = new List<TableMetadata>();\n\t\t\tres.Add(\n\t\t\t\tFetchTableMetaData(\"Customers\")\n\t\t\t);\n\t\t\tTables = res;\n\t\t}\n\n\t\tpublic void ReloadMetadata() {\n\t\t\tLoadMetaData();\n\t\t}\n\n\t\tpublic List<TableMetadata> GetMetadataTables() {\n\t\t\tif (Tables == null)\n\t\t\t\treturn new List<TableMetadata>();\n\n\t\t\treturn Tables;\n\t\t}\n\n\t\tprivate TableMetadata FetchTableMetaData(string tableName) {\n\t\t\tvar metaTable = new TableMetadata { TableName = tableName };\n\t\t\tGetColumnsMetadata(metaTable);\n\t\t\treturn metaTable;\n\t\t}\n\n\t\tprivate void GetColumnsMetadata(TableMetadata table) {\n\t\t\tvar tableColumns = _DbNRecoAdapter.Select(\n\t\t\t\t$\"PRAGMA table_info('{@table.TableName}');\"\n\t\t\t).ToList<ColumnMetadata>();\n\t\t\ttable.Columns = tableColumns;\n\t\t}\n\t}\n\n\tpublic interface IDatabaseMetadata {\n\n\t\tvoid ReloadMetadata();\n\t\tList<TableMetadata> GetMetadataTables();\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Db/Models/TableMetadata.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.GraphQLApi.Db.Models {\n\t\n\tpublic class TableMetadata {\n\n\t\t[Column(\"table_name\")]\n\t\tpublic string TableName { get; set; }\n\n\t\tpublic List<ColumnMetadata> Columns { get; set; }\n\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Builder;\n\nnamespace SqliteDemo.GraphQLApi\n{\n    // Simple grapql API based on Graphql.NET + NReco.Data\n    // If you're looking for production-ready Graphql-to-SQL engine try this component:\n    // https://www.nrecosite.com/graphql_to_sql_database.aspx\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var host = new WebHostBuilder()\n                .UseKestrel()\n                .UseContentRoot(Directory.GetCurrentDirectory())\n                .UseIISIntegration()\n                .UseIIS()\n                .UseStartup<Startup>()\n                .Build();\n\n            host.Run();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Properties/launchSettings.json",
    "content": "{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:62500/\",\n      \"sslPort\": 0\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"index.html\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"SqliteDemo.GraphQLApi\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"http://localhost:5000/index.html\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/SqliteDemo.GraphQLAPI.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"GraphQL\" Version=\"2.4.0\" />\n  </ItemGroup>\n\n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>\n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>  \n  \n</Project>\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/Startup.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.IO;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nusing SqliteDemo.GraphQLApi.Db.Models;\n\nusing NReco.Data;\nusing GraphQL;\nusing GraphQL.Types;\nusing SqliteDemo.GraphQLApi.Db.GraphQL;\n\nnamespace SqliteDemo.GraphQLApi {\n\n\t// Simple grapql API based on Graphql.NET + NReco.Data\n\t// If you're looking for production-ready Graphql-to-SQL engine try this component:\n\t// https://www.nrecosite.com/graphql_to_sql_database.aspx\n\tpublic class Startup {\n\t\tconst string dbConnectionFile = \"northwind.db\";\n\t\tprotected string ApplicationPath;\n\n\t\tpublic Startup(IWebHostEnvironment env) {\n\t\t\tvar builder = new ConfigurationBuilder()\n\t\t\t\t.SetBasePath(env.ContentRootPath)\n\t\t\t\t.AddJsonFile(\"appsettings.json\", optional: true, reloadOnChange: true)\n\t\t\t\t.AddJsonFile($\"appsettings.{env.EnvironmentName}.json\", optional: true)\n\t\t\t\t.AddEnvironmentVariables();\n\t\t\tApplicationPath = env.ContentRootPath;\n\n\t\t\tConfiguration = builder.Build();\n\t\t}\n\n\t\tpublic IConfigurationRoot Configuration {\n\t\t\tget;\n\t\t}\n\n\t\t// This method gets called by the runtime. Use this method to add services to the container.\n\t\tpublic void ConfigureServices(IServiceCollection services) {\n\t\t\tservices.AddLogging(loggingBuilder => {\n\t\t\t\tvar loggingSection = Configuration.GetSection(\"Logging\");\n\t\t\t\tloggingBuilder.AddConfiguration(loggingSection);\n\t\t\t\tloggingBuilder.AddConsole();\n\t\t\t});\n\n\t\t\t// NReco.Data services\n\t\t\tInjectNRecoDataService(services);\n\t\t\t\n\t\t\tInjectGraphQLSchema(services);\n\t\t\tservices.AddScoped<IDatabaseMetadata, DatabaseMetadata>();\n\t\t\t\n\t\t\t// Add framework services.\n\t\t\tservices.AddMvc(options => {\n\t\t\t\toptions.EnableEndpointRouting = false;\n\t\t\t});\n\t\t}\n\n\t\tprotected void InjectGraphQLSchema(IServiceCollection services) {\n\t\t\tservices.AddScoped<Schema>((servicePrv) => {\n\t\t\t\tvar dbAdapter = servicePrv.GetRequiredService<DbDataAdapter>();\n\t\t\t\tvar metaDatabase = servicePrv.GetRequiredService<IDatabaseMetadata>();\n\t\t\t\tvar schema = new Schema { Query = new GraphQLQuery(dbAdapter, metaDatabase) };\n\t\t\t\tschema.Initialize();\n\t\t\t\treturn schema;\n\t\t\t});\n\t\t}\n\n\t\tprotected void InjectNRecoDataService(IServiceCollection services) {\n\n\t\t\tservices.AddSingleton<IDbFactory, DbFactory>((servicePrv) => {\n\t\t\t\t// db-provider specific configuration code:\n\t\t\t\treturn new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t\t};\n\t\t\t});\n\t\t\tservices.AddSingleton<IDbCommandBuilder, DbCommandBuilder>((servicePrv) => {\n\t\t\t\tvar dbCmdBuilder = new DbCommandBuilder(servicePrv.GetRequiredService<IDbFactory>());\n\t\t\t\t// initialize dataviews here:\n\t\t\t\t//dbCmdBuilder.Views[\"articles_view\"] = ConfigureArticlesView();//new DbDataView(...);\n\t\t\t\treturn dbCmdBuilder;\n\t\t\t});\n\n\t\t\tservices.AddScoped<IDbConnection>((servicePrv) => {\n\t\t\t\tvar dbFactory = servicePrv.GetRequiredService<IDbFactory>();\n\t\t\t\tvar conn = dbFactory.CreateConnection();\n\t\t\t\tconn.ConnectionString = String.Format(\"Filename={0}\", Path.Combine(ApplicationPath, dbConnectionFile));\n\t\t\t\treturn conn;\n\t\t\t});\n\n\t\t\tservices.AddScoped<DbDataAdapter>();\n\t\t}\n\n\t\t// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n\t\tpublic void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) {\n\n\t\t\tapp.UseDefaultFiles();\n\t\t\tapp.UseStaticFiles();\n\n\t\t\tapp.UseMvc();\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/web.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\n  <!--\n    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380\n  -->\n\n  <system.webServer>\n    <handlers>\n      <add name=\"aspNetCore\" path=\"*\" verb=\"*\" modules=\"AspNetCoreModule\" resourceType=\"Unspecified\"/>\n    </handlers>\n    <aspNetCore processPath=\"%LAUNCHER_PATH%\" arguments=\"%LAUNCHER_ARGS%\" stdoutLogEnabled=\"false\" stdoutLogFile=\".\\logs\\stdout\" forwardWindowsAuthToken=\"false\"/>\n  </system.webServer>\n</configuration>\n"
  },
  {
    "path": "examples/SqliteDemo.GraphQLApi/wwwroot/index.html",
    "content": "﻿<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <title>NReco.Data GraphQL Example</title>\n\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\n    <!-- bootstrap (optional) -->\n    <link href=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css\" rel=\"stylesheet\" />\n    <script type=\"text/javascript\" src=\"//code.jquery.com/jquery-2.1.4.min.js\"></script>\n    <script type=\"text/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js\"></script>\n\n</head>\n<body>\n\n    <div class=\"container\">\n        <h1>\n            NReco.Data GraphQL Example\n            <small>simple GraphQL API to SQLite database (based on table meta-data)</small>\n        </h1>\n\n        <h3>Load data by table name</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"selectRows\" rows=\"8\">\n\t\t\t\t\t$.ajax(\"api/GraphQL\", {\n\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tquery : \"{ Customers_list { CustomerID CompanyName } }\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}).success(function (res) {\n\t\t\t\t\t\t$('#selectRowsResult').text( JSON.stringify(res) );\n\t\t\t\t\t});\n                </textarea>\n                <br/>\n                <a href=\"javascript:;\" rel=\"selectRows\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"selectRowsResult\" style=\"white-space:pre-wrap; max-height:250px;\"></pre>\n            </div>\n        </div>\n\n        <h3>Load one row by using arguments</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"selectOneRow\" rows=\"5\">\n\t\t\t\t\t$.ajax(\"api/GraphQL\", {\n\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tquery: \"{ Customers(CustomerID: \\\"ALFKI\\\") { CustomerID CompanyName } }\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}).success(function (res) {\n\t\t\t\t\t\t$('#selectOneRowResult').text( JSON.stringify(res) );\n\t\t\t\t\t});\n                </textarea>\n                <br/>\n                <a href=\"javascript:;\" rel=\"selectOneRow\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"selectOneRowResult\" style=\"white-space:pre-wrap; max-height:150px;\"></pre>\n            </div>\n        </div>\n\n    </div>\n\n    <script type=\"text/javascript\">\n        $(function() {\n            $('.run').click(function () {\n                var $textarea = $('#' + $(this).attr('rel'));\n                eval($textarea.val());\n            });\n        });\n    </script>\n\n</body>\n</html>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/.bowerrc",
    "content": "{\n  \"directory\": \"wwwroot/lib\"\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/.vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \".NET Core Launch (web)\",\n            \"type\": \"coreclr\",\n            \"request\": \"launch\",\n            \"preLaunchTask\": \"build\",\n            \"program\": \"${workspaceRoot}\\\\bin\\\\Debug\\\\netcoreapp1.0\\\\SqliteDemo.MVCApplication.dll\",\n            \"args\": [],\n            \"cwd\": \"${workspaceRoot}\",\n            \"stopAtEntry\": false,\n            \"internalConsoleOptions\": \"openOnSessionStart\",\n            \"launchBrowser\": {\n                \"enabled\": true,\n                \"args\": \"${auto-detect-url}\",\n                \"windows\": {\n                    \"command\": \"cmd.exe\",\n                    \"args\": \"/C start ${auto-detect-url}\"\n                },\n                \"osx\": {\n                    \"command\": \"open\"\n                },\n                \"linux\": {\n                    \"command\": \"xdg-open\"\n                }\n            },\n            \"env\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            },\n            \"sourceFileMap\": {\n                \"/Views\": \"${workspaceRoot}/Views\"\n            }\n        },\n        {\n            \"name\": \".NET Core Attach\",\n            \"type\": \"coreclr\",\n            \"request\": \"attach\",\n            \"processId\": \"${command.pickProcess}\"\n        }\n    ]\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/.vscode/tasks.json",
    "content": "{\n    \"version\": \"0.1.0\",\n    \"command\": \"dotnet\",\n    \"isShellCommand\": true,\n    \"args\": [],\n    \"tasks\": [\n        {\n            \"taskName\": \"build\",\n            \"args\": [\n                \"${workspaceRoot}\\\\project.json\"\n            ],\n            \"isBuildCommand\": true,\n            \"problemMatcher\": \"$msCompile\"\n        }\n    ]\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Controllers/ArticleController.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\n\nusing SqliteDemo.MVCApplication.Db.Context;\nusing SqliteDemo.MVCApplication.Db.Models;\nusing SqliteDemo.MVCApplication.Db.Interfaces;\nusing SqliteDemo.MVCApplication.Db.Repositories;\n\nnamespace SqliteDemo.MVCApplication.Controllers\n{\n\tpublic class ArticleController : Controller {\n\t\tIArticleRepository db;\n\n\t\tpublic ArticleController(ArticleRepository articleRepository) {\n\t\t\tdb = articleRepository;\n\t\t}\n\n\t\tpublic IActionResult Add() {\n\t\t\treturn View(\n\t\t\t\tnew Article(){\n\t\t\t\t\tUsersList = db.GetAllAuthors().ToList<User>()\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\t[HttpPost]\n\t\tpublic IActionResult Add(Article a) {\n\t\t\tTryValidateModel(a);\n\t\t\tif (ModelState.IsValid) {\n\t\t\t\tdb.Add(a);\n\t\t\t\treturn RedirectToAction(\"List\");\n\t\t\t}\n\t\t\treturn View(a);\n\t\t}\n\n\t\tpublic IActionResult Edit(int? id) {\n\t\t\tif (id.HasValue) {\n\t\t\t\tvar article = db.FindById(id.Value);\n\t\t\t\tarticle.UsersList = db.GetAllAuthors().ToList<User>();\n\t\t\t\treturn View(\n\t\t\t\t\tarticle\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn NotFound();\n\t\t}\n\n\t\t[HttpPost]\n\t\t[ValidateAntiForgeryToken]\n\t\tpublic async Task<IActionResult> Edit(Article article) {\n\t\t\tif (ModelState.IsValid) {\n\t\t\t\tawait db.Edit(article);\n\t\t\t\treturn RedirectToAction(\"List\");\n\t\t\t} else {\n\t\t\t\treturn View(article);\n\t\t\t}\n\t\t}\n\n\t\tpublic IActionResult ArticleItem(int id = 0) {\n\t\t\tif (id != 0) {\n\t\t\t\treturn View(\n\t\t\t\t\tdb.FindById(id)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn View(new Article());\n        }\n\n\t\tpublic IActionResult Delete(int? id) {\n\t\t\tif (id.HasValue) {\n\t\t\t\tdb.Remove(id.Value);\n\t\t\t\treturn RedirectToAction(\"List\");\n\t\t\t}\n\t\t\treturn NotFound();\n\t\t}\n\n\t\tpublic IActionResult List() {\n\t\t\treturn View(db.GetArticles());\n\t\t}\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Context/DbContext.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\n\nusing SqliteDemo.MVCApplication.Db.Models;\n\nnamespace SqliteDemo.MVCApplication.Db.Context {\n    public class DbCoreContext : DbContext {\n\t\tpublic DbSet<Article> Articles {\n\t\t\tget; set;\n\t\t}\n\n\t\tpublic DbSet<User> Users {\n\t\t\tget; set;\n\t\t}\n\n\t\tpublic DbCoreContext(DbContextOptions<DbCoreContext> options):base(options) {\n\t\t}\n\n\t\tprotected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {\n\t\t\t//optionsBuilder.UseSqlite(\"Filename=./coreApp2.db\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Interfaces/IArticleRepository.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing SqliteDemo.MVCApplication.Db.Models;\nusing SqliteDemo.MVCApplication.Db.Views;\n\nnamespace SqliteDemo.MVCApplication.Db.Interfaces {\n    interface IArticleRepository {\n\t\t\tvoid Add(Article a);\n\t\t\tTask<int> Edit(Article a);\n\t\t\tvoid Remove(int id);\n\t\t\tIEnumerable<ArticleView> GetArticles();\n\t\t\tArticle FindById(int id);\n\t\t\tIEnumerable<User> GetAllAuthors();\n\t\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Models/Article.cs",
    "content": "using System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\n\nnamespace SqliteDemo.MVCApplication.Db.Models {\n\tpublic class Article {\n\t\tpublic int? Id {\n\t\t\tget; set;\n\t\t}\n\n\t\t[Required]\n\t\tpublic string Title {\n\t\t\tget; set;\n\t\t}\n\t\t[Required]\n\t\tpublic int AuthorId {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string Content {\n\t\t\tget; set;\n\t\t}\n\n\t\t[NotMapped]\n\t\tpublic List<User> UsersList {get; set; } = new List<User>();\n\t\t[NotMapped]\n\t\tpublic string AuthorName {get; set; }\n\t}\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Models/User.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing System.ComponentModel.DataAnnotations;\n\nnamespace SqliteDemo.MVCApplication.Db.Models {\n    public class User {\n\t\tpublic int Id {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string FirstName {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string SecondName {\n\t\t\tget; set;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Repositories/ArticleRepository.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\n\nusing SqliteDemo.MVCApplication.Db.Models;\nusing SqliteDemo.MVCApplication.Db.Views;\nusing SqliteDemo.MVCApplication.Db.Interfaces;\nusing SqliteDemo.MVCApplication.Db.Context;\n\nusing NReco.Data;\nusing NReco.Data.Relex;\n\nnamespace SqliteDemo.MVCApplication.Db.Repositories {\n    public class ArticleRepository : IArticleRepository {\n\n\t\tprotected DbCoreContext dbContext;\n\t\tprotected DbDataAdapter _DbNRecoAdapter;\n\n\t\tpublic ArticleRepository(IServiceProvider serviceProvider) {\n\t\t\tdbContext = serviceProvider.GetService<DbCoreContext>();\n\t\t\t_DbNRecoAdapter = serviceProvider.GetService<DbDataAdapter>();\n\t\t}\n\n\t\tpublic async void Add(Article a) {\n\t\t\t//dbContext.Articles.Add(a);\n\t\t\t//await dbContext.SaveChangesAsync();\n\t\t\tawait _DbNRecoAdapter.InsertAsync(\"Articles\", a);\n\t\t}\n\n\t\tpublic async Task<int> Edit(Article a) {\n\t\t\treturn await _DbNRecoAdapter.UpdateAsync( \n\t\t\t\tnew Query(\n\t\t\t\t\t\"Articles\", \n\t\t\t\t\t(QField)\"Id\" == (QConst)a.Id \n\t\t\t\t), \n\t\t\t\ta\n\t\t\t);\n\t\t}\n\n\t\tpublic Article FindById(int id) {\n\t\t\tvar result = _DbNRecoAdapter.Select( \n\t\t\t\tnew Query(\n\t\t\t\t\t\"Articles\", \n\t\t\t\t\t(QField)\"Id\" == (QConst)id\n\t\t\t\t)\n\t\t\t).Single<Article>(); \n\t\t\treturn result;\n\t\t}\n\n\t\tpublic IEnumerable<ArticleView> GetArticles() {\n\t\t\treturn _DbNRecoAdapter.Select( new Query(\"articles_view\") ).ToList<ArticleView>(); \n\t\t}\n\n\t\tpublic void Remove(int id) {\n\t\t\t_DbNRecoAdapter.Delete(\n\t\t\t\tnew Query(\n\t\t\t\t\t\"Articles\", \n\t\t\t\t\t(QField)\"Id\" == (QConst)id \n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tpublic IEnumerable<User> GetAllAuthors() {\n\t\t\tvar relexParser = new RelexParser();\n\t\t\tvar relexQuery = \"Users[*;Id asc]\";\n\t\t\tvar q = relexParser.Parse(relexQuery);\n\n\t\t\treturn _DbNRecoAdapter.Select( q ).ToList<User>();\n\t\t}\n\t}\n} \n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Db/Views/ArticleView.cs",
    "content": "using System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\n\nnamespace SqliteDemo.MVCApplication.Db.Views {\n\tpublic class ArticleView {\n\t\tpublic int? Id {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string Title {\n\t\t\tget; set;\n\t\t}\n\t\tpublic int AuthorId {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string Content {\n\t\t\tget; set;\n\t\t}\n\t\tpublic string AuthorFirstName {get; set; }\n\t\tpublic string AuthorLastName {get; set; }\n\t}\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Hosting;\n\nnamespace SqliteDemo.MVCApplication\n{\n    // CRUD app that uses both EF Core AND NReco.Data\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var host = new WebHostBuilder()\n                .UseKestrel()\n                .UseContentRoot(Directory.GetCurrentDirectory())\n                .UseIISIntegration()\n                .UseIIS()\n                .UseStartup<Startup>()\n                .Build();\n\n            host.Run();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Project_Readme.html",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <title>Welcome to ASP.NET Core</title>\n    <style>\n        html {\n            background: #f1f1f1;\n            height: 100%;\n        }\n\n        body {\n            background: #fff;\n            color: #505050;\n            font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;\n            margin: 1%;\n            min-height: 95.5%;\n            border: 1px solid silver;\n            position: relative;\n        }\n\n        #header {\n            padding: 0;\n        }\n\n            #header h1 {\n                font-size: 44px;\n                font-weight: normal;\n                margin: 0;\n                padding: 10px 30px 10px 30px;\n            }\n\n            #header span {\n                margin: 0;\n                padding: 0 30px;\n                display: block;\n            }\n\n            #header p {\n                font-size: 20px;\n                color: #fff;\n                background: #007acc;\n                padding: 0 30px;\n                line-height: 50px;\n                margin-top: 25px;\n\n            }\n\n                #header p a {\n                    color: #fff;\n                    text-decoration: underline;\n                    font-weight: bold;\n                    padding-right: 35px;\n                    background: no-repeat right bottom url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAMAAAAcqPc3AAAANlBMVEUAAAAAeswfitI9mthXp91us+KCvuaTx+mjz+2x1u+83PLH4vTR5/ba7Pjj8Pns9fv1+v3////wy3dWAAAAAXRSTlMAQObYZgAAAHxJREFUeNp9kVcSwCAIRMHUYoH7XzaxOxJ9P8oyQ1uIqNPwh3s2aLmIM2YtqrLcQIeQEylhuCeUOlhgve5yoBCfWmlnlgkN4H8ykbpaE7gR03AbUHiwoOxUH9Xp+ubd41p1HF3mBPrfC87BHeTdaB3ceeKL9HGpcvX9zu6+DdMWT9KQPvYAAAAASUVORK5CYII=);\n                }\n\n        #main {\n            padding: 5px 30px;\n            clear: both;\n        }\n\n        .section {\n            width: 21.7%;\n            float: left;\n            margin: 0 0 0 4%;\n        }\n\n            .section h2 {\n                font-size: 13px;\n                text-transform: uppercase;\n                margin: 0;\n                border-bottom: 1px solid silver;\n                padding-bottom: 12px;\n                margin-bottom: 8px;\n            }\n\n            .section.first {\n                margin-left: 0;\n            }\n\n                .section.first h2 {\n                    font-size: 24px;\n                    text-transform: none;\n                    margin-bottom: 25px;\n                    border: none;\n                }\n\n                .section.first li {\n                    border-top: 1px solid silver;\n                    padding: 8px 0;\n                }\n\n            .section.last {\n                margin-right: 0;\n            }\n\n        ul {\n            list-style: none;\n            padding: 0;\n            margin: 0;\n            line-height: 20px;\n        }\n\n        li {\n            padding: 4px 0;\n        }\n\n        a {\n            color: #267cb2;\n            text-decoration: none;\n        }\n\n            a:hover {\n                text-decoration: underline;\n            }\n\n        #footer {\n            clear: both;\n            padding-top: 50px;\n        }\n\n            #footer p {\n                position: absolute;\n                bottom: 10px;\n            }\n    </style>\n</head>\n<body>\n\n    <div id=\"header\">\n        <h1>Welcome to ASP.NET Core</h1>\n        <span>\n            We've made some big updates in this release, so it’s <b>important</b> that you spend\n            a few minutes to learn what’s new.\n        </span>\n        <p>You've created a new ASP.NET Core project. <a href=\"http://go.microsoft.com/fwlink/?LinkId=518016\">Learn what's new</a></p>\n    </div>\n\n    <div id=\"main\">\n        <div class=\"section first\">\n            <h2>This application consists of:</h2>\n            <ul>\n                <li>Sample pages using ASP.NET Core MVC</li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=518004\">Bower</a> for managing client-side libraries</li>\n                <li>Theming using <a href=\"http://go.microsoft.com/fwlink/?LinkID=398939\">Bootstrap</a></li>\n            </ul>\n        </div>\n        <div class=\"section\">\n            <h2>How to</h2>\n            <ul>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=398600\">Add a Controller and View</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=699562\">Add an appsetting in config and access it in app.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699315\">Manage User Secrets using Secret Manager.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699316\">Use logging to log a message.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699317\">Add packages using NuGet.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699318\">Add client packages using Bower.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699319\">Target development, staging or production environment.</a></li>\n            </ul>\n        </div>\n        <div class=\"section\">\n            <h2>Overview</h2>\n            <ul>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=518008\">Conceptual overview of what is ASP.NET Core</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=699320\">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=398602\">Working with Data</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkId=398603\">Security</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=699321\">Client side development</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=699322\">Develop on different platforms</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=699323\">Read more on the documentation site</a></li>\n            </ul>\n        </div>\n        <div class=\"section last\">\n            <h2>Run & Deploy</h2>\n            <ul>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=517851\">Run your app</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=517853\">Run tools such as EF migrations and more</a></li>\n                <li><a href=\"http://go.microsoft.com/fwlink/?LinkID=398609\">Publish to Microsoft Azure Web Apps</a></li>\n            </ul>\n        </div>\n\n        <div id=\"footer\">\n            <p>We would love to hear your <a href=\"http://go.microsoft.com/fwlink/?LinkId=518015\">feedback</a></p>\n        </div>\n    </div>\n\n</body>\n</html>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Properties/launchSettings.json",
    "content": "{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:61473/\",\n      \"sslPort\": 0\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"SqliteDemo.MVCApplication\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/SqliteDemo.MVCApplication.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Update=\"wwwroot\\**\\*\">\n      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Sqlite\" Version=\"8.0.*\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Design\" Version=\"8.0.*\">\n      <PrivateAssets>All</PrivateAssets>\n    </PackageReference>\n\t\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"8.0.*\" />\n\t\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n  </ItemGroup>\n\n  <Target Name=\"PrepublishScript\" BeforeTargets=\"PrepareForPublish\">\n    <Exec Command=\"bower install\" />\n    <Exec Command=\"dotnet bundle\" />\n  </Target>\n\n  <ItemGroup>\n    <DotNetCliToolReference Include=\"BundlerMinifier.Core\" Version=\"3.2.*\" />\n    <DotNetCliToolReference Include=\"Microsoft.EntityFrameworkCore.Tools.DotNet\" Version=\"2.0.3\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Startup.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Linq;\nusing System.IO;\n\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nusing Microsoft.EntityFrameworkCore;\n\nusing SqliteDemo.MVCApplication.Db.Context;\nusing SqliteDemo.MVCApplication.Db.Models;\nusing SqliteDemo.MVCApplication.Db.Interfaces;\nusing SqliteDemo.MVCApplication.Db.Repositories;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.MVCApplication\n{\n\t// CRUD app that uses both EF Core AND NReco.Data\n    public class Startup\n    {\n        const string dbConnectionFile = \"mvcapp_database.db\";\n        protected string ApplicationPath;\n\n        public Startup(IHostingEnvironment env)\n        {\n            var builder = new ConfigurationBuilder()\n                .SetBasePath(env.ContentRootPath)\n                .AddJsonFile(\"appsettings.json\", optional: true, reloadOnChange: true)\n                .AddJsonFile($\"appsettings.{env.EnvironmentName}.json\", optional: true)\n                .AddEnvironmentVariables();\n\n            ApplicationPath = env.ContentRootPath;\n            Configuration = builder.Build();\n        }\n\n        public IConfigurationRoot Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n\t\t\tservices.AddLogging(loggingBuilder => {\n\t\t\t\tvar loggingSection = Configuration.GetSection(\"Logging\");\n\t\t\t\tloggingBuilder.AddConfiguration(loggingSection);\n\t\t\t\tloggingBuilder.AddConsole();\n\t\t\t});\n\n\t\t\tvar dbConnectionString = String.Format(\"Filename={0}\", Path.Combine(ApplicationPath, dbConnectionFile));\n\t\t\t// Add EF framework services.\n\t\t\tservices.AddDbContext<DbCoreContext>(\n                options => options.UseSqlite(\n                   dbConnectionString\n                )\n            );\n\t\t\t// let's inject NReco.Data services (based on EF DBConnection)\n            InjectNRecoDataService(services);\n\t\t\tservices.AddScoped<ArticleRepository>();\n\n            // Add framework services.\n            services.AddMvc(options => {\n\t\t\t\toptions.EnableEndpointRouting = false;\n\t\t\t});\n\t\t}\n\n        protected void InjectNRecoDataService(IServiceCollection services) {\n\n            services.AddSingleton<IDbFactory,DbFactory>( (servicePrv) => {\n\t\t\t\t// db-provider specific configuration code:\n\t\t\t\treturn new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t\t};\n\t\t\t});\n\t\t\tservices.AddSingleton<IDbCommandBuilder,DbCommandBuilder>( (servicePrv) => {\n\t\t\t\tvar dbCmdBuilder = new DbCommandBuilder(servicePrv.GetRequiredService<IDbFactory>() );\n\t\t\t\t// initialize dataviews here:\n\t\t\t\tdbCmdBuilder.Views[\"articles_view\"] = ConfigureArticlesView();//new DbDataView(...);\n\t\t\t\treturn dbCmdBuilder;\n\t\t\t} );\n\n            services.AddScoped<IDbConnection>( (servicePrv) => {\n                var dbCoreContext = servicePrv.GetRequiredService<DbCoreContext>();\n                var conn = dbCoreContext.Database.GetDbConnection();\n                return conn;\n            } );\n\n\t\t\tservices.AddScoped<DbDataAdapter>();\n        }\n\n\t\tprotected DbDataView ConfigureArticlesView() {\n\t\t\treturn new DbDataView(\n\t\t\t\t@\"SELECT @columns FROM articles a\n\t\t\t\t\tLEFT JOIN Users u ON (u.Id=a.AuthorId)\n\t\t\t\t@where[ WHERE {0}] @orderby[ ORDER BY {0}]\"\n\t\t\t) {\n\t\t\t\tFieldMapping = new Dictionary<string,string>() {\n\t\t\t\t\t{\"Id\", \"a.Id\"},\n\t\t\t\t\t{\"*\", \"a.*, u.FirstName as AuthorFirstName, u.SecondName as AuthorLastName\"}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)\n        {\n            app.UseDeveloperExceptionPage();\n\n            app.UseStaticFiles();\n\n            app.UseMvc(routes =>\n            {\n\t\t\t\troutes.MapRoute(\n\t\t\t\t\tname: \"articlelist\",\n\t\t\t\t\ttemplate: \"articles\",\n\t\t\t\t\tdefaults: new {\n\t\t\t\t\t\tcontroller = \"Article\",\n\t\t\t\t\t\taction = \"List\"\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\troutes.MapRoute(\n\t\t\t\t\tname: \"addnewarticle\",\n\t\t\t\t\ttemplate: \"article/add/{*id}\",\n\t\t\t\t\tdefaults: new {\n\t\t\t\t\t\tcontroller = \"Article\",\n\t\t\t\t\t\taction = \"Add\"\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\troutes.MapRoute(\n\t\t\t\t\tname: \"deletearticle\",\n\t\t\t\t\ttemplate: \"article/delete/{*id}\",\n\t\t\t\t\tdefaults: new {\n\t\t\t\t\t\tcontroller = \"Article\",\n\t\t\t\t\t\taction = \"Delete\"\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\troutes.MapRoute(\n\t\t\t\t\tname: \"articleedit\",\n\t\t\t\t\ttemplate: \"article/edit/{*id}\",\n\t\t\t\t\tdefaults: new {\n\t\t\t\t\t\tcontroller = \"Article\",\n\t\t\t\t\t\taction = \"Edit\"\n\t\t\t\t\t}\n\t\t\t\t);\n\n                routes.MapRoute(\n                    name: \"default\",\n                    template: \"{controller=Article}/{action=List}/{id?}\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Article/Add.cshtml",
    "content": "@model SqliteDemo.MVCApplication.Db.Models.Article\n@{\n\tViewBag.Title = \"Add Article\";\n}\n\n\n\n\n\n\n<form class=\"form-horizontal\" asp-action=\"add\" asp-controller=\"Article\">\n\t<div class=\"form-horizontal\">\n\t\t<h4>Add Article</h4>\n\t\t<hr />\n\t\t<div asp-validation-summary=\"ModelOnly\" class=\"text-danger\"></div>\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"Title\" class=\"col-md-2 control-label\"></label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<input asp-for=\"Title\" class=\"form-control\" />\n\t\t\t\t<span asp-validation-for=\"Title\" class=\"text-danger\"></span>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"Content\" class=\"col-md-2 control-label\"></label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<input asp-for=\"Content\" class=\"form-control\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"AuthorId\" class=\"col-md-2 control-label\">Author</label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<select class=\"form-control\" asp-for=\"AuthorId\" asp-items=\"@(new SelectList(Model.UsersList,\"Id\",\"FirstName\"))\">\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<div class=\"col-md-offset-2 col-md-10\">\n\t\t\t\t<input type=\"submit\" value=\"Add\" class=\"btn btn-default\" />\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n</form>\n\n@section scripts{\n\t<environment names=\"Development\">\n\t\t<script src=\"~/lib/jquery-validation/dist/jquery.validate.js\"></script>\n\t\t<script src=\"~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js\"></script>\n\t</environment>\n\t<environment names=\"Staging,Production\">\n\t\t<script src=\"https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js\"\n\t\t\t\tasp-fallback-src=\"~/lib/jquery-validation/dist/jquery.validate.min.js\"\n\t\t\t\tasp-fallback-test=\"window.jQuery && window.jQuery.validator\">\n\t\t</script>\n\t\t<script src=\"https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js\"\n\t\t\t\tasp-fallback-src=\"~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js\"\n\t\t\t\tasp-fallback-test=\"window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive\">\n\t\t</script>\n\t</environment>\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Article/ArticleItem.cshtml",
    "content": "@model SqliteDemo.MVCApplication.Db.Models.Article\n\n@{\n    ViewData[\"Title\"] = \"Article\";\n}\n<h2>@ViewData[\"Title\"].</h2>\n<h3>@ViewData[\"Message\"]</h3>\n\n@Model.Id\n\n<p>Use this area to provide article information.</p>\n\n@Model.Title"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Article/Edit.cshtml",
    "content": "@model SqliteDemo.MVCApplication.Db.Models.Article\n@{\n\tViewBag.Title = \"Edit Article\";\n}\n\n<form class=\"form-horizontal\" asp-action=\"edit\" asp-controller=\"article\" asp-route-id=\"@Model.Id\">\n\n\t<div class=\"form-horizontal\">\n\t\t<h4>Edit Article</h4>\n\t\t<hr />\n\t\t<div asp-validation-summary=\"ModelOnly\" class=\"text-danger\"></div>\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"Title\" class=\"col-md-2 control-label\"></label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<input asp-for=\"Title\" class=\"form-control\" />\n\t\t\t\t<span asp-validation-for=\"Title\" class=\"text-danger\"></span>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"Content\" class=\"col-md-2 control-label\"></label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<input asp-for=\"Content\" class=\"form-control\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<label asp-for=\"AuthorId\" class=\"col-md-2 control-label\">Author</label>\n\t\t\t<div class=\"col-md-10\">\n\t\t\t\t<select class=\"form-control\" asp-for=\"AuthorId\" asp-items=\"@(new SelectList(Model.UsersList,\"Id\",\"FirstName\"))\">\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"form-group\">\n\t\t\t<div class=\"col-md-offset-2 col-md-10\">\n\t\t\t\t<input type=\"submit\" value=\"Submit\" class=\"btn btn-default\" />\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n</form>\n\n<div>\n    <a class=\"btn btn-default\" asp-action=\"List\">Back to List</a>\n</div>\n\n@section scripts{\n\t<environment names=\"Development\">\n\t\t<script src=\"~/lib/jquery-validation/dist/jquery.validate.js\"></script>\n\t\t<script src=\"~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js\"></script>\n\t</environment>\n\t<environment names=\"Staging,Production\">\n\t\t<script src=\"https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js\"\n\t\t\t\tasp-fallback-src=\"~/lib/jquery-validation/dist/jquery.validate.min.js\"\n\t\t\t\tasp-fallback-test=\"window.jQuery && window.jQuery.validator\">\n\t\t</script>\n\t\t<script src=\"https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js\"\n\t\t\t\tasp-fallback-src=\"~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js\"\n\t\t\t\tasp-fallback-test=\"window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive\">\n\t\t</script>\n\t</environment>\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Article/List.cshtml",
    "content": "@model IEnumerable<SqliteDemo.MVCApplication.Db.Views.ArticleView>\n\n@{\n    ViewData[\"Title\"] = \"Articles\";\n}\n<h2>@ViewData[\"Title\"].</h2>\n<h3>@ViewData[\"Message\"]</h3>\n\n<p>\n    <a asp-action=\"Add\">Add New</a>\n</p>\n<table class=\"table\">\n    <thead>\n        <tr>\n\t\t\t<th>\n                @Html.DisplayNameFor(model => model.Id)\n            </th>\n            <th>\n                @Html.DisplayNameFor(model => model.Title)\n            </th>\n            <th>\n                Author\n            </th>\n            <th>\n                @Html.DisplayNameFor(model => model.Content)\n            </th>\n            <th></th>\n        </tr>\n    </thead>\n    <tbody>\n\t@foreach (var item in Model) {\n        <tr>\n            <td>\n                @Html.DisplayFor(modelItem => item.Id)\n            </td>\n            <td>\n                @Html.DisplayFor(modelItem => item.Title)\n            </td>\n            <td>\n                @Html.DisplayFor(modelItem => item.AuthorFirstName)\n                @Html.DisplayFor(modelItem => item.AuthorLastName)\n            </td>\n            <td>\n                @Html.DisplayFor(modelItem => item.Content)\n            </td>\n            @*<snippet_1>*@\n            <td>\n                <a asp-action=\"Edit\" asp-route-id=\"@item.Id\">Edit</a>\n            </td>\n            <td>\n                <a asp-action=\"Delete\" asp-route-id=\"@item.Id\">Delete</a>\n            </td>\n            @*</snippet_1>*@\n        </tr>\n\t}\n    </tbody>\n</table>\n\n<script type=\"text/javascript\">\n\tjQuery(document).ready(function () {\n\n\t});\n</script>"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Shared/Error.cshtml",
    "content": "﻿@{\n    ViewData[\"Title\"] = \"Error\";\n}\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred while processing your request.</h2>\n\n<h3>Development Mode</h3>\n<p>\n    Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.\n</p>\n<p>\n    <strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.\n</p>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/Shared/_Layout.cshtml",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>@ViewData[\"Title\"] - MVC NReco.Data Example</title>\n\n    <environment names=\"Development\">\n\t\t<script src=\"~/lib/jquery/dist/jquery.js\"></script>\n\n        <link rel=\"stylesheet\" href=\"~/lib/bootstrap/dist/css/bootstrap.css\" />\n        <link rel=\"stylesheet\" href=\"~/css/site.css\" />\n    </environment>\n    <environment names=\"Staging,Production\">\n\t\t<script src=\"~/lib/jquery/dist/jquery.js\"></script>\n\n        <link rel=\"stylesheet\" href=\"https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css\"\n              asp-fallback-href=\"~/lib/bootstrap/dist/css/bootstrap.min.css\"\n              asp-fallback-test-class=\"sr-only\" asp-fallback-test-property=\"position\" asp-fallback-test-value=\"absolute\" />\n        <link rel=\"stylesheet\" href=\"~/css/site.min.css\" asp-append-version=\"true\" />\n    </environment>\n</head>\n<body>\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n        <div class=\"container\">\n            <div class=\"navbar-header\">\n                <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\".navbar-collapse\">\n                    <span class=\"sr-only\">Toggle navigation</span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                </button>\n                <a asp-area=\"\" asp-controller=\"Home\" asp-action=\"Index\" class=\"navbar-brand\">MVC Application</a>\n            </div>\n            <div class=\"navbar-collapse collapse\">\n                <ul class=\"nav navbar-nav\">\n                    <li><a asp-area=\"\" asp-controller=\"Article\" asp-action=\"List\">Articles</a></li>\n                </ul>\n            </div>\n        </div>\n    </div>\n    <div class=\"container body-content\">\n        @RenderBody()\n        <hr />\n        <footer>\n            <p>&copy; @DateTime.Now.Year</p>\n        </footer>\n    </div>\n\n    <environment names=\"Development\">\n        <script src=\"~/lib/jquery/dist/jquery.js\"></script>\n        <script src=\"~/lib/bootstrap/dist/js/bootstrap.js\"></script>\n        <script src=\"~/js/site.js\" asp-append-version=\"true\"></script>\n    </environment>\n    <environment names=\"Staging,Production\">\n        <script src=\"https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js\"\n                asp-fallback-src=\"~/lib/jquery/dist/jquery.min.js\"\n                asp-fallback-test=\"window.jQuery\">\n        </script>\n        <script src=\"https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js\"\n                asp-fallback-src=\"~/lib/bootstrap/dist/js/bootstrap.min.js\"\n                asp-fallback-test=\"window.jQuery && window.jQuery.fn && window.jQuery.fn.modal\">\n        </script>\n        <script src=\"~/js/site.min.js\" asp-append-version=\"true\"></script>\n    </environment>\n\n    @RenderSection(\"scripts\", required: false)\n</body>\n</html>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/_ViewImports.cshtml",
    "content": "﻿@using SqliteDemo.MVCApplication\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/Views/_ViewStart.cshtml",
    "content": "﻿@{\n    Layout = \"_Layout\";\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/bower.json",
    "content": "{\n  \"name\": \"asp.net\",\n  \"private\": true,\n  \"dependencies\": {\n    \"bootstrap\": \"3.3.6\",\n    \"jquery\": \"2.2.0\",\n    \"jquery-validation\": \"1.14.0\",\n    \"jquery-validation-unobtrusive\": \"3.2.6\"\n  }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/bundleconfig.json",
    "content": "﻿// Configure bundling and minification for the project.\n// More info at https://go.microsoft.com/fwlink/?LinkId=808241\n[\n  {\n    \"outputFileName\": \"wwwroot/css/site.min.css\",\n    // An array of relative input file paths. Globbing patterns supported\n    \"inputFiles\": [\n      \"wwwroot/css/site.css\"\n    ]\n  },\n  {\n    \"outputFileName\": \"wwwroot/js/site.min.js\",\n    \"inputFiles\": [\n      \"wwwroot/js/site.js\"\n    ],\n    // Optionally specify minification options\n    \"minify\": {\n      \"enabled\": true,\n      \"renameLocals\": true\n    },\n    // Optinally generate .map file\n    \"sourceMap\": false\n  }\n]\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/web.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\n  <!--\n    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380\n  -->\n\n  <system.webServer>\n    <handlers>\n      <add name=\"aspNetCore\" path=\"*\" verb=\"*\" modules=\"AspNetCoreModule\" resourceType=\"Unspecified\"/>\n    </handlers>\n    <aspNetCore processPath=\"%LAUNCHER_PATH%\" arguments=\"%LAUNCHER_ARGS%\" stdoutLogEnabled=\"false\" stdoutLogFile=\".\\logs\\stdout\" forwardWindowsAuthToken=\"false\"/>\n  </system.webServer>\n</configuration>\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/_references.js",
    "content": "﻿/// <autosync enabled=\"true\" />\n/// <reference path=\"js/site.js\" />\n/// <reference path=\"lib/bootstrap/dist/js/bootstrap.js\" />\n/// <reference path=\"lib/jquery/dist/jquery.js\" />\n/// <reference path=\"lib/jquery-validation/dist/jquery.validate.js\" />\n/// <reference path=\"lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js\" />\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/css/site.css",
    "content": "﻿body {\n    padding-top: 50px;\n    padding-bottom: 20px;\n}\n\n/* Wrapping element */\n/* Set some basic padding to keep content from hitting the edges */\n.body-content {\n    padding-left: 15px;\n    padding-right: 15px;\n}\n\n/* Set widths on the form inputs since otherwise they're 100% wide */\ninput,\nselect,\ntextarea {\n    max-width: 280px;\n}\n\n/* Carousel */\n.carousel-caption p {\n    font-size: 20px;\n    line-height: 1.4;\n}\n\n/* Make .svg files in the carousel display properly in older browsers */\n.carousel-inner .item img[src$=\".svg\"]\n{\n    width: 100%;\n}\n\n/* Hide/rearrange for smaller screens */\n@media screen and (max-width: 767px) {\n  /* Hide captions */\n  .carousel-caption {\n    display: none\n  }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/js/site.js",
    "content": "﻿// Write your Javascript code.\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/.bower.json",
    "content": "{\n  \"name\": \"bootstrap\",\n  \"description\": \"The most popular front-end framework for developing responsive, mobile first projects on the web.\",\n  \"keywords\": [\n    \"css\",\n    \"js\",\n    \"less\",\n    \"mobile-first\",\n    \"responsive\",\n    \"front-end\",\n    \"framework\",\n    \"web\"\n  ],\n  \"homepage\": \"http://getbootstrap.com\",\n  \"license\": \"MIT\",\n  \"moduleType\": \"globals\",\n  \"main\": [\n    \"less/bootstrap.less\",\n    \"dist/js/bootstrap.js\"\n  ],\n  \"ignore\": [\n    \"/.*\",\n    \"_config.yml\",\n    \"CNAME\",\n    \"composer.json\",\n    \"CONTRIBUTING.md\",\n    \"docs\",\n    \"js/tests\",\n    \"test-infra\"\n  ],\n  \"dependencies\": {\n    \"jquery\": \"1.9.1 - 2\"\n  },\n  \"version\": \"3.3.6\",\n  \"_release\": \"3.3.6\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"v3.3.6\",\n    \"commit\": \"81df608a40bf0629a1dc08e584849bb1e43e0b7a\"\n  },\n  \"_source\": \"git://github.com/twbs/bootstrap.git\",\n  \"_target\": \"3.3.6\",\n  \"_originalSource\": \"bootstrap\"\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2011-2015 Twitter, Inc\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n  text-shadow: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n}\n.btn-default {\n  text-shadow: 0 1px 0 #fff;\n  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));\n  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n  background-color: #265a88;\n  background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #265a88;\n  border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #265a88;\n  background-image: none;\n}\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n  background-color: #419641;\n  background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n  background-color: #419641;\n  border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #419641;\n  background-image: none;\n}\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n  background-color: #2aabd2;\n  background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n  background-color: #2aabd2;\n  border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #2aabd2;\n  background-image: none;\n}\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n  background-color: #eb9316;\n  background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #eb9316;\n  border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #eb9316;\n  background-image: none;\n}\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n  background-color: #c12e2a;\n  background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #c12e2a;\n  border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #c12e2a;\n  background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-color: #e8e8e8;\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-color: #2e6da4;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));\n  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));\n  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);\n}\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));\n  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));\n  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n    background-repeat: repeat-x;\n  }\n}\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n}\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #b2dba1;\n}\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #9acfea;\n}\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #f5e79e;\n}\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dca7a7;\n}\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #286090;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n  text-shadow: none;\n}\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n}\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dcdcdc;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  margin: .67em 0;\n  font-size: 2em;\n}\nmark {\n  color: #000;\n  background: #ff0;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\nsup {\n  top: -.5em;\n}\nsub {\n  bottom: -.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  height: 0;\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  margin: 0;\n  font: inherit;\n  color: inherit;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  padding: .35em .625em .75em;\n  margin: 0 2px;\n  border: 1px solid #c0c0c0;\n}\nlegend {\n  padding: 0;\n  border: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    -webkit-box-shadow: none !important;\n            box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), 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');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\002a\";\n}\n.glyphicon-plus:before {\n  content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333;\n  background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #337ab7;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #23527c;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n       -o-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  padding: .2em;\n  background-color: #fcf8e3;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777;\n}\n.text-primary {\n  color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #286090;\n}\n.text-success {\n  color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #2b542c;\n}\n.text-info {\n  color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #245269;\n}\n.text-warning {\n  color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #66512c;\n}\n.text-danger {\n  color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #843534;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #286090;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  margin-left: -5px;\n  list-style: none;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-right: 5px;\n  padding-left: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  text-align: right;\n  border-right: 5px solid #eee;\n  border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #333;\n  word-break: break-all;\n  word-wrap: break-word;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n.row {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.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 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.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 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .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 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 992px) {\n  .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 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 1200px) {\n  .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 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  display: table-column;\n  float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  display: table-cell;\n  float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n.table-responsive {\n  min-height: .01%;\n  overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n  color: #999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999;\n}\n.form-control::-ms-expand {\n  background-color: transparent;\n  border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-top: 4px \\9;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  vertical-align: middle;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  min-height: 34px;\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #a94442;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 7px;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    padding-top: 7px;\n    margin-bottom: 0;\n    text-align: right;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 11px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  padding: 6px 12px;\n  margin-bottom: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  -ms-touch-action: manipulation;\n      touch-action: manipulation;\n  cursor: pointer;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  opacity: .65;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n.btn-primary {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #fff;\n  background-color: #286090;\n  border-color: #122b40;\n}\n.btn-primary:hover {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #fff;\n  background-color: #204d74;\n  border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #255625;\n}\n.btn-success:hover {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #fff;\n  background-color: #398439;\n  border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #1b6d85;\n}\n.btn-info:hover {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #fff;\n  background-color: #269abc;\n  border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #985f0d;\n}\n.btn-warning:hover {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #fff;\n  background-color: #d58512;\n  border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #761c19;\n}\n.btn-danger:hover {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #fff;\n  background-color: #ac2925;\n  border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n.btn-link {\n  font-weight: normal;\n  color: #337ab7;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #23527c;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity .15s linear;\n       -o-transition: opacity .15s linear;\n          transition: opacity .15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-timing-function: ease;\n       -o-transition-timing-function: ease;\n          transition-timing-function: ease;\n  -webkit-transition-duration: .35s;\n       -o-transition-duration: .35s;\n          transition-duration: .35s;\n  -webkit-transition-property: height, visibility;\n       -o-transition-property: height, visibility;\n          transition-property: height, visibility;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-top: 4px solid \\9;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #337ab7;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  content: \"\";\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  display: table-cell;\n  float: none;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group .form-control:focus {\n  z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555;\n  text-align: center;\n  background-color: #eee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.nav > li.disabled > a {\n  color: #777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777;\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eee;\n  border-color: #337ab7;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555;\n  cursor: default;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #337ab7;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  padding-right: 15px;\n  padding-left: 15px;\n  overflow-x: visible;\n  -webkit-overflow-scrolling: touch;\n  border-top: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  height: 50px;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-right: 15px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.navbar-form {\n  padding: 10px 15px;\n  margin-top: 8px;\n  margin-right: -15px;\n  margin-bottom: 8px;\n  margin-left: -15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-right: 0;\n    margin-left: 0;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-right: 15px;\n    margin-left: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-default .btn-link {\n  color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #ccc;\n}\n.navbar-inverse {\n  background-color: #222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  padding: 0 5px;\n  color: #ccc;\n  content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n  color: #777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  margin-left: -1px;\n  line-height: 1.42857143;\n  color: #337ab7;\n  text-decoration: none;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 2;\n  color: #23527c;\n  background-color: #eee;\n  border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 3;\n  color: #fff;\n  cursor: default;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n  border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-top-left-radius: 6px;\n  border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-top-right-radius: 6px;\n  border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #286090;\n}\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #449d44;\n}\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  background-color: #777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  padding-right: 15px;\n  padding-left: 15px;\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-right: 60px;\n    padding-left: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: border .2s ease-in-out;\n       -o-transition: border .2s ease-in-out;\n          transition: border .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-right: auto;\n  margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #337ab7;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n.alert-info {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n.alert-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n.alert-danger {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #337ab7;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n  -webkit-transition: width .6s ease;\n       -o-transition: width .6s ease;\n          transition: width .6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-object.img-thumbnail {\n  max-width: none;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  padding-left: 0;\n  margin-bottom: 20px;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  color: #555;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #eee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #c7ddef;\n}\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  margin-bottom: 0;\n  border: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ddd;\n}\n.panel-primary {\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #337ab7;\n}\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n  color: #dff0d8;\n  background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n  color: #fcf8e3;\n  background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #faebcc;\n}\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f2dede;\n  background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  filter: alpha(opacity=20);\n  opacity: .2;\n}\n.close:hover,\n.close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\nbutton.close {\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  overflow: hidden;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transition: -webkit-transform .3s ease-out;\n       -o-transition:      -o-transform .3s ease-out;\n          transition:         transform .3s ease-out;\n  -webkit-transform: translate(0, -25%);\n      -ms-transform: translate(0, -25%);\n       -o-transform: translate(0, -25%);\n          transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n      -ms-transform: translate(0, 0);\n       -o-transform: translate(0, 0);\n          transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  outline: 0;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.modal-backdrop.in {\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  filter: alpha(opacity=0);\n  opacity: 0;\n\n  line-break: auto;\n}\n.tooltip.in {\n  filter: alpha(opacity=90);\n  opacity: .9;\n}\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  background-color: #000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  right: 5px;\n  bottom: 0;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n\n  line-break: auto;\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  content: \"\";\n  border-width: 10px;\n}\n.popover.top > .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, .25);\n  border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-color: #fff;\n  border-bottom-width: 0;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, .25);\n  border-left-width: 0;\n}\n.popover.right > .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  content: \" \";\n  border-right-color: #fff;\n  border-left-width: 0;\n}\n.popover.bottom > .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  content: \" \";\n  border-right-width: 0;\n  border-left-color: #fff;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: .6s ease-in-out left;\n       -o-transition: .6s ease-in-out left;\n          transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform .6s ease-in-out;\n         -o-transition:      -o-transform .6s ease-in-out;\n            transition:         transform .6s ease-in-out;\n\n    -webkit-backface-visibility: hidden;\n            backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n            perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    left: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n            transform: translate3d(100%, 0, 0);\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    left: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n            transform: translate3d(-100%, 0, 0);\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    left: 0;\n    -webkit-transform: translate3d(0, 0, 0);\n            transform: translate3d(0, 0, 0);\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 15%;\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  background-color: rgba(0, 0, 0, 0);\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control.right {\n  right: 0;\n  left: auto;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #fff;\n  text-decoration: none;\n  filter: alpha(opacity=90);\n  outline: 0;\n  opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n  margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  font-family: serif;\n  line-height: 1;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  padding-left: 0;\n  margin-left: -30%;\n  text-align: center;\n  list-style: none;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n  border: 1px solid #fff;\n  border-radius: 10px;\n}\n.carousel-indicators .active {\n  width: 12px;\n  height: 12px;\n  margin: 0;\n  background-color: #fff;\n}\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -10px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -10px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -10px;\n  }\n  .carousel-caption {\n    right: 20%;\n    left: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-right: auto;\n  margin-left: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.js",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under the MIT license\n */\n\nif (typeof jQuery === 'undefined') {\n  throw new Error('Bootstrap\\'s JavaScript requires jQuery')\n}\n\n+function ($) {\n  'use strict';\n  var version = $.fn.jquery.split(' ')[0].split('.')\n  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) {\n    throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')\n  }\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.6\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n  // ============================================================\n\n  function transitionEnd() {\n    var el = document.createElement('bootstrap')\n\n    var transEndEventNames = {\n      WebkitTransition : 'webkitTransitionEnd',\n      MozTransition    : 'transitionend',\n      OTransition      : 'oTransitionEnd otransitionend',\n      transition       : 'transitionend'\n    }\n\n    for (var name in transEndEventNames) {\n      if (el.style[name] !== undefined) {\n        return { end: transEndEventNames[name] }\n      }\n    }\n\n    return false // explicit for ie8 (  ._.)\n  }\n\n  // http://blog.alexmaccaw.com/css-transitions\n  $.fn.emulateTransitionEnd = function (duration) {\n    var called = false\n    var $el = this\n    $(this).one('bsTransitionEnd', function () { called = true })\n    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n    setTimeout(callback, duration)\n    return this\n  }\n\n  $(function () {\n    $.support.transition = transitionEnd()\n\n    if (!$.support.transition) return\n\n    $.event.special.bsTransitionEnd = {\n      bindType: $.support.transition.end,\n      delegateType: $.support.transition.end,\n      handle: function (e) {\n        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n      }\n    }\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: alert.js v3.3.6\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // ALERT CLASS DEFINITION\n  // ======================\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n  var Alert   = function (el) {\n    $(el).on('click', dismiss, this.close)\n  }\n\n  Alert.VERSION = '3.3.6'\n\n  Alert.TRANSITION_DURATION = 150\n\n  Alert.prototype.close = function (e) {\n    var $this    = $(this)\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = $(selector)\n\n    if (e) e.preventDefault()\n\n    if (!$parent.length) {\n      $parent = $this.closest('.alert')\n    }\n\n    $parent.trigger(e = $.Event('close.bs.alert'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      // detach from parent, fire event then clean up data\n      $parent.detach().trigger('closed.bs.alert').remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent\n        .one('bsTransitionEnd', removeElement)\n        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n      removeElement()\n  }\n\n\n  // ALERT PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.alert')\n\n      if (!data) $this.data('bs.alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.alert\n\n  $.fn.alert             = Plugin\n  $.fn.alert.Constructor = Alert\n\n\n  // ALERT NO CONFLICT\n  // =================\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n  // ALERT DATA-API\n  // ==============\n\n  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: button.js v3.3.6\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // BUTTON PUBLIC CLASS DEFINITION\n  // ==============================\n\n  var Button = function (element, options) {\n    this.$element  = $(element)\n    this.options   = $.extend({}, Button.DEFAULTS, options)\n    this.isLoading = false\n  }\n\n  Button.VERSION  = '3.3.6'\n\n  Button.DEFAULTS = {\n    loadingText: 'loading...'\n  }\n\n  Button.prototype.setState = function (state) {\n    var d    = 'disabled'\n    var $el  = this.$element\n    var val  = $el.is('input') ? 'val' : 'html'\n    var data = $el.data()\n\n    state += 'Text'\n\n    if (data.resetText == null) $el.data('resetText', $el[val]())\n\n    // push to event loop to allow forms to submit\n    setTimeout($.proxy(function () {\n      $el[val](data[state] == null ? this.options[state] : data[state])\n\n      if (state == 'loadingText') {\n        this.isLoading = true\n        $el.addClass(d).attr(d, d)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d)\n      }\n    }, this), 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var changed = true\n    var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n    if ($parent.length) {\n      var $input = this.$element.find('input')\n      if ($input.prop('type') == 'radio') {\n        if ($input.prop('checked')) changed = false\n        $parent.find('.active').removeClass('active')\n        this.$element.addClass('active')\n      } else if ($input.prop('type') == 'checkbox') {\n        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false\n        this.$element.toggleClass('active')\n      }\n      $input.prop('checked', this.$element.hasClass('active'))\n      if (changed) $input.trigger('change')\n    } else {\n      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n      this.$element.toggleClass('active')\n    }\n  }\n\n\n  // BUTTON PLUGIN DEFINITION\n  // ========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.button')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  var old = $.fn.button\n\n  $.fn.button             = Plugin\n  $.fn.button.Constructor = Button\n\n\n  // BUTTON NO CONFLICT\n  // ==================\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n  // BUTTON DATA-API\n  // ===============\n\n  $(document)\n    .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      Plugin.call($btn, 'toggle')\n      if (!($(e.target).is('input[type=\"radio\"]') || $(e.target).is('input[type=\"checkbox\"]'))) e.preventDefault()\n    })\n    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n    })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: carousel.js v3.3.6\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CAROUSEL CLASS DEFINITION\n  // =========================\n\n  var Carousel = function (element, options) {\n    this.$element    = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options     = options\n    this.paused      = null\n    this.sliding     = null\n    this.interval    = null\n    this.$active     = null\n    this.$items      = null\n\n    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n  }\n\n  Carousel.VERSION  = '3.3.6'\n\n  Carousel.TRANSITION_DURATION = 600\n\n  Carousel.DEFAULTS = {\n    interval: 5000,\n    pause: 'hover',\n    wrap: true,\n    keyboard: true\n  }\n\n  Carousel.prototype.keydown = function (e) {\n    if (/input|textarea/i.test(e.target.tagName)) return\n    switch (e.which) {\n      case 37: this.prev(); break\n      case 39: this.next(); break\n      default: return\n    }\n\n    e.preventDefault()\n  }\n\n  Carousel.prototype.cycle = function (e) {\n    e || (this.paused = false)\n\n    this.interval && clearInterval(this.interval)\n\n    this.options.interval\n      && !this.paused\n      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n    return this\n  }\n\n  Carousel.prototype.getItemIndex = function (item) {\n    this.$items = item.parent().children('.item')\n    return this.$items.index(item || this.$active)\n  }\n\n  Carousel.prototype.getItemForDirection = function (direction, active) {\n    var activeIndex = this.getItemIndex(active)\n    var willWrap = (direction == 'prev' && activeIndex === 0)\n                || (direction == 'next' && activeIndex == (this.$items.length - 1))\n    if (willWrap && !this.options.wrap) return active\n    var delta = direction == 'prev' ? -1 : 1\n    var itemIndex = (activeIndex + delta) % this.$items.length\n    return this.$items.eq(itemIndex)\n  }\n\n  Carousel.prototype.to = function (pos) {\n    var that        = this\n    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n    if (pos > (this.$items.length - 1) || pos < 0) return\n\n    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n    if (activeIndex == pos) return this.pause().cycle()\n\n    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n  }\n\n  Carousel.prototype.pause = function (e) {\n    e || (this.paused = true)\n\n    if (this.$element.find('.next, .prev').length && $.support.transition) {\n      this.$element.trigger($.support.transition.end)\n      this.cycle(true)\n    }\n\n    this.interval = clearInterval(this.interval)\n\n    return this\n  }\n\n  Carousel.prototype.next = function () {\n    if (this.sliding) return\n    return this.slide('next')\n  }\n\n  Carousel.prototype.prev = function () {\n    if (this.sliding) return\n    return this.slide('prev')\n  }\n\n  Carousel.prototype.slide = function (type, next) {\n    var $active   = this.$element.find('.item.active')\n    var $next     = next || this.getItemForDirection(type, $active)\n    var isCycling = this.interval\n    var direction = type == 'next' ? 'left' : 'right'\n    var that      = this\n\n    if ($next.hasClass('active')) return (this.sliding = false)\n\n    var relatedTarget = $next[0]\n    var slideEvent = $.Event('slide.bs.carousel', {\n      relatedTarget: relatedTarget,\n      direction: direction\n    })\n    this.$element.trigger(slideEvent)\n    if (slideEvent.isDefaultPrevented()) return\n\n    this.sliding = true\n\n    isCycling && this.pause()\n\n    if (this.$indicators.length) {\n      this.$indicators.find('.active').removeClass('active')\n      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n      $nextIndicator && $nextIndicator.addClass('active')\n    }\n\n    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n    if ($.support.transition && this.$element.hasClass('slide')) {\n      $next.addClass(type)\n      $next[0].offsetWidth // force reflow\n      $active.addClass(direction)\n      $next.addClass(direction)\n      $active\n        .one('bsTransitionEnd', function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () {\n            that.$element.trigger(slidEvent)\n          }, 0)\n        })\n        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n    } else {\n      $active.removeClass('active')\n      $next.addClass('active')\n      this.sliding = false\n      this.$element.trigger(slidEvent)\n    }\n\n    isCycling && this.cycle()\n\n    return this\n  }\n\n\n  // CAROUSEL PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.carousel')\n      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n      var action  = typeof option == 'string' ? option : options.slide\n\n      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  var old = $.fn.carousel\n\n  $.fn.carousel             = Plugin\n  $.fn.carousel.Constructor = Carousel\n\n\n  // CAROUSEL NO CONFLICT\n  // ====================\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n\n  // CAROUSEL DATA-API\n  // =================\n\n  var clickHandler = function (e) {\n    var href\n    var $this   = $(this)\n    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n    if (!$target.hasClass('carousel')) return\n    var options = $.extend({}, $target.data(), $this.data())\n    var slideIndex = $this.attr('data-slide-to')\n    if (slideIndex) options.interval = false\n\n    Plugin.call($target, options)\n\n    if (slideIndex) {\n      $target.data('bs.carousel').to(slideIndex)\n    }\n\n    e.preventDefault()\n  }\n\n  $(document)\n    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n  $(window).on('load', function () {\n    $('[data-ride=\"carousel\"]').each(function () {\n      var $carousel = $(this)\n      Plugin.call($carousel, $carousel.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: collapse.js v3.3.6\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // COLLAPSE PUBLIC CLASS DEFINITION\n  // ================================\n\n  var Collapse = function (element, options) {\n    this.$element      = $(element)\n    this.options       = $.extend({}, Collapse.DEFAULTS, options)\n    this.$trigger      = $('[data-toggle=\"collapse\"][href=\"#' + element.id + '\"],' +\n                           '[data-toggle=\"collapse\"][data-target=\"#' + element.id + '\"]')\n    this.transitioning = null\n\n    if (this.options.parent) {\n      this.$parent = this.getParent()\n    } else {\n      this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n    }\n\n    if (this.options.toggle) this.toggle()\n  }\n\n  Collapse.VERSION  = '3.3.6'\n\n  Collapse.TRANSITION_DURATION = 350\n\n  Collapse.DEFAULTS = {\n    toggle: true\n  }\n\n  Collapse.prototype.dimension = function () {\n    var hasWidth = this.$element.hasClass('width')\n    return hasWidth ? 'width' : 'height'\n  }\n\n  Collapse.prototype.show = function () {\n    if (this.transitioning || this.$element.hasClass('in')) return\n\n    var activesData\n    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')\n\n    if (actives && actives.length) {\n      activesData = actives.data('bs.collapse')\n      if (activesData && activesData.transitioning) return\n    }\n\n    var startEvent = $.Event('show.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    if (actives && actives.length) {\n      Plugin.call(actives, 'hide')\n      activesData || actives.data('bs.collapse', null)\n    }\n\n    var dimension = this.dimension()\n\n    this.$element\n      .removeClass('collapse')\n      .addClass('collapsing')[dimension](0)\n      .attr('aria-expanded', true)\n\n    this.$trigger\n      .removeClass('collapsed')\n      .attr('aria-expanded', true)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse in')[dimension]('')\n      this.transitioning = 0\n      this.$element\n        .trigger('shown.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n    this.$element\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n  }\n\n  Collapse.prototype.hide = function () {\n    if (this.transitioning || !this.$element.hasClass('in')) return\n\n    var startEvent = $.Event('hide.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    var dimension = this.dimension()\n\n    this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n    this.$element\n      .addClass('collapsing')\n      .removeClass('collapse in')\n      .attr('aria-expanded', false)\n\n    this.$trigger\n      .addClass('collapsed')\n      .attr('aria-expanded', false)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.transitioning = 0\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse')\n        .trigger('hidden.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    this.$element\n      [dimension](0)\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n  }\n\n  Collapse.prototype.toggle = function () {\n    this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  }\n\n  Collapse.prototype.getParent = function () {\n    return $(this.options.parent)\n      .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n      .each($.proxy(function (i, element) {\n        var $element = $(element)\n        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n      }, this))\n      .end()\n  }\n\n  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n    var isOpen = $element.hasClass('in')\n\n    $element.attr('aria-expanded', isOpen)\n    $trigger\n      .toggleClass('collapsed', !isOpen)\n      .attr('aria-expanded', isOpen)\n  }\n\n  function getTargetFromTrigger($trigger) {\n    var href\n    var target = $trigger.attr('data-target')\n      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n    return $(target)\n  }\n\n\n  // COLLAPSE PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.collapse')\n      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false\n      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.collapse\n\n  $.fn.collapse             = Plugin\n  $.fn.collapse.Constructor = Collapse\n\n\n  // COLLAPSE NO CONFLICT\n  // ====================\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n  // COLLAPSE DATA-API\n  // =================\n\n  $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n    var $this   = $(this)\n\n    if (!$this.attr('data-target')) e.preventDefault()\n\n    var $target = getTargetFromTrigger($this)\n    var data    = $target.data('bs.collapse')\n    var option  = data ? 'toggle' : $this.data()\n\n    Plugin.call($target, option)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: dropdown.js v3.3.6\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // DROPDOWN CLASS DEFINITION\n  // =========================\n\n  var backdrop = '.dropdown-backdrop'\n  var toggle   = '[data-toggle=\"dropdown\"]'\n  var Dropdown = function (element) {\n    $(element).on('click.bs.dropdown', this.toggle)\n  }\n\n  Dropdown.VERSION = '3.3.6'\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = selector && $(selector)\n\n    return $parent && $parent.length ? $parent : $this.parent()\n  }\n\n  function clearMenus(e) {\n    if (e && e.which === 3) return\n    $(backdrop).remove()\n    $(toggle).each(function () {\n      var $this         = $(this)\n      var $parent       = getParent($this)\n      var relatedTarget = { relatedTarget: this }\n\n      if (!$parent.hasClass('open')) return\n\n      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return\n\n      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this.attr('aria-expanded', 'false')\n      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))\n    })\n  }\n\n  Dropdown.prototype.toggle = function (e) {\n    var $this = $(this)\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    clearMenus()\n\n    if (!isActive) {\n      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n        // if mobile we use a backdrop because click events don't delegate\n        $(document.createElement('div'))\n          .addClass('dropdown-backdrop')\n          .insertAfter($(this))\n          .on('click', clearMenus)\n      }\n\n      var relatedTarget = { relatedTarget: this }\n      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this\n        .trigger('focus')\n        .attr('aria-expanded', 'true')\n\n      $parent\n        .toggleClass('open')\n        .trigger($.Event('shown.bs.dropdown', relatedTarget))\n    }\n\n    return false\n  }\n\n  Dropdown.prototype.keydown = function (e) {\n    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n    var $this = $(this)\n\n    e.preventDefault()\n    e.stopPropagation()\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    if (!isActive && e.which != 27 || isActive && e.which == 27) {\n      if (e.which == 27) $parent.find(toggle).trigger('focus')\n      return $this.trigger('click')\n    }\n\n    var desc = ' li:not(.disabled):visible a'\n    var $items = $parent.find('.dropdown-menu' + desc)\n\n    if (!$items.length) return\n\n    var index = $items.index(e.target)\n\n    if (e.which == 38 && index > 0)                 index--         // up\n    if (e.which == 40 && index < $items.length - 1) index++         // down\n    if (!~index)                                    index = 0\n\n    $items.eq(index).trigger('focus')\n  }\n\n\n  // DROPDOWN PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.dropdown')\n\n      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown             = Plugin\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  // DROPDOWN NO CONFLICT\n  // ====================\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  // APPLY TO STANDARD DROPDOWN ELEMENTS\n  // ===================================\n\n  $(document)\n    .on('click.bs.dropdown.data-api', clearMenus)\n    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: modal.js v3.3.6\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // MODAL CLASS DEFINITION\n  // ======================\n\n  var Modal = function (element, options) {\n    this.options             = options\n    this.$body               = $(document.body)\n    this.$element            = $(element)\n    this.$dialog             = this.$element.find('.modal-dialog')\n    this.$backdrop           = null\n    this.isShown             = null\n    this.originalBodyPad     = null\n    this.scrollbarWidth      = 0\n    this.ignoreBackdropClick = false\n\n    if (this.options.remote) {\n      this.$element\n        .find('.modal-content')\n        .load(this.options.remote, $.proxy(function () {\n          this.$element.trigger('loaded.bs.modal')\n        }, this))\n    }\n  }\n\n  Modal.VERSION  = '3.3.6'\n\n  Modal.TRANSITION_DURATION = 300\n  Modal.BACKDROP_TRANSITION_DURATION = 150\n\n  Modal.DEFAULTS = {\n    backdrop: true,\n    keyboard: true,\n    show: true\n  }\n\n  Modal.prototype.toggle = function (_relatedTarget) {\n    return this.isShown ? this.hide() : this.show(_relatedTarget)\n  }\n\n  Modal.prototype.show = function (_relatedTarget) {\n    var that = this\n    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n    this.$element.trigger(e)\n\n    if (this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = true\n\n    this.checkScrollbar()\n    this.setScrollbar()\n    this.$body.addClass('modal-open')\n\n    this.escape()\n    this.resize()\n\n    this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n    this.$dialog.on('mousedown.dismiss.bs.modal', function () {\n      that.$element.one('mouseup.dismiss.bs.modal', function (e) {\n        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true\n      })\n    })\n\n    this.backdrop(function () {\n      var transition = $.support.transition && that.$element.hasClass('fade')\n\n      if (!that.$element.parent().length) {\n        that.$element.appendTo(that.$body) // don't move modals dom position\n      }\n\n      that.$element\n        .show()\n        .scrollTop(0)\n\n      that.adjustDialog()\n\n      if (transition) {\n        that.$element[0].offsetWidth // force reflow\n      }\n\n      that.$element.addClass('in')\n\n      that.enforceFocus()\n\n      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n      transition ?\n        that.$dialog // wait for modal to slide in\n          .one('bsTransitionEnd', function () {\n            that.$element.trigger('focus').trigger(e)\n          })\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        that.$element.trigger('focus').trigger(e)\n    })\n  }\n\n  Modal.prototype.hide = function (e) {\n    if (e) e.preventDefault()\n\n    e = $.Event('hide.bs.modal')\n\n    this.$element.trigger(e)\n\n    if (!this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = false\n\n    this.escape()\n    this.resize()\n\n    $(document).off('focusin.bs.modal')\n\n    this.$element\n      .removeClass('in')\n      .off('click.dismiss.bs.modal')\n      .off('mouseup.dismiss.bs.modal')\n\n    this.$dialog.off('mousedown.dismiss.bs.modal')\n\n    $.support.transition && this.$element.hasClass('fade') ?\n      this.$element\n        .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n      this.hideModal()\n  }\n\n  Modal.prototype.enforceFocus = function () {\n    $(document)\n      .off('focusin.bs.modal') // guard against infinite focus loop\n      .on('focusin.bs.modal', $.proxy(function (e) {\n        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n          this.$element.trigger('focus')\n        }\n      }, this))\n  }\n\n  Modal.prototype.escape = function () {\n    if (this.isShown && this.options.keyboard) {\n      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n        e.which == 27 && this.hide()\n      }, this))\n    } else if (!this.isShown) {\n      this.$element.off('keydown.dismiss.bs.modal')\n    }\n  }\n\n  Modal.prototype.resize = function () {\n    if (this.isShown) {\n      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n    } else {\n      $(window).off('resize.bs.modal')\n    }\n  }\n\n  Modal.prototype.hideModal = function () {\n    var that = this\n    this.$element.hide()\n    this.backdrop(function () {\n      that.$body.removeClass('modal-open')\n      that.resetAdjustments()\n      that.resetScrollbar()\n      that.$element.trigger('hidden.bs.modal')\n    })\n  }\n\n  Modal.prototype.removeBackdrop = function () {\n    this.$backdrop && this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  Modal.prototype.backdrop = function (callback) {\n    var that = this\n    var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $(document.createElement('div'))\n        .addClass('modal-backdrop ' + animate)\n        .appendTo(this.$body)\n\n      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {\n        if (this.ignoreBackdropClick) {\n          this.ignoreBackdropClick = false\n          return\n        }\n        if (e.target !== e.currentTarget) return\n        this.options.backdrop == 'static'\n          ? this.$element[0].focus()\n          : this.hide()\n      }, this))\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      if (!callback) return\n\n      doAnimate ?\n        this.$backdrop\n          .one('bsTransitionEnd', callback)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      var callbackRemove = function () {\n        that.removeBackdrop()\n        callback && callback()\n      }\n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$backdrop\n          .one('bsTransitionEnd', callbackRemove)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callbackRemove()\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  // these following methods are used to handle overflowing modals\n\n  Modal.prototype.handleUpdate = function () {\n    this.adjustDialog()\n  }\n\n  Modal.prototype.adjustDialog = function () {\n    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n    this.$element.css({\n      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n    })\n  }\n\n  Modal.prototype.resetAdjustments = function () {\n    this.$element.css({\n      paddingLeft: '',\n      paddingRight: ''\n    })\n  }\n\n  Modal.prototype.checkScrollbar = function () {\n    var fullWindowWidth = window.innerWidth\n    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8\n      var documentElementRect = document.documentElement.getBoundingClientRect()\n      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)\n    }\n    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth\n    this.scrollbarWidth = this.measureScrollbar()\n  }\n\n  Modal.prototype.setScrollbar = function () {\n    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n    this.originalBodyPad = document.body.style.paddingRight || ''\n    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n  }\n\n  Modal.prototype.resetScrollbar = function () {\n    this.$body.css('padding-right', this.originalBodyPad)\n  }\n\n  Modal.prototype.measureScrollbar = function () { // thx walsh\n    var scrollDiv = document.createElement('div')\n    scrollDiv.className = 'modal-scrollbar-measure'\n    this.$body.append(scrollDiv)\n    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n    this.$body[0].removeChild(scrollDiv)\n    return scrollbarWidth\n  }\n\n\n  // MODAL PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option, _relatedTarget) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.modal')\n      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option](_relatedTarget)\n      else if (options.show) data.show(_relatedTarget)\n    })\n  }\n\n  var old = $.fn.modal\n\n  $.fn.modal             = Plugin\n  $.fn.modal.Constructor = Modal\n\n\n  // MODAL NO CONFLICT\n  // =================\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n  // MODAL DATA-API\n  // ==============\n\n  $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this   = $(this)\n    var href    = $this.attr('href')\n    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n    if ($this.is('a')) e.preventDefault()\n\n    $target.one('show.bs.modal', function (showEvent) {\n      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n      $target.one('hidden.bs.modal', function () {\n        $this.is(':visible') && $this.trigger('focus')\n      })\n    })\n    Plugin.call($target, option, this)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tooltip.js v3.3.6\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TOOLTIP PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Tooltip = function (element, options) {\n    this.type       = null\n    this.options    = null\n    this.enabled    = null\n    this.timeout    = null\n    this.hoverState = null\n    this.$element   = null\n    this.inState    = null\n\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.VERSION  = '3.3.6'\n\n  Tooltip.TRANSITION_DURATION = 150\n\n  Tooltip.DEFAULTS = {\n    animation: true,\n    placement: 'top',\n    selector: false,\n    template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    container: false,\n    viewport: {\n      selector: 'body',\n      padding: 0\n    }\n  }\n\n  Tooltip.prototype.init = function (type, element, options) {\n    this.enabled   = true\n    this.type      = type\n    this.$element  = $(element)\n    this.options   = this.getOptions(options)\n    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))\n    this.inState   = { click: false, hover: false, focus: false }\n\n    if (this.$element[0] instanceof document.constructor && !this.options.selector) {\n      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')\n    }\n\n    var triggers = this.options.trigger.split(' ')\n\n    for (var i = triggers.length; i--;) {\n      var trigger = triggers[i]\n\n      if (trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (trigger != 'manual') {\n        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n    }\n\n    this.options.selector ?\n      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n      this.fixTitle()\n  }\n\n  Tooltip.prototype.getDefaults = function () {\n    return Tooltip.DEFAULTS\n  }\n\n  Tooltip.prototype.getOptions = function (options) {\n    options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n    if (options.delay && typeof options.delay == 'number') {\n      options.delay = {\n        show: options.delay,\n        hide: options.delay\n      }\n    }\n\n    return options\n  }\n\n  Tooltip.prototype.getDelegateOptions = function () {\n    var options  = {}\n    var defaults = this.getDefaults()\n\n    this._options && $.each(this._options, function (key, value) {\n      if (defaults[key] != value) options[key] = value\n    })\n\n    return options\n  }\n\n  Tooltip.prototype.enter = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true\n    }\n\n    if (self.tip().hasClass('in') || self.hoverState == 'in') {\n      self.hoverState = 'in'\n      return\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'in'\n\n    if (!self.options.delay || !self.options.delay.show) return self.show()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'in') self.show()\n    }, self.options.delay.show)\n  }\n\n  Tooltip.prototype.isInStateTrue = function () {\n    for (var key in this.inState) {\n      if (this.inState[key]) return true\n    }\n\n    return false\n  }\n\n  Tooltip.prototype.leave = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false\n    }\n\n    if (self.isInStateTrue()) return\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'out'\n\n    if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'out') self.hide()\n    }, self.options.delay.hide)\n  }\n\n  Tooltip.prototype.show = function () {\n    var e = $.Event('show.bs.' + this.type)\n\n    if (this.hasContent() && this.enabled) {\n      this.$element.trigger(e)\n\n      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n      if (e.isDefaultPrevented() || !inDom) return\n      var that = this\n\n      var $tip = this.tip()\n\n      var tipId = this.getUID(this.type)\n\n      this.setContent()\n      $tip.attr('id', tipId)\n      this.$element.attr('aria-describedby', tipId)\n\n      if (this.options.animation) $tip.addClass('fade')\n\n      var placement = typeof this.options.placement == 'function' ?\n        this.options.placement.call(this, $tip[0], this.$element[0]) :\n        this.options.placement\n\n      var autoToken = /\\s?auto?\\s?/i\n      var autoPlace = autoToken.test(placement)\n      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n      $tip\n        .detach()\n        .css({ top: 0, left: 0, display: 'block' })\n        .addClass(placement)\n        .data('bs.' + this.type, this)\n\n      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n      this.$element.trigger('inserted.bs.' + this.type)\n\n      var pos          = this.getPosition()\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n\n      if (autoPlace) {\n        var orgPlacement = placement\n        var viewportDim = this.getPosition(this.$viewport)\n\n        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :\n                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :\n                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :\n                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :\n                    placement\n\n        $tip\n          .removeClass(orgPlacement)\n          .addClass(placement)\n      }\n\n      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n      this.applyPlacement(calculatedOffset, placement)\n\n      var complete = function () {\n        var prevHoverState = that.hoverState\n        that.$element.trigger('shown.bs.' + that.type)\n        that.hoverState = null\n\n        if (prevHoverState == 'out') that.leave(that)\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n    }\n  }\n\n  Tooltip.prototype.applyPlacement = function (offset, placement) {\n    var $tip   = this.tip()\n    var width  = $tip[0].offsetWidth\n    var height = $tip[0].offsetHeight\n\n    // manually read margins because getBoundingClientRect includes difference\n    var marginTop = parseInt($tip.css('margin-top'), 10)\n    var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n    // we must check for NaN for ie 8/9\n    if (isNaN(marginTop))  marginTop  = 0\n    if (isNaN(marginLeft)) marginLeft = 0\n\n    offset.top  += marginTop\n    offset.left += marginLeft\n\n    // $.fn.offset doesn't round pixel values\n    // so we use setOffset directly with our own function B-0\n    $.offset.setOffset($tip[0], $.extend({\n      using: function (props) {\n        $tip.css({\n          top: Math.round(props.top),\n          left: Math.round(props.left)\n        })\n      }\n    }, offset), 0)\n\n    $tip.addClass('in')\n\n    // check to see if placing tip in new offset caused the tip to resize itself\n    var actualWidth  = $tip[0].offsetWidth\n    var actualHeight = $tip[0].offsetHeight\n\n    if (placement == 'top' && actualHeight != height) {\n      offset.top = offset.top + height - actualHeight\n    }\n\n    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n    if (delta.left) offset.left += delta.left\n    else offset.top += delta.top\n\n    var isVertical          = /top|bottom/.test(placement)\n    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n    $tip.offset(offset)\n    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n  }\n\n  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {\n    this.arrow()\n      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n      .css(isVertical ? 'top' : 'left', '')\n  }\n\n  Tooltip.prototype.setContent = function () {\n    var $tip  = this.tip()\n    var title = this.getTitle()\n\n    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n    $tip.removeClass('fade in top bottom left right')\n  }\n\n  Tooltip.prototype.hide = function (callback) {\n    var that = this\n    var $tip = $(this.$tip)\n    var e    = $.Event('hide.bs.' + this.type)\n\n    function complete() {\n      if (that.hoverState != 'in') $tip.detach()\n      that.$element\n        .removeAttr('aria-describedby')\n        .trigger('hidden.bs.' + that.type)\n      callback && callback()\n    }\n\n    this.$element.trigger(e)\n\n    if (e.isDefaultPrevented()) return\n\n    $tip.removeClass('in')\n\n    $.support.transition && $tip.hasClass('fade') ?\n      $tip\n        .one('bsTransitionEnd', complete)\n        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n      complete()\n\n    this.hoverState = null\n\n    return this\n  }\n\n  Tooltip.prototype.fixTitle = function () {\n    var $e = this.$element\n    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {\n      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n    }\n  }\n\n  Tooltip.prototype.hasContent = function () {\n    return this.getTitle()\n  }\n\n  Tooltip.prototype.getPosition = function ($element) {\n    $element   = $element || this.$element\n\n    var el     = $element[0]\n    var isBody = el.tagName == 'BODY'\n\n    var elRect    = el.getBoundingClientRect()\n    if (elRect.width == null) {\n      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n    }\n    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()\n    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n    return $.extend({}, elRect, scroll, outerDims, elOffset)\n  }\n\n  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }\n\n  }\n\n  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n    var delta = { top: 0, left: 0 }\n    if (!this.$viewport) return delta\n\n    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n    var viewportDimensions = this.getPosition(this.$viewport)\n\n    if (/right|left/.test(placement)) {\n      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n      if (topEdgeOffset < viewportDimensions.top) { // top overflow\n        delta.top = viewportDimensions.top - topEdgeOffset\n      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n      }\n    } else {\n      var leftEdgeOffset  = pos.left - viewportPadding\n      var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n      if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n        delta.left = viewportDimensions.left - leftEdgeOffset\n      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n      }\n    }\n\n    return delta\n  }\n\n  Tooltip.prototype.getTitle = function () {\n    var title\n    var $e = this.$element\n    var o  = this.options\n\n    title = $e.attr('data-original-title')\n      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n    return title\n  }\n\n  Tooltip.prototype.getUID = function (prefix) {\n    do prefix += ~~(Math.random() * 1000000)\n    while (document.getElementById(prefix))\n    return prefix\n  }\n\n  Tooltip.prototype.tip = function () {\n    if (!this.$tip) {\n      this.$tip = $(this.options.template)\n      if (this.$tip.length != 1) {\n        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')\n      }\n    }\n    return this.$tip\n  }\n\n  Tooltip.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n  }\n\n  Tooltip.prototype.enable = function () {\n    this.enabled = true\n  }\n\n  Tooltip.prototype.disable = function () {\n    this.enabled = false\n  }\n\n  Tooltip.prototype.toggleEnabled = function () {\n    this.enabled = !this.enabled\n  }\n\n  Tooltip.prototype.toggle = function (e) {\n    var self = this\n    if (e) {\n      self = $(e.currentTarget).data('bs.' + this.type)\n      if (!self) {\n        self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n        $(e.currentTarget).data('bs.' + this.type, self)\n      }\n    }\n\n    if (e) {\n      self.inState.click = !self.inState.click\n      if (self.isInStateTrue()) self.enter(self)\n      else self.leave(self)\n    } else {\n      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n    }\n  }\n\n  Tooltip.prototype.destroy = function () {\n    var that = this\n    clearTimeout(this.timeout)\n    this.hide(function () {\n      that.$element.off('.' + that.type).removeData('bs.' + that.type)\n      if (that.$tip) {\n        that.$tip.detach()\n      }\n      that.$tip = null\n      that.$arrow = null\n      that.$viewport = null\n    })\n  }\n\n\n  // TOOLTIP PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.tooltip')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip             = Plugin\n  $.fn.tooltip.Constructor = Tooltip\n\n\n  // TOOLTIP NO CONFLICT\n  // ===================\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: popover.js v3.3.6\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // POPOVER PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n  Popover.VERSION  = '3.3.6'\n\n  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n  // NOTE: POPOVER EXTENDS tooltip.js\n  // ================================\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n  Popover.prototype.constructor = Popover\n\n  Popover.prototype.getDefaults = function () {\n    return Popover.DEFAULTS\n  }\n\n  Popover.prototype.setContent = function () {\n    var $tip    = this.tip()\n    var title   = this.getTitle()\n    var content = this.getContent()\n\n    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n    ](content)\n\n    $tip.removeClass('fade top bottom left right in')\n\n    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n    // this manually by checking the contents.\n    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n  }\n\n  Popover.prototype.hasContent = function () {\n    return this.getTitle() || this.getContent()\n  }\n\n  Popover.prototype.getContent = function () {\n    var $e = this.$element\n    var o  = this.options\n\n    return $e.attr('data-content')\n      || (typeof o.content == 'function' ?\n            o.content.call($e[0]) :\n            o.content)\n  }\n\n  Popover.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n  }\n\n\n  // POPOVER PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.popover')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.popover\n\n  $.fn.popover             = Plugin\n  $.fn.popover.Constructor = Popover\n\n\n  // POPOVER NO CONFLICT\n  // ===================\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.6\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // SCROLLSPY CLASS DEFINITION\n  // ==========================\n\n  function ScrollSpy(element, options) {\n    this.$body          = $(document.body)\n    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)\n    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n    this.selector       = (this.options.target || '') + ' .nav li > a'\n    this.offsets        = []\n    this.targets        = []\n    this.activeTarget   = null\n    this.scrollHeight   = 0\n\n    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.VERSION  = '3.3.6'\n\n  ScrollSpy.DEFAULTS = {\n    offset: 10\n  }\n\n  ScrollSpy.prototype.getScrollHeight = function () {\n    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n  }\n\n  ScrollSpy.prototype.refresh = function () {\n    var that          = this\n    var offsetMethod  = 'offset'\n    var offsetBase    = 0\n\n    this.offsets      = []\n    this.targets      = []\n    this.scrollHeight = this.getScrollHeight()\n\n    if (!$.isWindow(this.$scrollElement[0])) {\n      offsetMethod = 'position'\n      offsetBase   = this.$scrollElement.scrollTop()\n    }\n\n    this.$body\n      .find(this.selector)\n      .map(function () {\n        var $el   = $(this)\n        var href  = $el.data('target') || $el.attr('href')\n        var $href = /^#./.test(href) && $(href)\n\n        return ($href\n          && $href.length\n          && $href.is(':visible')\n          && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n      })\n      .sort(function (a, b) { return a[0] - b[0] })\n      .each(function () {\n        that.offsets.push(this[0])\n        that.targets.push(this[1])\n      })\n  }\n\n  ScrollSpy.prototype.process = function () {\n    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n    var scrollHeight = this.getScrollHeight()\n    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n    var offsets      = this.offsets\n    var targets      = this.targets\n    var activeTarget = this.activeTarget\n    var i\n\n    if (this.scrollHeight != scrollHeight) {\n      this.refresh()\n    }\n\n    if (scrollTop >= maxScroll) {\n      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n    }\n\n    if (activeTarget && scrollTop < offsets[0]) {\n      this.activeTarget = null\n      return this.clear()\n    }\n\n    for (i = offsets.length; i--;) {\n      activeTarget != targets[i]\n        && scrollTop >= offsets[i]\n        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])\n        && this.activate(targets[i])\n    }\n  }\n\n  ScrollSpy.prototype.activate = function (target) {\n    this.activeTarget = target\n\n    this.clear()\n\n    var selector = this.selector +\n      '[data-target=\"' + target + '\"],' +\n      this.selector + '[href=\"' + target + '\"]'\n\n    var active = $(selector)\n      .parents('li')\n      .addClass('active')\n\n    if (active.parent('.dropdown-menu').length) {\n      active = active\n        .closest('li.dropdown')\n        .addClass('active')\n    }\n\n    active.trigger('activate.bs.scrollspy')\n  }\n\n  ScrollSpy.prototype.clear = function () {\n    $(this.selector)\n      .parentsUntil(this.options.target, '.active')\n      .removeClass('active')\n  }\n\n\n  // SCROLLSPY PLUGIN DEFINITION\n  // ===========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.scrollspy')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy             = Plugin\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n\n  // SCROLLSPY NO CONFLICT\n  // =====================\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n  // SCROLLSPY DATA-API\n  // ==================\n\n  $(window).on('load.bs.scrollspy.data-api', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      Plugin.call($spy, $spy.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tab.js v3.3.6\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TAB CLASS DEFINITION\n  // ====================\n\n  var Tab = function (element) {\n    // jscs:disable requireDollarBeforejQueryAssignment\n    this.element = $(element)\n    // jscs:enable requireDollarBeforejQueryAssignment\n  }\n\n  Tab.VERSION = '3.3.6'\n\n  Tab.TRANSITION_DURATION = 150\n\n  Tab.prototype.show = function () {\n    var $this    = this.element\n    var $ul      = $this.closest('ul:not(.dropdown-menu)')\n    var selector = $this.data('target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    if ($this.parent('li').hasClass('active')) return\n\n    var $previous = $ul.find('.active:last a')\n    var hideEvent = $.Event('hide.bs.tab', {\n      relatedTarget: $this[0]\n    })\n    var showEvent = $.Event('show.bs.tab', {\n      relatedTarget: $previous[0]\n    })\n\n    $previous.trigger(hideEvent)\n    $this.trigger(showEvent)\n\n    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n    var $target = $(selector)\n\n    this.activate($this.closest('li'), $ul)\n    this.activate($target, $target.parent(), function () {\n      $previous.trigger({\n        type: 'hidden.bs.tab',\n        relatedTarget: $this[0]\n      })\n      $this.trigger({\n        type: 'shown.bs.tab',\n        relatedTarget: $previous[0]\n      })\n    })\n  }\n\n  Tab.prototype.activate = function (element, container, callback) {\n    var $active    = container.find('> .active')\n    var transition = callback\n      && $.support.transition\n      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)\n\n    function next() {\n      $active\n        .removeClass('active')\n        .find('> .dropdown-menu > .active')\n          .removeClass('active')\n        .end()\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', false)\n\n      element\n        .addClass('active')\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', true)\n\n      if (transition) {\n        element[0].offsetWidth // reflow for transition\n        element.addClass('in')\n      } else {\n        element.removeClass('fade')\n      }\n\n      if (element.parent('.dropdown-menu').length) {\n        element\n          .closest('li.dropdown')\n            .addClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n      }\n\n      callback && callback()\n    }\n\n    $active.length && transition ?\n      $active\n        .one('bsTransitionEnd', next)\n        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n      next()\n\n    $active.removeClass('in')\n  }\n\n\n  // TAB PLUGIN DEFINITION\n  // =====================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.tab')\n\n      if (!data) $this.data('bs.tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tab\n\n  $.fn.tab             = Plugin\n  $.fn.tab.Constructor = Tab\n\n\n  // TAB NO CONFLICT\n  // ===============\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n  // TAB DATA-API\n  // ============\n\n  var clickHandler = function (e) {\n    e.preventDefault()\n    Plugin.call($(this), 'show')\n  }\n\n  $(document)\n    .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n    .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: affix.js v3.3.6\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // AFFIX CLASS DEFINITION\n  // ======================\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, Affix.DEFAULTS, options)\n\n    this.$target = $(this.options.target)\n      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n\n    this.$element     = $(element)\n    this.affixed      = null\n    this.unpin        = null\n    this.pinnedOffset = null\n\n    this.checkPosition()\n  }\n\n  Affix.VERSION  = '3.3.6'\n\n  Affix.RESET    = 'affix affix-top affix-bottom'\n\n  Affix.DEFAULTS = {\n    offset: 0,\n    target: window\n  }\n\n  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n    var scrollTop    = this.$target.scrollTop()\n    var position     = this.$element.offset()\n    var targetHeight = this.$target.height()\n\n    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n    if (this.affixed == 'bottom') {\n      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n    }\n\n    var initializing   = this.affixed == null\n    var colliderTop    = initializing ? scrollTop : position.top\n    var colliderHeight = initializing ? targetHeight : height\n\n    if (offsetTop != null && scrollTop <= offsetTop) return 'top'\n    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n    return false\n  }\n\n  Affix.prototype.getPinnedOffset = function () {\n    if (this.pinnedOffset) return this.pinnedOffset\n    this.$element.removeClass(Affix.RESET).addClass('affix')\n    var scrollTop = this.$target.scrollTop()\n    var position  = this.$element.offset()\n    return (this.pinnedOffset = position.top - scrollTop)\n  }\n\n  Affix.prototype.checkPositionWithEventLoop = function () {\n    setTimeout($.proxy(this.checkPosition, this), 1)\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var height       = this.$element.height()\n    var offset       = this.options.offset\n    var offsetTop    = offset.top\n    var offsetBottom = offset.bottom\n    var scrollHeight = Math.max($(document).height(), $(document.body).height())\n\n    if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n    if (this.affixed != affix) {\n      if (this.unpin != null) this.$element.css('top', '')\n\n      var affixType = 'affix' + (affix ? '-' + affix : '')\n      var e         = $.Event(affixType + '.bs.affix')\n\n      this.$element.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      this.affixed = affix\n      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n      this.$element\n        .removeClass(Affix.RESET)\n        .addClass(affixType)\n        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n    }\n\n    if (affix == 'bottom') {\n      this.$element.offset({\n        top: scrollHeight - height - offsetBottom\n      })\n    }\n  }\n\n\n  // AFFIX PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.affix')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.affix\n\n  $.fn.affix             = Plugin\n  $.fn.affix.Constructor = Affix\n\n\n  // AFFIX NO CONFLICT\n  // =================\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n  // AFFIX DATA-API\n  // ==============\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n      var data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n      if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n\n      Plugin.call($spy, data)\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/bootstrap/dist/js/npm.js",
    "content": "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\nrequire('../../js/transition.js')\nrequire('../../js/alert.js')\nrequire('../../js/button.js')\nrequire('../../js/carousel.js')\nrequire('../../js/collapse.js')\nrequire('../../js/dropdown.js')\nrequire('../../js/modal.js')\nrequire('../../js/tooltip.js')\nrequire('../../js/popover.js')\nrequire('../../js/scrollspy.js')\nrequire('../../js/tab.js')\nrequire('../../js/affix.js')"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery/.bower.json",
    "content": "{\n  \"name\": \"jquery\",\n  \"main\": \"dist/jquery.js\",\n  \"license\": \"MIT\",\n  \"ignore\": [\n    \"package.json\"\n  ],\n  \"keywords\": [\n    \"jquery\",\n    \"javascript\",\n    \"browser\",\n    \"library\"\n  ],\n  \"homepage\": \"https://github.com/jquery/jquery-dist\",\n  \"version\": \"2.2.0\",\n  \"_release\": \"2.2.0\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"2.2.0\",\n    \"commit\": \"6fc01e29bdad0964f62ef56d01297039cdcadbe5\"\n  },\n  \"_source\": \"git://github.com/jquery/jquery-dist.git\",\n  \"_target\": \"2.2.0\",\n  \"_originalSource\": \"jquery\"\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery/LICENSE.txt",
    "content": "Copyright jQuery Foundation and other contributors, https://jquery.org/\n\nThis software consists of voluntary contributions made by many\nindividuals. For exact contribution history, see the revision history\navailable at https://github.com/jquery/jquery\n\nThe following license applies to all parts of this software except as\ndocumented below:\n\n====\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n====\n\nAll files located in the node_modules and external directories are\nexternally maintained libraries used by this software which have their\nown licenses; we recommend you read them, as their terms may differ from\nthe terms above.\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery/dist/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v2.2.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2016-01-08T20:02Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Support: Firefox 18+\n// Can't be in strict mode, several libs including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n//\"use strict\";\nvar arr = [];\n\nvar document = window.document;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar support = {};\n\n\n\nvar\n\tversion = \"2.2.0\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android<4.1\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num != null ?\n\n\t\t\t// Return just the one element from the set\n\t\t\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return all the elements in a clean array\n\t\t\tslice.call( this );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = jQuery.isArray( copy ) ) ) ) {\n\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray( src ) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject( src ) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type( obj ) === \"function\";\n\t},\n\n\tisArray: Array.isArray,\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t// adding 1 corrects loss of precision from parseFloat (#15100)\n\t\tvar realStringObj = obj && obj.toString();\n\t\treturn !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;\n\t},\n\n\tisPlainObject: function( obj ) {\n\n\t\t// Not plain objects:\n\t\t// - Any object or value whose internal [[Class]] property is not \"[object Object]\"\n\t\t// - DOM nodes\n\t\t// - window\n\t\tif ( jQuery.type( obj ) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call( obj.constructor.prototype, \"isPrototypeOf\" ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the function hasn't returned already, we're confident that\n\t\t// |obj| is a plain object, created by {} or constructed with new Object\n\t\treturn true;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\n\t\t// Support: Android<4.0, iOS<6 (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tvar script,\n\t\t\tindirect = eval;\n\n\t\tcode = jQuery.trim( code );\n\n\t\tif ( code ) {\n\n\t\t\t// If the code includes a valid, prologue position\n\t\t\t// strict mode pragma, execute code by injecting a\n\t\t\t// script tag into the document.\n\t\t\tif ( code.indexOf( \"use strict\" ) === 1 ) {\n\t\t\t\tscript = document.createElement( \"script\" );\n\t\t\t\tscript.text = code;\n\t\t\t\tdocument.head.appendChild( script ).parentNode.removeChild( script );\n\t\t\t} else {\n\n\t\t\t\t// Otherwise, avoid the DOM node creation, insertion\n\t\t\t\t// and removal by using an indirect global eval\n\n\t\t\t\tindirect( code );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Support: IE9-11+\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android<4.1\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\n// JSHint would error on this code due to the Symbol not being defined in ES5.\n// Defining this global in .jshintrc would create a danger of using the global\n// unguarded in another place, it seems safer to just disable JSHint for these\n// three lines.\n/* jshint ignore: start */\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n/* jshint ignore: end */\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: iOS 8.2 (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.2.1\n * http://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2015-10-17\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// http://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, nidselect, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!compilerCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n\t\t\t\tif ( nodeType !== 1 ) {\n\t\t\t\t\tnewContext = context;\n\t\t\t\t\tnewSelector = selector;\n\n\t\t\t\t// qSA looks outside Element context, which is not what we want\n\t\t\t\t// Thanks to Andrew Dupont for this workaround technique\n\t\t\t\t// Support: IE <=8\n\t\t\t\t// Exclude object elements\n\t\t\t\t} else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rescape, \"\\\\$&\" );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\tnidselect = ridentifier.test( nid ) ? \"#\" + nid : \"[id='\" + nid + \"']\";\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = nidselect + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\tif ( newSelector ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, parent,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( (parent = document.defaultView) && parent.top !== parent ) {\n\t\t// Support: IE 11\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( document.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\treturn m ? [ m ] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( div ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( div.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !div.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibing-combinator selector` fails\n\t\t\tif ( !div.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!compilerCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( (oldCache = uniqueCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = ( /^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/ );\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t} );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tlen = this.length,\n\t\t\tret = [],\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\t// Support: Blackberry 4.6\n\t\t\t\t\t// gEBID returns nodes no longer in the document (#6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && ( pos ?\n\t\t\t\t\tpos.index( cur ) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn elem.contentDocument || jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnotwhite = ( /\\S+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( jQuery.isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && jQuery.type( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ) ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis === promise ? newDefer.promise() : this,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add( function() {\n\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 ||\n\t\t\t\t( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred.\n\t\t\t// If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// Add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) )\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n} );\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.triggerHandler ) {\n\t\t\tjQuery( document ).triggerHandler( \"ready\" );\n\t\t\tjQuery( document ).off( \"ready\" );\n\t\t}\n\t}\n} );\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called\n\t\t// after the browser event has already occurred.\n\t\t// Support: IE9-10 only\n\t\t// Older IE sometimes signals \"interactive\" too soon\n\t\tif ( document.readyState === \"complete\" ||\n\t\t\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\twindow.setTimeout( jQuery.ready );\n\n\t\t} else {\n\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed );\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Kick off the DOM ready check even if the user does not\njQuery.ready.promise();\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlen ? fn( elems[ 0 ], key ) : emptyGet;\n};\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\t/* jshint -W018 */\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tregister: function( owner, initial ) {\n\t\tvar value = initial || {};\n\n\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t// use plain assignment\n\t\tif ( owner.nodeType ) {\n\t\t\towner[ this.expando ] = value;\n\n\t\t// Otherwise secure it in a non-enumerable, non-writable property\n\t\t// configurability must be true to allow the property to be\n\t\t// deleted with the delete operator\n\t\t} else {\n\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\tvalue: value,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true\n\t\t\t} );\n\t\t}\n\t\treturn owner[ this.expando ];\n\t},\n\tcache: function( owner ) {\n\n\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t// but we should not, see #8335.\n\t\t// Always return an empty object.\n\t\tif ( !acceptData( owner ) ) {\n\t\t\treturn {};\n\t\t}\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ data ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ prop ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\t\t\towner[ this.expando ] && owner[ this.expando ][ key ];\n\t},\n\taccess: function( owner, key, value ) {\n\t\tvar stored;\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\tstored = this.get( owner, key );\n\n\t\t\treturn stored !== undefined ?\n\t\t\t\tstored : this.get( owner, jQuery.camelCase( key ) );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i, name, camel,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key === undefined ) {\n\t\t\tthis.register( owner );\n\n\t\t} else {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( jQuery.isArray( key ) ) {\n\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = key.concat( key.map( jQuery.camelCase ) );\n\t\t\t} else {\n\t\t\t\tcamel = jQuery.camelCase( key );\n\n\t\t\t\t// Try the string as a key before any manipulation\n\t\t\t\tif ( key in cache ) {\n\t\t\t\t\tname = [ key, camel ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\t\tname = camel;\n\t\t\t\t\tname = name in cache ?\n\t\t\t\t\t\t[ name ] : ( name.match( rnotwhite ) || [] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = name.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ name[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <= 35-45+\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://code.google.com/p/chromium/issues/detail?id=378607\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE11+\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data, camelKey;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key as-is\n\t\t\t\tdata = dataUser.get( elem, key ) ||\n\n\t\t\t\t\t// Try to find dashed key if it exists (gh-2779)\n\t\t\t\t\t// This is for 2.2.x only\n\t\t\t\t\tdataUser.get( elem, key.replace( rmultiDash, \"-$&\" ).toLowerCase() );\n\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\tcamelKey = jQuery.camelCase( key );\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key camelized\n\t\t\t\tdata = dataUser.get( elem, camelKey );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, camelKey, undefined );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tcamelKey = jQuery.camelCase( key );\n\t\t\tthis.each( function() {\n\n\t\t\t\t// First, attempt to store a copy or reference of any\n\t\t\t\t// data that might've been store with a camelCased key.\n\t\t\t\tvar data = dataUser.get( this, camelKey );\n\n\t\t\t\t// For HTML5 data-* attribute interop, we have to\n\t\t\t\t// store property names with dashes in a camelCase form.\n\t\t\t\t// This might not apply to all properties...*\n\t\t\t\tdataUser.set( this, camelKey, value );\n\n\t\t\t\t// *... In the case of properties that might _actually_\n\t\t\t\t// have dashes, we need to also store a copy of that\n\t\t\t\t// unchanged property.\n\t\t\t\tif ( key.indexOf( \"-\" ) > -1 && data !== undefined ) {\n\t\t\t\t\tdataUser.set( this, key, value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" ||\n\t\t\t!jQuery.contains( elem.ownerDocument, elem );\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted,\n\t\tscale = 1,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() { return tween.cur(); } :\n\t\t\tfunction() { return jQuery.css( elem, prop, \"\" ); },\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\tdo {\n\n\t\t\t// If previous iteration zeroed out, double until we get *something*.\n\t\t\t// Use string for doubling so we don't accidentally see scale as unchanged below\n\t\t\tscale = scale || \".5\";\n\n\t\t\t// Adjust and apply\n\t\t\tinitialInUnit = initialInUnit / scale;\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t// Break the loop if scale is unchanged or perfect, or if we've just had enough.\n\t\t} while (\n\t\t\tscale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations\n\t\t);\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([\\w:-]+)/ );\n\nvar rscriptType = ( /^$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE9\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE9\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE9-11+\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret = typeof context.getElementsByTagName !== \"undefined\" ?\n\t\t\tcontext.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== \"undefined\" ?\n\t\t\t\tcontext.querySelectorAll( tag || \"*\" ) :\n\t\t\t[];\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], ret ) :\n\t\tret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, contains, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( contains ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0-4.3, Safari<=5.1\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Safari<=5.1, Android<4.2\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<=11+\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE9\n// See #13393 for more info\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn this;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Support (at least): Chrome, IE9\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t//\n\t\t// Support: Firefox<=42+\n\t\t// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)\n\t\tif ( delegateCount && cur.nodeType &&\n\t\t\t( event.type !== \"click\" || isNaN( event.button ) || event.button < 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== \"click\" ) ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matches } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: ( \"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase \" +\n\t\t\"metaKey relatedTarget shiftKey target timeStamp view which\" ).split( \" \" ),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split( \" \" ),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: ( \"button buttons clientX clientY offsetX offsetY pageX pageY \" +\n\t\t\t\"screenX screenY toElement\" ).split( \" \" ),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX +\n\t\t\t\t\t( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -\n\t\t\t\t\t( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY +\n\t\t\t\t\t( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -\n\t\t\t\t\t( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: Cordova 2.5 (WebKit) (#13255)\n\t\t// All events should have a target; Cordova deviceready doesn't\n\t\tif ( !event.target ) {\n\t\t\tevent.target = document;\n\t\t}\n\n\t\t// Support: Safari 6.0+, Chrome<28\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android<4.0\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://code.google.com/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,\n\n\t// Support: IE 10-11, Edge 10240+\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\nfunction manipulationTarget( elem, content ) {\n\tif ( jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn elem.getElementsByTagName( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tisFunction = jQuery.isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( isFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( isFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android<4.1, PhantomJS<2\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tjQuery.globalEval( node.textContent.replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <= 35-45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <= 35-45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\n\t// Keep domManip exposed until 3.0 (gh-2225)\n\tdomManip: domManip,\n\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: QtWebKit\n\t\t\t// .get() because push.apply(_, arraylike) throws\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\n\n\nvar iframe,\n\telemdisplay = {\n\n\t\t// Support: Firefox\n\t\t// We have to pre-define these values for FF (#10227)\n\t\tHTML: \"block\",\n\t\tBODY: \"block\"\n\t};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\tdisplay = jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = ( iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" ) )\n\t\t\t\t.appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = iframe[ 0 ].contentDocument;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\nvar rmargin = ( /^margin/ );\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE<=11+, Firefox<=30+ (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar documentElement = document.documentElement;\n\n\n\n( function() {\n\tvar pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE9-11+\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:8px;height:0;top:0;left:-9999px;\" +\n\t\t\"padding:0;margin-top:1px;position:absolute\";\n\tcontainer.appendChild( div );\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\t\tdiv.style.cssText =\n\n\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t// Vendor-prefix box-sizing\n\t\t\t\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;\" +\n\t\t\t\"position:relative;display:block;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"top:1%;width:50%\";\n\t\tdiv.innerHTML = \"\";\n\t\tdocumentElement.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\t\treliableMarginLeftVal = divStyle.marginLeft === \"2px\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\t// Support: Android 4.0 - 4.3 only\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.marginRight = \"50%\";\n\t\tpixelMarginRightVal = divStyle.marginRight === \"4px\";\n\n\t\tdocumentElement.removeChild( container );\n\t}\n\n\tjQuery.extend( support, {\n\t\tpixelPosition: function() {\n\n\t\t\t// This test is executed only once but we still do memoizing\n\t\t\t// since we can use the boxSizingReliable pre-computing.\n\t\t\t// No need to check if the test was already performed, though.\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\tboxSizingReliable: function() {\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelMarginRight: function() {\n\n\t\t\t// Support: Android 4.0-4.3\n\t\t\t// We're checking for boxSizingReliableVal here instead of pixelMarginRightVal\n\t\t\t// since that compresses better and they're computed together anyway.\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn pixelMarginRightVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\n\t\t\t// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\treliableMarginRight: function() {\n\n\t\t\t// Support: Android 2.3\n\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t// This support function is only executed once so no memoizing is needed.\n\t\t\tvar ret,\n\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\n\t\t\t// Reset CSS: box-sizing; display; margin; border; padding\n\t\t\tmarginDiv.style.cssText = div.style.cssText =\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Vendor-prefix box-sizing\n\t\t\t\t\"-webkit-box-sizing:content-box;box-sizing:content-box;\" +\n\t\t\t\t\"display:block;margin:0;border:0;padding:0\";\n\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\tdiv.style.width = \"1px\";\n\t\t\tdocumentElement.appendChild( container );\n\n\t\t\tret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight );\n\n\t\t\tdocumentElement.removeChild( container );\n\t\t\tdiv.removeChild( marginDiv );\n\n\t\t\treturn ret;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// Support: IE9\n\t// getPropertyValue is only needed for .css('filter') (#12537)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE9-11+\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// At this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\n\t\t\t// At this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// At this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// Support: IE11 only\n\t// In IE 11 fullscreen elements inside of an iframe have\n\t// 100x too small dimensions (gh-1764).\n\tif ( document.msFullscreenElement && window.top !== window ) {\n\n\t\t// Support: IE11 only\n\t\t// Running getBoundingClientRect on a disconnected node\n\t\t// in IE throws an error.\n\t\tif ( elem.getClientRects().length ) {\n\t\t\tval = Math.round( elem.getBoundingClientRect()[ name ] * 100 );\n\t\t}\n\t}\n\n\t// Some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test( val ) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// Check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox &&\n\t\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// Use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = dataPriv.get( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = dataPriv.access(\n\t\t\t\t\telem,\n\t\t\t\t\t\"olddisplay\",\n\t\t\t\t\tdefaultDisplay( elem.nodeName )\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\thidden = isHidden( elem );\n\n\t\t\tif ( display !== \"none\" || !hidden ) {\n\t\t\t\tdataPriv.set(\n\t\t\t\t\telem,\n\t\t\t\t\t\"olddisplay\",\n\t\t\t\t\thidden ? display : jQuery.css( elem, \"display\" )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] ||\n\t\t\t( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tstyle[ name ] = value;\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] ||\n\t\t\t( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\t\t\t\t\telem.offsetWidth === 0 ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = extra && getStyles( elem ),\n\t\t\t\tsubtract = extra && augmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t);\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ name ] = value;\n\t\t\t\tvalue = jQuery.css( elem, name );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// Support: Android 2.3\njQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 &&\n\t\t\t\t( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE9\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE9-10 do not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t// Test default display if display is currently \"none\"\n\t\tcheckDisplay = display === \"none\" ?\n\t\t\tdataPriv.get( elem, \"olddisplay\" ) || defaultDisplay( elem.nodeName ) : display;\n\n\t\tif ( checkDisplay === \"inline\" && jQuery.css( elem, \"float\" ) === \"none\" ) {\n\t\t\tstyle.display = \"inline-block\";\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show\n\t\t\t\t// and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t// Any non-fx value stops us from restoring the original display value\n\t\t} else {\n\t\t\tdisplay = undefined;\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// Store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done( function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t} );\n\t\t}\n\t\tanim.done( function() {\n\t\t\tvar prop;\n\n\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t} );\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t// If this is a noop like .hide().hide(), restore an overwritten display value\n\t} else if ( ( display === \"none\" ? defaultDisplay( elem.nodeName ) : display ) === \"inline\" ) {\n\t\tstyle.display = display;\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( jQuery.isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tjQuery.proxy( result.stop, result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnotwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ?\n\t\topt.duration : opt.duration in jQuery.fx.speeds ?\n\t\t\tjQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\twindow.clearInterval( timerId );\n\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: iOS<=5.1, Android<=4.2+\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE<=11+\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: Android<=2.3\n\t// Options inside disabled selects are incorrectly marked as disabled\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<=11+\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tjQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle;\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ name ];\n\t\t\tattrHandle[ name ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tname.toLowerCase() :\n\t\t\t\tnull;\n\t\t\tattrHandle[ name ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\treturn tabindex ?\n\t\t\t\t\tparseInt( tabindex, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\t\trclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t\t0 :\n\t\t\t\t\t\t\t-1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnotwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 &&\n\t\t\t\t\t( \" \" + curValue + \" \" ).replace( rclass, \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnotwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 &&\n\t\t\t\t\t( \" \" + curValue + \" \" ).replace( rclass, \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( type === \"string\" ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + getClass( elem ) + \" \" ).replace( rclass, \" \" )\n\t\t\t\t\t.indexOf( className ) > -1\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\n\t\t\t\t\t// Handle most common string cases\n\t\t\t\t\tret.replace( rreturn, \"\" ) :\n\n\t\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE<11\n\t\t\t\t// option.value not trimmed (#14858)\n\t\t\t\treturn jQuery.trim( elem.value );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( support.optDisabled ?\n\t\t\t\t\t\t\t\t!option.disabled : option.getAttribute( \"disabled\" ) === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\n\t\t\t\t// Previously, `originalEvent: {}` was set here, so stopPropagation call\n\t\t\t\t// would not be triggered on donor event, since in our own\n\t\t\t\t// jQuery.event.stopPropagation function we had a check for existence of\n\t\t\t\t// originalEvent.stopPropagation method, so, consequently it would be a noop.\n\t\t\t\t//\n\t\t\t\t// But now, this \"simulate\" function is used only for events\n\t\t\t\t// for which stopPropagation() is noop, so there is no need for that anymore.\n\t\t\t\t//\n\t\t\t\t// For the compat branch though, guard for \"click\" and \"submit\"\n\t\t\t\t// events is still used, but was moved to jQuery.event.stopPropagation function\n\t\t\t\t// because `originalEvent` should point to the original event for the constancy\n\t\t\t\t// with other events and for more focused logic\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\n// Support: Firefox\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome, Safari\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = jQuery.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Support: Android 2.3\n// Workaround failure to string-cast null input\njQuery.parseJSON = function( data ) {\n\treturn JSON.parse( data + \"\" );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE9\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" ).replace( rhash, \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE8-11+\n\t\t\t// IE throws exception if url is malformed, e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE8-11+\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapAll( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( this[ 0 ] ) {\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each( function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t} ).end();\n\t}\n} );\n\n\njQuery.expr.filters.hidden = function( elem ) {\n\treturn !jQuery.expr.filters.visible( elem );\n};\njQuery.expr.filters.visible = function( elem ) {\n\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\t// Use OR instead of AND as the element is not visible if either is true\n\t// See tickets #10406 and #13132\n\treturn elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0;\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t} ) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE9\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE9\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = callback( \"error\" );\n\n\t\t\t\t// Support: IE9\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" ).prop( {\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t} ).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8+\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\t// Stop scripts or inline event handlers from being executed immediately\n\t// by using document.implementation\n\tcontext = context || ( support.createHTMLDocument ?\n\t\tdocument.implementation.createHTMLDocument( \"\" ) :\n\t\tdocument );\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = jQuery.trim( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( self, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\telem = this[ 0 ],\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\tbox = elem.getBoundingClientRect();\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: box.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0},\n\t\t// because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume getBoundingClientRect is there when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\t// Subtract offsetParent scroll positions\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true ) -\n\t\t\t\toffsetParent.scrollTop();\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true ) -\n\t\t\t\toffsetParent.scrollLeft();\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari<7-8+, Chrome<37-44+\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t} );\n} );\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t},\n\tsize: function() {\n\t\treturn this.length;\n\t}\n} );\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\nreturn jQuery;\n}));\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation/.bower.json",
    "content": "{\n  \"name\": \"jquery-validation\",\n  \"homepage\": \"http://jqueryvalidation.org/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/jzaefferer/jquery-validation.git\"\n  },\n  \"authors\": [\n    \"Jörn Zaefferer <joern.zaefferer@gmail.com>\"\n  ],\n  \"description\": \"Form validation made easy\",\n  \"main\": \"dist/jquery.validate.js\",\n  \"keywords\": [\n    \"forms\",\n    \"validation\",\n    \"validate\"\n  ],\n  \"license\": \"MIT\",\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"demo\",\n    \"lib\"\n  ],\n  \"dependencies\": {\n    \"jquery\": \">= 1.7.2\"\n  },\n  \"version\": \"1.14.0\",\n  \"_release\": \"1.14.0\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"1.14.0\",\n    \"commit\": \"c1343fb9823392aa9acbe1c3ffd337b8c92fed48\"\n  },\n  \"_source\": \"git://github.com/jzaefferer/jquery-validation.git\",\n  \"_target\": \">=1.8\",\n  \"_originalSource\": \"jquery-validation\"\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation/LICENSE.md",
    "content": "The MIT License (MIT)\n=====================\n\nCopyright Jörn Zaefferer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation/dist/additional-methods.js",
    "content": "/*!\n * jQuery Validation Plugin v1.14.0\n *\n * http://jqueryvalidation.org/\n *\n * Copyright (c) 2015 Jörn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\t\tdefine( [\"jquery\", \"./jquery.validate\"], factory );\n\t} else {\n\t\tfactory( jQuery );\n\t}\n}(function( $ ) {\n\n(function() {\n\n\tfunction stripHtml(value) {\n\t\t// remove html tags and space chars\n\t\treturn value.replace(/<.[^<>]*?>/g, \" \").replace(/&nbsp;|&#160;/gi, \" \")\n\t\t// remove punctuation\n\t\t.replace(/[.(),;:!?%#$'\\\"_+=\\/\\-“”’]*/g, \"\");\n\t}\n\n\t$.validator.addMethod(\"maxWords\", function(value, element, params) {\n\t\treturn this.optional(element) || stripHtml(value).match(/\\b\\w+\\b/g).length <= params;\n\t}, $.validator.format(\"Please enter {0} words or less.\"));\n\n\t$.validator.addMethod(\"minWords\", function(value, element, params) {\n\t\treturn this.optional(element) || stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n\t}, $.validator.format(\"Please enter at least {0} words.\"));\n\n\t$.validator.addMethod(\"rangeWords\", function(value, element, params) {\n\t\tvar valueStripped = stripHtml(value),\n\t\t\tregex = /\\b\\w+\\b/g;\n\t\treturn this.optional(element) || valueStripped.match(regex).length >= params[0] && valueStripped.match(regex).length <= params[1];\n\t}, $.validator.format(\"Please enter between {0} and {1} words.\"));\n\n}());\n\n// Accept a value from a file input based on a required mimetype\n$.validator.addMethod(\"accept\", function(value, element, param) {\n\t// Split mime on commas in case we have multiple types we can accept\n\tvar typeParam = typeof param === \"string\" ? param.replace(/\\s/g, \"\").replace(/,/g, \"|\") : \"image/*\",\n\toptionalValue = this.optional(element),\n\ti, file;\n\n\t// Element is optional\n\tif (optionalValue) {\n\t\treturn optionalValue;\n\t}\n\n\tif ($(element).attr(\"type\") === \"file\") {\n\t\t// If we are using a wildcard, make it regex friendly\n\t\ttypeParam = typeParam.replace(/\\*/g, \".*\");\n\n\t\t// Check if the element has a FileList before checking each file\n\t\tif (element.files && element.files.length) {\n\t\t\tfor (i = 0; i < element.files.length; i++) {\n\t\t\t\tfile = element.files[i];\n\n\t\t\t\t// Grab the mimetype from the loaded file, verify it matches\n\t\t\t\tif (!file.type.match(new RegExp( \"\\\\.?(\" + typeParam + \")$\", \"i\"))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Either return true because we've validated each file, or because the\n\t// browser does not support element.files and the FileList feature\n\treturn true;\n}, $.validator.format(\"Please enter a value with a valid mimetype.\"));\n\n$.validator.addMethod(\"alphanumeric\", function(value, element) {\n\treturn this.optional(element) || /^\\w+$/i.test(value);\n}, \"Letters, numbers, and underscores only please\");\n\n/*\n * Dutch bank account numbers (not 'giro' numbers) have 9 digits\n * and pass the '11 check'.\n * We accept the notation with spaces, as that is common.\n * acceptable: 123456789 or 12 34 56 789\n */\n$.validator.addMethod(\"bankaccountNL\", function(value, element) {\n\tif (this.optional(element)) {\n\t\treturn true;\n\t}\n\tif (!(/^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test(value))) {\n\t\treturn false;\n\t}\n\t// now '11 check'\n\tvar account = value.replace(/ /g, \"\"), // remove spaces\n\t\tsum = 0,\n\t\tlen = account.length,\n\t\tpos, factor, digit;\n\tfor ( pos = 0; pos < len; pos++ ) {\n\t\tfactor = len - pos;\n\t\tdigit = account.substring(pos, pos + 1);\n\t\tsum = sum + factor * digit;\n\t}\n\treturn sum % 11 === 0;\n}, \"Please specify a valid bank account number\");\n\n$.validator.addMethod(\"bankorgiroaccountNL\", function(value, element) {\n\treturn this.optional(element) ||\n\t\t\t($.validator.methods.bankaccountNL.call(this, value, element)) ||\n\t\t\t($.validator.methods.giroaccountNL.call(this, value, element));\n}, \"Please specify a valid bank or giro account number\");\n\n/**\n * BIC is the business identifier code (ISO 9362). This BIC check is not a guarantee for authenticity.\n *\n * BIC pattern: BBBBCCLLbbb (8 or 11 characters long; bbb is optional)\n *\n * BIC definition in detail:\n * - First 4 characters - bank code (only letters)\n * - Next 2 characters - ISO 3166-1 alpha-2 country code (only letters)\n * - Next 2 characters - location code (letters and digits)\n *   a. shall not start with '0' or '1'\n *   b. second character must be a letter ('O' is not allowed) or one of the following digits ('0' for test (therefore not allowed), '1' for passive participant and '2' for active participant)\n * - Last 3 characters - branch code, optional (shall not start with 'X' except in case of 'XXX' for primary office) (letters and digits)\n */\n$.validator.addMethod(\"bic\", function(value, element) {\n    return this.optional( element ) || /^([A-Z]{6}[A-Z2-9][A-NP-Z1-2])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test( value );\n}, \"Please specify a valid BIC code\");\n\n/*\n * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities\n * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal\n */\n$.validator.addMethod( \"cifES\", function( value ) {\n\t\"use strict\";\n\n\tvar num = [],\n\t\tcontrolDigit, sum, i, count, tmp, secondDigit;\n\n\tvalue = value.toUpperCase();\n\n\t// Quick format test\n\tif ( !value.match( \"((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)\" ) ) {\n\t\treturn false;\n\t}\n\n\tfor ( i = 0; i < 9; i++ ) {\n\t\tnum[ i ] = parseInt( value.charAt( i ), 10 );\n\t}\n\n\t// Algorithm for checking CIF codes\n\tsum = num[ 2 ] + num[ 4 ] + num[ 6 ];\n\tfor ( count = 1; count < 8; count += 2 ) {\n\t\ttmp = ( 2 * num[ count ] ).toString();\n\t\tsecondDigit = tmp.charAt( 1 );\n\n\t\tsum += parseInt( tmp.charAt( 0 ), 10 ) + ( secondDigit === \"\" ? 0 : parseInt( secondDigit, 10 ) );\n\t}\n\n\t/* The first (position 1) is a letter following the following criteria:\n\t *\tA. Corporations\n\t *\tB. LLCs\n\t *\tC. General partnerships\n\t *\tD. Companies limited partnerships\n\t *\tE. Communities of goods\n\t *\tF. Cooperative Societies\n\t *\tG. Associations\n\t *\tH. Communities of homeowners in horizontal property regime\n\t *\tJ. Civil Societies\n\t *\tK. Old format\n\t *\tL. Old format\n\t *\tM. Old format\n\t *\tN. Nonresident entities\n\t *\tP. Local authorities\n\t *\tQ. Autonomous bodies, state or not, and the like, and congregations and religious institutions\n\t *\tR. Congregations and religious institutions (since 2008 ORDER EHA/451/2008)\n\t *\tS. Organs of State Administration and regions\n\t *\tV. Agrarian Transformation\n\t *\tW. Permanent establishments of non-resident in Spain\n\t */\n\tif ( /^[ABCDEFGHJNPQRSUVW]{1}/.test( value ) ) {\n\t\tsum += \"\";\n\t\tcontrolDigit = 10 - parseInt( sum.charAt( sum.length - 1 ), 10 );\n\t\tvalue += controlDigit;\n\t\treturn ( num[ 8 ].toString() === String.fromCharCode( 64 + controlDigit ) || num[ 8 ].toString() === value.charAt( value.length - 1 ) );\n\t}\n\n\treturn false;\n\n}, \"Please specify a valid CIF number.\" );\n\n/*\n * Brazillian CPF number (Cadastrado de Pessoas Físicas) is the equivalent of a Brazilian tax registration number.\n * CPF numbers have 11 digits in total: 9 numbers followed by 2 check numbers that are being used for validation.\n */\n$.validator.addMethod(\"cpfBR\", function(value) {\n\t// Removing special characters from value\n\tvalue = value.replace(/([~!@#$%^&*()_+=`{}\\[\\]\\-|\\\\:;'<>,.\\/? ])+/g, \"\");\n\n\t// Checking value to have 11 digits only\n\tif (value.length !== 11) {\n\t\treturn false;\n\t}\n\n\tvar sum = 0,\n\t\tfirstCN, secondCN, checkResult, i;\n\n\tfirstCN = parseInt(value.substring(9, 10), 10);\n\tsecondCN = parseInt(value.substring(10, 11), 10);\n\n\tcheckResult = function(sum, cn) {\n\t\tvar result = (sum * 10) % 11;\n\t\tif ((result === 10) || (result === 11)) {result = 0;}\n\t\treturn (result === cn);\n\t};\n\n\t// Checking for dump data\n\tif (value === \"\" ||\n\t\tvalue === \"00000000000\" ||\n\t\tvalue === \"11111111111\" ||\n\t\tvalue === \"22222222222\" ||\n\t\tvalue === \"33333333333\" ||\n\t\tvalue === \"44444444444\" ||\n\t\tvalue === \"55555555555\" ||\n\t\tvalue === \"66666666666\" ||\n\t\tvalue === \"77777777777\" ||\n\t\tvalue === \"88888888888\" ||\n\t\tvalue === \"99999999999\"\n\t) {\n\t\treturn false;\n\t}\n\n\t// Step 1 - using first Check Number:\n\tfor ( i = 1; i <= 9; i++ ) {\n\t\tsum = sum + parseInt(value.substring(i - 1, i), 10) * (11 - i);\n\t}\n\n\t// If first Check Number (CN) is valid, move to Step 2 - using second Check Number:\n\tif ( checkResult(sum, firstCN) ) {\n\t\tsum = 0;\n\t\tfor ( i = 1; i <= 10; i++ ) {\n\t\t\tsum = sum + parseInt(value.substring(i - 1, i), 10) * (12 - i);\n\t\t}\n\t\treturn checkResult(sum, secondCN);\n\t}\n\treturn false;\n\n}, \"Please specify a valid CPF number\");\n\n/* NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator\n * Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0\n * Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)\n */\n$.validator.addMethod(\"creditcardtypes\", function(value, element, param) {\n\tif (/[^0-9\\-]+/.test(value)) {\n\t\treturn false;\n\t}\n\n\tvalue = value.replace(/\\D/g, \"\");\n\n\tvar validTypes = 0x0000;\n\n\tif (param.mastercard) {\n\t\tvalidTypes |= 0x0001;\n\t}\n\tif (param.visa) {\n\t\tvalidTypes |= 0x0002;\n\t}\n\tif (param.amex) {\n\t\tvalidTypes |= 0x0004;\n\t}\n\tif (param.dinersclub) {\n\t\tvalidTypes |= 0x0008;\n\t}\n\tif (param.enroute) {\n\t\tvalidTypes |= 0x0010;\n\t}\n\tif (param.discover) {\n\t\tvalidTypes |= 0x0020;\n\t}\n\tif (param.jcb) {\n\t\tvalidTypes |= 0x0040;\n\t}\n\tif (param.unknown) {\n\t\tvalidTypes |= 0x0080;\n\t}\n\tif (param.all) {\n\t\tvalidTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n\t}\n\tif (validTypes & 0x0001 && /^(5[12345])/.test(value)) { //mastercard\n\t\treturn value.length === 16;\n\t}\n\tif (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n\t\treturn value.length === 16;\n\t}\n\tif (validTypes & 0x0004 && /^(3[47])/.test(value)) { //amex\n\t\treturn value.length === 15;\n\t}\n\tif (validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test(value)) { //dinersclub\n\t\treturn value.length === 14;\n\t}\n\tif (validTypes & 0x0010 && /^(2(014|149))/.test(value)) { //enroute\n\t\treturn value.length === 15;\n\t}\n\tif (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n\t\treturn value.length === 16;\n\t}\n\tif (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n\t\treturn value.length === 16;\n\t}\n\tif (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n\t\treturn value.length === 15;\n\t}\n\tif (validTypes & 0x0080) { //unknown\n\t\treturn true;\n\t}\n\treturn false;\n}, \"Please enter a valid credit card number.\");\n\n/**\n * Validates currencies with any given symbols by @jameslouiz\n * Symbols can be optional or required. Symbols required by default\n *\n * Usage examples:\n *  currency: [\"£\", false] - Use false for soft currency validation\n *  currency: [\"$\", false]\n *  currency: [\"RM\", false] - also works with text based symbols such as \"RM\" - Malaysia Ringgit etc\n *\n *  <input class=\"currencyInput\" name=\"currencyInput\">\n *\n * Soft symbol checking\n *  currencyInput: {\n *     currency: [\"$\", false]\n *  }\n *\n * Strict symbol checking (default)\n *  currencyInput: {\n *     currency: \"$\"\n *     //OR\n *     currency: [\"$\", true]\n *  }\n *\n * Multiple Symbols\n *  currencyInput: {\n *     currency: \"$,£,¢\"\n *  }\n */\n$.validator.addMethod(\"currency\", function(value, element, param) {\n    var isParamString = typeof param === \"string\",\n        symbol = isParamString ? param : param[0],\n        soft = isParamString ? true : param[1],\n        regex;\n\n    symbol = symbol.replace(/,/g, \"\");\n    symbol = soft ? symbol + \"]\" : symbol + \"]?\";\n    regex = \"^[\" + symbol + \"([1-9]{1}[0-9]{0,2}(\\\\,[0-9]{3})*(\\\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\\\.[0-9]{0,2})?|0(\\\\.[0-9]{0,2})?|(\\\\.[0-9]{1,2})?)$\";\n    regex = new RegExp(regex);\n    return this.optional(element) || regex.test(value);\n\n}, \"Please specify a valid currency\");\n\n$.validator.addMethod(\"dateFA\", function(value, element) {\n\treturn this.optional(element) || /^[1-4]\\d{3}\\/((0?[1-6]\\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\\/(30|([1-2][0-9])|(0?[1-9]))))$/.test(value);\n}, $.validator.messages.date);\n\n/**\n * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.\n *\n * @example $.validator.methods.date(\"01/01/1900\")\n * @result true\n *\n * @example $.validator.methods.date(\"01/13/1990\")\n * @result false\n *\n * @example $.validator.methods.date(\"01.01.1900\")\n * @result false\n *\n * @example <input name=\"pippo\" class=\"{dateITA:true}\" />\n * @desc Declares an optional input element whose value must be a valid date.\n *\n * @name $.validator.methods.dateITA\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod(\"dateITA\", function(value, element) {\n\tvar check = false,\n\t\tre = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n\t\tadata, gg, mm, aaaa, xdata;\n\tif ( re.test(value)) {\n\t\tadata = value.split(\"/\");\n\t\tgg = parseInt(adata[0], 10);\n\t\tmm = parseInt(adata[1], 10);\n\t\taaaa = parseInt(adata[2], 10);\n\t\txdata = new Date(Date.UTC(aaaa, mm - 1, gg, 12, 0, 0, 0));\n\t\tif ( ( xdata.getUTCFullYear() === aaaa ) && ( xdata.getUTCMonth () === mm - 1 ) && ( xdata.getUTCDate() === gg ) ) {\n\t\t\tcheck = true;\n\t\t} else {\n\t\t\tcheck = false;\n\t\t}\n\t} else {\n\t\tcheck = false;\n\t}\n\treturn this.optional(element) || check;\n}, $.validator.messages.date);\n\n$.validator.addMethod(\"dateNL\", function(value, element) {\n\treturn this.optional(element) || /^(0?[1-9]|[12]\\d|3[01])[\\.\\/\\-](0?[1-9]|1[012])[\\.\\/\\-]([12]\\d)?(\\d\\d)$/.test(value);\n}, $.validator.messages.date);\n\n// Older \"accept\" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept\n$.validator.addMethod(\"extension\", function(value, element, param) {\n\tparam = typeof param === \"string\" ? param.replace(/,/g, \"|\") : \"png|jpe?g|gif\";\n\treturn this.optional(element) || value.match(new RegExp(\"\\\\.(\" + param + \")$\", \"i\"));\n}, $.validator.format(\"Please enter a value with a valid extension.\"));\n\n/**\n * Dutch giro account numbers (not bank numbers) have max 7 digits\n */\n$.validator.addMethod(\"giroaccountNL\", function(value, element) {\n\treturn this.optional(element) || /^[0-9]{1,7}$/.test(value);\n}, \"Please specify a valid giro account number\");\n\n/**\n * IBAN is the international bank account number.\n * It has a country - specific format, that is checked here too\n */\n$.validator.addMethod(\"iban\", function(value, element) {\n\t// some quick simple tests to prevent needless work\n\tif (this.optional(element)) {\n\t\treturn true;\n\t}\n\n\t// remove spaces and to upper case\n\tvar iban = value.replace(/ /g, \"\").toUpperCase(),\n\t\tibancheckdigits = \"\",\n\t\tleadingZeroes = true,\n\t\tcRest = \"\",\n\t\tcOperator = \"\",\n\t\tcountrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;\n\n\t// check the country code and find the country specific format\n\tcountrycode = iban.substring(0, 2);\n\tbbancountrypatterns = {\n\t\t\"AL\": \"\\\\d{8}[\\\\dA-Z]{16}\",\n\t\t\"AD\": \"\\\\d{8}[\\\\dA-Z]{12}\",\n\t\t\"AT\": \"\\\\d{16}\",\n\t\t\"AZ\": \"[\\\\dA-Z]{4}\\\\d{20}\",\n\t\t\"BE\": \"\\\\d{12}\",\n\t\t\"BH\": \"[A-Z]{4}[\\\\dA-Z]{14}\",\n\t\t\"BA\": \"\\\\d{16}\",\n\t\t\"BR\": \"\\\\d{23}[A-Z][\\\\dA-Z]\",\n\t\t\"BG\": \"[A-Z]{4}\\\\d{6}[\\\\dA-Z]{8}\",\n\t\t\"CR\": \"\\\\d{17}\",\n\t\t\"HR\": \"\\\\d{17}\",\n\t\t\"CY\": \"\\\\d{8}[\\\\dA-Z]{16}\",\n\t\t\"CZ\": \"\\\\d{20}\",\n\t\t\"DK\": \"\\\\d{14}\",\n\t\t\"DO\": \"[A-Z]{4}\\\\d{20}\",\n\t\t\"EE\": \"\\\\d{16}\",\n\t\t\"FO\": \"\\\\d{14}\",\n\t\t\"FI\": \"\\\\d{14}\",\n\t\t\"FR\": \"\\\\d{10}[\\\\dA-Z]{11}\\\\d{2}\",\n\t\t\"GE\": \"[\\\\dA-Z]{2}\\\\d{16}\",\n\t\t\"DE\": \"\\\\d{18}\",\n\t\t\"GI\": \"[A-Z]{4}[\\\\dA-Z]{15}\",\n\t\t\"GR\": \"\\\\d{7}[\\\\dA-Z]{16}\",\n\t\t\"GL\": \"\\\\d{14}\",\n\t\t\"GT\": \"[\\\\dA-Z]{4}[\\\\dA-Z]{20}\",\n\t\t\"HU\": \"\\\\d{24}\",\n\t\t\"IS\": \"\\\\d{22}\",\n\t\t\"IE\": \"[\\\\dA-Z]{4}\\\\d{14}\",\n\t\t\"IL\": \"\\\\d{19}\",\n\t\t\"IT\": \"[A-Z]\\\\d{10}[\\\\dA-Z]{12}\",\n\t\t\"KZ\": \"\\\\d{3}[\\\\dA-Z]{13}\",\n\t\t\"KW\": \"[A-Z]{4}[\\\\dA-Z]{22}\",\n\t\t\"LV\": \"[A-Z]{4}[\\\\dA-Z]{13}\",\n\t\t\"LB\": \"\\\\d{4}[\\\\dA-Z]{20}\",\n\t\t\"LI\": \"\\\\d{5}[\\\\dA-Z]{12}\",\n\t\t\"LT\": \"\\\\d{16}\",\n\t\t\"LU\": \"\\\\d{3}[\\\\dA-Z]{13}\",\n\t\t\"MK\": \"\\\\d{3}[\\\\dA-Z]{10}\\\\d{2}\",\n\t\t\"MT\": \"[A-Z]{4}\\\\d{5}[\\\\dA-Z]{18}\",\n\t\t\"MR\": \"\\\\d{23}\",\n\t\t\"MU\": \"[A-Z]{4}\\\\d{19}[A-Z]{3}\",\n\t\t\"MC\": \"\\\\d{10}[\\\\dA-Z]{11}\\\\d{2}\",\n\t\t\"MD\": \"[\\\\dA-Z]{2}\\\\d{18}\",\n\t\t\"ME\": \"\\\\d{18}\",\n\t\t\"NL\": \"[A-Z]{4}\\\\d{10}\",\n\t\t\"NO\": \"\\\\d{11}\",\n\t\t\"PK\": \"[\\\\dA-Z]{4}\\\\d{16}\",\n\t\t\"PS\": \"[\\\\dA-Z]{4}\\\\d{21}\",\n\t\t\"PL\": \"\\\\d{24}\",\n\t\t\"PT\": \"\\\\d{21}\",\n\t\t\"RO\": \"[A-Z]{4}[\\\\dA-Z]{16}\",\n\t\t\"SM\": \"[A-Z]\\\\d{10}[\\\\dA-Z]{12}\",\n\t\t\"SA\": \"\\\\d{2}[\\\\dA-Z]{18}\",\n\t\t\"RS\": \"\\\\d{18}\",\n\t\t\"SK\": \"\\\\d{20}\",\n\t\t\"SI\": \"\\\\d{15}\",\n\t\t\"ES\": \"\\\\d{20}\",\n\t\t\"SE\": \"\\\\d{20}\",\n\t\t\"CH\": \"\\\\d{5}[\\\\dA-Z]{12}\",\n\t\t\"TN\": \"\\\\d{20}\",\n\t\t\"TR\": \"\\\\d{5}[\\\\dA-Z]{17}\",\n\t\t\"AE\": \"\\\\d{3}\\\\d{16}\",\n\t\t\"GB\": \"[A-Z]{4}\\\\d{14}\",\n\t\t\"VG\": \"[\\\\dA-Z]{4}\\\\d{16}\"\n\t};\n\n\tbbanpattern = bbancountrypatterns[countrycode];\n\t// As new countries will start using IBAN in the\n\t// future, we only check if the countrycode is known.\n\t// This prevents false negatives, while almost all\n\t// false positives introduced by this, will be caught\n\t// by the checksum validation below anyway.\n\t// Strict checking should return FALSE for unknown\n\t// countries.\n\tif (typeof bbanpattern !== \"undefined\") {\n\t\tibanregexp = new RegExp(\"^[A-Z]{2}\\\\d{2}\" + bbanpattern + \"$\", \"\");\n\t\tif (!(ibanregexp.test(iban))) {\n\t\t\treturn false; // invalid country specific format\n\t\t}\n\t}\n\n\t// now check the checksum, first convert to digits\n\tibancheck = iban.substring(4, iban.length) + iban.substring(0, 4);\n\tfor (i = 0; i < ibancheck.length; i++) {\n\t\tcharAt = ibancheck.charAt(i);\n\t\tif (charAt !== \"0\") {\n\t\t\tleadingZeroes = false;\n\t\t}\n\t\tif (!leadingZeroes) {\n\t\t\tibancheckdigits += \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\".indexOf(charAt);\n\t\t}\n\t}\n\n\t// calculate the result of: ibancheckdigits % 97\n\tfor (p = 0; p < ibancheckdigits.length; p++) {\n\t\tcChar = ibancheckdigits.charAt(p);\n\t\tcOperator = \"\" + cRest + \"\" + cChar;\n\t\tcRest = cOperator % 97;\n\t}\n\treturn cRest === 1;\n}, \"Please specify a valid IBAN\");\n\n$.validator.addMethod(\"integer\", function(value, element) {\n\treturn this.optional(element) || /^-?\\d+$/.test(value);\n}, \"A positive or negative non-decimal number please\");\n\n$.validator.addMethod(\"ipv4\", function(value, element) {\n\treturn this.optional(element) || /^(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/i.test(value);\n}, \"Please enter a valid IP v4 address.\");\n\n$.validator.addMethod(\"ipv6\", function(value, element) {\n\treturn this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);\n}, \"Please enter a valid IP v6 address.\");\n\n$.validator.addMethod(\"lettersonly\", function(value, element) {\n\treturn this.optional(element) || /^[a-z]+$/i.test(value);\n}, \"Letters only please\");\n\n$.validator.addMethod(\"letterswithbasicpunc\", function(value, element) {\n\treturn this.optional(element) || /^[a-z\\-.,()'\"\\s]+$/i.test(value);\n}, \"Letters or punctuation only please\");\n\n$.validator.addMethod(\"mobileNL\", function(value, element) {\n\treturn this.optional(element) || /^((\\+|00(\\s|\\s?\\-\\s?)?)31(\\s|\\s?\\-\\s?)?(\\(0\\)[\\-\\s]?)?|0)6((\\s|\\s?\\-\\s?)?[0-9]){8}$/.test(value);\n}, \"Please specify a valid mobile number\");\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n$.validator.addMethod(\"mobileUK\", function(phone_number, element) {\n\tphone_number = phone_number.replace(/\\(|\\)|\\s+|-/g, \"\");\n\treturn this.optional(element) || phone_number.length > 9 &&\n\t\tphone_number.match(/^(?:(?:(?:00\\s?|\\+)44\\s?|0)7(?:[1345789]\\d{2}|624)\\s?\\d{3}\\s?\\d{3})$/);\n}, \"Please specify a valid mobile number\");\n\n/*\n * The número de identidad de extranjero ( NIE )is a code used to identify the non-nationals in Spain\n */\n$.validator.addMethod( \"nieES\", function( value ) {\n\t\"use strict\";\n\n\tvalue = value.toUpperCase();\n\n\t// Basic format test\n\tif ( !value.match( \"((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)\" ) ) {\n\t\treturn false;\n\t}\n\n\t// Test NIE\n\t//T\n\tif ( /^[T]{1}/.test( value ) ) {\n\t\treturn ( value[ 8 ] === /^[T]{1}[A-Z0-9]{8}$/.test( value ) );\n\t}\n\n\t//XYZ\n\tif ( /^[XYZ]{1}/.test( value ) ) {\n\t\treturn (\n\t\t\tvalue[ 8 ] === \"TRWAGMYFPDXBNJZSQVHLCKE\".charAt(\n\t\t\t\tvalue.replace( \"X\", \"0\" )\n\t\t\t\t\t.replace( \"Y\", \"1\" )\n\t\t\t\t\t.replace( \"Z\", \"2\" )\n\t\t\t\t\t.substring( 0, 8 ) % 23\n\t\t\t)\n\t\t);\n\t}\n\n\treturn false;\n\n}, \"Please specify a valid NIE number.\" );\n\n/*\n * The Número de Identificación Fiscal ( NIF ) is the way tax identification used in Spain for individuals\n */\n$.validator.addMethod( \"nifES\", function( value ) {\n\t\"use strict\";\n\n\tvalue = value.toUpperCase();\n\n\t// Basic format test\n\tif ( !value.match(\"((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)\") ) {\n\t\treturn false;\n\t}\n\n\t// Test NIF\n\tif ( /^[0-9]{8}[A-Z]{1}$/.test( value ) ) {\n\t\treturn ( \"TRWAGMYFPDXBNJZSQVHLCKE\".charAt( value.substring( 8, 0 ) % 23 ) === value.charAt( 8 ) );\n\t}\n\t// Test specials NIF (starts with K, L or M)\n\tif ( /^[KLM]{1}/.test( value ) ) {\n\t\treturn ( value[ 8 ] === String.fromCharCode( 64 ) );\n\t}\n\n\treturn false;\n\n}, \"Please specify a valid NIF number.\" );\n\njQuery.validator.addMethod( \"notEqualTo\", function( value, element, param ) {\n\treturn this.optional(element) || !$.validator.methods.equalTo.call( this, value, element, param );\n}, \"Please enter a different value, values must not be the same.\" );\n\n$.validator.addMethod(\"nowhitespace\", function(value, element) {\n\treturn this.optional(element) || /^\\S+$/i.test(value);\n}, \"No white space please\");\n\n/**\n* Return true if the field value matches the given format RegExp\n*\n* @example $.validator.methods.pattern(\"AR1004\",element,/^AR\\d{4}$/)\n* @result true\n*\n* @example $.validator.methods.pattern(\"BR1004\",element,/^AR\\d{4}$/)\n* @result false\n*\n* @name $.validator.methods.pattern\n* @type Boolean\n* @cat Plugins/Validate/Methods\n*/\n$.validator.addMethod(\"pattern\", function(value, element, param) {\n\tif (this.optional(element)) {\n\t\treturn true;\n\t}\n\tif (typeof param === \"string\") {\n\t\tparam = new RegExp(\"^(?:\" + param + \")$\");\n\t}\n\treturn param.test(value);\n}, \"Invalid format.\");\n\n/**\n * Dutch phone numbers have 10 digits (or 11 and start with +31).\n */\n$.validator.addMethod(\"phoneNL\", function(value, element) {\n\treturn this.optional(element) || /^((\\+|00(\\s|\\s?\\-\\s?)?)31(\\s|\\s?\\-\\s?)?(\\(0\\)[\\-\\s]?)?|0)[1-9]((\\s|\\s?\\-\\s?)?[0-9]){8}$/.test(value);\n}, \"Please specify a valid phone number.\");\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n$.validator.addMethod(\"phoneUK\", function(phone_number, element) {\n\tphone_number = phone_number.replace(/\\(|\\)|\\s+|-/g, \"\");\n\treturn this.optional(element) || phone_number.length > 9 &&\n\t\tphone_number.match(/^(?:(?:(?:00\\s?|\\+)44\\s?)|(?:\\(?0))(?:\\d{2}\\)?\\s?\\d{4}\\s?\\d{4}|\\d{3}\\)?\\s?\\d{3}\\s?\\d{3,4}|\\d{4}\\)?\\s?(?:\\d{5}|\\d{3}\\s?\\d{3})|\\d{5}\\)?\\s?\\d{4,5})$/);\n}, \"Please specify a valid phone number\");\n\n/**\n * matches US phone number format\n *\n * where the area code may not start with 1 and the prefix may not start with 1\n * allows '-' or ' ' as a separator and allows parens around area code\n * some people may want to put a '1' in front of their number\n *\n * 1(212)-999-2345 or\n * 212 999 2344 or\n * 212-999-0983\n *\n * but not\n * 111-123-5434\n * and not\n * 212 123 4567\n */\n$.validator.addMethod(\"phoneUS\", function(phone_number, element) {\n\tphone_number = phone_number.replace(/\\s+/g, \"\");\n\treturn this.optional(element) || phone_number.length > 9 &&\n\t\tphone_number.match(/^(\\+?1-?)?(\\([2-9]([02-9]\\d|1[02-9])\\)|[2-9]([02-9]\\d|1[02-9]))-?[2-9]([02-9]\\d|1[02-9])-?\\d{4}$/);\n}, \"Please specify a valid phone number\");\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n//Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers\n$.validator.addMethod(\"phonesUK\", function(phone_number, element) {\n\tphone_number = phone_number.replace(/\\(|\\)|\\s+|-/g, \"\");\n\treturn this.optional(element) || phone_number.length > 9 &&\n\t\tphone_number.match(/^(?:(?:(?:00\\s?|\\+)44\\s?|0)(?:1\\d{8,9}|[23]\\d{9}|7(?:[1345789]\\d{8}|624\\d{6})))$/);\n}, \"Please specify a valid uk phone number\");\n\n/**\n * Matches a valid Canadian Postal Code\n *\n * @example jQuery.validator.methods.postalCodeCA( \"H0H 0H0\", element )\n * @result true\n *\n * @example jQuery.validator.methods.postalCodeCA( \"H0H0H0\", element )\n * @result false\n *\n * @name jQuery.validator.methods.postalCodeCA\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod( \"postalCodeCA\", function( value, element ) {\n\treturn this.optional( element ) || /^[ABCEGHJKLMNPRSTVXY]\\d[A-Z] \\d[A-Z]\\d$/.test( value );\n}, \"Please specify a valid postal code\" );\n\n/*\n* Valida CEPs do brasileiros:\n*\n* Formatos aceitos:\n* 99999-999\n* 99.999-999\n* 99999999\n*/\n$.validator.addMethod(\"postalcodeBR\", function(cep_value, element) {\n\treturn this.optional(element) || /^\\d{2}.\\d{3}-\\d{3}?$|^\\d{5}-?\\d{3}?$/.test( cep_value );\n}, \"Informe um CEP válido.\");\n\n/* Matches Italian postcode (CAP) */\n$.validator.addMethod(\"postalcodeIT\", function(value, element) {\n\treturn this.optional(element) || /^\\d{5}$/.test(value);\n}, \"Please specify a valid postal code\");\n\n$.validator.addMethod(\"postalcodeNL\", function(value, element) {\n\treturn this.optional(element) || /^[1-9][0-9]{3}\\s?[a-zA-Z]{2}$/.test(value);\n}, \"Please specify a valid postal code\");\n\n// Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK)\n$.validator.addMethod(\"postcodeUK\", function(value, element) {\n\treturn this.optional(element) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\\s?(0AA))$/i.test(value);\n}, \"Please specify a valid UK postcode\");\n\n/*\n * Lets you say \"at least X inputs that match selector Y must be filled.\"\n *\n * The end result is that neither of these inputs:\n *\n *\t<input class=\"productinfo\" name=\"partnumber\">\n *\t<input class=\"productinfo\" name=\"description\">\n *\n *\t...will validate unless at least one of them is filled.\n *\n * partnumber:\t{require_from_group: [1,\".productinfo\"]},\n * description: {require_from_group: [1,\".productinfo\"]}\n *\n * options[0]: number of fields that must be filled in the group\n * options[1]: CSS selector that defines the group of conditionally required fields\n */\n$.validator.addMethod(\"require_from_group\", function(value, element, options) {\n\tvar $fields = $(options[1], element.form),\n\t\t$fieldsFirst = $fields.eq(0),\n\t\tvalidator = $fieldsFirst.data(\"valid_req_grp\") ? $fieldsFirst.data(\"valid_req_grp\") : $.extend({}, this),\n\t\tisValid = $fields.filter(function() {\n\t\t\treturn validator.elementValue(this);\n\t\t}).length >= options[0];\n\n\t// Store the cloned validator for future validation\n\t$fieldsFirst.data(\"valid_req_grp\", validator);\n\n\t// If element isn't being validated, run each require_from_group field's validation rules\n\tif (!$(element).data(\"being_validated\")) {\n\t\t$fields.data(\"being_validated\", true);\n\t\t$fields.each(function() {\n\t\t\tvalidator.element(this);\n\t\t});\n\t\t$fields.data(\"being_validated\", false);\n\t}\n\treturn isValid;\n}, $.validator.format(\"Please fill at least {0} of these fields.\"));\n\n/*\n * Lets you say \"either at least X inputs that match selector Y must be filled,\n * OR they must all be skipped (left blank).\"\n *\n * The end result, is that none of these inputs:\n *\n *\t<input class=\"productinfo\" name=\"partnumber\">\n *\t<input class=\"productinfo\" name=\"description\">\n *\t<input class=\"productinfo\" name=\"color\">\n *\n *\t...will validate unless either at least two of them are filled,\n *\tOR none of them are.\n *\n * partnumber:\t{skip_or_fill_minimum: [2,\".productinfo\"]},\n * description: {skip_or_fill_minimum: [2,\".productinfo\"]},\n * color:\t\t{skip_or_fill_minimum: [2,\".productinfo\"]}\n *\n * options[0]: number of fields that must be filled in the group\n * options[1]: CSS selector that defines the group of conditionally required fields\n *\n */\n$.validator.addMethod(\"skip_or_fill_minimum\", function(value, element, options) {\n\tvar $fields = $(options[1], element.form),\n\t\t$fieldsFirst = $fields.eq(0),\n\t\tvalidator = $fieldsFirst.data(\"valid_skip\") ? $fieldsFirst.data(\"valid_skip\") : $.extend({}, this),\n\t\tnumberFilled = $fields.filter(function() {\n\t\t\treturn validator.elementValue(this);\n\t\t}).length,\n\t\tisValid = numberFilled === 0 || numberFilled >= options[0];\n\n\t// Store the cloned validator for future validation\n\t$fieldsFirst.data(\"valid_skip\", validator);\n\n\t// If element isn't being validated, run each skip_or_fill_minimum field's validation rules\n\tif (!$(element).data(\"being_validated\")) {\n\t\t$fields.data(\"being_validated\", true);\n\t\t$fields.each(function() {\n\t\t\tvalidator.element(this);\n\t\t});\n\t\t$fields.data(\"being_validated\", false);\n\t}\n\treturn isValid;\n}, $.validator.format(\"Please either skip these fields or fill at least {0} of them.\"));\n\n/* Validates US States and/or Territories by @jdforsythe\n * Can be case insensitive or require capitalization - default is case insensitive\n * Can include US Territories or not - default does not\n * Can include US Military postal abbreviations (AA, AE, AP) - default does not\n *\n * Note: \"States\" always includes DC (District of Colombia)\n *\n * Usage examples:\n *\n *  This is the default - case insensitive, no territories, no military zones\n *  stateInput: {\n *     caseSensitive: false,\n *     includeTerritories: false,\n *     includeMilitary: false\n *  }\n *\n *  Only allow capital letters, no territories, no military zones\n *  stateInput: {\n *     caseSensitive: false\n *  }\n *\n *  Case insensitive, include territories but not military zones\n *  stateInput: {\n *     includeTerritories: true\n *  }\n *\n *  Only allow capital letters, include territories and military zones\n *  stateInput: {\n *     caseSensitive: true,\n *     includeTerritories: true,\n *     includeMilitary: true\n *  }\n *\n *\n *\n */\n\n$.validator.addMethod(\"stateUS\", function(value, element, options) {\n\tvar isDefault = typeof options === \"undefined\",\n\t\tcaseSensitive = ( isDefault || typeof options.caseSensitive === \"undefined\" ) ? false : options.caseSensitive,\n\t\tincludeTerritories = ( isDefault || typeof options.includeTerritories === \"undefined\" ) ? false : options.includeTerritories,\n\t\tincludeMilitary = ( isDefault || typeof options.includeMilitary === \"undefined\" ) ? false : options.includeMilitary,\n\t\tregex;\n\n\tif (!includeTerritories && !includeMilitary) {\n\t\tregex = \"^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$\";\n\t} else if (includeTerritories && includeMilitary) {\n\t\tregex = \"^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$\";\n\t} else if (includeTerritories) {\n\t\tregex = \"^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$\";\n\t} else {\n\t\tregex = \"^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$\";\n\t}\n\n\tregex = caseSensitive ? new RegExp(regex) : new RegExp(regex, \"i\");\n\treturn this.optional(element) || regex.test(value);\n},\n\"Please specify a valid state\");\n\n// TODO check if value starts with <, otherwise don't try stripping anything\n$.validator.addMethod(\"strippedminlength\", function(value, element, param) {\n\treturn $(value).text().length >= param;\n}, $.validator.format(\"Please enter at least {0} characters\"));\n\n$.validator.addMethod(\"time\", function(value, element) {\n\treturn this.optional(element) || /^([01]\\d|2[0-3]|[0-9])(:[0-5]\\d){1,2}$/.test(value);\n}, \"Please enter a valid time, between 00:00 and 23:59\");\n\n$.validator.addMethod(\"time12h\", function(value, element) {\n\treturn this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\\d){1,2}(\\ ?[AP]M))$/i.test(value);\n}, \"Please enter a valid time in 12-hour am/pm format\");\n\n// same as url, but TLD is optional\n$.validator.addMethod(\"url2\", function(value, element) {\n\treturn this.optional(element) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);\n}, $.validator.messages.url);\n\n/**\n * Return true, if the value is a valid vehicle identification number (VIN).\n *\n * Works with all kind of text inputs.\n *\n * @example <input type=\"text\" size=\"20\" name=\"VehicleID\" class=\"{required:true,vinUS:true}\" />\n * @desc Declares a required input element whose value must be a valid vehicle identification number.\n *\n * @name $.validator.methods.vinUS\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod(\"vinUS\", function(v) {\n\tif (v.length !== 17) {\n\t\treturn false;\n\t}\n\n\tvar LL = [ \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"J\", \"K\", \"L\", \"M\", \"N\", \"P\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\" ],\n\t\tVL = [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9 ],\n\t\tFL = [ 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 ],\n\t\trs = 0,\n\t\ti, n, d, f, cd, cdv;\n\n\tfor (i = 0; i < 17; i++) {\n\t\tf = FL[i];\n\t\td = v.slice(i, i + 1);\n\t\tif (i === 8) {\n\t\t\tcdv = d;\n\t\t}\n\t\tif (!isNaN(d)) {\n\t\t\td *= f;\n\t\t} else {\n\t\t\tfor (n = 0; n < LL.length; n++) {\n\t\t\t\tif (d.toUpperCase() === LL[n]) {\n\t\t\t\t\td = VL[n];\n\t\t\t\t\td *= f;\n\t\t\t\t\tif (isNaN(cdv) && n === 8) {\n\t\t\t\t\t\tcdv = LL[n];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs += d;\n\t}\n\tcd = rs % 11;\n\tif (cd === 10) {\n\t\tcd = \"X\";\n\t}\n\tif (cd === cdv) {\n\t\treturn true;\n\t}\n\treturn false;\n}, \"The specified vehicle identification number (VIN) is invalid.\");\n\n$.validator.addMethod(\"zipcodeUS\", function(value, element) {\n\treturn this.optional(element) || /^\\d{5}(-\\d{4})?$/.test(value);\n}, \"The specified US ZIP Code is invalid\");\n\n$.validator.addMethod(\"ziprange\", function(value, element) {\n\treturn this.optional(element) || /^90[2-5]\\d\\{2\\}-\\d{4}$/.test(value);\n}, \"Your ZIP-code must be in the range 902xx-xxxx to 905xx-xxxx\");\n\n}));"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation/dist/jquery.validate.js",
    "content": "/*!\n * jQuery Validation Plugin v1.14.0\n *\n * http://jqueryvalidation.org/\n *\n * Copyright (c) 2015 Jörn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\t\tdefine( [\"jquery\"], factory );\n\t} else {\n\t\tfactory( jQuery );\n\t}\n}(function( $ ) {\n\n$.extend($.fn, {\n\t// http://jqueryvalidation.org/validate/\n\tvalidate: function( options ) {\n\n\t\t// if nothing is selected, return nothing; can't chain anyway\n\t\tif ( !this.length ) {\n\t\t\tif ( options && options.debug && window.console ) {\n\t\t\t\tconsole.warn( \"Nothing selected, can't validate, returning nothing.\" );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// check if a validator for this form was already created\n\t\tvar validator = $.data( this[ 0 ], \"validator\" );\n\t\tif ( validator ) {\n\t\t\treturn validator;\n\t\t}\n\n\t\t// Add novalidate tag if HTML5.\n\t\tthis.attr( \"novalidate\", \"novalidate\" );\n\n\t\tvalidator = new $.validator( options, this[ 0 ] );\n\t\t$.data( this[ 0 ], \"validator\", validator );\n\n\t\tif ( validator.settings.onsubmit ) {\n\n\t\t\tthis.on( \"click.validate\", \":submit\", function( event ) {\n\t\t\t\tif ( validator.settings.submitHandler ) {\n\t\t\t\t\tvalidator.submitButton = event.target;\n\t\t\t\t}\n\n\t\t\t\t// allow suppressing validation by adding a cancel class to the submit button\n\t\t\t\tif ( $( this ).hasClass( \"cancel\" ) ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\n\t\t\t\t// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button\n\t\t\t\tif ( $( this ).attr( \"formnovalidate\" ) !== undefined ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// validate the form on submit\n\t\t\tthis.on( \"submit.validate\", function( event ) {\n\t\t\t\tif ( validator.settings.debug ) {\n\t\t\t\t\t// prevent form submit to be able to see console output\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t\tfunction handle() {\n\t\t\t\t\tvar hidden, result;\n\t\t\t\t\tif ( validator.settings.submitHandler ) {\n\t\t\t\t\t\tif ( validator.submitButton ) {\n\t\t\t\t\t\t\t// insert a hidden input as a replacement for the missing submit button\n\t\t\t\t\t\t\thidden = $( \"<input type='hidden'/>\" )\n\t\t\t\t\t\t\t\t.attr( \"name\", validator.submitButton.name )\n\t\t\t\t\t\t\t\t.val( $( validator.submitButton ).val() )\n\t\t\t\t\t\t\t\t.appendTo( validator.currentForm );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult = validator.settings.submitHandler.call( validator, validator.currentForm, event );\n\t\t\t\t\t\tif ( validator.submitButton ) {\n\t\t\t\t\t\t\t// and clean up afterwards; thanks to no-block-scope, hidden can be referenced\n\t\t\t\t\t\t\thidden.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( result !== undefined ) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// prevent submit for invalid forms or custom submit handlers\n\t\t\t\tif ( validator.cancelSubmit ) {\n\t\t\t\t\tvalidator.cancelSubmit = false;\n\t\t\t\t\treturn handle();\n\t\t\t\t}\n\t\t\t\tif ( validator.form() ) {\n\t\t\t\t\tif ( validator.pendingRequest ) {\n\t\t\t\t\t\tvalidator.formSubmitted = true;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn handle();\n\t\t\t\t} else {\n\t\t\t\t\tvalidator.focusInvalid();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn validator;\n\t},\n\t// http://jqueryvalidation.org/valid/\n\tvalid: function() {\n\t\tvar valid, validator, errorList;\n\n\t\tif ( $( this[ 0 ] ).is( \"form\" ) ) {\n\t\t\tvalid = this.validate().form();\n\t\t} else {\n\t\t\terrorList = [];\n\t\t\tvalid = true;\n\t\t\tvalidator = $( this[ 0 ].form ).validate();\n\t\t\tthis.each( function() {\n\t\t\t\tvalid = validator.element( this ) && valid;\n\t\t\t\terrorList = errorList.concat( validator.errorList );\n\t\t\t});\n\t\t\tvalidator.errorList = errorList;\n\t\t}\n\t\treturn valid;\n\t},\n\n\t// http://jqueryvalidation.org/rules/\n\trules: function( command, argument ) {\n\t\tvar element = this[ 0 ],\n\t\t\tsettings, staticRules, existingRules, data, param, filtered;\n\n\t\tif ( command ) {\n\t\t\tsettings = $.data( element.form, \"validator\" ).settings;\n\t\t\tstaticRules = settings.rules;\n\t\t\texistingRules = $.validator.staticRules( element );\n\t\t\tswitch ( command ) {\n\t\t\tcase \"add\":\n\t\t\t\t$.extend( existingRules, $.validator.normalizeRule( argument ) );\n\t\t\t\t// remove messages from rules, but allow them to be set separately\n\t\t\t\tdelete existingRules.messages;\n\t\t\t\tstaticRules[ element.name ] = existingRules;\n\t\t\t\tif ( argument.messages ) {\n\t\t\t\t\tsettings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"remove\":\n\t\t\t\tif ( !argument ) {\n\t\t\t\t\tdelete staticRules[ element.name ];\n\t\t\t\t\treturn existingRules;\n\t\t\t\t}\n\t\t\t\tfiltered = {};\n\t\t\t\t$.each( argument.split( /\\s/ ), function( index, method ) {\n\t\t\t\t\tfiltered[ method ] = existingRules[ method ];\n\t\t\t\t\tdelete existingRules[ method ];\n\t\t\t\t\tif ( method === \"required\" ) {\n\t\t\t\t\t\t$( element ).removeAttr( \"aria-required\" );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn filtered;\n\t\t\t}\n\t\t}\n\n\t\tdata = $.validator.normalizeRules(\n\t\t$.extend(\n\t\t\t{},\n\t\t\t$.validator.classRules( element ),\n\t\t\t$.validator.attributeRules( element ),\n\t\t\t$.validator.dataRules( element ),\n\t\t\t$.validator.staticRules( element )\n\t\t), element );\n\n\t\t// make sure required is at front\n\t\tif ( data.required ) {\n\t\t\tparam = data.required;\n\t\t\tdelete data.required;\n\t\t\tdata = $.extend( { required: param }, data );\n\t\t\t$( element ).attr( \"aria-required\", \"true\" );\n\t\t}\n\n\t\t// make sure remote is at back\n\t\tif ( data.remote ) {\n\t\t\tparam = data.remote;\n\t\t\tdelete data.remote;\n\t\t\tdata = $.extend( data, { remote: param });\n\t\t}\n\n\t\treturn data;\n\t}\n});\n\n// Custom selectors\n$.extend( $.expr[ \":\" ], {\n\t// http://jqueryvalidation.org/blank-selector/\n\tblank: function( a ) {\n\t\treturn !$.trim( \"\" + $( a ).val() );\n\t},\n\t// http://jqueryvalidation.org/filled-selector/\n\tfilled: function( a ) {\n\t\treturn !!$.trim( \"\" + $( a ).val() );\n\t},\n\t// http://jqueryvalidation.org/unchecked-selector/\n\tunchecked: function( a ) {\n\t\treturn !$( a ).prop( \"checked\" );\n\t}\n});\n\n// constructor for validator\n$.validator = function( options, form ) {\n\tthis.settings = $.extend( true, {}, $.validator.defaults, options );\n\tthis.currentForm = form;\n\tthis.init();\n};\n\n// http://jqueryvalidation.org/jQuery.validator.format/\n$.validator.format = function( source, params ) {\n\tif ( arguments.length === 1 ) {\n\t\treturn function() {\n\t\t\tvar args = $.makeArray( arguments );\n\t\t\targs.unshift( source );\n\t\t\treturn $.validator.format.apply( this, args );\n\t\t};\n\t}\n\tif ( arguments.length > 2 && params.constructor !== Array  ) {\n\t\tparams = $.makeArray( arguments ).slice( 1 );\n\t}\n\tif ( params.constructor !== Array ) {\n\t\tparams = [ params ];\n\t}\n\t$.each( params, function( i, n ) {\n\t\tsource = source.replace( new RegExp( \"\\\\{\" + i + \"\\\\}\", \"g\" ), function() {\n\t\t\treturn n;\n\t\t});\n\t});\n\treturn source;\n};\n\n$.extend( $.validator, {\n\n\tdefaults: {\n\t\tmessages: {},\n\t\tgroups: {},\n\t\trules: {},\n\t\terrorClass: \"error\",\n\t\tvalidClass: \"valid\",\n\t\terrorElement: \"label\",\n\t\tfocusCleanup: false,\n\t\tfocusInvalid: true,\n\t\terrorContainer: $( [] ),\n\t\terrorLabelContainer: $( [] ),\n\t\tonsubmit: true,\n\t\tignore: \":hidden\",\n\t\tignoreTitle: false,\n\t\tonfocusin: function( element ) {\n\t\t\tthis.lastActive = element;\n\n\t\t\t// Hide error label and remove error class on focus if enabled\n\t\t\tif ( this.settings.focusCleanup ) {\n\t\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.hideThese( this.errorsFor( element ) );\n\t\t\t}\n\t\t},\n\t\tonfocusout: function( element ) {\n\t\t\tif ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonkeyup: function( element, event ) {\n\t\t\t// Avoid revalidate the field when pressing one of the following keys\n\t\t\t// Shift       => 16\n\t\t\t// Ctrl        => 17\n\t\t\t// Alt         => 18\n\t\t\t// Caps lock   => 20\n\t\t\t// End         => 35\n\t\t\t// Home        => 36\n\t\t\t// Left arrow  => 37\n\t\t\t// Up arrow    => 38\n\t\t\t// Right arrow => 39\n\t\t\t// Down arrow  => 40\n\t\t\t// Insert      => 45\n\t\t\t// Num lock    => 144\n\t\t\t// AltGr key   => 225\n\t\t\tvar excludedKeys = [\n\t\t\t\t16, 17, 18, 20, 35, 36, 37,\n\t\t\t\t38, 39, 40, 45, 144, 225\n\t\t\t];\n\n\t\t\tif ( event.which === 9 && this.elementValue( element ) === \"\" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {\n\t\t\t\treturn;\n\t\t\t} else if ( element.name in this.submitted || element === this.lastElement ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonclick: function( element ) {\n\t\t\t// click on selects, radiobuttons and checkboxes\n\t\t\tif ( element.name in this.submitted ) {\n\t\t\t\tthis.element( element );\n\n\t\t\t// or option elements, check parent select in that case\n\t\t\t} else if ( element.parentNode.name in this.submitted ) {\n\t\t\t\tthis.element( element.parentNode );\n\t\t\t}\n\t\t},\n\t\thighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).addClass( errorClass ).removeClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).addClass( errorClass ).removeClass( validClass );\n\t\t\t}\n\t\t},\n\t\tunhighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).removeClass( errorClass ).addClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).removeClass( errorClass ).addClass( validClass );\n\t\t\t}\n\t\t}\n\t},\n\n\t// http://jqueryvalidation.org/jQuery.validator.setDefaults/\n\tsetDefaults: function( settings ) {\n\t\t$.extend( $.validator.defaults, settings );\n\t},\n\n\tmessages: {\n\t\trequired: \"This field is required.\",\n\t\tremote: \"Please fix this field.\",\n\t\temail: \"Please enter a valid email address.\",\n\t\turl: \"Please enter a valid URL.\",\n\t\tdate: \"Please enter a valid date.\",\n\t\tdateISO: \"Please enter a valid date ( ISO ).\",\n\t\tnumber: \"Please enter a valid number.\",\n\t\tdigits: \"Please enter only digits.\",\n\t\tcreditcard: \"Please enter a valid credit card number.\",\n\t\tequalTo: \"Please enter the same value again.\",\n\t\tmaxlength: $.validator.format( \"Please enter no more than {0} characters.\" ),\n\t\tminlength: $.validator.format( \"Please enter at least {0} characters.\" ),\n\t\trangelength: $.validator.format( \"Please enter a value between {0} and {1} characters long.\" ),\n\t\trange: $.validator.format( \"Please enter a value between {0} and {1}.\" ),\n\t\tmax: $.validator.format( \"Please enter a value less than or equal to {0}.\" ),\n\t\tmin: $.validator.format( \"Please enter a value greater than or equal to {0}.\" )\n\t},\n\n\tautoCreateRanges: false,\n\n\tprototype: {\n\n\t\tinit: function() {\n\t\t\tthis.labelContainer = $( this.settings.errorLabelContainer );\n\t\t\tthis.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );\n\t\t\tthis.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );\n\t\t\tthis.submitted = {};\n\t\t\tthis.valueCache = {};\n\t\t\tthis.pendingRequest = 0;\n\t\t\tthis.pending = {};\n\t\t\tthis.invalid = {};\n\t\t\tthis.reset();\n\n\t\t\tvar groups = ( this.groups = {} ),\n\t\t\t\trules;\n\t\t\t$.each( this.settings.groups, function( key, value ) {\n\t\t\t\tif ( typeof value === \"string\" ) {\n\t\t\t\t\tvalue = value.split( /\\s/ );\n\t\t\t\t}\n\t\t\t\t$.each( value, function( index, name ) {\n\t\t\t\t\tgroups[ name ] = key;\n\t\t\t\t});\n\t\t\t});\n\t\t\trules = this.settings.rules;\n\t\t\t$.each( rules, function( key, value ) {\n\t\t\t\trules[ key ] = $.validator.normalizeRule( value );\n\t\t\t});\n\n\t\t\tfunction delegate( event ) {\n\t\t\t\tvar validator = $.data( this.form, \"validator\" ),\n\t\t\t\t\teventType = \"on\" + event.type.replace( /^validate/, \"\" ),\n\t\t\t\t\tsettings = validator.settings;\n\t\t\t\tif ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {\n\t\t\t\t\tsettings[ eventType ].call( validator, this, event );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$( this.currentForm )\n\t\t\t\t.on( \"focusin.validate focusout.validate keyup.validate\",\n\t\t\t\t\t\":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], \" +\n\t\t\t\t\t\"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], \" +\n\t\t\t\t\t\"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], \" +\n\t\t\t\t\t\"[type='radio'], [type='checkbox']\", delegate)\n\t\t\t\t// Support: Chrome, oldIE\n\t\t\t\t// \"select\" is provided as event.target when clicking a option\n\t\t\t\t.on(\"click.validate\", \"select, option, [type='radio'], [type='checkbox']\", delegate);\n\n\t\t\tif ( this.settings.invalidHandler ) {\n\t\t\t\t$( this.currentForm ).on( \"invalid-form.validate\", this.settings.invalidHandler );\n\t\t\t}\n\n\t\t\t// Add aria-required to any Static/Data/Class required fields before first validation\n\t\t\t// Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html\n\t\t\t$( this.currentForm ).find( \"[required], [data-rule-required], .required\" ).attr( \"aria-required\", \"true\" );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/Validator.form/\n\t\tform: function() {\n\t\t\tthis.checkForm();\n\t\t\t$.extend( this.submitted, this.errorMap );\n\t\t\tthis.invalid = $.extend({}, this.errorMap );\n\t\t\tif ( !this.valid() ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ]);\n\t\t\t}\n\t\t\tthis.showErrors();\n\t\t\treturn this.valid();\n\t\t},\n\n\t\tcheckForm: function() {\n\t\t\tthis.prepareForm();\n\t\t\tfor ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {\n\t\t\t\tthis.check( elements[ i ] );\n\t\t\t}\n\t\t\treturn this.valid();\n\t\t},\n\n\t\t// http://jqueryvalidation.org/Validator.element/\n\t\telement: function( element ) {\n\t\t\tvar cleanElement = this.clean( element ),\n\t\t\t\tcheckElement = this.validationTargetFor( cleanElement ),\n\t\t\t\tresult = true;\n\n\t\t\tthis.lastElement = checkElement;\n\n\t\t\tif ( checkElement === undefined ) {\n\t\t\t\tdelete this.invalid[ cleanElement.name ];\n\t\t\t} else {\n\t\t\t\tthis.prepareElement( checkElement );\n\t\t\t\tthis.currentElements = $( checkElement );\n\n\t\t\t\tresult = this.check( checkElement ) !== false;\n\t\t\t\tif ( result ) {\n\t\t\t\t\tdelete this.invalid[ checkElement.name ];\n\t\t\t\t} else {\n\t\t\t\t\tthis.invalid[ checkElement.name ] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Add aria-invalid status for screen readers\n\t\t\t$( element ).attr( \"aria-invalid\", !result );\n\n\t\t\tif ( !this.numberOfInvalids() ) {\n\t\t\t\t// Hide error containers on last error\n\t\t\t\tthis.toHide = this.toHide.add( this.containers );\n\t\t\t}\n\t\t\tthis.showErrors();\n\t\t\treturn result;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/Validator.showErrors/\n\t\tshowErrors: function( errors ) {\n\t\t\tif ( errors ) {\n\t\t\t\t// add items to error list and map\n\t\t\t\t$.extend( this.errorMap, errors );\n\t\t\t\tthis.errorList = [];\n\t\t\t\tfor ( var name in errors ) {\n\t\t\t\t\tthis.errorList.push({\n\t\t\t\t\t\tmessage: errors[ name ],\n\t\t\t\t\t\telement: this.findByName( name )[ 0 ]\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// remove items from success list\n\t\t\t\tthis.successList = $.grep( this.successList, function( element ) {\n\t\t\t\t\treturn !( element.name in errors );\n\t\t\t\t});\n\t\t\t}\n\t\t\tif ( this.settings.showErrors ) {\n\t\t\t\tthis.settings.showErrors.call( this, this.errorMap, this.errorList );\n\t\t\t} else {\n\t\t\t\tthis.defaultShowErrors();\n\t\t\t}\n\t\t},\n\n\t\t// http://jqueryvalidation.org/Validator.resetForm/\n\t\tresetForm: function() {\n\t\t\tif ( $.fn.resetForm ) {\n\t\t\t\t$( this.currentForm ).resetForm();\n\t\t\t}\n\t\t\tthis.submitted = {};\n\t\t\tthis.lastElement = null;\n\t\t\tthis.prepareForm();\n\t\t\tthis.hideErrors();\n\t\t\tvar i, elements = this.elements()\n\t\t\t\t.removeData( \"previousValue\" )\n\t\t\t\t.removeAttr( \"aria-invalid\" );\n\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0; elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ],\n\t\t\t\t\t\tthis.settings.errorClass, \"\" );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements.removeClass( this.settings.errorClass );\n\t\t\t}\n\t\t},\n\n\t\tnumberOfInvalids: function() {\n\t\t\treturn this.objectLength( this.invalid );\n\t\t},\n\n\t\tobjectLength: function( obj ) {\n\t\t\t/* jshint unused: false */\n\t\t\tvar count = 0,\n\t\t\t\ti;\n\t\t\tfor ( i in obj ) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\treturn count;\n\t\t},\n\n\t\thideErrors: function() {\n\t\t\tthis.hideThese( this.toHide );\n\t\t},\n\n\t\thideThese: function( errors ) {\n\t\t\terrors.not( this.containers ).text( \"\" );\n\t\t\tthis.addWrapper( errors ).hide();\n\t\t},\n\n\t\tvalid: function() {\n\t\t\treturn this.size() === 0;\n\t\t},\n\n\t\tsize: function() {\n\t\t\treturn this.errorList.length;\n\t\t},\n\n\t\tfocusInvalid: function() {\n\t\t\tif ( this.settings.focusInvalid ) {\n\t\t\t\ttry {\n\t\t\t\t\t$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [])\n\t\t\t\t\t.filter( \":visible\" )\n\t\t\t\t\t.focus()\n\t\t\t\t\t// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find\n\t\t\t\t\t.trigger( \"focusin\" );\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\t// ignore IE throwing errors when focusing hidden elements\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tfindLastActive: function() {\n\t\t\tvar lastActive = this.lastActive;\n\t\t\treturn lastActive && $.grep( this.errorList, function( n ) {\n\t\t\t\treturn n.element.name === lastActive.name;\n\t\t\t}).length === 1 && lastActive;\n\t\t},\n\n\t\telements: function() {\n\t\t\tvar validator = this,\n\t\t\t\trulesCache = {};\n\n\t\t\t// select all valid inputs inside the form (no submit or reset buttons)\n\t\t\treturn $( this.currentForm )\n\t\t\t.find( \"input, select, textarea\" )\n\t\t\t.not( \":submit, :reset, :image, :disabled\" )\n\t\t\t.not( this.settings.ignore )\n\t\t\t.filter( function() {\n\t\t\t\tif ( !this.name && validator.settings.debug && window.console ) {\n\t\t\t\t\tconsole.error( \"%o has no name assigned\", this );\n\t\t\t\t}\n\n\t\t\t\t// select only the first element for each name, and only those with rules specified\n\t\t\t\tif ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\trulesCache[ this.name ] = true;\n\t\t\t\treturn true;\n\t\t\t});\n\t\t},\n\n\t\tclean: function( selector ) {\n\t\t\treturn $( selector )[ 0 ];\n\t\t},\n\n\t\terrors: function() {\n\t\t\tvar errorClass = this.settings.errorClass.split( \" \" ).join( \".\" );\n\t\t\treturn $( this.settings.errorElement + \".\" + errorClass, this.errorContext );\n\t\t},\n\n\t\treset: function() {\n\t\t\tthis.successList = [];\n\t\t\tthis.errorList = [];\n\t\t\tthis.errorMap = {};\n\t\t\tthis.toShow = $( [] );\n\t\t\tthis.toHide = $( [] );\n\t\t\tthis.currentElements = $( [] );\n\t\t},\n\n\t\tprepareForm: function() {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errors().add( this.containers );\n\t\t},\n\n\t\tprepareElement: function( element ) {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errorsFor( element );\n\t\t},\n\n\t\telementValue: function( element ) {\n\t\t\tvar val,\n\t\t\t\t$element = $( element ),\n\t\t\t\ttype = element.type;\n\n\t\t\tif ( type === \"radio\" || type === \"checkbox\" ) {\n\t\t\t\treturn this.findByName( element.name ).filter(\":checked\").val();\n\t\t\t} else if ( type === \"number\" && typeof element.validity !== \"undefined\" ) {\n\t\t\t\treturn element.validity.badInput ? false : $element.val();\n\t\t\t}\n\n\t\t\tval = $element.val();\n\t\t\tif ( typeof val === \"string\" ) {\n\t\t\t\treturn val.replace(/\\r/g, \"\" );\n\t\t\t}\n\t\t\treturn val;\n\t\t},\n\n\t\tcheck: function( element ) {\n\t\t\telement = this.validationTargetFor( this.clean( element ) );\n\n\t\t\tvar rules = $( element ).rules(),\n\t\t\t\trulesCount = $.map( rules, function( n, i ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}).length,\n\t\t\t\tdependencyMismatch = false,\n\t\t\t\tval = this.elementValue( element ),\n\t\t\t\tresult, method, rule;\n\n\t\t\tfor ( method in rules ) {\n\t\t\t\trule = { method: method, parameters: rules[ method ] };\n\t\t\t\ttry {\n\n\t\t\t\t\tresult = $.validator.methods[ method ].call( this, val, element, rule.parameters );\n\n\t\t\t\t\t// if a method indicates that the field is optional and therefore valid,\n\t\t\t\t\t// don't mark it as valid when there are no other rules\n\t\t\t\t\tif ( result === \"dependency-mismatch\" && rulesCount === 1 ) {\n\t\t\t\t\t\tdependencyMismatch = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tdependencyMismatch = false;\n\n\t\t\t\t\tif ( result === \"pending\" ) {\n\t\t\t\t\t\tthis.toHide = this.toHide.not( this.errorsFor( element ) );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !result ) {\n\t\t\t\t\t\tthis.formatAndAdd( element, rule );\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\tif ( this.settings.debug && window.console ) {\n\t\t\t\t\t\tconsole.log( \"Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\", e );\n\t\t\t\t\t}\n\t\t\t\t\tif ( e instanceof TypeError ) {\n\t\t\t\t\t\te.message += \".  Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\";\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( dependencyMismatch ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( this.objectLength( rules ) ) {\n\t\t\t\tthis.successList.push( element );\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t// return the custom message for the given element and validation method\n\t\t// specified in the element's HTML5 data attribute\n\t\t// return the generic message if present and no method specific message is present\n\t\tcustomDataMessage: function( element, method ) {\n\t\t\treturn $( element ).data( \"msg\" + method.charAt( 0 ).toUpperCase() +\n\t\t\t\tmethod.substring( 1 ).toLowerCase() ) || $( element ).data( \"msg\" );\n\t\t},\n\n\t\t// return the custom message for the given element name and validation method\n\t\tcustomMessage: function( name, method ) {\n\t\t\tvar m = this.settings.messages[ name ];\n\t\t\treturn m && ( m.constructor === String ? m : m[ method ]);\n\t\t},\n\n\t\t// return the first defined argument, allowing empty strings\n\t\tfindDefined: function() {\n\t\t\tfor ( var i = 0; i < arguments.length; i++) {\n\t\t\t\tif ( arguments[ i ] !== undefined ) {\n\t\t\t\t\treturn arguments[ i ];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\n\t\tdefaultMessage: function( element, method ) {\n\t\t\treturn this.findDefined(\n\t\t\t\tthis.customMessage( element.name, method ),\n\t\t\t\tthis.customDataMessage( element, method ),\n\t\t\t\t// title is never undefined, so handle empty string as undefined\n\t\t\t\t!this.settings.ignoreTitle && element.title || undefined,\n\t\t\t\t$.validator.messages[ method ],\n\t\t\t\t\"<strong>Warning: No message defined for \" + element.name + \"</strong>\"\n\t\t\t);\n\t\t},\n\n\t\tformatAndAdd: function( element, rule ) {\n\t\t\tvar message = this.defaultMessage( element, rule.method ),\n\t\t\t\ttheregex = /\\$?\\{(\\d+)\\}/g;\n\t\t\tif ( typeof message === \"function\" ) {\n\t\t\t\tmessage = message.call( this, rule.parameters, element );\n\t\t\t} else if ( theregex.test( message ) ) {\n\t\t\t\tmessage = $.validator.format( message.replace( theregex, \"{$1}\" ), rule.parameters );\n\t\t\t}\n\t\t\tthis.errorList.push({\n\t\t\t\tmessage: message,\n\t\t\t\telement: element,\n\t\t\t\tmethod: rule.method\n\t\t\t});\n\n\t\t\tthis.errorMap[ element.name ] = message;\n\t\t\tthis.submitted[ element.name ] = message;\n\t\t},\n\n\t\taddWrapper: function( toToggle ) {\n\t\t\tif ( this.settings.wrapper ) {\n\t\t\t\ttoToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );\n\t\t\t}\n\t\t\treturn toToggle;\n\t\t},\n\n\t\tdefaultShowErrors: function() {\n\t\t\tvar i, elements, error;\n\t\t\tfor ( i = 0; this.errorList[ i ]; i++ ) {\n\t\t\t\terror = this.errorList[ i ];\n\t\t\t\tif ( this.settings.highlight ) {\n\t\t\t\t\tthis.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.showLabel( error.element, error.message );\n\t\t\t}\n\t\t\tif ( this.errorList.length ) {\n\t\t\t\tthis.toShow = this.toShow.add( this.containers );\n\t\t\t}\n\t\t\tif ( this.settings.success ) {\n\t\t\t\tfor ( i = 0; this.successList[ i ]; i++ ) {\n\t\t\t\t\tthis.showLabel( this.successList[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toHide = this.toHide.not( this.toShow );\n\t\t\tthis.hideErrors();\n\t\t\tthis.addWrapper( this.toShow ).show();\n\t\t},\n\n\t\tvalidElements: function() {\n\t\t\treturn this.currentElements.not( this.invalidElements() );\n\t\t},\n\n\t\tinvalidElements: function() {\n\t\t\treturn $( this.errorList ).map(function() {\n\t\t\t\treturn this.element;\n\t\t\t});\n\t\t},\n\n\t\tshowLabel: function( element, message ) {\n\t\t\tvar place, group, errorID,\n\t\t\t\terror = this.errorsFor( element ),\n\t\t\t\telementID = this.idOrName( element ),\n\t\t\t\tdescribedBy = $( element ).attr( \"aria-describedby\" );\n\t\t\tif ( error.length ) {\n\t\t\t\t// refresh error/success class\n\t\t\t\terror.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );\n\t\t\t\t// replace message on existing label\n\t\t\t\terror.html( message );\n\t\t\t} else {\n\t\t\t\t// create error element\n\t\t\t\terror = $( \"<\" + this.settings.errorElement + \">\" )\n\t\t\t\t\t.attr( \"id\", elementID + \"-error\" )\n\t\t\t\t\t.addClass( this.settings.errorClass )\n\t\t\t\t\t.html( message || \"\" );\n\n\t\t\t\t// Maintain reference to the element to be placed into the DOM\n\t\t\t\tplace = error;\n\t\t\t\tif ( this.settings.wrapper ) {\n\t\t\t\t\t// make sure the element is visible, even in IE\n\t\t\t\t\t// actually showing the wrapped element is handled elsewhere\n\t\t\t\t\tplace = error.hide().show().wrap( \"<\" + this.settings.wrapper + \"/>\" ).parent();\n\t\t\t\t}\n\t\t\t\tif ( this.labelContainer.length ) {\n\t\t\t\t\tthis.labelContainer.append( place );\n\t\t\t\t} else if ( this.settings.errorPlacement ) {\n\t\t\t\t\tthis.settings.errorPlacement( place, $( element ) );\n\t\t\t\t} else {\n\t\t\t\t\tplace.insertAfter( element );\n\t\t\t\t}\n\n\t\t\t\t// Link error back to the element\n\t\t\t\tif ( error.is( \"label\" ) ) {\n\t\t\t\t\t// If the error is a label, then associate using 'for'\n\t\t\t\t\terror.attr( \"for\", elementID );\n\t\t\t\t} else if ( error.parents( \"label[for='\" + elementID + \"']\" ).length === 0 ) {\n\t\t\t\t\t// If the element is not a child of an associated label, then it's necessary\n\t\t\t\t\t// to explicitly apply aria-describedby\n\n\t\t\t\t\terrorID = error.attr( \"id\" ).replace( /(:|\\.|\\[|\\]|\\$)/g, \"\\\\$1\");\n\t\t\t\t\t// Respect existing non-error aria-describedby\n\t\t\t\t\tif ( !describedBy ) {\n\t\t\t\t\t\tdescribedBy = errorID;\n\t\t\t\t\t} else if ( !describedBy.match( new RegExp( \"\\\\b\" + errorID + \"\\\\b\" ) ) ) {\n\t\t\t\t\t\t// Add to end of list if not already present\n\t\t\t\t\t\tdescribedBy += \" \" + errorID;\n\t\t\t\t\t}\n\t\t\t\t\t$( element ).attr( \"aria-describedby\", describedBy );\n\n\t\t\t\t\t// If this element is grouped, then assign to all elements in the same group\n\t\t\t\t\tgroup = this.groups[ element.name ];\n\t\t\t\t\tif ( group ) {\n\t\t\t\t\t\t$.each( this.groups, function( name, testgroup ) {\n\t\t\t\t\t\t\tif ( testgroup === group ) {\n\t\t\t\t\t\t\t\t$( \"[name='\" + name + \"']\", this.currentForm )\n\t\t\t\t\t\t\t\t\t.attr( \"aria-describedby\", error.attr( \"id\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( !message && this.settings.success ) {\n\t\t\t\terror.text( \"\" );\n\t\t\t\tif ( typeof this.settings.success === \"string\" ) {\n\t\t\t\t\terror.addClass( this.settings.success );\n\t\t\t\t} else {\n\t\t\t\t\tthis.settings.success( error, element );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toShow = this.toShow.add( error );\n\t\t},\n\n\t\terrorsFor: function( element ) {\n\t\t\tvar name = this.idOrName( element ),\n\t\t\t\tdescriber = $( element ).attr( \"aria-describedby\" ),\n\t\t\t\tselector = \"label[for='\" + name + \"'], label[for='\" + name + \"'] *\";\n\n\t\t\t// aria-describedby should directly reference the error element\n\t\t\tif ( describer ) {\n\t\t\t\tselector = selector + \", #\" + describer.replace( /\\s+/g, \", #\" );\n\t\t\t}\n\t\t\treturn this\n\t\t\t\t.errors()\n\t\t\t\t.filter( selector );\n\t\t},\n\n\t\tidOrName: function( element ) {\n\t\t\treturn this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );\n\t\t},\n\n\t\tvalidationTargetFor: function( element ) {\n\n\t\t\t// If radio/checkbox, validate first element in group instead\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\telement = this.findByName( element.name );\n\t\t\t}\n\n\t\t\t// Always apply ignore filter\n\t\t\treturn $( element ).not( this.settings.ignore )[ 0 ];\n\t\t},\n\n\t\tcheckable: function( element ) {\n\t\t\treturn ( /radio|checkbox/i ).test( element.type );\n\t\t},\n\n\t\tfindByName: function( name ) {\n\t\t\treturn $( this.currentForm ).find( \"[name='\" + name + \"']\" );\n\t\t},\n\n\t\tgetLength: function( value, element ) {\n\t\t\tswitch ( element.nodeName.toLowerCase() ) {\n\t\t\tcase \"select\":\n\t\t\t\treturn $( \"option:selected\", element ).length;\n\t\t\tcase \"input\":\n\t\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\t\treturn this.findByName( element.name ).filter( \":checked\" ).length;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.length;\n\t\t},\n\n\t\tdepend: function( param, element ) {\n\t\t\treturn this.dependTypes[typeof param] ? this.dependTypes[typeof param]( param, element ) : true;\n\t\t},\n\n\t\tdependTypes: {\n\t\t\t\"boolean\": function( param ) {\n\t\t\t\treturn param;\n\t\t\t},\n\t\t\t\"string\": function( param, element ) {\n\t\t\t\treturn !!$( param, element.form ).length;\n\t\t\t},\n\t\t\t\"function\": function( param, element ) {\n\t\t\t\treturn param( element );\n\t\t\t}\n\t\t},\n\n\t\toptional: function( element ) {\n\t\t\tvar val = this.elementValue( element );\n\t\t\treturn !$.validator.methods.required.call( this, val, element ) && \"dependency-mismatch\";\n\t\t},\n\n\t\tstartRequest: function( element ) {\n\t\t\tif ( !this.pending[ element.name ] ) {\n\t\t\t\tthis.pendingRequest++;\n\t\t\t\tthis.pending[ element.name ] = true;\n\t\t\t}\n\t\t},\n\n\t\tstopRequest: function( element, valid ) {\n\t\t\tthis.pendingRequest--;\n\t\t\t// sometimes synchronization fails, make sure pendingRequest is never < 0\n\t\t\tif ( this.pendingRequest < 0 ) {\n\t\t\t\tthis.pendingRequest = 0;\n\t\t\t}\n\t\t\tdelete this.pending[ element.name ];\n\t\t\tif ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {\n\t\t\t\t$( this.currentForm ).submit();\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t} else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ]);\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t}\n\t\t},\n\n\t\tpreviousValue: function( element ) {\n\t\t\treturn $.data( element, \"previousValue\" ) || $.data( element, \"previousValue\", {\n\t\t\t\told: null,\n\t\t\t\tvalid: true,\n\t\t\t\tmessage: this.defaultMessage( element, \"remote\" )\n\t\t\t});\n\t\t},\n\n\t\t// cleans up all forms and elements, removes validator-specific events\n\t\tdestroy: function() {\n\t\t\tthis.resetForm();\n\n\t\t\t$( this.currentForm )\n\t\t\t\t.off( \".validate\" )\n\t\t\t\t.removeData( \"validator\" );\n\t\t}\n\n\t},\n\n\tclassRuleSettings: {\n\t\trequired: { required: true },\n\t\temail: { email: true },\n\t\turl: { url: true },\n\t\tdate: { date: true },\n\t\tdateISO: { dateISO: true },\n\t\tnumber: { number: true },\n\t\tdigits: { digits: true },\n\t\tcreditcard: { creditcard: true }\n\t},\n\n\taddClassRules: function( className, rules ) {\n\t\tif ( className.constructor === String ) {\n\t\t\tthis.classRuleSettings[ className ] = rules;\n\t\t} else {\n\t\t\t$.extend( this.classRuleSettings, className );\n\t\t}\n\t},\n\n\tclassRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tclasses = $( element ).attr( \"class\" );\n\n\t\tif ( classes ) {\n\t\t\t$.each( classes.split( \" \" ), function() {\n\t\t\t\tif ( this in $.validator.classRuleSettings ) {\n\t\t\t\t\t$.extend( rules, $.validator.classRuleSettings[ this ]);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeAttributeRule: function( rules, type, method, value ) {\n\n\t\t// convert the value to a number for number inputs, and for text for backwards compability\n\t\t// allows type=\"date\" and others to be compared as strings\n\t\tif ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {\n\t\t\tvalue = Number( value );\n\n\t\t\t// Support Opera Mini, which returns NaN for undefined minlength\n\t\t\tif ( isNaN( value ) ) {\n\t\t\t\tvalue = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif ( value || value === 0 ) {\n\t\t\trules[ method ] = value;\n\t\t} else if ( type === method && type !== \"range\" ) {\n\n\t\t\t// exception: the jquery validate 'range' method\n\t\t\t// does not test for the html5 'range' type\n\t\t\trules[ method ] = true;\n\t\t}\n\t},\n\n\tattributeRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\n\t\t\t// support for <input required> in both html5 and older browsers\n\t\t\tif ( method === \"required\" ) {\n\t\t\t\tvalue = element.getAttribute( method );\n\n\t\t\t\t// Some browsers return an empty string for the required attribute\n\t\t\t\t// and non-HTML5 browsers might have required=\"\" markup\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\tvalue = true;\n\t\t\t\t}\n\n\t\t\t\t// force non-HTML5 browsers to return bool\n\t\t\t\tvalue = !!value;\n\t\t\t} else {\n\t\t\t\tvalue = $element.attr( method );\n\t\t\t}\n\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\n\t\t// maxlength may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs\n\t\tif ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {\n\t\t\tdelete rules.maxlength;\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\tdataRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\t\t\tvalue = $element.data( \"rule\" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\t\treturn rules;\n\t},\n\n\tstaticRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tvalidator = $.data( element.form, \"validator\" );\n\n\t\tif ( validator.settings.rules ) {\n\t\t\trules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeRules: function( rules, element ) {\n\t\t// handle dependency check\n\t\t$.each( rules, function( prop, val ) {\n\t\t\t// ignore rule when param is explicitly false, eg. required:false\n\t\t\tif ( val === false ) {\n\t\t\t\tdelete rules[ prop ];\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( val.param || val.depends ) {\n\t\t\t\tvar keepRule = true;\n\t\t\t\tswitch ( typeof val.depends ) {\n\t\t\t\tcase \"string\":\n\t\t\t\t\tkeepRule = !!$( val.depends, element.form ).length;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"function\":\n\t\t\t\t\tkeepRule = val.depends.call( element, element );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( keepRule ) {\n\t\t\t\t\trules[ prop ] = val.param !== undefined ? val.param : true;\n\t\t\t\t} else {\n\t\t\t\t\tdelete rules[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// evaluate parameters\n\t\t$.each( rules, function( rule, parameter ) {\n\t\t\trules[ rule ] = $.isFunction( parameter ) ? parameter( element ) : parameter;\n\t\t});\n\n\t\t// clean number parameters\n\t\t$.each([ \"minlength\", \"maxlength\" ], function() {\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\trules[ this ] = Number( rules[ this ] );\n\t\t\t}\n\t\t});\n\t\t$.each([ \"rangelength\", \"range\" ], function() {\n\t\t\tvar parts;\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\tif ( $.isArray( rules[ this ] ) ) {\n\t\t\t\t\trules[ this ] = [ Number( rules[ this ][ 0 ]), Number( rules[ this ][ 1 ] ) ];\n\t\t\t\t} else if ( typeof rules[ this ] === \"string\" ) {\n\t\t\t\t\tparts = rules[ this ].replace(/[\\[\\]]/g, \"\" ).split( /[\\s,]+/ );\n\t\t\t\t\trules[ this ] = [ Number( parts[ 0 ]), Number( parts[ 1 ] ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tif ( $.validator.autoCreateRanges ) {\n\t\t\t// auto-create ranges\n\t\t\tif ( rules.min != null && rules.max != null ) {\n\t\t\t\trules.range = [ rules.min, rules.max ];\n\t\t\t\tdelete rules.min;\n\t\t\t\tdelete rules.max;\n\t\t\t}\n\t\t\tif ( rules.minlength != null && rules.maxlength != null ) {\n\t\t\t\trules.rangelength = [ rules.minlength, rules.maxlength ];\n\t\t\t\tdelete rules.minlength;\n\t\t\t\tdelete rules.maxlength;\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\t// Converts a simple string to a {string: true} rule, e.g., \"required\" to {required:true}\n\tnormalizeRule: function( data ) {\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tvar transformed = {};\n\t\t\t$.each( data.split( /\\s/ ), function() {\n\t\t\t\ttransformed[ this ] = true;\n\t\t\t});\n\t\t\tdata = transformed;\n\t\t}\n\t\treturn data;\n\t},\n\n\t// http://jqueryvalidation.org/jQuery.validator.addMethod/\n\taddMethod: function( name, method, message ) {\n\t\t$.validator.methods[ name ] = method;\n\t\t$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];\n\t\tif ( method.length < 3 ) {\n\t\t\t$.validator.addClassRules( name, $.validator.normalizeRule( name ) );\n\t\t}\n\t},\n\n\tmethods: {\n\n\t\t// http://jqueryvalidation.org/required-method/\n\t\trequired: function( value, element, param ) {\n\t\t\t// check if dependency is met\n\t\t\tif ( !this.depend( param, element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\t\t\tif ( element.nodeName.toLowerCase() === \"select\" ) {\n\t\t\t\t// could be an array for select-multiple or a string, both are fine this way\n\t\t\t\tvar val = $( element ).val();\n\t\t\t\treturn val && val.length > 0;\n\t\t\t}\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\treturn this.getLength( value, element ) > 0;\n\t\t\t}\n\t\t\treturn value.length > 0;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/email-method/\n\t\temail: function( value, element ) {\n\t\t\t// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address\n\t\t\t// Retrieved 2014-01-14\n\t\t\t// If you have a problem with this implementation, report a bug against the above spec\n\t\t\t// Or use custom methods to implement your own email validation\n\t\t\treturn this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/url-method/\n\t\turl: function( value, element ) {\n\n\t\t\t// Copyright (c) 2010-2013 Diego Perini, MIT licensed\n\t\t\t// https://gist.github.com/dperini/729294\n\t\t\t// see also https://mathiasbynens.be/demo/url-regex\n\t\t\t// modified to allow protocol-relative URLs\n\t\t\treturn this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})).?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/i.test( value );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/date-method/\n\t\tdate: function( value, element ) {\n\t\t\treturn this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/dateISO-method/\n\t\tdateISO: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d{4}[\\/\\-](0?[1-9]|1[012])[\\/\\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/number-method/\n\t\tnumber: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test( value );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/digits-method/\n\t\tdigits: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d+$/.test( value );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/creditcard-method/\n\t\t// based on http://en.wikipedia.org/wiki/Luhn_algorithm\n\t\tcreditcard: function( value, element ) {\n\t\t\tif ( this.optional( element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\t\t\t// accept only spaces, digits and dashes\n\t\t\tif ( /[^0-9 \\-]+/.test( value ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar nCheck = 0,\n\t\t\t\tnDigit = 0,\n\t\t\t\tbEven = false,\n\t\t\t\tn, cDigit;\n\n\t\t\tvalue = value.replace( /\\D/g, \"\" );\n\n\t\t\t// Basing min and max length on\n\t\t\t// http://developer.ean.com/general_info/Valid_Credit_Card_Types\n\t\t\tif ( value.length < 13 || value.length > 19 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor ( n = value.length - 1; n >= 0; n--) {\n\t\t\t\tcDigit = value.charAt( n );\n\t\t\t\tnDigit = parseInt( cDigit, 10 );\n\t\t\t\tif ( bEven ) {\n\t\t\t\t\tif ( ( nDigit *= 2 ) > 9 ) {\n\t\t\t\t\t\tnDigit -= 9;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCheck += nDigit;\n\t\t\t\tbEven = !bEven;\n\t\t\t}\n\n\t\t\treturn ( nCheck % 10 ) === 0;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/minlength-method/\n\t\tminlength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length >= param;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/maxlength-method/\n\t\tmaxlength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length <= param;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/rangelength-method/\n\t\trangelength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/min-method/\n\t\tmin: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value >= param;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/max-method/\n\t\tmax: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value <= param;\n\t\t},\n\n\t\t// http://jqueryvalidation.org/range-method/\n\t\trange: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );\n\t\t},\n\n\t\t// http://jqueryvalidation.org/equalTo-method/\n\t\tequalTo: function( value, element, param ) {\n\t\t\t// bind to the blur event of the target in order to revalidate whenever the target field is updated\n\t\t\t// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead\n\t\t\tvar target = $( param );\n\t\t\tif ( this.settings.onfocusout ) {\n\t\t\t\ttarget.off( \".validate-equalTo\" ).on( \"blur.validate-equalTo\", function() {\n\t\t\t\t\t$( element ).valid();\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn value === target.val();\n\t\t},\n\n\t\t// http://jqueryvalidation.org/remote-method/\n\t\tremote: function( value, element, param ) {\n\t\t\tif ( this.optional( element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\n\t\t\tvar previous = this.previousValue( element ),\n\t\t\t\tvalidator, data;\n\n\t\t\tif (!this.settings.messages[ element.name ] ) {\n\t\t\t\tthis.settings.messages[ element.name ] = {};\n\t\t\t}\n\t\t\tprevious.originalMessage = this.settings.messages[ element.name ].remote;\n\t\t\tthis.settings.messages[ element.name ].remote = previous.message;\n\n\t\t\tparam = typeof param === \"string\" && { url: param } || param;\n\n\t\t\tif ( previous.old === value ) {\n\t\t\t\treturn previous.valid;\n\t\t\t}\n\n\t\t\tprevious.old = value;\n\t\t\tvalidator = this;\n\t\t\tthis.startRequest( element );\n\t\t\tdata = {};\n\t\t\tdata[ element.name ] = value;\n\t\t\t$.ajax( $.extend( true, {\n\t\t\t\tmode: \"abort\",\n\t\t\t\tport: \"validate\" + element.name,\n\t\t\t\tdataType: \"json\",\n\t\t\t\tdata: data,\n\t\t\t\tcontext: validator.currentForm,\n\t\t\t\tsuccess: function( response ) {\n\t\t\t\t\tvar valid = response === true || response === \"true\",\n\t\t\t\t\t\terrors, message, submitted;\n\n\t\t\t\t\tvalidator.settings.messages[ element.name ].remote = previous.originalMessage;\n\t\t\t\t\tif ( valid ) {\n\t\t\t\t\t\tsubmitted = validator.formSubmitted;\n\t\t\t\t\t\tvalidator.prepareElement( element );\n\t\t\t\t\t\tvalidator.formSubmitted = submitted;\n\t\t\t\t\t\tvalidator.successList.push( element );\n\t\t\t\t\t\tdelete validator.invalid[ element.name ];\n\t\t\t\t\t\tvalidator.showErrors();\n\t\t\t\t\t} else {\n\t\t\t\t\t\terrors = {};\n\t\t\t\t\t\tmessage = response || validator.defaultMessage( element, \"remote\" );\n\t\t\t\t\t\terrors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : message;\n\t\t\t\t\t\tvalidator.invalid[ element.name ] = true;\n\t\t\t\t\t\tvalidator.showErrors( errors );\n\t\t\t\t\t}\n\t\t\t\t\tprevious.valid = valid;\n\t\t\t\t\tvalidator.stopRequest( element, valid );\n\t\t\t\t}\n\t\t\t}, param ) );\n\t\t\treturn \"pending\";\n\t\t}\n\t}\n\n});\n\n// ajax mode: abort\n// usage: $.ajax({ mode: \"abort\"[, port: \"uniqueport\"]});\n// if mode:\"abort\" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()\n\nvar pendingRequests = {},\n\tajax;\n// Use a prefilter if available (1.5+)\nif ( $.ajaxPrefilter ) {\n\t$.ajaxPrefilter(function( settings, _, xhr ) {\n\t\tvar port = settings.port;\n\t\tif ( settings.mode === \"abort\" ) {\n\t\t\tif ( pendingRequests[port] ) {\n\t\t\t\tpendingRequests[port].abort();\n\t\t\t}\n\t\t\tpendingRequests[port] = xhr;\n\t\t}\n\t});\n} else {\n\t// Proxy ajax\n\tajax = $.ajax;\n\t$.ajax = function( settings ) {\n\t\tvar mode = ( \"mode\" in settings ? settings : $.ajaxSettings ).mode,\n\t\t\tport = ( \"port\" in settings ? settings : $.ajaxSettings ).port;\n\t\tif ( mode === \"abort\" ) {\n\t\t\tif ( pendingRequests[port] ) {\n\t\t\t\tpendingRequests[port].abort();\n\t\t\t}\n\t\t\tpendingRequests[port] = ajax.apply(this, arguments);\n\t\t\treturn pendingRequests[port];\n\t\t}\n\t\treturn ajax.apply(this, arguments);\n\t};\n}\n\n}));"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation-unobtrusive/.bower.json",
    "content": "{\n  \"name\": \"jquery-validation-unobtrusive\",\n  \"version\": \"3.2.6\",\n  \"homepage\": \"https://github.com/aspnet/jquery-validation-unobtrusive\",\n  \"description\": \"Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.\",\n  \"main\": [\n    \"jquery.validate.unobtrusive.js\"\n  ],\n  \"ignore\": [\n    \"**/.*\",\n    \"*.json\",\n    \"*.md\",\n    \"*.txt\",\n    \"gulpfile.js\"\n  ],\n  \"keywords\": [\n    \"jquery\",\n    \"asp.net\",\n    \"mvc\",\n    \"validation\",\n    \"unobtrusive\"\n  ],\n  \"authors\": [\n    \"Microsoft\"\n  ],\n  \"license\": \"http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/aspnet/jquery-validation-unobtrusive.git\"\n  },\n  \"dependencies\": {\n    \"jquery-validation\": \">=1.8\",\n    \"jquery\": \">=1.8\"\n  },\n  \"_release\": \"3.2.6\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"v3.2.6\",\n    \"commit\": \"13386cd1b5947d8a5d23a12b531ce3960be1eba7\"\n  },\n  \"_source\": \"git://github.com/aspnet/jquery-validation-unobtrusive.git\",\n  \"_target\": \"3.2.6\",\n  \"_originalSource\": \"jquery-validation-unobtrusive\"\n}"
  },
  {
    "path": "examples/SqliteDemo.MVCApplication/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
    "content": "/*!\n** Unobtrusive validation support library for jQuery and jQuery Validate\n** Copyright (C) Microsoft Corporation. All rights reserved.\n*/\n\n/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */\n/*global document: false, jQuery: false */\n\n(function ($) {\n    var $jQval = $.validator,\n        adapters,\n        data_validation = \"unobtrusiveValidation\";\n\n    function setValidationValues(options, ruleName, value) {\n        options.rules[ruleName] = value;\n        if (options.message) {\n            options.messages[ruleName] = options.message;\n        }\n    }\n\n    function splitAndTrim(value) {\n        return value.replace(/^\\s+|\\s+$/g, \"\").split(/\\s*,\\s*/g);\n    }\n\n    function escapeAttributeValue(value) {\n        // As mentioned on http://api.jquery.com/category/selectors/\n        return value.replace(/([!\"#$%&'()*+,./:;<=>?@\\[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n    }\n\n    function getModelPrefix(fieldName) {\n        return fieldName.substr(0, fieldName.lastIndexOf(\".\") + 1);\n    }\n\n    function appendModelPrefix(value, prefix) {\n        if (value.indexOf(\"*.\") === 0) {\n            value = value.replace(\"*.\", prefix);\n        }\n        return value;\n    }\n\n    function onError(error, inputElement) {  // 'this' is the form element\n        var container = $(this).find(\"[data-valmsg-for='\" + escapeAttributeValue(inputElement[0].name) + \"']\"),\n            replaceAttrValue = container.attr(\"data-valmsg-replace\"),\n            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;\n\n        container.removeClass(\"field-validation-valid\").addClass(\"field-validation-error\");\n        error.data(\"unobtrusiveContainer\", container);\n\n        if (replace) {\n            container.empty();\n            error.removeClass(\"input-validation-error\").appendTo(container);\n        }\n        else {\n            error.hide();\n        }\n    }\n\n    function onErrors(event, validator) {  // 'this' is the form element\n        var container = $(this).find(\"[data-valmsg-summary=true]\"),\n            list = container.find(\"ul\");\n\n        if (list && list.length && validator.errorList.length) {\n            list.empty();\n            container.addClass(\"validation-summary-errors\").removeClass(\"validation-summary-valid\");\n\n            $.each(validator.errorList, function () {\n                $(\"<li />\").html(this.message).appendTo(list);\n            });\n        }\n    }\n\n    function onSuccess(error) {  // 'this' is the form element\n        var container = error.data(\"unobtrusiveContainer\");\n\n        if (container) {\n            var replaceAttrValue = container.attr(\"data-valmsg-replace\"),\n                replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;\n\n            container.addClass(\"field-validation-valid\").removeClass(\"field-validation-error\");\n            error.removeData(\"unobtrusiveContainer\");\n\n            if (replace) {\n                container.empty();\n            }\n        }\n    }\n\n    function onReset(event) {  // 'this' is the form element\n        var $form = $(this),\n            key = '__jquery_unobtrusive_validation_form_reset';\n        if ($form.data(key)) {\n            return;\n        }\n        // Set a flag that indicates we're currently resetting the form.\n        $form.data(key, true);\n        try {\n            $form.data(\"validator\").resetForm();\n        } finally {\n            $form.removeData(key);\n        }\n\n        $form.find(\".validation-summary-errors\")\n            .addClass(\"validation-summary-valid\")\n            .removeClass(\"validation-summary-errors\");\n        $form.find(\".field-validation-error\")\n            .addClass(\"field-validation-valid\")\n            .removeClass(\"field-validation-error\")\n            .removeData(\"unobtrusiveContainer\")\n            .find(\">*\")  // If we were using valmsg-replace, get the underlying error\n                .removeData(\"unobtrusiveContainer\");\n    }\n\n    function validationInfo(form) {\n        var $form = $(form),\n            result = $form.data(data_validation),\n            onResetProxy = $.proxy(onReset, form),\n            defaultOptions = $jQval.unobtrusive.options || {},\n            execInContext = function (name, args) {\n                var func = defaultOptions[name];\n                func && $.isFunction(func) && func.apply(form, args);\n            }\n\n        if (!result) {\n            result = {\n                options: {  // options structure passed to jQuery Validate's validate() method\n                    errorClass: defaultOptions.errorClass || \"input-validation-error\",\n                    errorElement: defaultOptions.errorElement || \"span\",\n                    errorPlacement: function () {\n                        onError.apply(form, arguments);\n                        execInContext(\"errorPlacement\", arguments);\n                    },\n                    invalidHandler: function () {\n                        onErrors.apply(form, arguments);\n                        execInContext(\"invalidHandler\", arguments);\n                    },\n                    messages: {},\n                    rules: {},\n                    success: function () {\n                        onSuccess.apply(form, arguments);\n                        execInContext(\"success\", arguments);\n                    }\n                },\n                attachValidation: function () {\n                    $form\n                        .off(\"reset.\" + data_validation, onResetProxy)\n                        .on(\"reset.\" + data_validation, onResetProxy)\n                        .validate(this.options);\n                },\n                validate: function () {  // a validation function that is called by unobtrusive Ajax\n                    $form.validate();\n                    return $form.valid();\n                }\n            };\n            $form.data(data_validation, result);\n        }\n\n        return result;\n    }\n\n    $jQval.unobtrusive = {\n        adapters: [],\n\n        parseElement: function (element, skipAttach) {\n            /// <summary>\n            /// Parses a single HTML element for unobtrusive validation attributes.\n            /// </summary>\n            /// <param name=\"element\" domElement=\"true\">The HTML element to be parsed.</param>\n            /// <param name=\"skipAttach\" type=\"Boolean\">[Optional] true to skip attaching the\n            /// validation to the form. If parsing just this single element, you should specify true.\n            /// If parsing several elements, you should specify false, and manually attach the validation\n            /// to the form when you are finished. The default is false.</param>\n            var $element = $(element),\n                form = $element.parents(\"form\")[0],\n                valInfo, rules, messages;\n\n            if (!form) {  // Cannot do client-side validation without a form\n                return;\n            }\n\n            valInfo = validationInfo(form);\n            valInfo.options.rules[element.name] = rules = {};\n            valInfo.options.messages[element.name] = messages = {};\n\n            $.each(this.adapters, function () {\n                var prefix = \"data-val-\" + this.name,\n                    message = $element.attr(prefix),\n                    paramValues = {};\n\n                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)\n                    prefix += \"-\";\n\n                    $.each(this.params, function () {\n                        paramValues[this] = $element.attr(prefix + this);\n                    });\n\n                    this.adapt({\n                        element: element,\n                        form: form,\n                        message: message,\n                        params: paramValues,\n                        rules: rules,\n                        messages: messages\n                    });\n                }\n            });\n\n            $.extend(rules, { \"__dummy__\": true });\n\n            if (!skipAttach) {\n                valInfo.attachValidation();\n            }\n        },\n\n        parse: function (selector) {\n            /// <summary>\n            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated\n            /// with the [data-val=true] attribute value and enables validation according to the data-val-*\n            /// attribute values.\n            /// </summary>\n            /// <param name=\"selector\" type=\"String\">Any valid jQuery selector.</param>\n\n            // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one\n            // element with data-val=true\n            var $selector = $(selector),\n                $forms = $selector.parents()\n                                  .addBack()\n                                  .filter(\"form\")\n                                  .add($selector.find(\"form\"))\n                                  .has(\"[data-val=true]\");\n\n            $selector.find(\"[data-val=true]\").each(function () {\n                $jQval.unobtrusive.parseElement(this, true);\n            });\n\n            $forms.each(function () {\n                var info = validationInfo(this);\n                if (info) {\n                    info.attachValidation();\n                }\n            });\n        }\n    };\n\n    adapters = $jQval.unobtrusive.adapters;\n\n    adapters.add = function (adapterName, params, fn) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"params\" type=\"Array\" optional=\"true\">[Optional] An array of parameter names (strings) that will\n        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and\n        /// mmmm is the parameter name).</param>\n        /// <param name=\"fn\" type=\"Function\">The function to call, which adapts the values from the HTML\n        /// attributes into jQuery Validate rules and/or messages.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        if (!fn) {  // Called with no params, just a function\n            fn = params;\n            params = [];\n        }\n        this.push({ name: adapterName, params: params, adapt: fn });\n        return this;\n    };\n\n    adapters.addBool = function (adapterName, ruleName) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation rule has no parameter values.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"ruleName\" type=\"String\" optional=\"true\">[Optional] The name of the jQuery Validate rule. If not provided, the value\n        /// of adapterName will be used instead.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, function (options) {\n            setValidationValues(options, ruleName || adapterName, true);\n        });\n    };\n\n    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and\n        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"minRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you only\n        /// have a minimum value.</param>\n        /// <param name=\"maxRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you only\n        /// have a maximum value.</param>\n        /// <param name=\"minMaxRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you\n        /// have both a minimum and maximum value.</param>\n        /// <param name=\"minAttribute\" type=\"String\" optional=\"true\">[Optional] The name of the HTML attribute that\n        /// contains the minimum value. The default is \"min\".</param>\n        /// <param name=\"maxAttribute\" type=\"String\" optional=\"true\">[Optional] The name of the HTML attribute that\n        /// contains the maximum value. The default is \"max\".</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, [minAttribute || \"min\", maxAttribute || \"max\"], function (options) {\n            var min = options.params.min,\n                max = options.params.max;\n\n            if (min && max) {\n                setValidationValues(options, minMaxRuleName, [min, max]);\n            }\n            else if (min) {\n                setValidationValues(options, minRuleName, min);\n            }\n            else if (max) {\n                setValidationValues(options, maxRuleName, max);\n            }\n        });\n    };\n\n    adapters.addSingleVal = function (adapterName, attribute, ruleName) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation rule has a single value.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>\n        /// <param name=\"attribute\" type=\"String\">[Optional] The name of the HTML attribute that contains the value.\n        /// The default is \"val\".</param>\n        /// <param name=\"ruleName\" type=\"String\" optional=\"true\">[Optional] The name of the jQuery Validate rule. If not provided, the value\n        /// of adapterName will be used instead.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, [attribute || \"val\"], function (options) {\n            setValidationValues(options, ruleName || adapterName, options.params[attribute]);\n        });\n    };\n\n    $jQval.addMethod(\"__dummy__\", function (value, element, params) {\n        return true;\n    });\n\n    $jQval.addMethod(\"regex\", function (value, element, params) {\n        var match;\n        if (this.optional(element)) {\n            return true;\n        }\n\n        match = new RegExp(params).exec(value);\n        return (match && (match.index === 0) && (match[0].length === value.length));\n    });\n\n    $jQval.addMethod(\"nonalphamin\", function (value, element, nonalphamin) {\n        var match;\n        if (nonalphamin) {\n            match = value.match(/\\W/g);\n            match = match && match.length >= nonalphamin;\n        }\n        return match;\n    });\n\n    if ($jQval.methods.extension) {\n        adapters.addSingleVal(\"accept\", \"mimtype\");\n        adapters.addSingleVal(\"extension\", \"extension\");\n    } else {\n        // for backward compatibility, when the 'extension' validation method does not exist, such as with versions\n        // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for\n        // validating the extension, and ignore mime-type validations as they are not supported.\n        adapters.addSingleVal(\"extension\", \"extension\", \"accept\");\n    }\n\n    adapters.addSingleVal(\"regex\", \"pattern\");\n    adapters.addBool(\"creditcard\").addBool(\"date\").addBool(\"digits\").addBool(\"email\").addBool(\"number\").addBool(\"url\");\n    adapters.addMinMax(\"length\", \"minlength\", \"maxlength\", \"rangelength\").addMinMax(\"range\", \"min\", \"max\", \"range\");\n    adapters.addMinMax(\"minlength\", \"minlength\").addMinMax(\"maxlength\", \"minlength\", \"maxlength\");\n    adapters.add(\"equalto\", [\"other\"], function (options) {\n        var prefix = getModelPrefix(options.element.name),\n            other = options.params.other,\n            fullOtherName = appendModelPrefix(other, prefix),\n            element = $(options.form).find(\":input\").filter(\"[name='\" + escapeAttributeValue(fullOtherName) + \"']\")[0];\n\n        setValidationValues(options, \"equalTo\", element);\n    });\n    adapters.add(\"required\", function (options) {\n        // jQuery Validate equates \"required\" with \"mandatory\" for checkbox elements\n        if (options.element.tagName.toUpperCase() !== \"INPUT\" || options.element.type.toUpperCase() !== \"CHECKBOX\") {\n            setValidationValues(options, \"required\", true);\n        }\n    });\n    adapters.add(\"remote\", [\"url\", \"type\", \"additionalfields\"], function (options) {\n        var value = {\n            url: options.params.url,\n            type: options.params.type || \"GET\",\n            data: {}\n        },\n            prefix = getModelPrefix(options.element.name);\n\n        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {\n            var paramName = appendModelPrefix(fieldName, prefix);\n            value.data[paramName] = function () {\n                var field = $(options.form).find(\":input\").filter(\"[name='\" + escapeAttributeValue(paramName) + \"']\");\n                // For checkboxes and radio buttons, only pick up values from checked fields.\n                if (field.is(\":checkbox\")) {\n                    return field.filter(\":checked\").val() || field.filter(\":hidden\").val() || '';\n                }\n                else if (field.is(\":radio\")) {\n                    return field.filter(\":checked\").val() || '';\n                }\n                return field.val();\n            };\n        });\n\n        setValidationValues(options, \"remote\", value);\n    });\n    adapters.add(\"password\", [\"min\", \"nonalphamin\", \"regex\"], function (options) {\n        if (options.params.min) {\n            setValidationValues(options, \"minlength\", options.params.min);\n        }\n        if (options.params.nonalphamin) {\n            setValidationValues(options, \"nonalphamin\", options.params.nonalphamin);\n        }\n        if (options.params.regex) {\n            setValidationValues(options, \"regex\", options.params.regex);\n        }\n    });\n\n    $(function () {\n        $jQval.unobtrusive.parse(document);\n    });\n}(jQuery));"
  },
  {
    "path": "examples/SqliteDemo.SqlLogging/LoggingDbFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Data.Common;\nusing System.Data;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Diagnostics;\n\nusing NReco.Data;\n\n\nnamespace SqliteDemo.SqlLogging {\n\n\t/// <summary>\n\t/// Extends generic DbFactory by wrapping IDbCommand with special proxy implementation.\n\t/// </summary>\n    public class LoggingDbFactory : DbFactory {\n\n\t\tpublic LoggingDbFactory(DbProviderFactory dbPrvFactory) : base(dbPrvFactory) {\n\n\t\t}\n\n\t\tprotected void DbCommandExecuting(DbCommand cmd) {\n\n\t\t}\n\n\t\tprotected void DbCommandExecuted(DbCommand cmd, TimeSpan execTime) {\n\t\t\t// call your logging library here\n\t\t\t// in this example console is used for the sake of simplicity\n\t\t\tConsole.WriteLine($\"Executed ({execTime.TotalMilliseconds.ToString(\"0.###\")}ms): {cmd.CommandText}\");\n\t\t}\n\n\t\tpublic override IDbCommand CreateCommand() {\n\t\t\tvar realCmd = (DbCommand)base.CreateCommand();\n\t\t\treturn new LoggingDbCommand(realCmd, this);\n\t\t}\n\n\t\tpublic class LoggingDbCommand : DbCommand {\n\t\t\tDbCommand DbCmd;\n\t\t\tLoggingDbFactory LogDbFactory;\n\n\t\t\tinternal LoggingDbCommand(DbCommand realCmd, LoggingDbFactory logDbFactory) {\n\t\t\t\tDbCmd = realCmd;\n\t\t\t\tLogDbFactory = logDbFactory;\n\t\t\t}\n\n\t\t\tpublic override string CommandText { get => DbCmd.CommandText; set => DbCmd.CommandText = value; }\n\t\t\tpublic override int CommandTimeout { get => DbCmd.CommandTimeout; set => DbCmd.CommandTimeout = value; }\n\t\t\tpublic override CommandType CommandType { get => DbCmd.CommandType; set => DbCmd.CommandType = value; }\n\t\t\tpublic override bool DesignTimeVisible { get => DbCmd.DesignTimeVisible; set => DbCmd.DesignTimeVisible = value; }\n\t\t\tpublic override UpdateRowSource UpdatedRowSource { get => DbCmd.UpdatedRowSource; set => DbCmd.UpdatedRowSource = value; }\n\t\t\tprotected override DbConnection DbConnection { get => DbCmd.Connection; set => DbCmd.Connection = value; }\n\n\t\t\tprotected override DbParameterCollection DbParameterCollection => DbCmd.Parameters;\n\n\t\t\tprotected override DbTransaction DbTransaction { get => DbCmd.Transaction; set => DbCmd.Transaction = value; }\n\n\t\t\tpublic override void Cancel() {\n\t\t\t\tDbCmd.Cancel();\n\t\t\t}\n\n\n\t\t\tpublic override void Prepare() {\n\t\t\t\tDbCmd.Prepare();\n\t\t\t}\n\n\t\t\tprotected override DbParameter CreateDbParameter() {\n\t\t\t\treturn DbCmd.CreateParameter();\n\t\t\t}\n\n\t\t\tT ExecuteWithLogging<T>(Func<T> exec) {\n\t\t\t\tLogDbFactory.DbCommandExecuting(this);\n\t\t\t\tvar sw = new Stopwatch();\n\t\t\t\tsw.Start();\n\t\t\t\tT res = exec();\n\t\t\t\tsw.Stop();\n\t\t\t\tLogDbFactory.DbCommandExecuted(this, sw.Elapsed);\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tasync Task<T> ExecuteWithLogging<T>(Func<Task<T>> exec) {\n\t\t\t\tLogDbFactory.DbCommandExecuting(this);\n\t\t\t\tvar sw = new Stopwatch();\n\t\t\t\tsw.Start();\n\t\t\t\tT res = await exec().ConfigureAwait(false);\n\t\t\t\tsw.Stop();\n\t\t\t\tLogDbFactory.DbCommandExecuted(this, sw.Elapsed);\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tpublic override int ExecuteNonQuery() {\n\t\t\t\treturn ExecuteWithLogging( DbCmd.ExecuteNonQuery );\n\t\t\t}\n\n\t\t\tpublic override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken) {\n\t\t\t\treturn ExecuteWithLogging( ()=> DbCmd.ExecuteNonQueryAsync(cancellationToken) );\n\t\t\t}\n\n\t\t\tpublic override object ExecuteScalar() {\n\t\t\t\treturn ExecuteWithLogging( DbCmd.ExecuteScalar );\n\t\t\t}\n\n\t\t\tpublic override Task<object> ExecuteScalarAsync(CancellationToken cancellationToken) {\n\t\t\t\treturn ExecuteWithLogging( () => DbCmd.ExecuteScalarAsync(cancellationToken) );\n\t\t\t}\n\n\t\t\tprotected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) {\n\t\t\t\treturn ExecuteWithLogging( () => DbCmd.ExecuteReader(behavior) );\n\t\t\t}\n\n\t\t\tprotected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) {\n\t\t\t\treturn ExecuteWithLogging( () => DbCmd.ExecuteReaderAsync(behavior, cancellationToken) );\n\t\t\t}\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "examples/SqliteDemo.SqlLogging/Program.cs",
    "content": "﻿using System;\nusing System.IO;\nusing NReco.Data;\n\nnamespace SqliteDemo.SqlLogging { \n    class Program {\n\n        static void Main(string[] args) {\n\n\t\t\t// configure ADO.NET and NReco.Data components\n\t\t\tvar dbFactory = new LoggingDbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t};\n\t\t\tvar dbCmdBuilder = new DbCommandBuilder(dbFactory);\n\t\t\tvar dbConn = dbFactory.CreateConnection();\n\t\t\tdbConn.ConnectionString = \"Data Source=\"+Path.Combine(Directory.GetCurrentDirectory(), \"northwind.db\");\n\t\t\tvar dbAdapter = new DbDataAdapter(dbConn, dbCmdBuilder);\n\n\t\t\t// lets perform some queries to illustrate that logging works\n\t\t\tvar employeesCnt = dbAdapter.Select(new Query(\"Employees\").Select(QField.Count)).Single<int>();\n\n\t\t\tdbConn.Open(); // open connection for transaction\n\t\t\ttry {\n\t\t\t\tusing (var tr = dbConn.BeginTransaction()) {\n\t\t\t\t\tdbAdapter.Transaction = tr;\n\n\t\t\t\t\t// some updates\n\t\t\t\t\tdbAdapter.Insert(\"Employees\", new {\n\t\t\t\t\t\tEmployeeID = 1001,\n\t\t\t\t\t\tFirstName = \"Test\",\n\t\t\t\t\t\tLastName = \"Test\"\n\t\t\t\t\t});\n\t\t\t\t\tvar deleted = dbAdapter.DeleteAsync(new Query(\"Employees\", (QField)\"EmployeeID\">(QConst)1000)).Result;\n\n\t\t\t\t\ttr.Rollback(); // do not save these changes\n\t\t\t\t\tdbAdapter.Transaction = null; // clear transaction context\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tdbConn.Close();\n\t\t\t}\n\n\t\t\tConsole.WriteLine(\"Press any key to continue...\");\n\t\t\tConsole.ReadKey();\n\t\t}\n\n    }\n}"
  },
  {
    "path": "examples/SqliteDemo.SqlLogging/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"SqliteDemo.SqlLogging\": {\n      \"commandName\": \"Project\",\n      \"workingDirectory\": \"$(ProjectDir)\"\n    }\n  }\n}"
  },
  {
    "path": "examples/SqliteDemo.SqlLogging/SqliteDemo.SqlLogging.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n   <ItemGroup>\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" />\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\t\n  </ItemGroup>\n  \n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>  \n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>\n  \n</Project>"
  },
  {
    "path": "examples/SqliteDemo.WebApi/Controllers/DataApiController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\n\nusing NReco.Data;\n\nnamespace SqliteDemo.WebApi.Controllers\n{\n    [Route(\"api/db\")]\n    public class DataApiController : Controller\n    {\n\t\tDbDataAdapter DbAdapter;\n\n\t\tDictionary<string,string> allowedTableToIdName;\n\n\t\tpublic DataApiController(DbDataAdapter dbAdapter) {\n\t\t\tDbAdapter = dbAdapter;\n\n\t\t\tallowedTableToIdName = new Dictionary<string, string>() {\n\t\t\t\t{\"Categories\", \"CategoryID\"},\n\t\t\t\t{\"Customers\", \"CustomerID\"},\n\t\t\t\t{\"Orders\", \"OrderID\"},\n\t\t\t\t{\"Products\", \"ProductID\"}\n\t\t\t};\n\t\t}\n\n\t\tvoid CheckTable(string table) {\n\t\t\tif (!allowedTableToIdName.ContainsKey(table))\n\t\t\t\tthrow new NotSupportedException($\"Queries to table {table} are not allowed\");\n\t\t}\n\t\tQuery GetQueryByPk(string table, object idValue) {\n\t\t\tvar pkFldName = allowedTableToIdName[table];\n\t\t\tvar q = new Query(table, (QField)pkFldName == new QConst(idValue) );\n\t\t\treturn q;\n\t\t}\n\n        // GET api/db/rows?relex=Products[*;ProductID asc]\n        [HttpGet(\"rows\")]\n\t\t[HttpPost(\"rows\")]\n        public async Task<List<Dictionary<string,object>>> Get(string relex) {\n            var relexParser = new NReco.Data.Relex.RelexParser();\n\t\t\tvar q = relexParser.Parse(relex);\n\t\t\tCheckTable(q.Table.Name);\n\t\t\treturn await DbAdapter.Select(q).ToDictionaryListAsync().ConfigureAwait(false);\n        }\n\n        // GET api/db/Products/1\n        [HttpGet(\"{table}/{id}\")]\n        public async Task<Dictionary<string,object>> Get(string table, string id)\n        {\n\t\t\tCheckTable(table);\n\t\t\tvar q = GetQueryByPk(table, id);\n            return await DbAdapter.Select(q).ToDictionaryAsync().ConfigureAwait(false);\n        }\n\n        // POST api/db/Products\n        [HttpPost(\"{table}\")]\n        public async Task<bool> Post(string table, [FromBody]IDictionary<string,object> values) {\n\t\t\tCheckTable(table);\n\t\t\treturn await DbAdapter.InsertAsync(table, values).ConfigureAwait(false)>0;\n\t\t}\n\n        // PUT api/db/Products/1 + serialized json object in body\n        [HttpPut(\"{table}/{id}\")]\n        public async Task<bool> Put(string table, string id, [FromBody]IDictionary<string,object> values) {\n\t\t\tCheckTable(table);\n\t\t\tvar q = GetQueryByPk(table, id);\n\t\t\treturn await DbAdapter.UpdateAsync(q, values).ConfigureAwait(false)>0;\n        }\n\n        // DELETE api/db/Products/1\n        [HttpDelete(\"{table}/{id}\")]\n        public async Task<bool> Delete(string table, string id) {\n\t\t\tCheckTable(table);\n\t\t\tvar q = GetQueryByPk(table, id);\n\t\t\treturn await DbAdapter.DeleteAsync(q).ConfigureAwait(false)>0;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/Data/NRecoDataServiceCollectionsExt.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Data;\n\nusing Microsoft.Extensions.DependencyInjection;\nusing NReco.Data;\n\nnamespace SqliteDemo.WebApi\n{\n    \n\tpublic static class NRecoDataServiceCollectionsExt {\n\n\t\tpublic static IServiceCollection AddNRecoDataSqlite(this IServiceCollection services, string dbConnectionString = null) {\n\t\t\t\n\t\t\tservices.AddSingleton<IDbFactory,DbFactory>( (servicePrv) => {\n\t\t\t\t// db-provider specific configuration code:\n\t\t\t\treturn new DbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t\t};\n\t\t\t});\n\t\t\tservices.AddSingleton<IDbCommandBuilder,DbCommandBuilder>( (servicePrv) => {\n\t\t\t\tvar dbCmdBuilder = new DbCommandBuilder(servicePrv.GetRequiredService<IDbFactory>() );\n\t\t\t\t// initialize dataviews here:\n\t\t\t\t//dbCmdBuilder.Views[\"some_view\"] = new DbDataView(...);\n\t\t\t\treturn dbCmdBuilder;\n\t\t\t} );\n\n\t\t\tif (dbConnectionString!=null) {\n\t\t\t\t// lets add IDbConnection to services; otherwise NReco.Data components will use IDbConnection instance defined outside\n\t\t\t\tservices.AddScoped<IDbConnection>( (servicePrv) => {\n\t\t\t\t\tvar dbFactory = servicePrv.GetRequiredService<IDbFactory>();\n\t\t\t\t\tvar conn = dbFactory.CreateConnection();\n\t\t\t\t\tconn.ConnectionString = dbConnectionString;\n\t\t\t\t\treturn conn;\n\t\t\t\t} );\n\t\t\t}\n\t\t\tservices.AddScoped<DbDataAdapter>();\n\n\t\t\treturn services;\n\t\t}\n\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Builder;\n\nnamespace SqliteDemo.WebApi\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var host = new WebHostBuilder()\n                .UseKestrel()\n                .UseContentRoot(Directory.GetCurrentDirectory())\n                .UseIISIntegration()\n                .UseIIS()\n                .UseStartup<Startup>()\n                .Build();\n\n            host.Run();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/Properties/launchSettings.json",
    "content": "{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:59530/\",\n      \"sslPort\": 0\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"index.html\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"SqliteDemo.WebApi\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"http://localhost:5000/index.html\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "examples/SqliteDemo.WebApi/SqliteDemo.WebApi.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.NewtonsoftJson\" Version=\"8.0.*\" />  \n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n    <PackageReference Include=\"NReco.Data\" Version=\"1.2.*\" /> \n  </ItemGroup>\n\n  <ItemGroup>  \n    <MySourceFiles Include=\"$(MSBuildProjectDirectory)/../DemoData/northwind.db\"/>  \n  </ItemGroup>\n  <Target Name=\"CopySqliteDbFile\" BeforeTargets=\"Build\">\n\t<Copy SourceFiles=\"@(MySourceFiles)\"  \n          DestinationFolder=\"$(MSBuildProjectDirectory)\"/>  \n  </Target>\n  \n</Project>\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/Startup.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.IO;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace SqliteDemo.WebApi\n{\n    public class Startup\n    {\n        IWebHostEnvironment HostingEnv;\n\n        public Startup(IWebHostEnvironment env)\n        {\n\t\t\tHostingEnv = env;\n            var builder = new ConfigurationBuilder()\n                .SetBasePath(env.ContentRootPath)\n                .AddJsonFile(\"appsettings.json\", optional: true, reloadOnChange: true)\n                .AddJsonFile($\"appsettings.{env.EnvironmentName}.json\", optional: true);\n\n            builder.AddEnvironmentVariables();\n            Configuration = builder.Build();\n        }\n\n        public IConfigurationRoot Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddLogging(loggingBuilder => {\n                var loggingSection = Configuration.GetSection(\"Logging\");\n                loggingBuilder.AddConfiguration(loggingSection);\n                loggingBuilder.AddConsole();\n            });\n\n            services.AddMvc(options => {\n                options.EnableEndpointRouting = false;\n            }).AddNewtonsoftJson(options => {\n                options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;\n                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();\n                options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter { CamelCaseText = false });\n            });\n\n\t\t\t// add NReco.Data services\n\t\t\tvar sqliteDbPath = Path.Combine( HostingEnv.ContentRootPath, \"northwind.db\");\n\t\t\tservices.AddNRecoDataSqlite($\"Data Source={sqliteDbPath}\");\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)\n        {\n\t\t\tapp.UseDefaultFiles();\n\t\t\tapp.UseStaticFiles();\n            app.UseMvc();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/web.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\n  <!--\n    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380\n  -->\n\n  <system.webServer>\n    <handlers>\n      <add name=\"aspNetCore\" path=\"*\" verb=\"*\" modules=\"AspNetCoreModule\" resourceType=\"Unspecified\"/>\n    </handlers>\n    <aspNetCore processPath=\"%LAUNCHER_PATH%\" arguments=\"%LAUNCHER_ARGS%\" stdoutLogEnabled=\"false\" stdoutLogFile=\".\\logs\\stdout\" forwardWindowsAuthToken=\"false\"/>\n  </system.webServer>\n</configuration>\n"
  },
  {
    "path": "examples/SqliteDemo.WebApi/wwwroot/index.html",
    "content": "﻿<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <title>NReco.Data WebApi Example</title>\n\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\n    <!-- bootstrap (optional) -->\n    <link href=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css\" rel=\"stylesheet\" />\n    <script type=\"text/javascript\" src=\"//code.jquery.com/jquery-2.1.4.min.js\"></script>\n    <script type=\"text/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js\"></script>\n\n</head>\n<body>\n\n    <div class=\"container\">\n        <h1>\n            NReco.Data WebApi Example\n            <small>simple generic REST API to database</small>\n        </h1>\n\n        <h3>Load rows</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"selectRows\" rows=\"8\">$.ajax(\"api/db/rows\", {\n    type: \"GET\",\n    data: {\n        relex : \"Products(UnitPrice>20)[*;ProductID desc]\"\n    }\n}).success(function (res) {\n    $('#selectRowsResult').text( JSON.stringify(res) );\n});\n                </textarea>\n                <br/>\n                <a href=\"javascript:;\" rel=\"selectRows\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"selectRowsResult\" style=\"white-space:pre-wrap; max-height:250px;\"></pre>\n            </div>\n        </div>\n\n        <h3>Load one row</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"selectOneRow\" rows=\"5\">$.ajax(\"api/db/Products/1\", {\n    type: \"GET\"\n}).success(function (res) {\n    $('#selectOneRowResult').text( JSON.stringify(res) );\n});\n                </textarea>\n                <br/>\n                <a href=\"javascript:;\" rel=\"selectOneRow\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"selectOneRowResult\" style=\"white-space:pre-wrap; max-height:150px;\"></pre>\n            </div>\n        </div>\n\n        <h3>Add new row</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"addRow\" rows=\"8\">\n$.ajax(\"api/db/Products\", {\n    type: \"POST\",\n    contentType: \"application/json\",\n    data: JSON.stringify( {\n        ProductID   : 100,\n        ProductName : \"Test Product\"\n    } )\n}).success(function (res) {\n    $('#addRowResult').text( JSON.stringify(res) );\n});\n                </textarea>\n                <br />\n                <a href=\"javascript:;\" rel=\"addRow\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"addRowResult\" style=\"white-space:pre-wrap; max-height:150px;\"></pre>\n            </div>\n        </div>\n\n        <h3>Update row</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"updateRow\" rows=\"8\">\n$.ajax(\"api/db/Products/100\", {\n    type: \"PUT\",\n    contentType: \"application/json\",\n    data: JSON.stringify( {\n        ProductName : \"Test Product (updated)\"\n    } )\n}).success(function (res) {\n    $('#updateRowResult').text( JSON.stringify(res) );\n});\n                </textarea>\n                <br />\n                <a href=\"javascript:;\" rel=\"updateRow\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"updateRowResult\" style=\"white-space:pre-wrap; max-height:150px;\"></pre>\n            </div>\n        </div>\n\n\n        <h3>Delete row</h3>\n        <div class=\"row\">\n            <div class=\"col-md-6\">\n                <textarea class=\"form-control\" id=\"delRow\" rows=\"8\">\n$.ajax(\"api/db/Products/100\", {\n    type: \"DELETE\"\n}).success(function (res) {\n    $('#deleteRowResult').text( JSON.stringify(res) );\n});\n                </textarea>\n                <br />\n                <a href=\"javascript:;\" rel=\"delRow\" class=\"btn btn-default run\">Run</a>\n            </div>\n            <div class=\"col-md-6\">\n                <pre id=\"deleteRowResult\" style=\"white-space:pre-wrap; max-height:150px;\"></pre>\n            </div>\n        </div>\n\n    </div>\n\n    <script type=\"text/javascript\">\n        $(function() {\n            $('.run').click(function () {\n                var $textarea = $('#' + $(this).attr('rel'));\n                eval($textarea.val());\n            });\n        });\n    </script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/NReco.Data/DataHelper.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\nusing System.Reflection;\nusing System.IO;\n\nnamespace NReco.Data {\n\t\n\tinternal static class DataHelper {\n\n\t\tinternal static bool IsNullOrDBNull(object v) {\n\t\t\treturn v==null || DBNull.Value.Equals(v);\n\t\t}\n\n\t\tinternal static void EnsureConnectionOpen(IDbConnection connection, Action a) {\n\t\t\tbool closeConn = false;\n\t\t\tif (connection.State != ConnectionState.Open) {\n\t\t\t\tconnection.Open();\n\t\t\t\tcloseConn = true;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\ta();\n\t\t\t} finally {\n\t\t\t\tif (closeConn && connection.State!=ConnectionState.Closed)\n\t\t\t\t\tconnection.Close();\n\t\t\t}\n\t\t}\n\n\t\tinternal static QNode MapQValue(QNode qNode, Func<IQueryValue,IQueryValue> mapFunc) {\n\t\t\tif (qNode is QGroupNode) {\n\t\t\t\tvar group = new QGroupNode((QGroupNode)qNode);\n\t\t\t\tfor (int i = 0; i < group.Nodes.Count; i++)\n\t\t\t\t\tgroup.Nodes[i] = MapQValue(group.Nodes[i], mapFunc);\n\t\t\t\treturn group;\n\t\t\t}\n\t\t\tif (qNode is QConditionNode) {\n\t\t\t\tvar origCndNode = (QConditionNode)qNode;\n\t\t\t\tvar cndNode = new QConditionNode(origCndNode.Name,\n\t\t\t\t\t\tmapFunc(origCndNode.LValue),\n\t\t\t\t\t\torigCndNode.Condition,\n\t\t\t\t\t\tmapFunc(origCndNode.RValue));\n\t\t\t\treturn cndNode;\n\t\t\t}\n\t\t\tif (qNode is QNegationNode) {\n\t\t\t\tvar negNode = new QNegationNode((QNegationNode)qNode);\n\t\t\t\tfor (int i = 0; i < negNode.Nodes.Count; i++)\n\t\t\t\t\tnegNode.Nodes[i] = MapQValue(negNode.Nodes[i], mapFunc);\n\t\t\t\treturn negNode;\n\t\t\t}\n\t\t\treturn qNode;\n\t\t}\n\n\t\tinternal static RecordSet GetRecordSetByReader(IDataReader rdr) {\n\t\t\tvar rsCols = new List<RecordSet.Column>(rdr.FieldCount);\n\t\t\tvar rsPkCols = new List<RecordSet.Column>();\n\n\t\t\t#if NET_STANDARD\n\t\t\t// lets populate data schema\n\t\t\tif (rdr is DbDataReader) {\n\t\t\t\tvar dbRdr = (DbDataReader)rdr;\n\t\t\t\tif (dbRdr.CanGetColumnSchema()) {\n\t\t\t\t\tforeach (var dbCol in dbRdr.GetColumnSchema()) {\n\t\t\t\t\t\tvar c = new RecordSet.Column(dbCol);\n\t\t\t\t\t\t// if this is default implementation resolve DataType with GetFieldType\n\t\t\t\t\t\tif (c.DataType==null) {\n\t\t\t\t\t\t\tc.DataType = rdr.GetFieldType(rdr.GetOrdinal(c.Name));\n\t\t\t\t\t\t}\n\t\t\t\t\t\trsCols.Add(c);\n\t\t\t\t\t\tif (dbCol.IsKey.HasValue && dbCol.IsKey.Value)\n\t\t\t\t\t\t\trsPkCols.Add(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t#endif\n\n\t\t\tif (rsCols.Count==0) {\n\t\t\t\t// lets suggest columns by standard IDataReader interface\n\t\t\t\tfor (int i=0; i<rdr.FieldCount; i++) {\n\t\t\t\t\tvar colName = rdr.GetName(i);\n\t\t\t\t\tvar colType = rdr.GetFieldType(i);\n\t\t\t\t\trsCols.Add( new RecordSet.Column(colName, colType) );\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar rs = new RecordSet(rsCols.ToArray(), 1);\n\t\t\tif (rsPkCols.Count>0)\n\t\t\t\trs.PrimaryKey = rsPkCols.ToArray();\n\t\t\treturn rs;\n\t\t}\n\n\t\tinternal static void EnsureDataTableColumnsByReader(DataTable tbl, IDataReader rdr) {\n\t\t\t#if NET_STANDARD\n\t\t\t// lets populate data schema\n\t\t\tif (rdr is DbDataReader) {\n\t\t\t\tvar dbRdr = (DbDataReader)rdr;\n\t\t\t\tif (dbRdr.CanGetColumnSchema()) {\n\t\t\t\t\tvar pkCols = new List<DataColumn>();\n\t\t\t\t\tforeach (var dbCol in dbRdr.GetColumnSchema()) {\n\t\t\t\t\t\tDataColumn col = null;\n\t\t\t\t\t\tif (!tbl.Columns.Contains(dbCol.ColumnName)) {\n\t\t\t\t\t\t\tcol = tbl.Columns.Add(dbCol.ColumnName, dbCol.DataType);\n\t\t\t\t\t\t\tif (dbCol.AllowDBNull.HasValue)\n\t\t\t\t\t\t\t\tcol.AllowDBNull = dbCol.AllowDBNull.Value;\n\t\t\t\t\t\t\tif (dbCol.IsAutoIncrement.HasValue && dbCol.IsAutoIncrement.Value)\n\t\t\t\t\t\t\t\tcol.AutoIncrement = true;\n\t\t\t\t\t\t\tif (dbCol.IsReadOnly.HasValue)\n\t\t\t\t\t\t\t\tcol.ReadOnly = dbCol.IsReadOnly.Value;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = tbl.Columns[dbCol.ColumnName];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (dbCol.IsKey.HasValue && dbCol.IsKey.Value)\n\t\t\t\t\t\t\tpkCols.Add(col);\n\t\t\t\t\t}\n\t\t\t\t\tif (pkCols.Count > 0 && (tbl.PrimaryKey == null || tbl.PrimaryKey.Length == 0))\n\t\t\t\t\t\ttbl.PrimaryKey = pkCols.ToArray();\n\t\t\t\t}\n\t\t\t}\n\t\t\t#endif\n\n\t\t\t// lets suggest columns by standard IDataReader interface\n\t\t\tfor (int i = 0; i < rdr.FieldCount; i++) {\n\t\t\t\tvar colName = rdr.GetName(i);\n\t\t\t\tvar colType = rdr.GetFieldType(i);\n\t\t\t\tif (!tbl.Columns.Contains(colName)) {\n\t\t\t\t\ttbl.Columns.Add(colName, colType);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tinternal static IEnumerable<KeyValuePair<string, IQueryValue>> GetChangeset(IDictionary data) {\n\t\t\tif (data == null)\n\t\t\t\tyield break;\n\t\t\tforeach (DictionaryEntry entry in data) {\n\t\t\t\tvar qVal = entry.Value is IQueryValue ? (IQueryValue)entry.Value : new QConst(entry.Value);\n\t\t\t\tyield return new KeyValuePair<string, IQueryValue>( Convert.ToString( entry.Key ), qVal );\n\t\t\t}\n\t\t}\n\n\t\tinternal static IEnumerable<KeyValuePair<string, IQueryValue>> GetChangeset(IDictionary<string,object> data) {\n\t\t\tif (data == null)\n\t\t\t\tyield break;\n\t\t\tforeach (var entry in data) {\n\t\t\t\tvar qVal = entry.Value is IQueryValue ? (IQueryValue)entry.Value : new QConst(entry.Value);\n\t\t\t\tyield return new KeyValuePair<string, IQueryValue>( entry.Key, qVal );\n\t\t\t}\n\t\t}\n\n\t\tinternal static IEnumerable<KeyValuePair<string, IQueryValue>> GetChangeset(object o, DataMapper dtoMapper) {\n\t\t\tif (o == null)\n\t\t\t\tyield break;\n\t\t\tvar oType = o.GetType();\n\t\t\tvar schema = (dtoMapper??DataMapper.Instance).GetSchema(oType);\n\t\t\tforeach (var columnMapping in schema.Columns) {\n\t\t\t\tif (columnMapping.IsReadOnly || columnMapping.GetVal==null)\n\t\t\t\t\tcontinue;\n\t\t\t\tvar pVal = columnMapping.GetVal(o);\n\t\t\t\tvar qVal = pVal is IQueryValue ? (IQueryValue)pVal : new QConst(pVal);\n\t\t\t\tvar fldName = columnMapping.ColumnName;\n\t\t\t\tyield return new KeyValuePair<string, IQueryValue>(fldName, qVal );\n\t\t\t}\n\t\t}\n\n\t\tinternal static bool IsSimpleIdentifier(string s) {\n\t\t\tif (s!=null)\n\t\t\t\tfor (int i=0; i<s.Length; i++) {\n\t\t\t\t\tvar ch = s[i];\n\t\t\t\t\tif (!Char.IsLetterOrDigit(ch) && ch!='-' && ch!='_')\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\treturn true;\t\t\t\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DataMapper.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Concurrent;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\nusing System.Reflection;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing System.IO;\n\nnamespace NReco.Data {\n\t\n\tinternal class DataMapper {\n\t\t\n\t\tinternal readonly static DataMapper Instance = new DataMapper();\n\n\t\tIDictionary<Type,PocoModelSchema> SchemaCache;\n\n\t\tinternal DataMapper() {\n\t\t\tSchemaCache = new ConcurrentDictionary<Type, PocoModelSchema>();\n\t\t}\n\n\t\tPocoModelSchema InferSchema(Type t) {\n\t\t\tvar keyCols = new List<ColumnMapping>();\n\t\t\tvar cols = new List<ColumnMapping>();\n\t\t\tforeach (var prop in t.GetProperties()) {\n\t\t\t\tvar metadata = CheckSchemaAttributes(prop.GetCustomAttributes());\n\t\t\t\tif (metadata.Item3) // not mapped\n\t\t\t\t\tcontinue; \n\t\t\t\tvar colMapping = new ColumnMapping( \n\t\t\t\t\tmetadata.Item1 ?? prop.Name, t, prop.Name, prop.PropertyType, \n\t\t\t\t\tprop.CanRead, prop.CanWrite,\n\t\t\t\t\tmetadata.Item4, metadata.Item5, metadata.Item2);\n\t\t\t\tif (metadata.Item2) // is key\n\t\t\t\t\tkeyCols.Add(colMapping);\n\t\t\t\tcols.Add(colMapping);\n\t\t\t}\n\t\t\tforeach (var fld in t.GetFields()) {\n\t\t\t\tvar metadata = CheckSchemaAttributes(fld.GetCustomAttributes());\n\t\t\t\tif (metadata.Item3) // not mapped\n\t\t\t\t\tcontinue; \n\t\t\t\tvar colMapping = new ColumnMapping( \n\t\t\t\t\tmetadata.Item1 ?? fld.Name, t, fld.Name, fld.FieldType, \n\t\t\t\t\ttrue, true,\n\t\t\t\t\tmetadata.Item4, metadata.Item5, metadata.Item2);\n\t\t\t\tif (metadata.Item2) // is key\n\t\t\t\t\tkeyCols.Add(colMapping);\n\t\t\t\tcols.Add(colMapping);\n\t\t\t}\n\t\t\tvar typeAttrs = t.GetCustomAttributes(true);\n\t\t\tvar tableAttr = typeAttrs.Where(a=>a is TableAttribute).Select(a=>(TableAttribute)a).FirstOrDefault();\n\t\t\treturn new PocoModelSchema( ( tableAttr?.Name ) ?? t.Name, cols.ToArray(), keyCols.ToArray(), t );\n\t\t}\n\n\t\tinternal PocoModelSchema GetSchema(Type t) {\n\t\t\tPocoModelSchema schema = null;\n\t\t\tif (!SchemaCache.TryGetValue(t, out schema)) {\n\t\t\t\tschema = InferSchema(t);\n\t\t\t\tSchemaCache[t] = schema;\n\t\t\t}\n\t\t\treturn schema;\n\t\t}\n\n\t\tTuple<string,bool,bool,bool,bool> CheckSchemaAttributes(IEnumerable<Attribute> attrs) {\n\t\t\tbool isNotMapped = false;\n\t\t\tbool isKey = false;\n\t\t\tbool isDbGenerated = false;\n\t\t\tbool isIdentity = false;\n\t\t\tstring colName = null;\n\t\t\tforeach (var attr in attrs) {\n\t\t\t\tif (attr is NotMappedAttribute) {\n\t\t\t\t\tisNotMapped = true;\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (attr is KeyAttribute) {\n\t\t\t\t\tisKey = true;\n\t\t\t\t} else if (attr is ColumnAttribute) {\n\t\t\t\t\tvar colAttr = (ColumnAttribute)attr;\n\t\t\t\t\tcolName = colAttr.Name;\n\t\t\t\t} else if (attr is DatabaseGeneratedAttribute) {\n\t\t\t\t\tvar dbGenAttr = ((DatabaseGeneratedAttribute)attr);\n\t\t\t\t\tisDbGenerated = dbGenAttr.DatabaseGeneratedOption != DatabaseGeneratedOption.None;\n\t\t\t\t\tif (dbGenAttr.DatabaseGeneratedOption==DatabaseGeneratedOption.Identity)\n\t\t\t\t\t\tisIdentity = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new Tuple<string,bool,bool,bool,bool>(colName, isKey, isNotMapped, isDbGenerated, isIdentity);\n\t\t}\n\n\t\tinternal void MapTo(IDataRecord record, object o, Type type, PocoModelSchema schema) {\n\t\t\tfor (int i = 0; i < record.FieldCount; i++) {\n\t\t\t\tvar fieldName = record.GetName(i);\n\t\t\t\tvar colMapping = schema.GetColumnMapping(fieldName);\n\t\t\t\tif (colMapping==null || colMapping.SetVal==null)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tvar fieldValue = record.GetValue(i);\n\t\t\t\t\n\t\t\t\tif (DataHelper.IsNullOrDBNull(fieldValue)) {\n\t\t\t\t\tfieldValue = null;\n\t\t\t\t\tif (Nullable.GetUnderlyingType(colMapping.ValueType) == null && colMapping.ValueType.IsValueType)\n\t\t\t\t\t\tfieldValue = colMapping.DefaultValue;\n\t\t\t\t}\n\t\t\t\tcolMapping.SetValue(o, fieldValue);\n\t\t\t}\n\t\t}\n\n\t\tinternal T MapTo<T>(IDataRecord record) {\n\t\t\treturn (T)MapTo(record, typeof(T));\n\t\t}\n\n\t\tinternal object MapTo(IDataRecord record, Type type) {\n\t\t\tvar schema = GetSchema(type);\n\t\t\tif (schema.CreateModel==null)\n\t\t\t\tthrow new ArgumentException($\"Type '{type.Name}' does not have a default constructor\");\t\n\t\t\tvar o = schema.CreateModel();\n\t\t\tMapTo(record, o, type, schema);\n\t\t\treturn o;\n\t\t}\n\n\t\tinternal class PocoModelSchema {\n\t\t\t\n\t\t\tinternal readonly string TableName;\n\n\t\t\tinternal readonly ColumnMapping[] Key;\n\n\t\t\tinternal readonly ColumnMapping[] Columns;\n\n\t\t\tinternal readonly Type ModelType;\n\n\t\t\tDictionary<string,ColumnMapping> ColNameMap;\n\n\t\t\tinternal Func<object> CreateModel;\n\n\t\t\tinternal PocoModelSchema(string tableName, ColumnMapping[] cols, ColumnMapping[] key, Type modelType) {\n\t\t\t\tTableName = tableName;\n\t\t\t\tColumns = cols;\n\t\t\t\tKey = key;\n\t\t\t\tColNameMap = new Dictionary<string, ColumnMapping>(Columns.Length);\n\t\t\t\tfor (int i=0; i<Columns.Length; i++) {\n\t\t\t\t\tColNameMap[Columns[i].ColumnName] = Columns[i];\n\t\t\t\t}\n\t\t\t\tModelType = modelType;\n\n\t\t\t\tif (modelType.GetConstructor(Type.EmptyTypes)!=null) {\n\t\t\t\t\tvar createExpr = Expression.Lambda<Func<object>>( Expression.New(modelType) );\n\t\t\t\t\tCreateModel = createExpr.Compile();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal ColumnMapping GetColumnMapping(string colName) {\n\t\t\t\tColumnMapping colMapping = null;\n\t\t\t\tColNameMap.TryGetValue(colName, out colMapping);\n\t\t\t\treturn colMapping;\n\t\t\t}\n\t\t}\n\n\t\tinternal class ColumnMapping {\n\t\t\tinternal readonly string ColumnName;\n\t\t\tinternal readonly Type ValueType;\n\n\t\t\tinternal readonly Func<object,object> GetVal;\n\t\t\tinternal readonly Action<object,object> SetVal;\n\n\t\t\tinternal readonly bool IsReadOnly;\n\n\t\t\tinternal readonly bool IsIdentity;\n\n\t\t\tinternal readonly bool IsKey;\n\n\t\t\tinternal object DefaultValue;\n\n\t\t\treadonly Type ConvertToType;\n\t\t\treadonly bool IsEnum;\n\n\t\t\tinternal ColumnMapping(\n\t\t\t\t\tstring colName, Type t, \n\t\t\t\t\tstring propOrFieldName, Type propOrFieldType, \n\t\t\t\t\tbool canRead, bool canWrite,\n\t\t\t\t\tbool isReadOnly, bool isIdentity, bool isKey) {\n\t\t\t\tColumnName = colName;\n\t\t\t\tValueType = propOrFieldType;\n\t\t\t\tIsReadOnly = isReadOnly;\n\t\t\t\tIsIdentity = isIdentity;\n\t\t\t\tIsKey = isKey;\n\n\t\t\t\tDefaultValue = null;\n\t\t\t\tif (ValueType.IsValueType)\n\t\t\t\t\tDefaultValue = Activator.CreateInstance(ValueType);\n\n\t\t\t\tConvertToType = ValueType;\n\t\t\t\tif (Nullable.GetUnderlyingType(ValueType) != null)\n\t\t\t\t\tConvertToType = Nullable.GetUnderlyingType(ValueType);\n\t\t\t\tIsEnum = ConvertToType.IsEnum;\n\n\t\t\t\t// compose get\n\t\t\t\tif (canRead) {\n\t\t\t\t\tvar getParamObj = Expression.Parameter(typeof(object));\n\t\t\t\t\tvar getterExpr = Expression.Lambda<Func<object,object>>(\n\t\t\t\t\t\t\tExpression.Convert(\n\t\t\t\t\t\t\t\tExpression.PropertyOrField( Expression.Convert(getParamObj,t), propOrFieldName ),\n\t\t\t\t\t\t\t\ttypeof(object)\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tgetParamObj\n\t\t\t\t\t\t);\n\t\t\t\t\tGetVal = getterExpr.Compile();\n\t\t\t\t}\n\n\t\t\t\t// compose set\n\t\t\t\tif (canWrite) {\n\t\t\t\t\tvar setParamObj = Expression.Parameter(typeof(object));\n\t\t\t\t\tvar setParamVal = Expression.Parameter(typeof(object));\n\t\t\t\t\tvar setterExpr = Expression.Lambda<Action<object,object>>(\n\t\t\t\t\t\tExpression.Assign( \n\t\t\t\t\t\t\tExpression.PropertyOrField( Expression.Convert(setParamObj,t) , propOrFieldName ), \n\t\t\t\t\t\t\tExpression.Convert(setParamVal, propOrFieldType)\n\t\t\t\t\t\t), setParamObj, setParamVal\n\t\t\t\t\t);\n\t\t\t\t\tSetVal = setterExpr.Compile();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal bool SetValue(object obj, object val) {\n\t\t\t\tif (SetVal==null)\n\t\t\t\t\treturn false;\n\t\t\t\tif (val!=null) {\n\t\t\t\t\tif (IsEnum) {\n\t\t\t\t\t\tval = Enum.Parse(ConvertToType, val.ToString(), true); \n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = Convert.ChangeType(val, ConvertToType );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tSetVal(obj, val);\n\t\t\t\treturn true;\t\t\t\n\t\t\t}\n\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbBatchCommandBuilder.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Data;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Batch command builder that can produce several SQL statements into one <see cref=\"IDbCommand\"/>.\n\t/// </summary>\n\tpublic class DbBatchCommandBuilder : DbCommandBuilder {\n\t\t\n\t\t/// <summary>\n\t\t/// Gets current <see cref=\"IDbCommand\"/> with batch of SQL statements.\n\t\t/// </summary>\n\t\tpublic IDbCommand CurrentBatchCommand { get; private set; } = null;\n\n\t\t/// <summary>\n\t\t/// Gets or sets separator between SQL statements (';' by default).\n\t\t/// </summary>\n\t\tpublic string SqlStatementSeparator { get; set; } = \";\";\n\n\t\tpublic DbBatchCommandBuilder(IDbFactory dbFactory) : base(dbFactory) {\n\n\t\t}\n\n\t\tpublic void BeginBatch() {\n\t\t\tCurrentBatchCommand = base.GetCommand();\n\t\t}\n\n\t\tpublic IDbCommand EndBatch() {\n\t\t\tif (CurrentBatchCommand==null)\n\t\t\t\tthrow new InvalidOperationException(\"BatchEnd should follow after BeginBatch\");\n\t\t\tvar cmd = CurrentBatchCommand;\n\t\t\tCurrentBatchCommand = null;\n\t\t\treturn cmd;\n\t\t}\n\n\t\tprotected override IDbCommand GetCommand() {\n\t\t\tif (CurrentBatchCommand!=null)\n\t\t\t\treturn CurrentBatchCommand;\n\t\t\treturn base.GetCommand();\n\t\t}\n\n\t\tprotected override void SetCommandText(IDbCommand cmd, string sqlStatement) {\n\t\t\tif (CurrentBatchCommand!=null && CurrentBatchCommand.CommandText!=null && CurrentBatchCommand.CommandText.Length>0) {\n\t\t\t\tCurrentBatchCommand.CommandText += SqlStatementSeparator + sqlStatement;\n\t\t\t} else {\n\t\t\t\tbase.SetCommandText(cmd, sqlStatement);\n\t\t\t}\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbCommandBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Text;\nusing System.ComponentModel;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Automatically generates SQL commands for SELECT/INSERT/UPDATE/DELETE queries.\n\t/// </summary>\n\tpublic class DbCommandBuilder : IDbCommandBuilder\n\t{\n\n\t\t/// <summary>\n\t\t/// Gets DB Factory component.\n\t\t/// </summary>\n\t\tpublic IDbFactory DbFactory {  get; private set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets template for SQL SELECT query.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Template is processed with <see cref=\"StringTemplate\"/>.\n\t\t/// List of available variables:\n\t\t/// <list>\n\t\t/// <item>@columns (comma-separated list of fields from Query or '*')</item>\n\t\t/// <item>@table (table name, possibly with alias like 'users u')</item>\n\t\t/// <item>@where (query conditions, may be empty)</item>\n\t\t/// <item>@orderby (order by expression, may be empty)</item>\n\t\t/// <item>@recordoffset (starting record index offset, 0 by default)</item>\n\t\t/// <item>@recordcount (max number of records to return, empty if not specified)</item>\n\t\t/// <item>@recordtop (recordoffset+recordcount, empty if recordcount is not specified)</item>\t\n\t\t/// <item>@&lt;extendedPropertyKey&gt; (value from Query.ExtendedProperties dictionary)</item>\n\t\t/// </list>\n\t\t/// @record* variables are useful for database-specific paging optimizations, for example:\n\t\t/// <code>\n\t\t/// // MS SQL TOP syntax\n\t\t/// DbCommandBuilder cmdBuilder;\n\t\t/// cmdBuilder = \"SELECT @recordtop[TOP {0}] @columns FROM @table @where[ WHERE {0}] @groupby[ GROUP BY {0}] @orderby[ ORDER BY {0}]\";\n\t\t/// </code>\n\t\t/// <code>\n\t\t/// // PostgreSql LIMIT and OFFSET syntax\n\t\t/// DbCommandBuilder cmdBuilder;\n\t\t/// cmdBuilder = \"SELECT @columns FROM @table @where[ WHERE {0}] @groupby[ GROUP BY {0}] @orderby[ ORDER BY {0}] @recordcount[LIMIT {0}] @recordoffset[OFFSET {0}]\";\n\t\t/// </code>\n\t\t/// Note that if offset is applied on DB level and <see cref=\"DbDataAdapter.ApplyOffset\"/> should be false. \n\t\t/// </remarks>\n\t\tpublic string SelectTemplate { get; set; } = \"SELECT @columns FROM @table@where[ WHERE {0}]@groupby[ GROUP BY {0}]@orderby[ ORDER BY {0}]\";\n\n\t\t/// <summary>\n\t\t/// Gets or sets template for SQL UPDATE query.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Template is processed with <see cref=\"StringTemplate\"/>.\n\t\t/// List of available variables:\n\t\t/// <list>\n\t\t/// <item>@table (table name)</item>\n\t\t/// <item>@set (comma-separated set statements)</item>\t\t\n\t\t/// <item>@where (query conditions, may be empty)</item>\t\t\n\t\t/// </list>\n\t\t/// </remarks>\n\t\tpublic string UpdateTemplate { get; set; } = \"UPDATE @table SET @set @where[WHERE {0}]\";\n\n\t\t/// <summary>\n\t\t/// Gets or sets template for SQL INSERT query.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Template is processed with <see cref=\"StringTemplate\"/>.\n\t\t/// List of available variables:\n\t\t/// <list>\n\t\t/// <item>@table (table name)</item>\n\t\t/// <item>@columns (comma-separated list of columns)</item>\t\n\t\t/// <item>@values (comma-separated list of values)</item>\t\t\n\t\t/// </list>\n\t\t/// </remarks>\t\t\n\t\tpublic string InsertTemplate { get; set; } = \"INSERT INTO @table (@columns) VALUES (@values)\";\n\t\t\n\t\t/// <summary>\n\t\t/// Gets or sets template for SQL DELETE query.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Template is processed with <see cref=\"StringTemplate\"/>.\n\t\t/// List of available variables:\n\t\t/// <list>\n\t\t/// <item>@table (table name)</item>\n\t\t/// <item>@where (query conditions, may be empty)</item>\t\n\t\t/// </list>\n\t\t/// </remarks>\t\t\t\n\t\tpublic string DeleteTemplate { get; set; } = \"DELETE FROM @table @where[WHERE {0}]\";\n\n\t\t/// <summary>\n\t\t/// Gets or sets view name -> <see cref=\"DbDataView\"/> dictionary.\n\t\t/// </summary>\n\t\tpublic IDictionary<string,DbDataView> Views { get; set; }\n\n\t\tFunc<string, StringTemplate> _createStringTemplate;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the DbCommandBuilder.\n\t\t/// </summary>\n\t\t/// <param name=\"dbFactory\">DB provider-specific factory implementation</param>\n\t\tpublic DbCommandBuilder(IDbFactory dbFactory) {\n\t\t\tDbFactory = dbFactory;\n\t\t\tViews = new Dictionary<string,DbDataView>();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the DbCommandBuilder with the specified StringTemplate factory method.\n\t\t/// </summary>\n\t\t/// <param name=\"dbFactory\">DB provider-specific factory implementation</param>\n\t\t/// <param name=\"createStringTemplate\">StringTemplate factory method</param>\n\t\tpublic DbCommandBuilder(IDbFactory dbFactory, Func<string, StringTemplate> createStringTemplate) {\n\t\t\tDbFactory = dbFactory;\n\t\t\tViews = new Dictionary<string, DbDataView>();\n\t\t\t_createStringTemplate = createStringTemplate;\n\t\t}\n\n\t\tprotected ISqlExpressionBuilder GetSqlBuilder(IDbCommand cmd) {\n\t\t\tISqlExpressionBuilder sqlBuilder = null;\n\t\t\tsqlBuilder = DbFactory.CreateSqlBuilder(cmd, (q) => { return BuildSelectInternal(q,sqlBuilder,true); } );\n\t\t\treturn sqlBuilder;\n\t\t}\n\n\t\tprotected virtual IDbCommand GetCommand() {\n\t\t\treturn DbFactory.CreateCommand();\n\t\t}\n\n\t\tprotected virtual void SetCommandText(IDbCommand cmd, string sqlStatement) {\n\t\t\tcmd.CommandText = sqlStatement;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the automatically generated <see cref=\"IDbCommand\"/> object to select rows by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">query that determines table and select options</param>\n\t\t/// <returns></returns>\n\t\tpublic virtual IDbCommand GetSelectCommand(Query query) {\n\t\t\tvar cmd = GetCommand();\n\t\t\tvar cmdSqlBuilder = GetSqlBuilder(cmd);\n\t\t\tSetCommandText(cmd,BuildSelectInternal(query, cmdSqlBuilder, false));\n\t\t\treturn cmd;\n\t\t}\n\n\t\tDbDataView defaultSelectView = null;\n\n\t\tinternal string BuildSelectInternal(Query query, ISqlExpressionBuilder sqlBuilder, bool isSubquery) {\n\t\t\tDbDataView view = null;\n\t\t\tif (Views==null || !Views.TryGetValue(query.Table.Name, out view)) {\n\t\t\t\t// default template\n\t\t\t\tif (defaultSelectView!=null && defaultSelectView.SelectTemplate == SelectTemplate)\n\t\t\t\t\tview = defaultSelectView;\n\t\t\t\telse\n\t\t\t\t\tview = defaultSelectView = new DbDataView(SelectTemplate, CreateStringTemplate);\n\t\t\t}\n\t\t\treturn view.FormatSelectSql(query,sqlBuilder,isSubquery);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the automatically generated <see cref=\"IDbCommand\"/> object to delete rows by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">query that determines delete table and conditions</param>\n\t\t/// <returns>delete SQL command</returns>\t\n\t\tpublic virtual IDbCommand GetDeleteCommand(Query query) {\n\t\t\tvar cmd = GetCommand();\n\t\t\tvar dbSqlBuilder = GetSqlBuilder(cmd);\n\n\t\t\t// prepare WHERE part\n\t\t\tvar whereExpression = dbSqlBuilder.BuildExpression( query.Condition );\n\t\t\tvar tblName = dbSqlBuilder.BuildTableName( new QTable(query.Table.Name, null) );\n\n\t\t\tvar deleteTpl = CreateStringTemplate(DeleteTemplate);\n\t\t\tSetCommandText(cmd, deleteTpl.FormatTemplate( (varName) => {\n\t\t\t\tswitch (varName) {\n\t\t\t\t\tcase \"table\": return new StringTemplate.TokenResult(tblName);\n\t\t\t\t\tcase \"where\": return new StringTemplate.TokenResult(whereExpression);\n\t\t\t\t}\n\t\t\t\treturn StringTemplate.TokenResult.NotDefined;\n\t\t\t}) );\n\n\t\t\treturn cmd;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the automatically generated <see cref=\"IDbCommand\"/> object to update rows by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">query that determines update table and conditions</param>\n\t\t/// <param name=\"data\">changeset data</param>\n\t\t/// <returns>update SQL command</returns>\t\n\t\tpublic virtual IDbCommand GetUpdateCommand(Query query, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tvar cmd = GetCommand();\n\t\t\tvar dbSqlBuilder = GetSqlBuilder(cmd);\n\n\t\t\t// prepare fields Part\n\t\t\tvar setExpression = new StringBuilder();\n\n\t\t\tforeach (var setField in data) {\n\t\t\t\tif (setExpression.Length>0)\n\t\t\t\t\tsetExpression.Append(',');\n\n\t\t\t\tsetExpression.Append( dbSqlBuilder.BuildValue(new QField(setField.Key)) );\n\t\t\t\tsetExpression.Append('=');\n\t\t\t\tsetExpression.Append( dbSqlBuilder.BuildValue(setField.Value) );\n\t\t\t}\n\n\t\t\t// prepare WHERE part\n\t\t\tstring whereExpression = dbSqlBuilder.BuildExpression( query.Condition );\n\t\t\tvar tblName = dbSqlBuilder.BuildTableName( new QTable(query.Table.Name, null) );\n\n\t\t\tvar updateTpl = CreateStringTemplate(UpdateTemplate);\n\t\t\tSetCommandText(cmd, updateTpl.FormatTemplate( (varName) => {\n\t\t\t\tswitch (varName) {\n\t\t\t\t\tcase \"table\": return new StringTemplate.TokenResult(tblName);\n\t\t\t\t\tcase \"set\": return new StringTemplate.TokenResult(setExpression.ToString());\n\t\t\t\t\tcase \"where\": return new StringTemplate.TokenResult(whereExpression);\n\t\t\t\t}\n\t\t\t\treturn StringTemplate.TokenResult.NotDefined;\n\t\t\t}) );\n\t\t\t\n\t\t\treturn cmd;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the automatically generated <see cref=\"IDbCommand\"/> object to insert new record.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">table name</param>\n\t\t/// <param name=\"data\">new record data</param>\n\t\t/// <returns>insert SQL command</returns>\t\n\t\tpublic virtual IDbCommand GetInsertCommand(string tableName, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tvar cmd = GetCommand();\n\t\t\tvar dbSqlBuilder = GetSqlBuilder(cmd);\n\t\t\t\n\t\t\t// Prepare fields part\n\t\t\tvar columns = new StringBuilder();\n\t\t\tvar values = new StringBuilder();\n\t\t\tforeach (var setField in data) {\n\t\t\t\tif (columns.Length>0)\n\t\t\t\t\tcolumns.Append(',');\n\t\t\t\tcolumns.Append( dbSqlBuilder.BuildValue( (QField)setField.Key) );\n\n\t\t\t\tif (values.Length>0)\n\t\t\t\t\tvalues.Append(',');\n\t\t\t\tvalues.Append(dbSqlBuilder.BuildValue(setField.Value));\n\t\t\t}\n\n\t\t\tvar tblName = dbSqlBuilder.BuildTableName( new QTable(tableName, null) );\n\t\t\tvar colStr = columns.ToString();\n\t\t\tvar valStr = values.ToString();\n\n\t\t\tvar insertTpl = CreateStringTemplate(InsertTemplate);\n\t\t\tSetCommandText(cmd, insertTpl.FormatTemplate( (varName) => {\n\t\t\t\tswitch (varName) {\n\t\t\t\t\tcase \"table\": return new StringTemplate.TokenResult(tblName);\n\t\t\t\t\tcase \"columns\": return new StringTemplate.TokenResult(colStr);\n\t\t\t\t\tcase \"values\": return new StringTemplate.TokenResult(valStr);\n\t\t\t\t}\n\t\t\t\treturn StringTemplate.TokenResult.NotDefined;\n\t\t\t}) );\n\t\t\t\n\t\t\treturn cmd;\n\t\t}\n\n\t\tStringTemplate CreateStringTemplate(string tpl) {\n\t\t\tif (_createStringTemplate != null)\n\t\t\t\treturn _createStringTemplate(tpl);\n\t\t\treturn new StringTemplate(tpl);\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbCommandBuilderExtensions.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Collections;\nusing System.Linq;\nusing System.Text;\nusing System.Data.Common;\nusing System.Data;\nusing System.Reflection;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// Extension methods for <see cref=\"IDbCommandBuilder\"/> interface.\n\t/// </summary>\n\tpublic static class DbCommandBuilderExtensions {\n\n\t\tpublic static IDbCommand GetUpdateCommand(this IDbCommandBuilder cmdBuilder, Query q, IDictionary<string,object> data) {\n\t\t\treturn cmdBuilder.GetUpdateCommand(q, DataHelper.GetChangeset(data) );\n\t\t}\n\t\tpublic static IDbCommand GetUpdateCommand(this IDbCommandBuilder cmdBuilder, Query q, object poco) {\n\t\t\treturn cmdBuilder.GetUpdateCommand(q, DataHelper.GetChangeset(poco, null) );\n\t\t}\n\n\t\tpublic static IDbCommand GetInsertCommand(this IDbCommandBuilder cmdBuilder, string table, IDictionary<string,object> data) {\n\t\t\treturn cmdBuilder.GetInsertCommand(table, DataHelper.GetChangeset(data) );\n\t\t}\n\t\tpublic static IDbCommand GetInsertCommand(this IDbCommandBuilder cmdBuilder, string table, object poco) {\n\t\t\treturn cmdBuilder.GetInsertCommand(table, DataHelper.GetChangeset(poco, null) );\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbDataAdapter.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data.Common;\nusing System.Data;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Data adapter between database and application data models. Implements select, insert, update and delete operations.\n\t/// </summary>\n\tpublic partial class DbDataAdapter : IRecordSetAdapter, IDisposable {\n\n\t\t/// <summary>\n\t\t/// Gets <see cref=\"IDbConnection\"/> associated with this data adapter.\n\t\t/// </summary>\n\t\tpublic IDbConnection Connection { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Gets <see cref=\"IDbCommandBuilder\"/> associated with this data adapter.\n\t\t/// </summary>\n\t\tpublic IDbCommandBuilder CommandBuilder { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets <see cref=\"IDbTransaction\"/> initiated for the <see cref=\"Connection\"/>.\n\t\t/// </summary>\n\t\tpublic IDbTransaction Transaction { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets flag that determines whether query record offset is applied during reading query results.\n\t\t/// </summary>\n\t\tpublic bool ApplyOffset { get; set; } = true;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the DbDataAdapter.\n\t\t/// </summary>\n\t\t/// <param name=\"connection\">database connection instance</param>\n\t\t/// <param name=\"cmdBuilder\">command builder instance</param>\n\t\tpublic DbDataAdapter(IDbConnection connection, IDbCommandBuilder cmdBuilder) {\n\t\t\tConnection = connection;\n\t\t\tCommandBuilder = cmdBuilder;\n\t\t}\n\n\t\tprivate void SetupCmd(IDbCommand cmd) {\n\t\t\tcmd.Connection = Connection;\n\t\t\tif (Transaction!=null)\n\t\t\t\tcmd.Transaction = Transaction;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns prepared select query. \n\t\t/// </summary>\n\t\t/// <param name=\"q\">query to execute</param>\n\t\t/// <returns>prepared select query</returns>\n\t\tpublic SelectQuery Select(Query q) {\n\t\t\treturn new SelectQueryByQuery(this, q);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"SelectQuery\"/> based on a raw SQL query.\n\t\t/// </summary>\n\t\t/// <param name=\"sql\">The raw SQL query.</param>\n\t\t/// <param name=\"parameters\">The values to be assigned to parameters.</param>\n\t\t/// <returns>prepared select query</returns>\n\t\t/// <remarks>Semantics of this method is similar to EF Core DbSet.FromSql. Any parameter values you supply will automatically be converted to a DbParameter:\n\t\t/// <code>dbAdapter.Select(\"SELECT * FROM [dbo].[SearchBlogs]({0})\", userSuppliedSearchTerm).ToRecordSet()</code>.\n\t\t/// <para>You can also construct a DbParameter and supply it to as a parameter value. This allows you to use named\n        /// parameters in the SQL query string - \n\t\t/// <code>dbAdapter.Select(\"SELECT * FROM [dbo].[SearchBlogs]({@searchTerm})\", new SqlParameter(\"@searchTerm\", userSuppliedSearchTerm)).ToRecordSet()</code>\n\t\t/// </para>\n\t\t/// </remarks>\n\t\tpublic SelectQuery Select(RawSqlString sql, params object[] parameters) {\n\t\t\treturn new SelectQueryBySql(this, sql.Format, parameters);\n\t\t}\n\n#if NET_STANDARD\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"SelectQuery\"/> based on an interpolated string representing a SQL query.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Semantics of this method is similar to EF Core DbSet.FromSql:\n\t\t/// <code>\n\t\t/// dbAdapter.Select($\"SELECT * FROM Users WHERE id={userId}\").Single&lt;User&gt;();\n\t\t/// </code>\n\t\t/// All parameters will automatically be converted to a DbParameter.\n\t\t/// </remarks>\n\t\tpublic SelectQuery Select(FormattableString sql) {\n\t\t\treturn new SelectQueryBySql(this, sql.Format, sql.GetArguments());\n\t\t}\n#endif\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"SelectQuery\"/> based on specified <see cref=\"IDbCommand\"/> instance.\n\t\t/// </summary>\n\t\t/// <param name=\"cmd\">custom command</param>\n\t\t/// <returns>prepared select query</returns>\n\t\t/// <remarks>This method allows to execute custom SQL command and map results like for usual SELECT command.</remarks>\n\t\tpublic SelectQuery Select(IDbCommand cmd) {\n\t\t\treturn new SelectQueryByCmd(this, cmd);\n\t\t}\n\n\t\tint InsertInternal(string tableName, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tif (tableName==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(tableName)}\");\n\t\t\treturn ExecuteNonQuery( CommandBuilder.GetInsertCommand(tableName, data) );\n\t\t}\n\n\t\tTask<int> InsertInternalAsync(string tableName, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tif (tableName==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(tableName)}\");\n\t\t\treturn ExecuteNonQueryAsync( CommandBuilder.GetInsertCommand(tableName, data), CancellationToken.None );\n\t\t}\n\n\t\tDataMapper.ColumnMapping FindAutoIncrementColumn(object pocoModel) {\n\t\t\tvar schema = DataMapper.Instance.GetSchema(pocoModel.GetType());\n\t\t\tforeach (var colMapping in schema.Columns)\n\t\t\t\tif (colMapping.IsIdentity)\n\t\t\t\t\treturn colMapping;\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Executes INSERT statement generated by specified table name and dictionary values.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">table name</param>\n\t\t/// <param name=\"data\">dictonary with new record data (column -> value)</param>\n\t\t/// <returns>Number of inserted data records.</returns>\n\t\tpublic int Insert(string tableName, IDictionary<string,object> data) {\n\t\t\tif (data==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(data)}\");\n\t\t\treturn InsertInternal(tableName, DataHelper.GetChangeset(data) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes INSERT statement generated by specified table name and dictionary values.\n\t\t/// </summary>\n\t\tpublic Task<int> InsertAsync(string tableName, IDictionary<string,object> data) {\n\t\t\tif (data==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(data)}\");\n\t\t\treturn InsertInternalAsync(tableName, DataHelper.GetChangeset(data) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Executes INSERT statement generated by specified table name and annotated POCO model.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">table name</param>\n\t\t/// <param name=\"pocoModel\">POCO model with public properties that match table columns.</param>\n\t\t/// <returns>Number of inserted data records.</returns>\n\t\tpublic int Insert(string tableName, object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\tint affected = 0;\n\t\t\tDataHelper.EnsureConnectionOpen(Connection, () => {\n\t\t\t\taffected = InsertInternal(tableName, DataHelper.GetChangeset( pocoModel, null) );\n\t\t\t\tvar autoIncrementCol = FindAutoIncrementColumn(pocoModel);\n\t\t\t\tif (autoIncrementCol!=null) {\n\t\t\t\t\tvar insertedId = CommandBuilder.DbFactory.GetInsertId(Connection, Transaction);\n\t\t\t\t\tif (insertedId!=null)\n\t\t\t\t\t\tautoIncrementCol.SetValue(pocoModel, insertedId);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn affected;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes INSERT statement generated by specified table name and POCO model.\n\t\t/// </summary>\n\t\tpublic async Task<int> InsertAsync(string tableName, object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\tif (tableName==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(tableName)}\");\n\n\t\t\tCancellationToken cancel = CancellationToken.None;\n\t\t\tvar isClosedConn = Connection.State == ConnectionState.Closed;\n\t\t\tif (isClosedConn) {\n\t\t\t\tawait Connection.OpenAsync(cancel).ConfigureAwait(false);\n\t\t\t}\n\t\t\tint affected = 0;\n\t\t\ttry {\n\t\t\t\taffected = await InsertInternalAsync(tableName, DataHelper.GetChangeset( pocoModel, null) ).ConfigureAwait(false);\n\t\t\t\tvar autoIncrementCol = FindAutoIncrementColumn(pocoModel);\n\t\t\t\tif (autoIncrementCol!=null) {\n\t\t\t\t\tvar insertedId = await CommandBuilder.DbFactory.GetInsertIdAsync(Connection, Transaction, cancel).ConfigureAwait(false);\n\t\t\t\t\tif (insertedId!=null)\n\t\t\t\t\t\tautoIncrementCol.SetValue(pocoModel, insertedId);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (isClosedConn)\n\t\t\t\t\tConnection.Close();\n\t\t\t}\t\t\t\n\n\t\t\treturn affected;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Executes INSERT statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\t/// <param name=\"pocoModel\">POCO model (possibly annotated).</param>\n\t\t/// <returns>Number of inserted data records.</returns>\n\t\tpublic int Insert(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\tvar schema = DataMapper.Instance.GetSchema(pocoModel.GetType());\n\t\t\treturn Insert(schema.TableName, pocoModel);\t\t\t\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes INSERT statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\tpublic Task<int> InsertAsync(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\tvar schema = DataMapper.Instance.GetSchema(pocoModel.GetType());\n\t\t\treturn InsertAsync(schema.TableName, pocoModel);\t\t\t\t\n\t\t}\n\n\t\tint UpdateInternal(Query query, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tif (query==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(query)}\");\n\t\t\treturn ExecuteNonQuery( CommandBuilder.GetUpdateCommand(query, data) );\n\t\t}\n\n\t\tTask<int> UpdateInternalAsync(Query query, IEnumerable<KeyValuePair<string,IQueryValue>> data) {\n\t\t\tif (query==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(query)}\");\n\t\t\treturn ExecuteNonQueryAsync( CommandBuilder.GetUpdateCommand(query, data), CancellationToken.None );\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Executes UPDATE statement generated by specified <see cref=\"Query\"/> and dictionary values.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">query that determines data records to update.</param>\n\t\t/// <param name=\"data\">dictonary with changeset data (column -> value)</param>\n\t\t/// <returns>Number of updated data records.</returns>\n\t\tpublic int Update(Query query, IDictionary<string,object> data) {\n\t\t\tif (data==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(data)}\");\n\t\t\treturn UpdateInternal(query, DataHelper.GetChangeset(data) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes UPDATE statement generated by specified <see cref=\"Query\"/> and dictionary values.\n\t\t/// </summary>\n\t\tpublic Task<int> UpdateAsync(Query query, IDictionary<string,object> data) {\n\t\t\tif (data==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(data)}\");\n\t\t\treturn UpdateInternalAsync(query, DataHelper.GetChangeset(data) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Executes UPDATE statement generated by specified <see cref=\"Query\"/> and POCO model.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">query that determines data records to update.</param>\n\t\t/// <param name=\"pocoModel\">POCO model with public properties that match table columns.</param>\n\t\t/// <returns>Number of updated data records.</returns>\n\t\tpublic int Update(Query query, object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn UpdateInternal(query, DataHelper.GetChangeset( pocoModel, null) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes UPDATE statement generated by specified <see cref=\"Query\"/> and POCO model.\n\t\t/// </summary>\n\t\tpublic Task<int> UpdateAsync(Query query, object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn UpdateInternalAsync(query, DataHelper.GetChangeset( pocoModel, null) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Executes UPDATE statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\t/// <param name=\"pocoModel\">annotated POCO model (key should be defined).</param>\t\n\t\t/// <returns>Number of updated data records.</returns>\n\t\tpublic int Update(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn Update( GetQueryByKey(pocoModel), pocoModel);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes UPDATE statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\tpublic Task<int> UpdateAsync(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn UpdateAsync( GetQueryByKey(pocoModel), pocoModel);\n\t\t}\n\n\t\tQuery GetQueryByKey(object pocoModel) {\n\t\t\tvar schema = DataMapper.Instance.GetSchema(pocoModel.GetType());\n\t\t\tif (schema.Key.Length==0)\n\t\t\t\tthrow new ArgumentException(\"Specified object doesn't have properties annotated with KeyAttribute.\");\n\t\t\tvar q = new Query( new QTable(schema.TableName, null) );\n\t\t\tvar andGroup = QGroupNode.And();\n\t\t\tq.Condition = andGroup;\n\t\t\tfor (int i=0; i<schema.Key.Length; i++) {\n\t\t\t\tvar keyCol = schema.Key[i];\n\t\t\t\tif (keyCol.GetVal!=null)\n\t\t\t\t\tandGroup.Nodes.Add( (QField)keyCol.ColumnName == new QConst(keyCol.GetVal(pocoModel) ) );\n\t\t\t}\n\t\t\treturn q;\n\t\t}\n\n\t\tvoid EnsurePrimaryKey(RecordSet recordSet) {\n\t\t\tif (recordSet.PrimaryKey==null || recordSet.PrimaryKey.Length==0)\n\t\t\t\tthrow new NotSupportedException(\"Update operation can be performed only for RecordSet with PrimaryKey\");\n\t\t}\n\n\t\tRecordSet IRecordSetAdapter.Select(Query q) {\n\t\t\treturn Select(q).ToRecordSet();\n\t\t}\n\n\t\tTask<RecordSet> IRecordSetAdapter.SelectAsync(Query q) {\n\t\t\treturn Select(q).ToRecordSetAsync();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Calls the respective INSERT, UPDATE, or DELETE statements for each inserted, updated, or deleted row in the specified <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">The name of the source table.</param>\n\t\t/// <param name=\"recordSet\"><see cref=\"RecordSet\"/> to use to update the data source.</param>\n\t\t/// <returns>The number of rows successfully updated.</returns>\n\t\t/// <remarks>\n\t\t/// <para><see cref=\"RecordSet.PrimaryKey\"/> should be set before calling <see cref=\"DbDataAdapter.Update(string, RecordSet)\"/>.</para>\n\t\t/// When an application calls the Update method, <see cref=\"DbDataAdapter\"/> examines the <see cref=\"RecordSet.Row.State\"/> property,\n\t\t/// and executes the required INSERT, UPDATE, or DELETE statements iteratively for each row (based on the order of rows in RecordSet).\n\t\t/// </remarks>\n\t\tpublic int Update(string tableName, RecordSet recordSet) {\n\t\t\tEnsurePrimaryKey(recordSet);\n\t\t\tint affected = 0;\n\t\t\tusing (var rsAdapter = new RecordSetAdapter(this, tableName, recordSet)) {\n\t\t\t\taffected = rsAdapter.Update();\n\t\t\t}\n\t\t\trecordSet.AcceptChanges();\n\t\t\treturn affected;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// An asynchronous version of <see cref=\"Update(string, RecordSet)\"/> that calls the respective INSERT, UPDATE, or DELETE statements \n\t\t/// for each added, updated, or deleted row in the specified <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">The name of the source table.</param>\n\t\t/// <param name=\"recordSet\"><see cref=\"RecordSet\"/> to use to update the data source.</param>\n\t\t/// <param name=\"cancel\">The cancellation instruction.</param>\n\t\t/// <returns>The number of rows successfully updated.</returns>\n\t\tpublic Task<int> UpdateAsync(string tableName, RecordSet recordSet) {\n\t\t\treturn UpdateAsync(tableName, recordSet, CancellationToken.None); \n\t\t}\n\n\t\t/// <summary>\n\t\t/// An asynchronous version of <see cref=\"Update(string, RecordSet)\"/> that calls the respective INSERT, UPDATE, or DELETE statements \n\t\t/// for each added, updated, or deleted row in the specified <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">The name of the source table.</param>\n\t\t/// <param name=\"recordSet\"><see cref=\"RecordSet\"/> to use to update the data source.</param>\n\t\t/// <param name=\"cancel\">The cancellation instruction.</param>\n\t\t/// <returns>The number of rows successfully updated.</returns>\n\t\tpublic async Task<int> UpdateAsync(string tableName, RecordSet recordSet, CancellationToken cancel) {\n\t\t\tEnsurePrimaryKey(recordSet);\n\t\t\tint affected = 0;\n\t\t\tusing (var rsAdapter = new RecordSetAdapter(this, tableName, recordSet)) {\n\t\t\t\taffected = await rsAdapter.UpdateAsync(cancel).ConfigureAwait(false);\n\t\t\t}\n\t\t\trecordSet.AcceptChanges();\n\t\t\treturn affected;\t\t\n\t\t}\n\n\n\t\t/// <summary>\n\t\t/// Executes DELETE statement generated by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"q\">query that determines data records to delete.</param>\n\t\t/// <returns>Number of actually deleted records.</returns>\n\t\tpublic int Delete(Query q) {\n\t\t\treturn ExecuteNonQuery( CommandBuilder.GetDeleteCommand(q) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Executes DELETE statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\t/// <param name=\"pocoModel\">annotated POCO model (key should be defined).</param>\t\n\t\t/// <returns>Number of actually deleted records.</returns>\n\t\tpublic int Delete(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn Delete( GetQueryByKey(pocoModel) );\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes DELETE statement generated by annotated POCO model.\n\t\t/// </summary>\n\t\tpublic Task<int> DeleteAsync(object pocoModel) {\n\t\t\tif (pocoModel==null)\n\t\t\t\tthrow new ArgumentNullException($\"{nameof(pocoModel)}\");\n\t\t\treturn DeleteAsync(  GetQueryByKey(pocoModel) );\t\t\t\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes DELETE statement generated by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\tpublic Task<int> DeleteAsync(Query q) {\n\t\t\treturn DeleteAsync(q, CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously executes DELETE statement generated by specified <see cref=\"Query\"/>.\n\t\t/// </summary>\n\t\tpublic Task<int> DeleteAsync(Query q, CancellationToken cancel) {\n\t\t\treturn ExecuteNonQueryAsync( CommandBuilder.GetDeleteCommand(q), cancel );\n\t\t}\n\n\t\tprivate int ExecuteNonQuery(IDbCommand cmd) {\n\t\t\tint affectedRecords = 0;\n\t\t\tSetupCmd(cmd);\n\t\t\tusing (cmd) {\n\t\t\t\tDataHelper.EnsureConnectionOpen(Connection, () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\taffectedRecords = cmd.ExecuteNonQuery();\n\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\tthrow new ExecuteDbCommandException(cmd, ex);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn affectedRecords;\n\t\t}\n\n\t\tprivate async Task<int> ExecuteNonQueryAsync(IDbCommand cmd, CancellationToken cancel) {\n\t\t\tint affected = 0;\n\t\t\tusing (cmd) {\n\t\t\t\tSetupCmd(cmd);\n\t\t\t\tvar isClosedConn = cmd.Connection.State == ConnectionState.Closed;\n\t\t\t\tif (isClosedConn) {\n\t\t\t\t\tawait cmd.Connection.OpenAsync(cancel).ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\taffected = await cmd.ExecuteNonQueryAsync(cancel).ConfigureAwait(false);\t\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tthrow new ExecuteDbCommandException(cmd, ex);\n\t\t\t\t} finally {\n\t\t\t\t\tif (isClosedConn)\n\t\t\t\t\t\tcmd.Connection.Close();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn affected;\n\t\t}\n\n\t\tpublic void Dispose() {\n\t\t\tDispose(true);\n\t\t}\n\n\t\tprotected virtual void Dispose(bool disposing) {\n\t\t\tif (disposing) {\n\t\t\t\tConnection = null;\n\t\t\t\tCommandBuilder = null;\n\t\t\t\tTransaction = null;\n\t\t\t}\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbDataView.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.ComponentModel;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// Represents application-level read-only data view (complex query that can be queries a table).\n\t/// </summary>\n\tpublic class DbDataView {\n\t\t\n\t\t/// <summary>\n\t\t/// Gets select template string for <see cref=\"StringTemplate\"/>.\n\t\t/// </summary>\n\t\tpublic string SelectTemplate { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Query fields mapping to SQL expressions (optional).\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Field mappings are useful for defining SQL-calculated columns, or resolving ambigious columns names:\n\t\t/// <code>\n\t\t/// var dbView = new DbDataView(\n\t\t///\t\t@\"SELECT @columns FROM persons p\n\t\t///\t\t  LEFT JOIN countries c ON (c.id=p.country_id)\n\t\t///\t\t@where[ WHERE {0}] @orderby[ ORDER BY {0}]\") {\n\t\t///\t\tFieldMapping = new Dictionary&lt;string,string&gt;() {\n\t\t///\t\t\t// just id is ambigious\n\t\t///\t\t\t{\"id\", \"p.id\"},  \n\t\t///\t\t\t// SQL expression for calculated \"expired\" field\n\t\t///\t\t\t{\"expired\", \"CASE WHEN DATEDIFF(dd, p.added_date, NOW() )>30 THEN 1 ELSE 0 END\" } \n\t\t///     }\n\t\t/// } );\n\t\t/// </code>\n\t\t/// </remarks>\n\t\tpublic IDictionary<string,string> FieldMapping { get; set; }\n\n\t\tFunc<string, StringTemplate> CreateStringTemplate;\n\n\t\tpublic DbDataView(string selectTemplate) {\n\t\t\tSelectTemplate = selectTemplate;\n\t\t}\n\n\t\tpublic DbDataView(string selectTemplate, Func<string, StringTemplate> createStringTemplate) : this(selectTemplate) {\n\t\t\tCreateStringTemplate = createStringTemplate;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Generates SELECT SQL statement by given <see cref=\"Query\"/> and <see cref=\"ISqlExpressionBuilder\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"query\">formal query structure</param>\n\t\t/// <param name=\"sqlBuilder\">SQL builder component</param>\n\t\t/// <param name=\"isSubquery\">subquery flag (true if this is sub-query select)</param>\n\t\t/// <returns>SQL select command text</returns>\n\t\tpublic virtual string FormatSelectSql(Query query, ISqlExpressionBuilder sqlBuilder, bool isSubquery) {\n\t\t\tvar isCount = IsCountQuery(query);\n\t\t\tstring columns = BuildSelectColumns(query, sqlBuilder);\n\t\t\tstring groupBy = BuildGroupBy(query, sqlBuilder);\n\t\t\tstring orderBy = BuildOrderBy(query, sqlBuilder);\n\t\t\tstring whereExpression = BuildWhere(query, sqlBuilder);\n\t\t\tvar tblName = sqlBuilder.BuildTableName(query.Table);\n\n\t\t\tvar selectTpl = CreateStringTemplate!=null ? CreateStringTemplate(SelectTemplate) : new StringTemplate(SelectTemplate);\n\t\t\treturn selectTpl.FormatTemplate( (varName) => {\n\t\t\t\tswitch (varName) {\n\t\t\t\t\tcase \"table\": return new StringTemplate.TokenResult( tblName );\n\t\t\t\t\tcase \"where\": return new StringTemplate.TokenResult( whereExpression );\n\t\t\t\t\tcase \"groupby\": return groupBy == null ? StringTemplate.TokenResult.NotDefined : new StringTemplate.TokenResult( groupBy );\n\t\t\t\t\tcase \"orderby\": return isCount ? StringTemplate.TokenResult.NotApplicable : new StringTemplate.TokenResult( orderBy );\n\t\t\t\t\tcase \"columns\": return new StringTemplate.TokenResult( columns );\n\t\t\t\t\tcase \"recordoffset\": return query.RecordOffset > 0 ? new StringTemplate.TokenResult( query.RecordOffset ) : StringTemplate.TokenResult.NotDefined;\n\t\t\t\t\tcase \"recordcount\": return query.RecordCount<Int32.MaxValue ? new StringTemplate.TokenResult( query.RecordCount ) : StringTemplate.TokenResult.NotDefined;\n\t\t\t\t\tcase \"recordtop\": return query.RecordCount<Int32.MaxValue ? new StringTemplate.TokenResult( query.RecordOffset+query.RecordCount ) : StringTemplate.TokenResult.NotDefined;\n\t\t\t\t}\n\t\t\t\tif (query.ExtendedProperties!=null && query.ExtendedProperties.ContainsKey(varName))\n\t\t\t\t\treturn new StringTemplate.TokenResult(query.ExtendedProperties[varName]);\n\t\t\t\treturn StringTemplate.TokenResult.NotDefined;\n\t\t\t});\t\t\t\n\t\t} \n\n\t\tstring BuildWhere(Query query, ISqlExpressionBuilder sqlBuilder) {\n\t\t\tvar condition = FieldMapping==null ? query.Condition : DataHelper.MapQValue(query.Condition, ApplyFieldMapping);\n\t\t\treturn sqlBuilder.BuildExpression(condition);\n\t\t}\n\n\t\tIQueryValue ApplyFieldMapping(IQueryValue qValue) {\n\t\t\tif (qValue is QField) {\n\t\t\t\tvar qFld = (QField)qValue;\n\t\t\t\tif (FieldMapping.ContainsKey(qFld.Name)) {\n\t\t\t\t\treturn new QField(qFld.Name, FieldMapping[qFld.Name]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn qValue;\n\t\t}\n\n\t\tstring ApplyFieldMapping(string field) {\n\t\t\tif (FieldMapping!=null && FieldMapping.ContainsKey(field))\n\t\t\t\treturn FieldMapping[field];\n\t\t\treturn field;\n\t\t}\n\n\t\tstring BuildOrderBy(Query query, ISqlExpressionBuilder sqlBuilder) {\n\t\t\tvar orderBy = new StringBuilder();\n\t\t\tif (query.Sort!=null && query.Sort.Length>0) {\n\t\t\t\tforeach (var sortFld in query.Sort) {\n\t\t\t\t\tif (orderBy.Length>0)\n\t\t\t\t\t\torderBy.Append(',');\n\t\t\t\t\torderBy.Append( sqlBuilder.BuildValue( (IQueryValue) sortFld.Field) );\n\t\t\t\t\torderBy.Append(' ');\n\t\t\t\t\torderBy.Append(sortFld.SortDirection == ListSortDirection.Ascending ? QSort.Asc : QSort.Desc);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn orderBy.ToString();\n\t\t}\n\n\t\tstring BuildSelectColumns(Query query, ISqlExpressionBuilder sqlBuilder) {\n\t\t\t// Compose fields part\n\t\t\tif (query.Fields == null || query.Fields.Length == 0)\n\t\t\t\treturn ApplyFieldMapping(\"*\");\n\n\t\t\tvar columns = new StringBuilder();\n\t\t\tforeach (var qField in query.Fields) {\n\t\t\t\tvar f = qField;\n\t\t\t\tif (FieldMapping!=null && FieldMapping.ContainsKey(f.Name))\n\t\t\t\t\tf = new QField(f.Name, FieldMapping[f.Name]);\t\n\n\t\t\t\tvar fld = sqlBuilder.BuildValue((IQueryValue)f);\n\t\t\t\tif (fld!=f.Name && f.Expression!=null) { // use \"as\" only for expression-fields\n\t\t\t\t\t// special handling for 'count(*)' mapping\n\t\t\t\t\tif (f.Expression.ToLower()==\"count(*)\")\n\t\t\t\t\t\tfld = ApplyFieldMapping(\"count(*)\");\n\t\t\t\t\tfld = String.IsNullOrEmpty(f.Name) ? fld : String.Format(\"{0} as {1}\", fld, sqlBuilder.BuildValue((QField)f.Name) );\n\t\t\t\t}\n\t\t\t\tif (columns.Length>0)\n\t\t\t\t\tcolumns.Append(',');\n\t\t\t\tcolumns.Append(fld);\n\t\t\t}\n\t\t\treturn columns.ToString();\n\t\t}\n\n\t\tstring BuildGroupBy(Query query, ISqlExpressionBuilder sqlBuilder) {\n\t\t\tif (query.Fields == null || query.Fields.Length == 0 || !query.Fields.Any(isAggregateField))\n\t\t\t\treturn null;\n\t\t\tvar groupByCols = new StringBuilder();\n\t\t\tforeach (var qField in query.Fields)\n\t\t\t\tif (!isAggregateField(qField)) {\n\t\t\t\t\tvar f = qField;\n\t\t\t\t\tif (FieldMapping != null && FieldMapping.ContainsKey(f.Name))\n\t\t\t\t\t\tf = new QField(f.Name, FieldMapping[f.Name]);\n\n\t\t\t\t\tif (groupByCols.Length > 0)\n\t\t\t\t\t\tgroupByCols.Append(',');\n\t\t\t\t\tgroupByCols.Append(sqlBuilder.BuildValue((IQueryValue)f));\n\t\t\t\t}\n\t\t\treturn groupByCols.Length>0 ? groupByCols.ToString() : null;\n\n\t\t\tbool isAggregateField(QField fld) {\n\t\t\t\tif (fld is QAggregateField)\n\t\t\t\t\treturn true;\n\t\t\t\t// special handling for count(*)\n\t\t\t\tif (fld.Expression != null && fld.Expression.ToLower() == QField.Count.Expression)\n\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tbool IsCountQuery(Query q) {\n\t\t\tif (q.Fields==null || q.Fields.Length!=1 || q.Fields[0].Expression==null)\n\t\t\t\treturn false;\n\t\t\tvar exprLower = q.Fields[0].Expression.Trim().ToLower();\n\t\t\treturn exprLower.StartsWith(\"count(\") && exprLower.EndsWith(\")\");\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbFactory.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Generic <see cref=\"IDbFactory\"/> implementation that may be used with most ADO.NET Data Providers.\n\t/// </summary>\n\t/// <example>\n\t/// var dbFactory = new DbFactory(System.Data.SqlClient.SqlClientFactory.Instance);\n\t/// </example>\n\tpublic class DbFactory : IDbFactory {\n\n\t\tprotected DbProviderFactory DbPrvFactory;\n\n\t\tpublic string ParamPlaceholderFormat { get; set; }\n\n\t\tpublic int CommandTimeout { get; set; }\n\n\t\tpublic string ParamNameFormat { get; set; } = \"@p{0}\";\n\n\t\tpublic string IdentifierFormat { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets SQL command for retrieving ID for last inserted row.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// LastInsertIdSelectText for popular databases:\n\t\t/// <list>\n\t\t/// <item>MsSql (System.Data.SqlClient): \"SELECT @@IDENTITY\"</item>\n\t\t/// <item>Sqlite (Microsoft.Data.Sqlite): \"SELECT last_insert_rowid()\"</item>\n\t\t/// <item>PostgreSql (Npgsql): \"SELECT lastval()\"</item>\n\t\t/// <item>MySql (MySql.Data): \"SELECT LAST_INSERT_ID()\"</item>\n\t\t/// </list>\n\t\t/// </remarks>\n\t\tpublic string LastInsertIdSelectText { get; set; }\n\n\t\tpublic DbFactory(DbProviderFactory dbProviderFactory) {\n\t\t\tDbPrvFactory = dbProviderFactory;\n\t\t\tCommandTimeout = -1;\n\t\t}\n\n\t\tpublic virtual IDbCommand CreateCommand() {\n\t\t\tvar cmd = DbPrvFactory.CreateCommand();\n\t\t\tif (CommandTimeout >= 0)\n\t\t\t\tcmd.CommandTimeout = CommandTimeout;\n\t\t\treturn cmd;\n\t\t}\n\n\t\tpublic virtual IDbConnection CreateConnection() {\n\t\t\treturn DbPrvFactory.CreateConnection();\n\t\t}\n\n\t\tpublic virtual CommandParameter AddCommandParameter(IDbCommand cmd, object value) {\n\t\t\tvar param = DbPrvFactory.CreateParameter();\n\t\t\tparam.ParameterName = GetCmdParameterName(cmd.Parameters.Count);\n\t\t\tparam.Value = value ?? DBNull.Value;\n\t\t\tcmd.Parameters.Add(param);\n\t\t\treturn new CommandParameter( GetCmdParameterPlaceholder(param.ParameterName), param );\n\t\t}\n\n\t\tpublic virtual ISqlExpressionBuilder CreateSqlBuilder(IDbCommand dbCommand, Func<Query,string> buildSubquery) {\n\t\t\tvar sqlBuilder = new DbSqlExpressionBuilder(dbCommand, this) {\n\t\t\t\tBuildSubquery = buildSubquery,\n\t\t\t\tFormatIdentifier = ApplyIdentifierFormat\n\t\t\t};\n\t\t\treturn sqlBuilder;\n\t\t}\n\n\t\tprotected virtual string ApplyIdentifierFormat(string name) {\n\t\t\treturn IdentifierFormat!=null ? String.Format(IdentifierFormat, name) : name;\n\t\t}\n\n\t\tpublic virtual object GetInsertId(IDbConnection connection, IDbTransaction transaction) {\n\t\t\tif (String.IsNullOrEmpty(LastInsertIdSelectText)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (connection.State != ConnectionState.Open)\n\t\t\t\tthrow new InvalidOperationException(\"GetInsertId requires opened connection\");\n\t\t\tusing (var cmd = CreateCommand()) {\n\t\t\t\tcmd.CommandText = LastInsertIdSelectText;\n\t\t\t\tcmd.Connection = connection;\n\t\t\t\tcmd.Transaction = transaction;\n\t\t\t\treturn cmd.ExecuteScalar();\n\t\t\t}\n\t\t}\n\n\t\tpublic async Task<object> GetInsertIdAsync(IDbConnection connection, IDbTransaction transaction, CancellationToken cancel) {\n\t\t\tif (String.IsNullOrEmpty(LastInsertIdSelectText)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (connection.State != ConnectionState.Open)\n\t\t\t\tthrow new InvalidOperationException(\"GetInsertId requires opened connection\");\n\t\t\tusing (var cmd = CreateCommand()) {\n\t\t\t\tcmd.CommandText = LastInsertIdSelectText;\n\t\t\t\tcmd.Connection = connection;\n\t\t\t\tcmd.Transaction = transaction;\n\t\t\t\treturn await cmd.ExecuteScalarAsync(cancel);\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual string GetCmdParameterName(int paramIndex) {\n\t\t\treturn String.Format(ParamNameFormat, paramIndex);\n\t\t}\n\n\t\tprotected virtual string GetCmdParameterPlaceholder(string paramName) {\n\t\t\tif (ParamPlaceholderFormat == null)\n\t\t\t\treturn paramName;\n\t\t\treturn String.Format(ParamPlaceholderFormat, paramName);\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/DbSqlExpressionBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Linq;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Generic implementation of DB-specific SQL expression builder.\n\t/// </summary>\n\tpublic class DbSqlExpressionBuilder : SqlExpressionBuilder\n\t{\n\n\t\tprotected IDbCommand Command { get; private set; }\n\t\tprotected IDbFactory DbFactory { get; private set; }\n\n\t\tpublic Func<Query,string> BuildSubquery { get; set; }\n\n\t\tpublic Func<string,string> FormatIdentifier { get; set; }\n\n\t\tpublic DbSqlExpressionBuilder(IDbCommand cmd, IDbFactory dbFactory) {\n\t\t\tCommand = cmd;\n\t\t\tDbFactory = dbFactory;\n\t\t}\n\t\t\n\t\tprotected override string BuildConditionLValue(QConditionNode node) {\n\t\t\tvar lValue = base.BuildConditionLValue(node);\n\t\t\treturn (node.LValue is Query) ?\t\"(\"+lValue+\")\" : lValue;\n\t\t}\n\n\t\tprotected override string BuildConditionRValue(QConditionNode node) {\n\t\t\tvar rValue = base.BuildConditionRValue(node);\n\t\t\treturn (node.RValue is Query && ((node.Condition & Conditions.In) != Conditions.In)) ?\n\t\t\t\t\"(\" + rValue + \")\" : rValue;\n\t\t}\n\n\t\tpublic override string BuildValue(IQueryValue v) {\n\t\t\tif (v is Query) {\n\t\t\t\t// refactoring is needed for subqueries handling. TBD: find better solution without 'buildSubquery' delegate.\n\t\t\t\tif (BuildSubquery==null)\n\t\t\t\t\tthrow new NotImplementedException(\"Subqueries are not supported in this context\");\n\t\t\t\treturn BuildSubquery( (Query)v );\n\t\t\t}\n\t\t\treturn base.BuildValue(v);\n\t\t}\n\n\t\tprotected override string BuildValue(QConst value) {\n\t\t\tobject constValue = value.Value;\n\n\t\t\t// do not use parameter for nulls (type param cannot be determined by null)\n\t\t\tif (constValue==null && !(value is QVar))\n\t\t\t\treturn \"NULL\";\n\n\t\t\t// all non-null constants are passed as parameters\t\t\t\t\t\t\n\t\t\tvar cmdParam = DbFactory.AddCommandParameter(Command,constValue);\n\t\t\tif (value is QVar) {\n\t\t\t\tcmdParam.Parameter.SourceColumn = ((QVar)value).Name;\n\t\t\t}\n\t\t\treturn cmdParam.Placeholder;\n\t\t}\n\t\t\n\t\tprotected override string BuildValue(string str) {\n\t\t\treturn DbFactory.AddCommandParameter(Command,str).Placeholder;\n\t\t}\n\t\t\n\t\tprotected override string BuildIdentifier(string name) {\n\t\t\treturn FormatIdentifier!=null ? FormatIdentifier(name) : name;\n\t\t}\n\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/ExecuteDbCommandException.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Data.Common;\nusing System.Data;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// The exception that is thrown when execution of <see cref=\"IDbCommand\"/> is failed.\n\t/// </summary>\n\tpublic class ExecuteDbCommandException : Exception {\n\t\t\n\t\t/// <summary>\n\t\t/// Gets a command that generated the error. \n\t\t/// </summary>\n\t\tpublic IDbCommand Command { get; private set; }\n\n\t\tpublic ExecuteDbCommandException(IDbCommand dbCmd, Exception innerException) \n\t\t\t: base(innerException.Message, innerException) {\n\t\t\tCommand = dbCmd;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/IDbCommandBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Data;\nusing System.ComponentModel;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace NReco.Data\n{\n\n\t/// <summary>\n\t/// Automatically generates single-table commands to create-update-delete-retrieve database records.\n\t/// </summary>\n\tpublic interface IDbCommandBuilder \n\t{\n\t\tIDbCommand GetSelectCommand(Query query);\n\n\t\tIDbCommand GetInsertCommand(string tableName, IEnumerable<KeyValuePair<string,IQueryValue>> data);\n\n\t\tIDbCommand GetDeleteCommand(Query query);\n\n\t\tIDbCommand GetUpdateCommand(Query query, IEnumerable<KeyValuePair<string,IQueryValue>> data);\n\n\t\tIDbFactory DbFactory { get; }\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/IDbFactory.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;\n\nnamespace NReco.Data\n{\n\n\t/// <summary>\n\t/// Represents factory for creating db-specific ADO.NET component implementations.\n\t/// </summary>\n\tpublic interface IDbFactory {\n\n\t\t/// <summary>\n\t\t/// Create command \n\t\t/// </summary>\n\t\tIDbCommand CreateCommand();\n\n\t\t/// <summary>\n\t\t/// Create connection \n\t\t/// </summary>\n\t\tIDbConnection CreateConnection();\n\n\t\t/// <summary>\n\t\t/// Add new constant parameter\n\t\t/// </summary>\n\t\tCommandParameter AddCommandParameter(IDbCommand cmd, object value);\n\n\t\t/// <summary>\n\t\t/// Creare SQL builder\n\t\t/// </summary>\n\t\tISqlExpressionBuilder CreateSqlBuilder(IDbCommand dbCommand, Func<Query,string> buildSubquery);\n\n\t\t/// <summary>\n\t\t/// Gets ID of last inserted record\n\t\t/// </summary>\n\t\tobject GetInsertId(IDbConnection connection, IDbTransaction transaction);\n\n\t\t/// <summary>\n\t\t/// Asynchronously gets ID of last inserted record\n\t\t/// </summary>\n\t\tTask<object> GetInsertIdAsync(IDbConnection connection, IDbTransaction transaction, CancellationToken cancel);\n\t}\n\n\tpublic sealed class CommandParameter {\n\t\tpublic string Placeholder { get; private set; }\n\t\tpublic IDbDataParameter Parameter { get; private set; }\n\n\t\tpublic CommandParameter(string placeholder, IDbDataParameter dbParam) {\n\t\t\tPlaceholder = placeholder;\n\t\t\tParameter = dbParam;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/IRecordSetAdapter.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data\n{\n\n\t/// <summary>\n\t/// Represents data adapter between database and <see cref=\"RecordSet\"/> models.\n\t/// </summary>\n\tpublic interface IRecordSetAdapter {\n\t\t\n\t\t/// <summary>\n\t\t/// Returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tRecordSet Select(Query q);\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tTask<RecordSet> SelectAsync(Query q);\n\n\t\t/// <summary>\n\t\t/// Commits <see cref=\"RecordSet\"/> changes to the database.\n\t\t/// </summary>\n\t\tint Update(string table, RecordSet rs);\n\n\t\t/// <summary>\n\t\t/// An asynchronous version of <see cref=\"Update(string, RecordSet)\"/>\n\t\t/// </summary>\n\t\tTask<int> UpdateAsync(string table, RecordSet rs);\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/ISqlExpressionBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents SQL builder interface.\n\t/// </summary>\n\tpublic interface ISqlExpressionBuilder\n\t{\n\t\t/// <summary>\n\t\t/// Builds SQL-compatible string by specified <see cref=\"QTable\"/>. \n\t\t/// </summary>\n\t\tstring BuildTableName(QTable tbl);\n\n\t\t/// <summary>\n\t\t/// Builds SQL-compatible string by specified <see cref=\"IQueryValue\"/>. \n\t\t/// </summary>\n\t\tstring BuildValue(IQueryValue v);\n\n\t\t/// <summary>\n\t\t/// Builds SQL-compatible string by specified <see cref=\"QNode\"/>.\n\t\t/// </summary>\n\t\tstring BuildExpression(QNode node);\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DataReaderAsyncExt.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\t\n\tinternal static class DataReaderAsyncExt {\n\t\t\n\t\tinternal static Task<bool> ReadAsync(this IDataReader rdr, CancellationToken cancel) {\n\t\t\tif (rdr is DbDataReader) {\n\t\t\t\treturn ((DbDataReader)rdr).ReadAsync(cancel);\n\t\t\t} else {\n\t\t\t\treturn Task.FromResult(rdr.Read());\n\t\t\t}\n\t\t}\n\n\t\tinternal static Task<int> GetValuesAsync(this IDataReader rdr, object[] values, CancellationToken cancel) {\n\t\t\tif (rdr is DbDataReader) {\n\t\t\t\treturn ((DbDataReader)rdr).GetValuesAsync(values, cancel);\n\t\t\t} else {\n\t\t\t\treturn Task.FromResult(rdr.GetValues(values));\n\t\t\t}\n\t\t}\n\n\t}\n\n\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DataReaderResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\t\n\tinternal interface IDataReaderResult<T> {\n\t\tT Result { get; }\n\t\tvoid Init(IDataReader rdr);\n\t\tvoid Read(IDataReader rdr);\n\t\tvoid End();\n\t}\n\n\tinternal class SingleDataReaderResult<T> : IDataReaderResult<T> {\n\t\tpublic T Result { get; private set; }\n\n\t\tFunc<IDataReader,T> Convert;\n\n\t\tinternal SingleDataReaderResult(Func<IDataReader,T> convert) {\n\t\t\tConvert = convert;\n\t\t\tResult = default(T);\n\t\t}\n\n\t\tpublic void Init(IDataReader rdr) { }\n\t\tpublic void End() { }\n\n\t\tpublic void Read(IDataReader rdr) {\n\t\t\tResult = Convert(rdr);\n\t\t}\n\t}\n\n\tinternal class ListDataReaderResult<T> : IDataReaderResult<List<T>> {\n\t\tpublic List<T> Result { get; private set; }\n\n\t\tFunc<IDataReader,T> Convert;\n\n\t\tinternal ListDataReaderResult(Func<IDataReader,T> convert) {\n\t\t\tConvert = convert;\n\t\t\tResult = new List<T>();\n\t\t}\n\n\t\tpublic void Init(IDataReader rdr) { }\n\t\tpublic void End() { }\n\n\t\tpublic void Read(IDataReader rdr) {\n\t\t\tResult.Add( Convert(rdr) );\n\t\t}\n\t}\n\n\tinternal class RecordSetDataReaderResult : IDataReaderResult<RecordSet> {\n\t\tpublic RecordSet Result { get; private set; }\n\t\t\n\t\tinternal RecordSetDataReaderResult() {\n\t\t\tResult = null;\n\t\t}\n\n\t\tpublic void Init(IDataReader rdr) {\n\t\t\tif (Result==null) {\n\t\t\t\tResult = DataHelper.GetRecordSetByReader(rdr);\n\t\t\t}\n\t\t}\n\t\tpublic void End() { }\n\n\t\tpublic void Read(IDataReader rdr) {\n\t\t\tvar rowValues = new object[rdr.FieldCount];\n\t\t\trdr.GetValues(rowValues);\n\t\t\tResult.Add(rowValues).AcceptChanges();\n\t\t}\t\t\t\t\n\t}\n\n\tinternal class DataTableDataReaderResult : IDataReaderResult<DataTable> {\n\n\t\tpublic DataTable Result { get; private set; }\n\n\t\tint[] RdrIdxToTblIdx;\n\n\t\tinternal DataTableDataReaderResult(DataTable res) {\n\t\t\tResult = res;\n\t\t}\n\n\t\tpublic void Init(IDataReader rdr) {\n\t\t\tDataHelper.EnsureDataTableColumnsByReader(Result, rdr);\n\n\t\t\tvar tblColToIdx = new Dictionary<string, int>(Result.Columns.Count);\n\t\t\tfor (int i = 0; i < Result.Columns.Count; i++)\n\t\t\t\ttblColToIdx[Result.Columns[i].ColumnName] = i;\n\n\t\t\tRdrIdxToTblIdx = new int[rdr.FieldCount];\n\t\t\tfor (int i = 0; i < rdr.FieldCount; i++) {\n\t\t\t\tRdrIdxToTblIdx[i] = tblColToIdx[rdr.GetName(i)];\n\t\t\t}\n\n\t\t\tResult.BeginLoadData();\n\t\t}\n\n\t\tpublic void Read(IDataReader rdr) {\n\t\t\tvar rowValues = new object[Result.Columns.Count];\n\t\t\tfor (int i = 0; i < rdr.FieldCount; i++) {\n\t\t\t\trowValues[RdrIdxToTblIdx[i]] = rdr.GetValue(i);\n\t\t\t}\n\t\t\tResult.LoadDataRow(rowValues, true);\n\t\t}\n\n\t\tpublic void End() {\n\t\t\tResult.EndLoadData();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DbCommandAsyncExt.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\t\n\tinternal static class DbCommandAsyncExt {\n\t\t\n\t\tinternal static Task<int> ExecuteNonQueryAsync(this IDbCommand cmd, CancellationToken cancel) {\n\t\t\tif (cmd is DbCommand) {\n\t\t\t\treturn ((DbCommand)cmd).ExecuteNonQueryAsync(cancel);\n\t\t\t} else {\n\t\t\t\treturn Task.FromResult<int>( cmd.ExecuteNonQuery() );\n\t\t\t}\n\t\t}\n\n\t\tinternal static Task<object> ExecuteScalarAsync(this IDbCommand cmd, CancellationToken cancel) {\n\t\t\tif (cmd is DbCommand) {\n\t\t\t\treturn ((DbCommand)cmd).ExecuteScalarAsync(cancel);\n\t\t\t} else {\n\t\t\t\treturn Task.FromResult<object>( cmd.ExecuteScalar() );\n\t\t\t}\n\t\t}\n\n\t}\n\n\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DbConnectionAsyncExt.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\t\n\tinternal static class DbConnectionAsyncExt {\n\t\t\n\t\tinternal static Task OpenAsync(this IDbConnection conn, CancellationToken cancel) {\n\t\t\tif (conn is DbConnection) {\n\t\t\t\treturn ((DbConnection)conn).OpenAsync(cancel);\n\t\t\t} else {\n\t\t\t\tconn.Open();\n\t\t\t\t#if NET_STANDARD\n\t\t\t\treturn Task.CompletedTask;\n\t\t\t\t#else\n\t\t\t\treturn Task.FromResult(true);\n\t\t\t\t#endif\n\t\t\t}\n\t\t}\n\n\t}\n\n\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DbDataAdapter.MapperContext.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016-2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Data;\n\nnamespace NReco.Data {\n\t\n\tpublic partial class DbDataAdapter {\n\t\t\n\t\t/// <summary>\n\t\t/// Represents <see cref=\"DbDataAdapter.SelectQuery\"/> context for custom data mapping to POCO models.\n\t\t/// </summary>\n\t\tpublic interface IMapperContext {\n\n\t\t\t/// <summary>\n\t\t\t/// Data reader with current record's data.\n\t\t\t/// </summary>\n\t\t\tIDataReader DataReader { get; }\n\n\t\t\t/// <summary>\n\t\t\t/// Target POCO model type.\n\t\t\t/// </summary>\n\t\t\tType ObjectType { get; }\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Performs default data mapping to specified object (data annotations are used if present).\n\t\t\t/// </summary>\n\t\t\tvoid MapTo(object o);\n\n\t\t\t/// <summary>\n\t\t\t/// Creates model of specified type and performs default mapping to this object.\n\t\t\t/// </summary>\n\t\t\tobject MapTo(Type t);  \n\t\t}\n\n\t\tinternal sealed class MapperContext : IMapperContext {\n\t\t\t\n\t\t\tpublic IDataReader DataReader { get; private set; }\n\t\t\t\n\t\t\tpublic Type ObjectType { get; private set; }\n\n\t\t\tDataMapper Mapper;\n\n\t\t\tinternal MapperContext(DataMapper mapper, IDataReader rdr, Type toType) {\n\t\t\t\tMapper = mapper;\n\t\t\t\tDataReader = rdr;\n\t\t\t\tObjectType =toType;\n\t\t\t}\n\n\t\t\tpublic void MapTo(object o) {\n\t\t\t\tvar t = o.GetType();\n\t\t\t\tvar schema = Mapper.GetSchema(t);\n\t\t\t\tMapper.MapTo(DataReader, o, t, schema);\n\t\t\t}\n\n\t\t\tpublic object MapTo(Type t) {\n\t\t\t\treturn Mapper.MapTo(DataReader, t);\n\t\t\t}\n\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DbDataAdapter.RawSqlString.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016-2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n\nnamespace NReco.Data {\n\t\n\tpublic partial class DbDataAdapter {\n\n\t\t/// <summary>\n\t\t/// A string representing a raw SQL query. \n\t\t/// This type enables overload resolution between the regular and interpolated <see cref=\"Select(FormattableString)\"/> overloads.\n\t\t/// </summary>\n\t\tpublic struct RawSqlString {\n\t\t\tinternal string Format;\n\t\t\tpublic RawSqlString(string s) {\n\t\t\t\tFormat = s;\n\t\t\t}\n\t\t\tpublic static implicit operator RawSqlString(string value) {\n\t\t\t\treturn new RawSqlString(value);\n\t\t\t}\n\n#if NET_STANDARD\n\t\t\tpublic static implicit operator RawSqlString(FormattableString value) {\n\t\t\t\t// implicit cast from FormattableString is never called because compiler chooses Select(FormattableString) overload\n\t\t\t\tthrow new InvalidOperationException();\n\t\t\t}\n#endif\n\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/DbDataAdapter.SelectQuery.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data {\n\t\n\tpublic partial class DbDataAdapter {\n\n\t\t/// <summary>\n\t\t/// Represents select query (returned by <see cref=\"DbDataAdapter.Select\"/> method).\n\t\t/// </summary>\n\t\tpublic abstract class SelectQuery : IQueryModelResult, IQueryDictionaryResult, IQueryRecordSetResult\t, IQueryDataTableResult\n\t\t{\n\t\t\treadonly protected DbDataAdapter Adapter;\n\t\t\tDataMapper DtoMapper;\n\t\t\tFunc<IDataReaderMapperContext, object> CustomMappingHandler = null;\n\t\t\tbool ApplyOffset;\n\n\t\t\tinternal SelectQuery(DbDataAdapter adapter) {\n\t\t\t\tAdapter = adapter;\n\t\t\t\tDtoMapper = DataMapper.Instance;\n\t\t\t\tApplyOffset = Adapter.ApplyOffset;\n\t\t\t}\n\n\t\t\tint DataReaderRecordOffset {\n\t\t\t\tget {\n\t\t\t\t\treturn ApplyOffset ? RecordOffset : 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal virtual int RecordOffset { get { return 0; } }\n\n\t\t\tinternal virtual int RecordCount { get { return Int32.MaxValue; } }\n\n\t\t\tinternal abstract IDbCommand GetSelectCmd();\n\n\t\t\tinternal virtual string FirstFieldName { get { return null; } }\n\n\t\t\tinternal virtual string TableName { get { return null; } }\n\n\t\t\t/// <summary>\n\t\t\t/// Configures custom mapping handler for POCO models.\n\t\t\t/// </summary>\n\t\t\tpublic SelectQuery SetMapper(Func<IDataReaderMapperContext,object> handler) {\n\t\t\t\tCustomMappingHandler = handler;\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Sets flag that determines whether query record offset is applied during reading query results.\n\t\t\t/// </summary>\n\t\t\t/// <remarks>ApplyOffset = false is used when offset is applied in SQL query, and no need to skip N records while reading from DbDataReader.</remarks>\n\t\t\tpublic SelectQuery SetApplyOffset(bool applyOffset) {\n\t\t\t\tApplyOffset = applyOffset;\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns the first record from the query result. \n\t\t\t/// </summary>\n\t\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\t\tpublic T Single<T>() {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand(selectCmd, CommandBehavior.SingleRow,\n\t\t\t\t\t\t(rdr) => new DataReaderResult(rdr, DataReaderRecordOffset, 1, FirstFieldName)\n\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).Single<T>() \n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously returns the first record from the query result. \n\t\t\t/// </summary>\n\t\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\t\tpublic Task<T> SingleAsync<T>(CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.SingleRow,\n\t\t\t\t\t\t(rdr, c) => \n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, 1, FirstFieldName)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).SingleAsync<T>(c),\n\t\t\t\t\t\tcancel );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns a list with all query results.\n\t\t\t/// </summary>\n\t\t\t/// <returns>list with query results</returns>\n\t\t\tpublic List<T> ToList<T>() {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr) => new DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToList<T>());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously returns a list with all query results.\n\t\t\t/// </summary>\n\t\t\tpublic Task<List<T>> ToListAsync<T>(CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr, c) => \n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToListAsync<T>(c),\n\t\t\t\t\t\tcancel);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns dictionary with first record values.\n\t\t\t/// </summary>\n\t\t\t/// <returns>dictionary with field values or null if query returns zero records.</returns>\n\t\t\tpublic Dictionary<string,object> ToDictionary() {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand(selectCmd, CommandBehavior.SingleRow,\n\t\t\t\t\t\t(rdr) => new DataReaderResult(rdr, DataReaderRecordOffset, 1)\n\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToDictionary());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously returns dictionary with first record values.\n\t\t\t/// </summary>\n\t\t\tpublic Task<Dictionary<string,object>> ToDictionaryAsync(CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.SingleRow,\n\t\t\t\t\t\t(rdr, c) => \n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, 1)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToDictionaryAsync(c),\n\t\t\t\t\t\tcancel);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns a list of dictionaries with all query results.\n\t\t\t/// </summary>\n\t\t\tpublic List<Dictionary<string,object>> ToDictionaryList() {\n\t\t\t\treturn ToList<Dictionary<string,object>>();\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously a list of dictionaries with all query results.\n\t\t\t/// </summary>\n\t\t\tpublic Task<List<Dictionary<string, object>>> ToDictionaryListAsync(CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr, c) => \n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToDictionaryListAsync(c),\n\t\t\t\t\t\tcancel);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns all query results as <see cref=\"RecordSet\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic RecordSet ToRecordSet() {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr) => new DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToRecordSet());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously returns all query results as <see cref=\"RecordSet\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic Task<RecordSet> ToRecordSetAsync(CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr, c) => \n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToRecordSetAsync(c),\n\t\t\t\t\t\tcancel);\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Returns all query results as <see cref=\"DataTable\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic DataTable ToDataTable() => ToDataTable(TableName!=null ? new DataTable(TableName) : null);\n\n\t\t\t/// <summary>\n\t\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic DataTable ToDataTable(DataTable tbl) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr) => new DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToDataTable(tbl));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic Task<DataTable> ToDataTableAsync(CancellationToken cancel = default(CancellationToken))\n\t\t\t\t=> ToDataTableAsync(TableName != null ? new DataTable(TableName) : null, cancel);\n\n\t\t\t/// <summary>\n\t\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic Task<DataTable> ToDataTableAsync(DataTable tbl, CancellationToken cancel = default(CancellationToken)) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync(selectCmd, CommandBehavior.Default,\n\t\t\t\t\t\t(rdr, c) =>\n\t\t\t\t\t\t\tnew DataReaderResult(rdr, DataReaderRecordOffset, RecordCount)\n\t\t\t\t\t\t\t\t.SetMapper(CustomMappingHandler).ToDataTableAsync(tbl, c),\n\t\t\t\t\t\tcancel);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Executes data reader and returns custom handler result. \n\t\t\t/// </summary>\n\t\t\tpublic T ExecuteReader<T>(Func<IDataReader,T> readHandler) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommand<T>(selectCmd, CommandBehavior.Default, rdr => {\n\t\t\t\t\t\tif (DataReaderRecordOffset > 0 || RecordCount < Int32.MaxValue)\n\t\t\t\t\t\t\trdr = new OffsetCountDataReaderWrapper(rdr, DataReaderRecordOffset, RecordCount);\n\t\t\t\t\t\treturn readHandler(rdr);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Asynchronously executes data reader and returns custom handler result. \n\t\t\t/// </summary>\n\t\t\tpublic Task<T> ExecuteReaderAsync<T>(Func<IDataReader, CancellationToken, Task<T>> readHandlerAsync, CancellationToken cancel) {\n\t\t\t\tusing (var selectCmd = GetSelectCmd()) {\n\t\t\t\t\treturn ExecuteCommandAsync<T>(selectCmd, CommandBehavior.Default, (rdr,cToken) => {\n\t\t\t\t\t\tif (DataReaderRecordOffset > 0 || RecordCount < Int32.MaxValue)\n\t\t\t\t\t\t\trdr = new OffsetCountDataReaderWrapper(rdr, DataReaderRecordOffset, RecordCount);\n\t\t\t\t\t\treturn readHandlerAsync(rdr, cToken);\n\t\t\t\t\t}, cancel);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal T ExecuteCommand<T>(IDbCommand cmd, CommandBehavior cmdBehaviour, Func<IDataReader,T> getResult) {\n\t\t\t\tT res = default(T);\n\t\t\t\tDataHelper.EnsureConnectionOpen(cmd.Connection, () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tusing (var rdr = cmd.ExecuteReader(cmdBehaviour)) {\n\t\t\t\t\t\t\tres = getResult(rdr);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\tthrow new ExecuteDbCommandException(cmd, ex);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tinternal async Task<T> ExecuteCommandAsync<T>(\n\t\t\t\t\tIDbCommand cmd, CommandBehavior cmdBehaviour,\n\t\t\t\t\tFunc<IDataReader,CancellationToken,Task<T>> getResultAsync, CancellationToken cancel) {\n\n\t\t\t\tvar isOpenConn = cmd.Connection.State != ConnectionState.Closed;\n\t\t\t\tif (!isOpenConn) {\n\t\t\t\t\tawait cmd.Connection.OpenAsync(cancel).ConfigureAwait(false);\n\t\t\t\t}\n\t\t\t\tIDataReader rdr = null;\n\t\t\t\tT res = default(T);\n\t\t\t\ttry {\n\t\t\t\t\tif (cmd is DbCommand) {\n\t\t\t\t\t\trdr = await ((DbCommand)cmd).ExecuteReaderAsync(cmdBehaviour, cancel).ConfigureAwait(false);\n\t\t\t\t\t} else {\n\t\t\t\t\t\trdr = cmd.ExecuteReader(cmdBehaviour);\n\t\t\t\t\t}\n\t\t\t\t\tres = await getResultAsync(rdr, cancel).ConfigureAwait(false);\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tthrow new ExecuteDbCommandException(cmd, ex);\n\t\t\t\t} finally {\n\t\t\t\t\tif (rdr!=null)\n\t\t\t\t\t\trdr.Dispose();\n\t\t\t\t\tif (!isOpenConn)\n\t\t\t\t\t\tcmd.Connection.Close();\n\t\t\t\t}\n\t\t\t\treturn res;\n\t\t\t}\n\n\n\t\t}\n\t\t\n\t\tinternal class SelectQueryByQuery : SelectQuery {\n\t\t\t\n\t\t\treadonly Query Query;\n\n\t\t\tinternal SelectQueryByQuery(DbDataAdapter adapter, Query q) \n\t\t\t\t: base(adapter) {\n\t\t\t\tQuery = q;\n\t\t\t}\n\n\t\t\tinternal override IDbCommand GetSelectCmd() {\n\t\t\t\tvar selectCmd = Adapter.CommandBuilder.GetSelectCommand(Query);\n\t\t\t\tAdapter.SetupCmd(selectCmd);\n\t\t\t\treturn selectCmd;\n\t\t\t}\n\n\t\t\tinternal override int RecordOffset { get { return Query.RecordOffset; } }\n\n\t\t\tinternal override int RecordCount { get { return Query.RecordCount; } }\n\n\t\t\tinternal override string FirstFieldName { \n\t\t\t\tget { \n\t\t\t\t\treturn Query.Fields!=null && Query.Fields.Length>0 ? Query.Fields[0].Name : null; \n\t\t\t\t} \n\t\t\t}\n\n\t\t\tinternal override string TableName {\n\t\t\t\tget {\n\t\t\t\t\treturn Query.Table.Name;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tinternal class SelectQueryBySql : SelectQuery {\n\t\t\t\n\t\t\treadonly string Sql;\n\t\t\tobject[] Parameters;\n\n\t\t\tinternal SelectQueryBySql(DbDataAdapter adapter, string sql, object[] parameters) \n\t\t\t\t: base(adapter) {\n\t\t\t\tSql = sql;\n\t\t\t\tParameters = parameters;\n\t\t\t}\n\n\t\t\tinternal override IDbCommand GetSelectCmd() {\n\t\t\t\tvar selectCmd = Adapter.CommandBuilder.DbFactory.CreateCommand();\n\n\t\t\t\tvar fmtArgs = new string[Parameters.Length];\n\t\t\t\tfor (int i=0; i<Parameters.Length; i++) {\n\t\t\t\t\tvar paramVal = Parameters[i];\n\t\t\t\t\t\n\t\t\t\t\tif (paramVal is IDataParameter) {\n\t\t\t\t\t\t// this is already composed command parameter\n\t\t\t\t\t\tselectCmd.Parameters.Add(paramVal);\n\t\t\t\t\t\tfmtArgs[i] = ((IDataParameter)paramVal).ParameterName;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar cmdParam = Adapter.CommandBuilder.DbFactory.AddCommandParameter(selectCmd, paramVal);\n\t\t\t\t\t\tfmtArgs[i] = cmdParam.Placeholder;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tselectCmd.CommandText = String.Format(Sql, fmtArgs);\n\n\t\t\t\tAdapter.SetupCmd(selectCmd);\n\t\t\t\treturn selectCmd;\n\t\t\t}\n\n\t\t}\n\n\t\tinternal class SelectQueryByCmd : SelectQuery {\n\n\t\t\treadonly IDbCommand Cmd;\n\n\t\t\tinternal SelectQueryByCmd(DbDataAdapter adapter, IDbCommand cmd)\n\t\t\t\t: base(adapter) {\n\t\t\t\tCmd = cmd;\n\t\t\t}\n\n\t\t\tinternal override IDbCommand GetSelectCmd() {\n\t\t\t\tAdapter.SetupCmd(Cmd);\n\t\t\t\treturn Cmd;\n\t\t\t}\n\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Internal/OffsetCountDataReaderWrapper.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Data.Common;\nusing System.Data;\nusing System.Collections;\nusing System.Threading.Tasks;\nusing System.Threading;\n\nnamespace NReco.Data {\n\tinternal class OffsetCountDataReaderWrapper : DbDataReader {\n\n\t\tIDataReader Rdr;\n\t\tint Offset;\n\t\tint Count;\n\n\t\tinternal OffsetCountDataReaderWrapper(IDataReader rdr, int offset, int count) {\n\t\t\tRdr = rdr;\n\t\t\tOffset = offset;\n\t\t\tCount = count;\n\t\t}\n\n\t\tpublic override object this[int ordinal] => Rdr[ordinal];\n\n\t\tpublic override object this[string name] => Rdr[name];\n\n\t\tpublic override int FieldCount => Rdr.FieldCount;\n\t\tpublic override int Depth => Rdr.Depth;\n\n\t\tpublic override bool HasRows {\n\t\t\tget {\n\t\t\t\tif (Rdr is DbDataReader dbRdr)\n\t\t\t\t\treturn dbRdr.HasRows;\n\t\t\t\tthrow new NotImplementedException();\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool IsClosed => Rdr.IsClosed;\n\n\t\tpublic override int RecordsAffected => Rdr.RecordsAffected;\n\n\t\tpublic override bool GetBoolean(int ordinal) {\n\t\t\treturn Rdr.GetBoolean(ordinal);\n\t\t}\n\n\t\tpublic override byte GetByte(int ordinal) {\n\t\t\treturn Rdr.GetByte(ordinal);\n\t\t}\n\n\t\tpublic override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) {\n\t\t\treturn Rdr.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length);\n\t\t}\n\n\t\tpublic override char GetChar(int ordinal) {\n\t\t\treturn Rdr.GetChar(ordinal);\n\t\t}\n\n\t\tpublic override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) {\n\t\t\treturn Rdr.GetChars(ordinal, dataOffset, buffer, bufferOffset, length);\n\t\t}\n\n\t\tpublic override string GetDataTypeName(int ordinal) {\n\t\t\treturn Rdr.GetDataTypeName(ordinal);\n\t\t}\n\n\t\tpublic override DateTime GetDateTime(int ordinal) {\n\t\t\treturn Rdr.GetDateTime(ordinal);\n\t\t}\n\n\t\tpublic override decimal GetDecimal(int ordinal) {\n\t\t\treturn Rdr.GetDecimal(ordinal);\n\t\t}\n\n\t\tpublic override double GetDouble(int ordinal) {\n\t\t\treturn Rdr.GetDouble(ordinal);\n\t\t}\n\n\t\tpublic override IEnumerator GetEnumerator() {\n\t\t\treturn new DbEnumerator(this, false);\n\t\t}\n\n\t\tpublic override Type GetFieldType(int ordinal) => Rdr.GetFieldType(ordinal);\n\n\t\tpublic override float GetFloat(int ordinal) => Rdr.GetFloat(ordinal);\n\n\t\tpublic override Guid GetGuid(int ordinal) => Rdr.GetGuid(ordinal);\n\n\t\tpublic override short GetInt16(int ordinal) => Rdr.GetInt16(ordinal);\n\n\t\tpublic override int GetInt32(int ordinal) => Rdr.GetInt32(ordinal);\n\n\t\tpublic override long GetInt64(int ordinal) => Rdr.GetInt64(ordinal);\n\n\t\tpublic override string GetName(int ordinal) => Rdr.GetName(ordinal);\n\n\t\tpublic override int GetOrdinal(string name) => Rdr.GetOrdinal(name);\n\n\t\tpublic override string GetString(int ordinal) => Rdr.GetString(ordinal);\n\n\t\tpublic override object GetValue(int ordinal) => Rdr.GetValue(ordinal);\n\n\t\tpublic override int GetValues(object[] values) => Rdr.GetValues(values);\n\n\t\tpublic override bool IsDBNull(int ordinal) => Rdr.IsDBNull(ordinal);\n\n\t\tpublic override bool NextResult() => Rdr.NextResult();\n\n\t\tpublic override DataTable GetSchemaTable() => Rdr.GetSchemaTable();\n\n\t\tpublic override void Close() => Rdr.Close();\n\n\t\tpublic override bool Read() {\n\t\t\twhile (Offset > 0) {\n\t\t\t\tif (!Rdr.Read()) {\n\t\t\t\t\tOffset = 0;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tOffset--;\n\t\t\t}\n\n\t\t\tvar res = Rdr.Read();\n\t\t\tif (res)\n\t\t\t\tCount--;\n\t\t\treturn res && Count >= 0;\n\t\t}\n\n\t\tasync Task<bool> ReadWithOffsetCountAsync(DbDataReader dbRdr, CancellationToken cancellationToken) {\n\t\t\twhile (Offset > 0) {\n\t\t\t\tif (!await dbRdr.ReadAsync(cancellationToken)) {\n\t\t\t\t\tOffset = 0;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tOffset--;\n\t\t\t}\n\t\t\tvar res = await dbRdr.ReadAsync(cancellationToken);\n\t\t\tif (res)\n\t\t\t\tCount--;\n\t\t\treturn res && Count >= 0;\n\t\t}\n\n\t\tpublic override Task<bool> ReadAsync(CancellationToken cancellationToken) {\n\t\t\tif (Rdr is DbDataReader dbRdr) {\n\t\t\t\treturn ReadWithOffsetCountAsync(dbRdr, cancellationToken);\n\t\t\t} else {\n\t\t\t\t// use default impl that uses sync \"Read\" where offset/count are handled\n\t\t\t\treturn base.ReadAsync(cancellationToken);\n\t\t\t}\n\t\t}\n\n\t}\n}\n\n\n"
  },
  {
    "path": "src/NReco.Data/Internal/RecordSetAdapter.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\nusing System.Data.Common;\n\nnamespace NReco.Data {\n\n\n\tinternal class RecordSetAdapter : IDisposable {\n\t\tRecordSet RS;\n\t\tDbDataAdapter DbAdapter;\n\t\tstring TableName;\n\t\tIDbCommand InsertCmd = null;\n\t\tIDbCommand UpdateCmd = null;\n\t\tIDbCommand DeleteCmd = null;\n\t\tRecordSet.Column[] setColumns;\n\t\tRecordSet.Column autoIncrementCol;\n\n\t\tinternal RecordSetAdapter(DbDataAdapter dbAdapter, string tblName, RecordSet rs) {\n\t\t\tRS = rs;\n\t\t\tDbAdapter = dbAdapter;\n\t\t\tTableName = tblName;\n\t\t\tsetColumns = RS.Columns.Where(c=>!c.ReadOnly).ToArray();\n\t\t\tautoIncrementCol = RS.Columns.Where(c=>c.AutoIncrement).FirstOrDefault();\n\t\t}\n\n\t\tIEnumerable<KeyValuePair<string,IQueryValue>> GetSetColumns() {\n\t\t\treturn setColumns.Select( c => new KeyValuePair<string,IQueryValue>(c.Name, new QVar(c.Name).Set(null) ) );\n\t\t}\n\t\tQuery GetPkQuery() {\n\t\t\tvar q = new Query(new QTable(TableName, null));\n\t\t\tvar grpAnd = QGroupNode.And();\n\t\t\tq.Condition = grpAnd;\n\t\t\tforeach (var pkCol in RS.PrimaryKey) {\n\t\t\t\tgrpAnd.Nodes.Add( (QField)pkCol.Name == new QVar(pkCol.Name).Set(null) );\n\t\t\t}\n\t\t\treturn q;\n\t\t}\n\n\t\tbool IsBinaryType(Type t) {\n\t\t\treturn t==typeof(byte[])\n\t\t\t\t|| t==typeof(System.Data.SqlTypes.SqlBytes) || t==typeof(System.Data.SqlTypes.SqlBinary)\t;\n\t\t}\n\n\t\tvoid FillCmdParams(IDbCommand cmd, RecordSet.Row row) {\n\t\t\tforeach (DbParameter p in cmd.Parameters) {\n\t\t\t\tif (!String.IsNullOrEmpty(p.SourceColumn)) {\n\t\t\t\t\tif (!row.RecordSet.Columns.Contains(p.SourceColumn))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tvar rowVal = row[p.SourceColumn];\n\t\t\t\t\tif (rowVal==null) {\n\t\t\t\t\t\tp.Value = DBNull.Value;\n\t\t\t\t\t\tvar col = RS.Columns[p.SourceColumn];\n\t\t\t\t\t\tif (IsBinaryType(col.DataType))\n\t\t\t\t\t\t\tp.DbType = DbType.Binary;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.Value = rowVal;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t}\n\n\t\tvoid PrepareInsertCmd(RecordSet.Row row) {\n\t\t\tif (InsertCmd==null) {\n\t\t\t\tInsertCmd = DbAdapter.CommandBuilder.GetInsertCommand(TableName, GetSetColumns() );\n\t\t\t\tInsertCmd.Connection = DbAdapter.Connection;\n\t\t\t\tInsertCmd.Transaction = DbAdapter.Transaction;\n\t\t\t}\n\t\t\tFillCmdParams(InsertCmd, row);\t\t\n\t\t}\n\n\t\tint ExecuteInsertCmd(RecordSet.Row row) {\n\t\t\tPrepareInsertCmd(row);\n\t\t\tvar affected = InsertCmd.ExecuteNonQuery();\n\t\t\tif (autoIncrementCol!=null) {\n\t\t\t\trow[autoIncrementCol.Name] = DbAdapter.CommandBuilder.DbFactory.GetInsertId(DbAdapter.Connection, DbAdapter.Transaction);\n\t\t\t}\n\t\t\treturn affected;\n\t\t}\n\n\t\tasync Task<int> ExecuteInsertCmdAsync(RecordSet.Row row, CancellationToken cancel) {\n\t\t\tPrepareInsertCmd(row);\n\t\t\tvar affected = await InsertCmd.ExecuteNonQueryAsync(cancel).ConfigureAwait(false);\n\t\t\tif (autoIncrementCol!=null) {\n\t\t\t\trow[autoIncrementCol.Name] = DbAdapter.CommandBuilder.DbFactory.GetInsertId(DbAdapter.Connection, DbAdapter.Transaction);\n\t\t\t}\n\t\t\treturn affected;\n\t\t}\n\n\t\tvoid PrepareUpdateCmd(RecordSet.Row row) {\n\t\t\tif (UpdateCmd==null) {\n\t\t\t\tUpdateCmd = DbAdapter.CommandBuilder.GetUpdateCommand( GetPkQuery(), GetSetColumns() );\n\t\t\t\tUpdateCmd.Connection = DbAdapter.Connection;\n\t\t\t\tUpdateCmd.Transaction = DbAdapter.Transaction;\n\t\t\t}\n\t\t\tFillCmdParams(UpdateCmd, row);\n\t\t}\n\n\t\tint ExecuteUpdateCmd(RecordSet.Row row) {\n\t\t\tPrepareUpdateCmd(row);\n\t\t\treturn UpdateCmd.ExecuteNonQuery();\n\t\t}\n\n\t\tTask<int> ExecuteUpdateCmdAsync(RecordSet.Row row, CancellationToken cancel) {\n\t\t\tPrepareUpdateCmd(row);\n\t\t\treturn UpdateCmd.ExecuteNonQueryAsync(cancel);\n\t\t}\n\n\t\tvoid PrepareDeleteCmd(RecordSet.Row row) {\n\t\t\tif (DeleteCmd==null) {\n\t\t\t\tDeleteCmd = DbAdapter.CommandBuilder.GetDeleteCommand( GetPkQuery() );\n\t\t\t\tDeleteCmd.Connection = DbAdapter.Connection;\n\t\t\t\tDeleteCmd.Transaction = DbAdapter.Transaction;\n\t\t\t}\n\t\t\tFillCmdParams(DeleteCmd, row);\n\t\t}\n\n\t\tint ExecuteDeleteCmd(RecordSet.Row row) {\n\t\t\tPrepareDeleteCmd(row);\n\t\t\treturn DeleteCmd.ExecuteNonQuery();\n\t\t}\n\n\t\tTask<int> ExecuteDeleteCmdAsync(RecordSet.Row row, CancellationToken cancel) {\n\t\t\tPrepareDeleteCmd(row);\t\n\t\t\treturn DeleteCmd.ExecuteNonQueryAsync(cancel);\t\t\t\t\t\n\t\t}\n\n\t\tinternal int Update() {\n\t\t\tint affected = 0;\n\t\t\tDataHelper.EnsureConnectionOpen( DbAdapter.Connection, () => {\n\t\t\t\tforeach (var row in RS) {\n\t\t\t\t\tif ( (row.State&RecordSet.RowState.Added) == RecordSet.RowState.Added) {\n\t\t\t\t\t\taffected += ExecuteInsertCmd(row);\n\t\t\t\t\t} else if ( (row.State&RecordSet.RowState.Deleted) == RecordSet.RowState.Deleted ) {\n\t\t\t\t\t\taffected += ExecuteDeleteCmd(row);\n\t\t\t\t\t} else if ( (row.State&RecordSet.RowState.Modified) == RecordSet.RowState.Modified ) {\n\t\t\t\t\t\taffected += ExecuteUpdateCmd(row);\n\t\t\t\t\t}\n\t\t\t\t\trow.AcceptChanges();\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn affected;\n\t\t}\n\n\t\tinternal async Task<int> UpdateAsync(CancellationToken cancel) {\n\t\t\tint affected = 0;\n\t\t\tvar isOpenConn = DbAdapter.Connection.State != ConnectionState.Closed;\n\t\t\tif (!isOpenConn) {\n\t\t\t\tawait DbAdapter.Connection.OpenAsync(cancel).ConfigureAwait(false);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tforeach (var row in RS) {\n\t\t\t\t\tif ( (row.State&RecordSet.RowState.Added) == RecordSet.RowState.Added) {\n\t\t\t\t\t\taffected += await ExecuteInsertCmdAsync(row,cancel).ConfigureAwait(false);\n\t\t\t\t\t} else if ( (row.State&RecordSet.RowState.Deleted) == RecordSet.RowState.Deleted ) {\n\t\t\t\t\t\taffected += await ExecuteDeleteCmdAsync(row,cancel).ConfigureAwait(false);\n\t\t\t\t\t} else if ( (row.State&RecordSet.RowState.Modified) == RecordSet.RowState.Modified ) {\n\t\t\t\t\t\taffected += await ExecuteUpdateCmdAsync(row,cancel).ConfigureAwait(false);\n\t\t\t\t\t}\n\t\t\t\t\trow.AcceptChanges();\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (!isOpenConn)\n\t\t\t\t\tDbAdapter.Connection.Close();\n\t\t\t}\n\t\t\treturn affected;\n\t\t}\n\n\t\tpublic void Dispose() {\n\t\t\tRS = null;\n\t\t\tDbAdapter = null;\n\t\t\tsetColumns = null;\n\t\t\tautoIncrementCol = null;\n\t\t\tif (InsertCmd!=null) {\n\t\t\t\tInsertCmd.Dispose();\n\t\t\t\tInsertCmd = null;\n\t\t\t}\n\t\t\tif (UpdateCmd!=null) {\n\t\t\t\tUpdateCmd.Dispose();\n\t\t\t\tUpdateCmd = null;\n\t\t\t}\n\t\t\tif (DeleteCmd!=null) {\n\t\t\t\tDeleteCmd.Dispose();\n\t\t\t\tDeleteCmd = null;\n\t\t\t}\n\t\t}\t\n\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/NReco.Data.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Description>Fast lightweight data access library for .NET Core (micro-ORM): simple API for CRUD operations, dynamic queries, SQL commands generation (command builder), abstract queries that have simple string representation + parser, schema-less data access, flexible query results mapping to annotated POCO models, app-level data views, RecordSet structure (replacement for DataTable). Try out NReco.Data if you're looking for Dapper alternative with abstract queries and automated SQL generation.</Description>\n    <Title>Micro-ORM with abstract queries and SQL generation for any ADO.NET connector.</Title>\n\t<Copyright>Copyright (c) 2016-2025 Vitalii Fedorchenko</Copyright>\n    <AssemblyTitle>NReco.Data</AssemblyTitle>\n    <VersionPrefix>1.2.11</VersionPrefix>\n    <Authors>Vitalii Fedorchenko</Authors>\n    <TargetFrameworks>netstandard2.0;net45</TargetFrameworks>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <AssemblyName>NReco.Data</AssemblyName>\n    <PackageId>NReco.Data</PackageId>\n    <PackageTags>DAL;ado.net;data;sql;query;generator;sql-builder;database;orm;micro-orm;data-mapper;poco;schema-less;relex;recordset;netstandard;netcore;net45</PackageTags>\n\t<PackageReleaseNotes>Source code and examples: https://github.com/nreco/data\nAPI reference: https://www.nrecosite.com/doc/NReco.Data/\n\nv.1.2.11 changes:\n- Fix: RelexParser.ParseCondition doesn't throw an exception for invalid relex condition #78\n\nv.1.2.10 changes:\n- Make DbFactory.CreateConnection virtual to allow specific connection handling in inheritors #71\n\nv.1.2.9 changes:\n- StringTemplate added support of nested tokens (controlled via ReplaceNestedTokens property) #70\n\nv.1.2.8 changes:\n- QRawSql/QRaw: ability to specify custom SQL with parameters #69\n\nv.1.2.7 changes:\n- StringTemplate: alternative syntax for token placeholders #68\n\nv.1.2.6 changes:\n- Not (QNegationNode) is not supported by RelexParser #67\n\nv.1.2.5 changes:\n- RecordSet.Column.DataType is null when loaded from the DbDataReader with default \"GetColumnSchema\" implementation #65\n\nv.1.2.4 changes:\n- handle DbGenerated attribute with option \"None\" correctly #64\n\nv.1.2.3 changes:\n- now DbFactory.AddCommandParameter is virtual\n- added DbFactory.GetCmdParameterName (to allow very custom param names - like for Snowflake ADO.NET provider)\n\nv.1.2.2 changes:\n- fixed DbDataAdapter.Select().ExecuteReader offset/count handling when ApplyOffset=true #63\n\nv.1.2.1 changes:\n- QAggregateField: ability to specify custom SQL template #62\n\nv.1.2.0 changes:\n- added simple aggregate queries with QAggregateField #60\n- fixed issue with RelexBuilder and QVar #61\n\nv.1.1.1 changes:\n- fixed issue with DbDataAdapter.Update for RecordSet when query contains parameters that are not mapped to Row columns #55\n\t\t\n</PackageReleaseNotes>\t\n    <PackageIconUrl>https://www.nrecosite.com/img/nreco-logo-200.png</PackageIconUrl>\n    <PackageProjectUrl>https://www.nrecosite.com/dalc_net.aspx</PackageProjectUrl>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/nreco/data/master/LICENSE</PackageLicenseUrl>\n    <RepositoryUrl>https://github.com/nreco/data</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\t\n    <NetStandardImplicitPackageVersion Condition=\" '$(TargetFramework)' == 'netstandard1.5' \">1.6.0</NetStandardImplicitPackageVersion>\n    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>\n    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>\n    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>\n    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>\n    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>\n    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>\n    <GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>\n    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\n    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>\n    <SignAssembly>false</SignAssembly>\n    <AssemblyOriginatorKeyFile>NReco.Data.snk</AssemblyOriginatorKeyFile>\t\n  </PropertyGroup>\n\n  <ItemGroup Condition=\" '$(TargetFramework)' == 'net45' \">\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.ComponentModel.DataAnnotations\" />\n    <Reference Include=\"System\" />\n  </ItemGroup>\n  \n  <PropertyGroup Condition=\" '$(TargetFramework)' == 'netstandard2.0' \">\n    <DefineConstants>$(DefineConstants);NET_STANDARD;NET_STANDARD2</DefineConstants>\n  </PropertyGroup>  \n\n  <ItemGroup Condition=\" '$(TargetFramework)' == 'netstandard2.0' \"> \n    <PackageReference Include=\"System.ComponentModel.Annotations\" Version=\"4.4.0\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "src/NReco.Data/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Resources;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"NReco.Data\")]\n[assembly: AssemblyDescription(\"Fast lightweight schema-less data access library (micro-ORM): dynamic queries, SQL commands generation (command builder), relational expressions parser, flexible query results mapping to annotated POCO models, app-level data views, RecordSet structure (replacement for DataTable).\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"NReco.Data\")]\n[assembly: AssemblyCopyright(\"Copyright © Vitalii Fedorchenko 2016-2025\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: NeutralResourcesLanguage(\"en\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.2.11.0\")]\n[assembly: AssemblyFileVersion(\"1.2.11.0\")]\n"
  },
  {
    "path": "src/NReco.Data/Query/IQueryValue.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Marker interface for query values.\n\t/// </summary>\n\tpublic interface IQueryValue\n\t{\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QAggregateField.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Text.RegularExpressions;\nusing System.Text;\nusing System.Linq;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents query aggregate field.\n\t/// </summary>\n\tpublic class QAggregateField : QField\n\t{\n\t\t/// <summary>\n\t\t/// Aggregate function name.\n\t\t/// </summary>\n\t\tpublic string AggregateFunction { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Aggregate function arguments.\n\t\t/// </summary>\n\t\tpublic QField[] Arguments { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of QAggregateField.\n\t\t/// </summary>\n\t\t/// <param name=\"fld\">field name</param>\n\t\t/// <param name=\"aggregateFunction\">aggregate function name</param>\n\t\t/// <param name=\"argFields\">list of arguments for the aggregate function</param>\n\t\tpublic QAggregateField(string fld, string aggregateFunction, params QField[] argFields) \n\t\t\t: base(null, fld, GetAggrExpr(aggregateFunction, argFields.Select(f=>f.ToString()).ToArray() ) ) {\n\t\t\tAggregateFunction = aggregateFunction;\n\t\t\tArguments = argFields;\n\t\t}\n\n\t\tprivate static char[] CustomAggrSqlChars = new[] {'(', '{' };\n\n\t\tinternal static string GetAggrExpr(string aggrFunc, string[] args) {\n\t\t\tif (aggrFunc.IndexOfAny(CustomAggrSqlChars) >= 0)\n\t\t\t\treturn String.Format(aggrFunc, args);\n\n\t\t\tvar sb = new StringBuilder(aggrFunc);\n\t\t\tsb.Append('(');\n\t\t\tfor (int i = 0; i < args.Length; i++) {\n\t\t\t\tif (i > 0)\n\t\t\t\t\tsb.Append(',');\n\t\t\t\tsb.Append(args[i].ToString());\n\t\t\t}\n\t\t\tsb.Append(')');\n\t\t\treturn sb.ToString();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a string representation of QField\n\t\t/// </summary>\n\t\t/// <returns>string in [prefix].[field name] format</returns>\n\t\tpublic override string ToString() {\n\t\t\treturn String.IsNullOrEmpty(Prefix) ? Name : Prefix+\".\"+Name;\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QConditionNode.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\n\nnamespace NReco.Data {\n\n\t//[Serializable]\n\tpublic class QConditionNode : QNode {\n\t\t\n\t\tprivate IQueryValue _LValue;\n\t\tprivate Conditions _Condition;\n\t\tprivate IQueryValue _RValue;\n\n\t\tpublic IQueryValue LValue {\n\t\t\tget { return _LValue; }\n\t\t}\n\n\t\tpublic Conditions Condition {\n\t\t\tget { return _Condition; }\n\t\t} \n\t\n\t\tpublic IQueryValue RValue {\n\t\t\tget { return _RValue; }\n\t\t}\n\t\t\n\t\tpublic override IList<QNode> Nodes { \n\t\t\tget {\n\t\t\t\tvar l = new List<QNode>();\n\t\t\t\tif (LValue is QNode)\n\t\t\t\t\tl.Add( (QNode)LValue );\n\t\t\t\tif (RValue is QNode)\n\t\t\t\t\tl.Add( (QNode)RValue );\n\t\t\t\treturn l; \n\t\t\t}\n\t\t}\n\n\t\n\t\tpublic QConditionNode(IQueryValue lvalue, Conditions conditions, IQueryValue rvalue) {\n\t\t\t_RValue = rvalue;\n\t\t\t_Condition = conditions;\n\t\t\t_LValue = lvalue;\n\t\t}\n\n\t\tpublic QConditionNode(string name, IQueryValue lvalue, Conditions conditions, IQueryValue rvalue) : \n\t\t\tthis(lvalue, conditions, rvalue) {\n\t\t\tName = name;\n\t\t}\n\n\t\tpublic QConditionNode(QConditionNode node) {\n\t\t\tName = node.Name;\n\t\t\t_LValue = node.LValue;\n\t\t\t_Condition = node.Condition;\n\t\t\t_RValue = node.RValue;\n\t\t}\n\n\t}\n\n\t[Flags]\n\tpublic enum Conditions {\n\t\tEqual = 1,\n\t\tLessThan = 2,\n\t\tGreaterThan = 4,\n\t\tLike = 8,\n\t\tIn = 16,\n\t\tNull = 32,\n\t\tNot = 64\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QConst.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// Represents query constant.\n\t/// </summary>\n\t//[Serializable]\n\tpublic class QConst : IQueryValue {\n\t\tobject _Value;\n\t\tTypeCode _Type;\n\t\t\n\t\t/// <summary>\n\t\t/// Get constant value object\n\t\t/// </summary>\n\t\tpublic virtual object Value {\n\t\t\tget { return _Value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Get TypeCode of constant value\n\t\t/// </summary>\n\t\tpublic TypeCode Type { \n\t\t\tget {\n\t\t\t\treturn _Type!=TypeCode.Empty ? _Type : Convert.GetTypeCode(Value);\n\t\t\t} \n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QConst with specified value object\n\t\t/// </summary>\n\t\t/// <param name=\"value\">object of constant value</param>\n\t\tpublic QConst(object value) {\n\t\t\t_Value = value;\n\t\t\t_Type = TypeCode.Empty;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QConst with specified value object and explicit type\n\t\t/// </summary>\n\t\t/// <param name=\"value\">object of constant value</param>\n\t\tpublic QConst(object value, TypeCode type) {\n\t\t\t_Value = value;\n\t\t\t_Type = type;\n\t\t}\n\t\t\n\t\tpublic static explicit operator QConst(int value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(long value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(float value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(string value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(decimal value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(Array value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(double value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\t\t\n\t\tpublic static explicit operator QConst(DateTime value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static explicit operator QConst(bool value) {\n\t\t\treturn new QConst(value);\n\t\t}\n\n\t\tpublic static QConditionNode operator ==(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.Equal, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator !=(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.Equal|Conditions.Not, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator <(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.LessThan, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator >(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.GreaterThan, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator >=(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.GreaterThan|Conditions.Equal, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator <=(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.LessThan|Conditions.Equal, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator %(QConst lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.Like, rvalue );\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QField.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Text.RegularExpressions;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents query field.\n\t/// </summary>\n\tpublic class QField : IQueryValue\n\t{\n\t\t/// <summary>\n\t\t/// Get field name\n\t\t/// </summary>\n\t\tpublic string Name { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Get field prefix (usually matches query source name alias)\n\t\t/// </summary>\n\t\tpublic string Prefix { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Get optional expression string that represents calculated field\n\t\t/// </summary>\n\t\tpublic string Expression { get; private set; }\n\n\t\tprivate static char[] ExpressionChars = new[] { '(', ')','+','-','*','/' };\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of QField with specified field name\n\t\t/// </summary>\n\t\t/// <remarks>If field name contains expression-specific chars ('(', ')','+','-','*','/') it is treated as a calculated field expression</remarks>\n\t\t/// <param name=\"fld\">field name</param>\n\t\tpublic QField(string fld) {\n\t\t\tif (fld.IndexOfAny(ExpressionChars) >= 0) {\n\t\t\t\tExpression = fld;\n\t\t\t\tSetNameByExpression();\n\t\t\t} else {\n\t\t\t\tSetName(fld);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of QField with specified field name and expression\n\t\t/// </summary>\n\t\t/// <param name=\"fld\">field name</param>\n\t\t/// <param name=\"expression\">expression string</param>\n\t\tpublic QField(string fld, string expression) {\n\t\t\tSetName(fld);\n\t\t\tExpression = expression;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of QField with specified field prefix, name and expression\n\t\t/// </summary>\n\t\t/// <param name=\"prefix\">field prefix</param>\n\t\t/// <param name=\"fld\">field name</param>\n\t\t/// <param name=\"expression\">expression string</param>\n\t\tpublic QField(string prefix, string fld, string expression) {\n\t\t\tPrefix = prefix;\n\t\t\tName = fld;\n\t\t\tExpression = expression;\n\t\t}\n\n\t\tstatic Regex AsFieldNameRegex = new Regex(@\"\\s*[a-z][a-zA-Z0-9_]*\\s*$\", RegexOptions.Compiled | RegexOptions.Singleline);\n\n\t\tprivate void SetNameByExpression() {\n\t\t\tName = Expression;\n\t\t\tvar asIdx = Expression.LastIndexOf(\" as \");\n\t\t\tif (asIdx>0) {\n\t\t\t\tvar tail = Expression.Substring(asIdx + 4);\n\t\t\t\tif (AsFieldNameRegex.IsMatch(tail)) {\n\t\t\t\t\tName = tail.Trim();\n\t\t\t\t\tExpression = Expression.Substring(0, asIdx);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void SetName(string nameStr) {\n\t\t\tvar dotIdx = nameStr!=null ? nameStr.LastIndexOf('.') : -1;\n\t\t\tif (dotIdx > 0) {\n\t\t\t\tPrefix = nameStr.Substring(0, dotIdx);\n\t\t\t\tName = nameStr.Substring(dotIdx + 1);\n\t\t\t} else {\n\t\t\t\tName = nameStr;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a string representation of QField\n\t\t/// </summary>\n\t\t/// <returns>string in [prefix].[field name] format</returns>\n\t\tpublic override string ToString() {\n\t\t\treturn String.IsNullOrEmpty(Prefix) ? Name : Prefix+\".\"+Name;\n\t\t}\n\n\t\tpublic static implicit operator QField(string fld) {\n\t\t\treturn new QField(fld);\n\t\t}\n\t\tpublic static implicit operator string(QField fld) {\n\t\t\treturn fld.ToString();\n\t\t}\n\t\t\n\t\tpublic static QConditionNode operator ==(QField lvalue, IQueryValue rvalue) {\n\t\t\tif (rvalue == null || ((rvalue is QConst && !(rvalue is QVar)) && DataHelper.IsNullOrDBNull( ((QConst)rvalue).Value ) )) {\n\t\t\t\treturn new QConditionNode(lvalue, Conditions.Null, null);\n\t\t\t}\n\t\t\treturn new QConditionNode( lvalue, Conditions.Equal, rvalue );\n\t\t}\n\n\t\tpublic static QConditionNode operator !=(QField lvalue, IQueryValue rvalue) {\n\t\t\tif (rvalue == null || ((rvalue is QConst && !(rvalue is QVar)) && DataHelper.IsNullOrDBNull( ((QConst)rvalue).Value ) )) {\n\t\t\t\treturn new QConditionNode(lvalue, Conditions.Null|Conditions.Not, null);\n\t\t\t}\n\t\t\treturn new QConditionNode( lvalue, Conditions.Equal|Conditions.Not, rvalue );\n\t\t}\n\n\t\tpublic static QConditionNode operator ==(QField lvalue, DBNull dbNull) {\n\t\t\treturn new QConditionNode(lvalue, Conditions.Null, null);\n\t\t}\n\n\t\tpublic static QConditionNode operator !=(QField lvalue, DBNull dbNull) {\n\t\t\treturn new QConditionNode(lvalue, Conditions.Null | Conditions.Not, null);\n\t\t}\n\n\t\tpublic static QConditionNode operator <(QField lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.LessThan, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator >(QField lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.GreaterThan, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator >=(QField lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.GreaterThan|Conditions.Equal, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator <=(QField lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.LessThan|Conditions.Equal, rvalue );\n\t\t}\t\t\n\n\t\tpublic static QConditionNode operator %(QField lvalue, IQueryValue rvalue) {\n\t\t\treturn new QConditionNode( lvalue, Conditions.Like, rvalue );\n\t\t}\t\t\n\t\t\n\t\tpublic static readonly QField Count = new QField(\"cnt\", \"count(*)\");\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QGroupNode.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace NReco.Data\n{\n\t\n\t/// <summary>\n\t/// Represents group of nodes combined with logical OR/AND operator\n\t/// </summary>\n\tpublic class QGroupNode : QNode {\n\t\t\n\t\tprivate List<QNode> _Nodes;\n\t\n\t\t/// <summary>\n\t\t/// List of group child nodes\n\t\t/// </summary>\n\t\tpublic override IList<QNode> Nodes {\n\t\t\tget {\n\t\t\t\treturn _Nodes;\n\t\t\t}\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Logical operator type (<see cref=\"NReco.Data.QGroupType\"/>)\n\t\t/// </summary>\n\t\tpublic QGroupType GroupType { get; set; }\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QueryGroupNode with specified logical operator\n\t\t/// </summary>\n\t\t/// <param name=\"type\">group logical operator (<see cref=\"NReco.Data.QGroupType\"/>)</param>\n\t\tpublic QGroupNode(QGroupType type) {\n\t\t\tGroupType = type;\n\t\t\t_Nodes = new List<QNode>();\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QueryGroupNode that copies specified QueryGroupNode\n\t\t/// </summary>\n\t\t/// <param name=\"likeGroup\">QueryGroupNode to copy from</param>\n\t\tpublic QGroupNode(QGroupNode likeGroup)\n\t\t\t: this(likeGroup.GroupType) { \n\t\t\tName = likeGroup.Name;\n\t\t\t_Nodes.AddRange(likeGroup.Nodes);\n\t\t}\n\t\t\n\n\t\t/// <summary>\n\t\t/// OR operator\n\t\t/// </summary>\n\t\tpublic static QGroupNode operator | (QGroupNode node1, QNode node2) {\n\t\t\t\n\t\t\tif ( node1.GroupType==QGroupType.Or) {\n\t\t\t\tnode1.Nodes.Add( node2 );\n\t\t\t\treturn node1;\n\t\t\t}\n\t\t\tQGroupNode res = new QGroupNode(QGroupType.Or);\n\t\t\tres.Nodes.Add(node1);\n\t\t\tres.Nodes.Add(node2);\n\t\t\treturn res;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// AND operator\n\t\t/// </summary>\n\t\tpublic static QGroupNode operator & (QGroupNode node1, QNode node2) {\n\t\t\tif ( node1.GroupType==QGroupType.And) {\n\t\t\t\tnode1.Nodes.Add( node2 );\n\t\t\t\treturn node1;\n\t\t\t}\n\t\t\tQGroupNode res = new QGroupNode(QGroupType.And);\n\t\t\tres.Nodes.Add(node1);\n\t\t\tres.Nodes.Add(node2);\n\t\t\treturn res;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Compose AND group node with specified child nodes\n\t\t/// </summary>\n\t\t/// <param name=\"nodes\">child nodes</param>\n\t\t/// <returns>QueryGroupNode of AND type</returns>\n\t\tpublic static QGroupNode And(params QNode[] nodes) {\n\t\t\tvar andGrp = new QGroupNode(QGroupType.And);\n\t\t\tandGrp._Nodes.AddRange(nodes);\n\t\t\treturn andGrp;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Compose OR group node with specified child nodes\n\t\t/// </summary>\n\t\t/// <param name=\"nodes\">child nodes</param>\n\t\t/// <returns>QueryGroupNode of OR type</returns>\n\t\tpublic static QGroupNode Or(params QNode[] nodes) {\n\t\t\tvar orGrp = new QGroupNode(QGroupType.Or);\n\t\t\torGrp._Nodes.AddRange(nodes);\n\t\t\treturn orGrp;\n\t\t}\n\n\t}\n\n\t/// <summary>\n\t/// Describes the group node types\n\t/// </summary>\n\tpublic enum QGroupType {\n\t\t/// <summary>\n\t\t/// Logical OR group type\n\t\t/// </summary>\n\t\tOr, \n\n\t\t/// <summary>\n\t\t/// Logical AND group type\n\t\t/// </summary>\n\t\tAnd\n\t}\t\n\n\n\t\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QNegationNode.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// Represents logical negation operator\n\t/// </summary>\n\tpublic class QNegationNode : QNode {\n\t\t\n\t\tprivate QNode[] SingleNodeList;\n\t\n\t\tpublic override IList<QNode> Nodes {\n\t\t\tget { return SingleNodeList; } \n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QueryNegationNode that wraps specified node  \n\t\t/// </summary>\n\t\t/// <param name=\"node\">condition node to negate</param>\n\t\tpublic QNegationNode(QNode node) {\n\t\t\tSingleNodeList = new QNode[] { node };\n\t\t}\n\n\t\tpublic QNegationNode(QNegationNode copyNode) {\n\t\t\tSingleNodeList = new QNode[] { copyNode.Nodes[0] };\n\t\t\tName = copyNode.Name;\n\t\t}\n\n\t\t\n\t}\n\n\n\t\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QNode.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents abstract query node that contains child nodes.\n\t/// </summary>\n\t//[Serializable]\n\tpublic abstract class QNode\n\t{\n\t\tpublic abstract IList<QNode> Nodes { get; }\n\n\t\tpublic string Name { get; set; }\t\n\t\n\t\tinternal QNode() {\n\t\t}\n\n\t\t/// <summary>\n\t\t/// OR operator\n\t\t/// </summary>\n\t\tpublic static QGroupNode operator | (QNode node1, QNode node2) {\n\t\t\tQGroupNode res = new QGroupNode(QGroupType.Or);\n\t\t\tres.Nodes.Add(node1);\n\t\t\tres.Nodes.Add(node2);\n\t\t\treturn res;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// AND operator\n\t\t/// </summary>\n\t\tpublic static QGroupNode operator & (QNode node1, QNode node2) {\n\t\t\tQGroupNode res = new QGroupNode(QGroupType.And);\n\t\t\tres.Nodes.Add(node1);\n\t\t\tres.Nodes.Add(node2);\n\t\t\treturn res;\n\t\t}\t\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QRawSql.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents raw SQL query value\n\t/// </summary>\n\t//[Serializable]\n\tpublic class QRawSql : IQueryValue {\n\n\t\t/// <summary>\n\t\t/// Get SQL text\n\t\t/// </summary>\n\t\tpublic string SqlText => GetSqlText(ResolveToSqlConstant);\n\n\t\tstring sqlTemplate;\n\t\tobject[] args;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QRawSql with specfield SQL.\n\t\t/// </summary>\n\t\t/// <param name=\"sqlText\">Raw SQL</param>\n\t\tpublic QRawSql(string sqlText) {\n\t\t\tsqlTemplate = sqlText;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QRawSql with specfield SQL template and arguments.\n\t\t/// </summary>\n\t\t/// <param name=\"sqlTemplate\">SQL template that can be resolved with <code>String.Format</code></param>\n\t\t/// <param name=\"args\">arguments that should be used to get final SQL text</param>\n\t\tpublic QRawSql(string sqlTemplate, object[] args) {\n\t\t\tthis.sqlTemplate = sqlTemplate;\n\t\t\tthis.args = args;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns SQL text where arguments are resolved with specified handler.\n\t\t/// </summary>\n\t\tpublic string GetSqlText(Func<object, string> resolveArgValue) {\n\t\t\tif (args == null || args.Length == 0)\n\t\t\t\treturn sqlTemplate;\n\t\t\tvar resolvedArgs = new object[args.Length];\n\t\t\tfor (int i = 0; i < args.Length; i++)\n\t\t\t\tresolvedArgs[i] = resolveArgValue(args[i]);\n\t\t\treturn String.Format(sqlTemplate, resolvedArgs);\n\t\t}\n\n\t\tstring ResolveToSqlConstant(object o) {\n\t\t\tif (o == null || DBNull.Value.Equals(o))\n\t\t\t\treturn \"NULL\";\n\t\t\tvar val = Convert.ToString(o, System.Globalization.CultureInfo.InvariantCulture);\n\t\t\treturn \"'\" + val.Replace(@\"'\", @\"\\'\") + \"'\";\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QRawSqlNode.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace NReco.Data {\n\n\tpublic class QRawSqlNode : QNode {\n\n\t\t/// <summary>\n\t\t/// Nodes collection\n\t\t/// </summary>\n\t\tpublic override IList<QNode> Nodes { get { return new QNode[0]; } }\n\n\t\tpublic string SqlText => rawSql.SqlText;\n\n\t\tQRawSql rawSql;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QRawSql with specfield SQL.\n\t\t/// </summary>\n\t\t/// <param name=\"sqlText\">Raw SQL</param>\n\t\tpublic QRawSqlNode(string sqlText) {\n\t\t\trawSql = new QRawSql(sqlText);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the query node with specfield SQL template and arguments.\n\t\t/// </summary>\n\t\t/// <param name=\"sqlTemplate\">SQL template that can be resolved with <code>String.Format</code></param>\n\t\t/// <param name=\"args\">arguments that should be used to get final SQL text</param>\n\t\tpublic QRawSqlNode(string sqlTemplate, object[] args) {\n\t\t\trawSql = new QRawSql(sqlTemplate, args);\n\t\t}\n\n\t\tpublic string GetSqlText(Func<object, string> resolveArgValue) => rawSql.GetSqlText(resolveArgValue);\n\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QSort.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Linq;\nusing System.ComponentModel;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents query sort option. \n\t/// </summary>\n\tpublic class QSort\n\t{\n\t\tpublic const string Asc = \"asc\";\n\t\tpublic const string Desc = \"desc\";\n\n\t\t/// <summary>\n\t\t/// Get QField sort target\n\t\t/// </summary>\n\t\tpublic QField Field { get; private set; }\n\t\t\n\t\t/// <summary>\n\t\t/// Get sort direction (asc or desc)\n\t\t/// </summary>\n\t\tpublic ListSortDirection SortDirection { get; private set; }\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QSoft with specified field name\n\t\t/// </summary>\n\t\t/// <param name=\"sortFld\">field name with optional direction suffix like \"id desc\"</param>\n\t\tpublic QSort(string sortFld) {\n\t\t\tSortDirection = ListSortDirection.Ascending;\n\n\t\t\tsortFld = sortFld.Trim();\n\t\t\tint lastSpaceIdx = sortFld.LastIndexOf(' ');\n\t\t\tstring lastWord = lastSpaceIdx != -1 ? sortFld.Substring(lastSpaceIdx + 1).ToLower() : null;\n\t\t\tbool sortDirectionFound = true;\n\n\t\t\tif (lastWord == Asc || lastWord == \"ascending\")\n\t\t\t\tSortDirection = ListSortDirection.Ascending;\n\t\t\telse if (lastWord == Desc || lastWord == \"descending\")\n\t\t\t\tSortDirection = ListSortDirection.Descending;\n\t\t\telse\n\t\t\t\tsortDirectionFound = false;\n\n\t\t\tField = new QField( sortDirectionFound ? sortFld.Substring(0, lastSpaceIdx).TrimEnd() : sortFld );\n\t\t\tif (Field.Name == String.Empty)\n\t\t\t\tthrow new ArgumentException(\"Invalid sort field\");\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QSoft with specified field name and sort direction\n\t\t/// </summary>\n\t\t/// <param name=\"fld\">field name</param>\n\t\t/// <param name=\"direction\">sort direction</param>\n\t\tpublic QSort(string fld, ListSortDirection direction) {\n\t\t\tField = (QField)fld;\n\t\t\tSortDirection = direction;\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Returns a string representation of QSort\n\t\t/// </summary>\n\t\t/// <returns>string in [field name] [asc|desc] format</returns>\n\t\tpublic override string ToString() {\n\t\t\treturn String.Format(\"{0} {1}\", Field.ToString(), SortDirection==ListSortDirection.Ascending ? Asc : Desc );\n\t\t}\n\n\t\tpublic static implicit operator QSort(string value) {\n\t\t\treturn new QSort(value);\n\t\t}\n\t\tpublic static implicit operator string(QSort value) {\n\t\t\treturn value.ToString();\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QTable.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.ComponentModel;\nusing System.Text.RegularExpressions;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents query table information\n\t/// </summary>\n\t//[Serializable]\n\tpublic class QTable\n\t{\n\n\t\t/// <summary>\n\t\t/// Get source name (string identifier)\n\t\t/// </summary>\n\t\tpublic string Name { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Get source name alias used in query nodes\n\t\t/// </summary>\n\t\tpublic string Alias { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QSource with the specified source name\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">source name string</param>\n\t\tpublic QTable(string tableName) {\n\t\t\tint dotIdx = tableName.LastIndexOf('.'); // allow dot in table name (alias for this case is required), like dbo.users.u\n\t\t\tif (dotIdx >= 0) {\n\t\t\t\tName = tableName.Substring(0, dotIdx);\n\t\t\t\tAlias = tableName.Substring(dotIdx+1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tName = tableName;\n\t\t\t\tAlias = null;\n\t\t\t}\n\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QSource with the specified source name and alias\n\t\t/// </summary>\n\t\t/// <param name=\"tableName\">source name string</param>\n\t\t/// <param name=\"alias\">alias string</param>\n\t\tpublic QTable(string tableName, string alias) {\n\t\t\tName = tableName;\n\t\t\tAlias = alias;\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Returns a string representation of this QSource\n\t\t/// </summary>\n\t\t/// <returns>string that represents QSource in [name].[alias] format</returns>\n\t\tpublic override string ToString() {\n\t\t\treturn String.IsNullOrEmpty(Alias) ? Name : Name+\".\"+Alias;\n\t\t}\n\n\t\tpublic static implicit operator QTable(string value) {\n\t\t\treturn new QTable(value);\n\t\t}\n\t\tpublic static implicit operator string(QTable value) {\n\t\t\treturn value.ToString();\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/QVar.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Represents query variable\n\t/// </summary>\n\t/// <remarks>All query variables should be set before processing the query. \n\t/// Accessing undefined variable will cause InvalidOperationException.</remarks>\n\t//[Serializable]\n\tpublic class QVar : QConst, IQueryValue {\n\n\t\t/// <summary>\n\t\t/// Get variable name\n\t\t/// </summary>\n\t\tpublic string Name {\n\t\t\tget; private set;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Get actual value represented by this variable\n\t\t/// </summary>\n\t\tpublic override object Value {\n\t\t\tget {\n\t\t\t\tif (!_isDefined)\n\t\t\t\t\tthrow new InvalidOperationException(String.Format(\"Query variable '{0}' is not defined\", Name));\n\t\t\t\treturn _VarValue; \n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Get format for variable value (null if formatting is not needed)\n\t\t/// </summary>\n\t\tpublic string Format { get; private set; }\n\n\t\tprivate object _VarValue;\n\t\tprivate bool _isDefined = false;\n\n\t\t/// <summary>\n\t\t/// Determines whether this variable is set (defined).\n\t\t/// </summary>\n\t\tpublic bool HasValue {\n\t\t\tget { return _isDefined;  }\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QVar with specified variable name\n\t\t/// </summary>\n\t\t/// <param name=\"varName\">variable name</param>\n\t\tpublic QVar(string varName) : base(null) {\n\t\t\tvar formatIdx = varName.IndexOf(':');\n\t\t\tif (formatIdx >= 0) {\n\t\t\t\tName = varName.Substring(0, formatIdx);\n\t\t\t\tFormat = varName.Substring(formatIdx+1);\n\t\t\t\tif (Format.Length==0)\n\t\t\t\t\tthrow new ArgumentException(\"Format cannot be empty\");\n\t\t\t} else { \n\t\t\t\tName = varName;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the QVar with specified variable name and format\n\t\t/// </summary>\n\t\t/// <param name=\"varName\">variable name</param>\n\t\t/// <param name=\"format\">the string format applied on setting of the variable</param>\n\t\tpublic QVar(string varName, string format) : base(null) {\n\t\t\tName = varName;\n\t\t\tFormat = format;\n\t\t}\n\n\n\t\t/// <summary>\n\t\t/// Assigns a value for this variable\n\t\t/// </summary>\n\t\t/// <remarks>Assigned QVar can be used as QConst</remarks>\n\t\t/// <param name=\"varValue\">variable value</param>\n\t\tpublic QVar Set(object varValue) {\n\t\t\tif (Format != null) {\n\t\t\t\t_VarValue = String.Format(Format, varValue);\n\t\t\t} else { \n\t\t\t\t_VarValue = varValue;\n\t\t\t}\n\t\t\t_isDefined = true;\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Makes this variable undefined. \n\t\t/// </summary>\n\t\tpublic void Unset() {\n\t\t\t_isDefined = false;\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Query/Query.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\n\n#if !NET_STANDARD\nusing System.Runtime.Serialization;\n#endif\n\nnamespace NReco.Data\n{\n\n\t/// <summary>\n\t/// Represents abstract data query structure.\n\t/// </summary>\n\t//[Serializable]\n\tpublic class Query : QNode, IQueryValue\n\t{\n\t\tprivate QSort[] _Sort = null;\n\t\tprivate QField[] _Fields = null;\n\t\tprivate int _RecordOffset = 0;\n\t\tprivate int _RecordCount = Int32.MaxValue;\n\t\tprivate QTable _Table = null;\n\t\t\n\t\t/// <summary>\n\t\t/// Query conditions tree. Can be null.\n\t\t/// </summary>\n\t\tpublic QNode Condition { get; set; }\n\n\t\t/// <summary>\n\t\t/// List of child nodes\n\t\t/// </summary>\n\t\tpublic override IList<QNode> Nodes {\n\t\t\tget { return new QNode[] { Condition }; }\n\t\t}\n\n\t\t/// <summary>\n\t\t/// List of sort fields. Can be null.\n\t\t/// </summary>\n\t\tpublic QSort[] Sort {\n\t\t\tget { return _Sort; } \n\t\t\tset { _Sort = value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// List of fields to load. Null means all available fields.\n\t\t/// </summary>\n\t\tpublic QField[] Fields {\n\t\t\tget { return _Fields; }\n\t\t\tset { _Fields = value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Get or set starting record to load\n\t\t/// </summary>\n\t\tpublic int RecordOffset {\n\t\t\tget { return _RecordOffset; }\n\t\t\tset { _RecordOffset = value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Get or set max records count to load\n\t\t/// </summary>\n\t\tpublic int RecordCount {\n\t\t\tget { return _RecordCount; }\n\t\t\tset { _RecordCount = value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Get or set target source name of this query\n\t\t/// </summary>\n\t\tpublic QTable Table { \n\t\t\tget { return _Table; }\n\t\t\tset { _Table = value; }\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Get or set query extended properties. \n\t\t/// </summary>\n\t\t/// <remarks>Extended properties may be used for passing custom query parameters.</remarks>\n\t\tpublic IDictionary<string,object> ExtendedProperties { get; set; }\n\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the Query with specified table\n\t\t/// </summary>\n\t\t/// <param name=\"table\">target table</param>\n\t\tpublic Query(QTable table) {\n\t\t\t_Table = table;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the Query with specified table and condition\n\t\t/// </summary>\n\t\t/// <param name=\"table\">target table</param>\n\t\t/// <param name=\"condition\">conditions root node</param>\n\t\tpublic Query(QTable table, QNode condition) {\n\t\t\t_Table = table;\n\t\t\tCondition = condition;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the Query with identical options of specified query\n\t\t/// </summary>\n\t\t/// <param name=\"q\">query with options to copy</param>\n\t\tpublic Query(Query q) {\n\t\t\t_Table = q.Table;\n\t\t\t_Sort = q.Sort;\n\t\t\t_RecordOffset = q.RecordOffset;\n\t\t\t_RecordCount = q.RecordCount;\n\t\t\tCondition = q.Condition;\n\t\t\t_Fields = q.Fields;\n\t\t\tif (q.ExtendedProperties!=null)\n\t\t\t\tExtendedProperties = new Dictionary<string,object>( q.ExtendedProperties );\n\t\t}\n\t\t\n\t\t/// <summary>\n\t\t/// Set query sort by specified list of QSort\n\t\t/// </summary>\n\t\t/// <param name=\"sortFields\"></param>\n\t\tpublic Query OrderBy(params QSort[] sortFields) {\n\t\t\tif (sortFields != null && sortFields.Length > 0) {\n\t\t\t\t_Sort = sortFields;\n\t\t\t} else {\n\t\t\t\t_Sort = null;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Set query fields by specified list of field names\n\t\t/// </summary>\n\t\t/// <param name=\"fields\">list of field names</param>\n\t\tpublic Query Select(params QField[] fields) {\n\t\t\tif (fields != null && fields.Length > 0) {\n\t\t\t\t_Fields = fields;\n\t\t\t} else {\n\t\t\t\t_Fields = null;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Finds all QVar constants (\"name\":var in relex) and passes them to specified set handler.\n\t\t/// </summary>\n\t\t/// <param name=\"setVar\">handler for <see cref=\"QVar\"/> constants.</param>\n\t\t/// <example>\n\t\t/// The following code unsets all query variables:\n\t\t/// <code>\n\t\t/// </code>\n\t\t/// </example>\n\t\tpublic void SetVars(Action<QVar> setVar) {\n\t\t\tSetVarsInternal(Condition, setVar);\n\t\t}\n\n\t\tprivate void SetVarsInternal(QNode node, Action<QVar> setVar) {\n\t\t\tif (node is QConditionNode) {\n\t\t\t\tvar cndNode = (QConditionNode)node;\n\t\t\t\tif (cndNode.LValue is QVar)\n\t\t\t\t\tsetVar( (QVar) cndNode.LValue);\n\t\t\t\tif (cndNode.RValue is QVar)\n\t\t\t\t\tsetVar( (QVar) cndNode.RValue);\n\t\t\t}\n\t\t\tif (node != null)\n\t\t\t\tforeach (var cNode in node.Nodes)\n\t\t\t\t\tSetVarsInternal(cNode, setVar);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a string that represents current query in relex format\n\t\t/// </summary>\n\t\t/// <returns>relex string</returns>\n\t\tpublic override string ToString() {\n\t\t\treturn (new NReco.Data.Relex.RelexBuilder()).BuildRelex(this);\n\t\t}\n\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/RecordSet.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Data;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// Represents a set of in-memory data records with the same schema.\n\t/// </summary>\n\tpublic sealed class RecordSet : ICollection<RecordSet.Row> {\n\t\t\n\t\t/// <summary>\n\t\t/// Gets the columns of this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic ColumnCollection Columns { \n\t\t\tget {\n\t\t\t\treturn columns;\n\t\t\t}\n\t\t}\n\t\tColumnCollection columns = null;\n\t\t\n\t\t\n\t\t/// <summary>\n\t\t/// Gets or sets an array of columns that function as primary keys for this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic Column[] PrimaryKey { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets the total number of <see cref=\"RecordSet.Rows\"/> in this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic int Count {\n\t\t\tget { return Rows.Count; }\n\t\t}\n\n\t\tList<Row> Rows;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of <see cref=\"RecordSet\"/> with specified list of <see cref=\"RecordSet.Column\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"columns\">columns array</param>\n\t\tpublic RecordSet(Column[] columns) : this(columns, 1) {\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of <see cref=\"RecordSet\"/> with specified list of <see cref=\"RecordSet.Column\"/> and capacity.\n\t\t/// </summary>\n\t\t/// <param name=\"columns\">columns array</param>\n\t\t/// <param name=\"rowsCapacity\">initial rows list capacity</param>\n\t\tpublic RecordSet(Column[] columns, int rowsCapacity) {\n\t\t\tRows = new List<Row>(rowsCapacity);\n\t\t\tthis.columns = new ColumnCollection(columns);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a new row.\n\t\t/// </summary>\n\t\t/// <returns>new row instance</returns>\n\t\tpublic Row Add() {\n\t\t\treturn Add( (object[])null);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a row using specified values and adds it to the <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"values\">The array of values that are used to create the new row.</param>\n\t\t/// <returns>new row instance</returns>\n\t\tpublic Row Add(object[] values) {\n\t\t\tif (values==null)\n\t\t\t\tvalues = new object[columns.Columns.Length];\n\t\t\tif (values.Length!=columns.Columns.Length)\n\t\t\t\tthrow new ArgumentException(\"Values array does not match number of columns in the RecordSet.\");\n\t\t\tvar r = new Row(this,values);\n\t\t\tRows.Add(r);\n\t\t\treturn r;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a row using specified column -> value dictionary and adds it to the <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"values\">Dictionary with column -> value pairs.</param>\n\t\t/// <returns>new row instance</returns>\n\t\tpublic Row Add(IDictionary<string,object> values) {\n\t\t\tvar r = new Row(this, new object[columns.Columns.Length]);\n\t\t\tobject v;\n\t\t\tfor (int i=0; i<columns.Columns.Length; i++) {\n\t\t\t\tif (values.TryGetValue(columns.Columns[i].Name, out v)) {\n\t\t\t\t\tr[i] = v;\n\t\t\t\t}\n\t\t\t}\n\t\t\tRows.Add(r);\n\t\t\treturn r;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Commits all the changes made to this <see cref=\"RecordSet\"/> since the last time <see cref=\"AcceptChanges\"/> was called.\n\t\t/// </summary>\n\t\tpublic void AcceptChanges() {\n\t\t\tRows.RemoveAll( (r) => {\n\t\t\t\tvar del = (r.State&RowState.Deleted)==RowState.Deleted;\n\t\t\t\tif (del) {\n\t\t\t\t\tr.Detach();\n\t\t\t\t}\n\t\t\t\treturn r.State==RowState.Detached;\n\t\t\t} );\n\t\t\tforeach (var r in Rows)\n\t\t\t\tr.AcceptChanges();\n\t\t}\n\n\t\tpublic void SetPrimaryKey(params string[] columnNames) {\n\t\t\tvar pkCols = new Column[columnNames.Length];\n\t\t\tfor (int i=0; i<columnNames.Length; i++) {\n\t\t\t\tpkCols[i] = Columns[columnNames[i]];\n\t\t\t}\n\t\t\tPrimaryKey = pkCols;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Clears the collection of all rows.\n\t\t/// </summary>\n\t\tpublic void Clear() {\n\t\t\tforeach (var r in Rows)\n\t\t\t\tr.Detach();\n\t\t\tRows.Clear();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines whether the specified row is present in this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"row\"></param>\n\t\t/// <returns></returns>\n\t\tpublic bool Contains(Row row) {\n\t\t\treturn Rows.Contains(row);\n\t\t}\n\n\t\tbool ICollection<Row>.IsReadOnly {\n\t\t\tget { return false; }\n\t\t}\n\n\t\tvoid ICollection<Row>.Add(Row r) {\n\t\t\tthrow new NotSupportedException();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the row at the specified index.\n\t\t/// </summary>\n\t\t/// <param name=\"rowIndex\">The zero-based index of the row to return.</param>\n\t\tpublic Row this[int rowIndex] {\n\t\t\tget { return Rows[rowIndex]; }\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Removes the row from this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"r\">row to remove</param>\n\t\t/// <returns>true if row was successfully removed from the <see cref=\"RecordSet\"/>; otherwise, false.</returns>\n\t\tpublic bool Remove(Row r) {\n\t\t\tif (Rows.Remove(r)) {\n\t\t\t\tr.Detach();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tvoid ICollection<Row>.CopyTo(Row[] array, int arrayIndex) {\n\t\t\tRows.CopyTo(array, arrayIndex);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through the rows in this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic IEnumerator<Row> GetEnumerator() {\n\t\t\treturn Rows.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through the rows in this <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tIEnumerator IEnumerable.GetEnumerator() {\n\t\t\treturn Rows.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Fills a <see cref=\"RecordSet\"/> with values from a data source using the supplied <see cref=\"IDataReader\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"rdr\">An <see cref=\"IDataReader\"/> that provides a result set.</param>\n\t\t/// <returns>Number of loaded rows.</returns>\n\t\tpublic int Load(IDataReader rdr) {\n\t\t\tint processed = 0;\n\t\t\twhile (rdr.Read()) {\n\t\t\t\tTuple<int,int>[] rdrToRsColIdx = null;\n\t\t\t\tif (rdrToRsColIdx==null) {\n\t\t\t\t\tvar rdrToRsColIdxList = new List<Tuple<int, int>>();\n\t\t\t\t\tfor (int i=0; i<rdr.FieldCount; i++) {\n\t\t\t\t\t\tvar colName = rdr.GetName(i);\n\t\t\t\t\t\tif (this.Columns.Contains(colName))\n\t\t\t\t\t\t\trdrToRsColIdxList.Add( new Tuple<int, int>(i, this.Columns.GetOrdinal(colName) ) );\n\t\t\t\t\t}\n\t\t\t\t\trdrToRsColIdx = rdrToRsColIdxList.ToArray();\n\t\t\t\t}\n\n\t\t\t\tprocessed++;\n\n\t\t\t\tvar r = this.Add();\n\t\t\t\tfor (int i=0; i<rdrToRsColIdx.Length; i++) {\n\t\t\t\t\tvar t = rdrToRsColIdx[i];\n\t\t\t\t\tr[ t.Item2 ] = rdr.GetValue(t.Item1);\n\t\t\t\t}\n\t\t\t\tr.AcceptChanges();\n\n\t\t\t}\n\t\t\treturn processed;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"RecordSet\"/> and reads all rows from the supplied <see cref=\"IDataReader\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"rdr\">An <see cref=\"IDataReader\"/> that provides a result set.</param>\n\t\t/// <returns><see cref=\"RecordSet\"/> with schema inferred by reader and populated with incoming data.</returns>\n\t\tpublic static RecordSet FromReader(IDataReader rdr) {\n\t\t\treturn FromReader(rdr, -1);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"RecordSet\"/> and reads all rows from the supplied <see cref=\"IDataReader\"/>.\n\t\t/// </summary>\n\t\t/// <param name=\"rdr\">An <see cref=\"IDataReader\"/> that provides a result set.</param>\n\t\t/// <param name=\"rowsCount\">Max number of rows to load (-1 means no limit).</param> \n\t\t/// <returns><see cref=\"RecordSet\"/> with schema inferred by reader and populated with incoming data.</returns>\n\t\tpublic static RecordSet FromReader(IDataReader rdr, int rowsCount) {\n\t\t\tRecordSet rs = DataHelper.GetRecordSetByReader(rdr);\n\t\t\tint read = 0;\n\t\t\tbool loadAll = rowsCount<0;\n\t\t\twhile ( (loadAll || read<rowsCount) && rdr.Read()) {\n\t\t\t\t// just copy values\n\t\t\t\tvar rowValues = new object[rdr.FieldCount];\n\t\t\t\trdr.GetValues(rowValues);\n\t\t\t\trs.Add(rowValues).AcceptChanges();\n\t\t\t\tread++;\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates an empty <see cref=\"RecordSet\"/> with schema inferred from the annotated object model.\n\t\t/// </summary>\n\t\t/// <typeparam name=\"T\">annotated model type</typeparam>\n\t\t/// <returns>empty <see cref=\"RecordSet\"/></returns>\n\t\tpublic static RecordSet FromModel<T>() {\n\t\t\treturn RecordSet.FromModel<T>(null, RowState.Added);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"RecordSet\"/> with schema and row inferred from the annotated object model.\n\t\t/// </summary>\n\t\t/// <typeparam name=\"T\">annotated model type</typeparam>\n\t\t/// <param name=\"model\">model instance</param>\n\t\t/// <param name=\"rowState\">intial state of row created by model</param>\n\t\t/// <returns><see cref=\"RecordSet\"/> with one row</returns>\n\t\tpublic static RecordSet FromModel<T>(T model, RowState rowState) {\n\t\t\treturn RecordSet.FromModel<T>(new[] {model}, rowState);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a <see cref=\"RecordSet\"/> with schema and rows inferred from the annotated object models.\n\t\t/// </summary>\n\t\t/// <typeparam name=\"T\">annotated model type</typeparam>\n\t\t/// <param name=\"models\">sequence of models</param>\n\t\t/// <param name=\"rowState\">intial state of rows created by models</param>\n\t\t/// <returns><see cref=\"RecordSet\"/> with rows</returns>\n\t\tpublic static RecordSet FromModel<T>(IEnumerable<T> models, RowState rowState) {\n\t\t\tvar schema = DataMapper.Instance.GetSchema(typeof(T));\n\t\t\tif (schema.Columns.Length==0)\n\t\t\t\tthrow new ArgumentException($\"Model of type {typeof(T).Name} has no columns\");\n\t\t\tvar rsCols = new Column[schema.Columns.Length];\n\t\t\tvar pkCols = new List<Column>(schema.Key.Length);\n\t\t\tfor (int i=0; i<rsCols.Length; i++) {\n\t\t\t\tvar modelCol = schema.Columns[i];\n\t\t\t\trsCols[i] = new Column(modelCol.ColumnName, modelCol.ValueType) {\n\t\t\t\t\tAutoIncrement = modelCol.IsIdentity,\n\t\t\t\t\tReadOnly = modelCol.IsReadOnly\n\t\t\t\t};\n\t\t\t\tif (modelCol.IsKey)\n\t\t\t\t\tpkCols.Add(rsCols[i]);\n\t\t\t}\n\t\t\tvar rs = new RecordSet(rsCols);\n\t\t\trs.PrimaryKey = pkCols.ToArray();\n\t\t\tif (models!=null) {\n\t\t\t\tforeach (var dto in models) {\n\t\t\t\t\tvar rowData = new object[schema.Columns.Length];\n\t\t\t\t\tfor (int i=0; i<schema.Columns.Length; i++) {\n\t\t\t\t\t\tvar modelCol = schema.Columns[i];\n\t\t\t\t\t\tif (modelCol.GetVal!=null)\n\t\t\t\t\t\t\trowData[i] = modelCol.GetVal(dto);\n\t\t\t\t\t}\n\t\t\t\t\trs.Add(rowData).rowState = rowState;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously creates a <see cref=\"RecordSet\"/> from a data source using the supplied <see cref=\"IDataReader\"/>.\n\t\t/// </summary>\n\t\tpublic static Task<RecordSet> FromReaderAsync(IDataReader rdr) {\n\t\t\treturn FromReaderAsync(rdr, CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously creates a <see cref=\"RecordSet\"/> from a data source using the supplied <see cref=\"IDataReader\"/>.\n\t\t/// </summary>\n\t\tpublic static async Task<RecordSet> FromReaderAsync(IDataReader rdr, CancellationToken cancel) {\n\t\t\tRecordSet rs = null;\n\t\t\twhile (await rdr.ReadAsync(cancel).ConfigureAwait(false)) {\n\t\t\t\tif (rs==null) {\n\t\t\t\t\trs = DataHelper.GetRecordSetByReader(rdr);\n\t\t\t\t}\n\t\t\t\t// just copy values\n\t\t\t\tvar rowValues = new object[rdr.FieldCount];\n\t\t\t\tawait rdr.GetValuesAsync(rowValues, cancel).ConfigureAwait(false);\n\t\t\t\trs.Add(rowValues).AcceptChanges();\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Represents the schema of a column in a <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic sealed class Column {\n\n\t\t\tbool _AutoIncrement = false;\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets the name of the column.\n\t\t\t/// </summary>\n\t\t\tpublic string Name { get; private set; }\t\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets the type of data stored in the column.\n\t\t\t/// </summary>\n\t\t\tpublic Type DataType { get; set; }\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets a value that indicates whether null values are allowed in this column.\n\t\t\t/// </summary>\n\t\t\tpublic bool AllowDBNull { get; set; } = true;\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets a value that indicates whether the column automatically increments the value of the column for new rows.\n\t\t\t/// </summary>\n\t\t\tpublic bool AutoIncrement { \n\t\t\t\tget { return _AutoIncrement; } \n\t\t\t\tset { _AutoIncrement = value; if (value) ReadOnly = true; } \n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets a value that indicates whether the column allows for changes when committed to data source.\n\t\t\t/// </summary>\n\t\t\tpublic bool ReadOnly { get; set; } = false;\n\n\t\t\tpublic Column(string name) {\n\t\t\t\tName = name;\n\t\t\t}\n\n\t\t\tpublic Column(string name, Type dataType) {\n\t\t\t\tName = name;\n\t\t\t\tDataType = dataType;\n\t\t\t}\n\n\t\t\t#if NET_STANDARD\n\t\t\tinternal Column(System.Data.Common.DbColumn dbCol) {\n\t\t\t\tName = dbCol.ColumnName;\n\t\t\t\tDataType = dbCol.DataType;\n\t\t\t\tAllowDBNull = dbCol.AllowDBNull.HasValue ? dbCol.AllowDBNull.Value : true;\n\t\t\t\tReadOnly = dbCol.IsReadOnly.HasValue ? dbCol.IsReadOnly.Value : false;\n\t\t\t\tAutoIncrement = dbCol.IsAutoIncrement.HasValue ? dbCol.IsAutoIncrement.Value : false;\n\t\t\t}\n\t\t\t#endif\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Represents a row of data in a <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic sealed class Row {\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Gets the current state of the row with regard to its relationship to the <see cref=\"RecordSet\"/>.\n\t\t\t/// </summary>\n\t\t\tpublic RowState State { \n\t\t\t\tget {\n\t\t\t\t\treturn rowState;\n\t\t\t\t}\n\t\t\t}\n\t\t\tinternal RowState rowState;\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Gets the <see cref=\"RecordSet\"/> that contains this row.\n\t\t\t/// </summary>\n\t\t\tpublic RecordSet RecordSet {\n\t\t\t\tget { return rs;  }\n\t\t\t}\n\n\t\t\tRecordSet rs;\n\t\t\tobject[] values;\n\n\t\t\tinternal Row(RecordSet rs, object[] values) {\n\t\t\t\tthis.rs = rs;\n\t\t\t\tthis.values = values;\n\t\t\t\trowState = RowState.Added;\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets all the values for this row through an array.\n\t\t\t/// </summary>\n\t\t\tpublic object[] ItemArray {\n\t\t\t\tget { return values; }\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Deletes the <see cref=\"RecordSet.Row\"/>.\n\t\t\t/// </summary>\n\t\t\t/// <remarks>\n\t\t\t/// If the <see cref=\"State\"/> of the row is Added, the <see cref=\"State\"/> becomes Detached and the row is removed from the table when you call <see cref=\"RecordSet.AcceptChanges\"/>.\n\t\t\t/// The <see cref=\"State\"/> becomes Deleted after you use the <see cref=\"Delete\"/> method on an existing <see cref=\"Row\"/>. \n\t\t\t/// It remains Deleted until you call <see cref=\"RecordSet.AcceptChanges\"/>.\n\t\t\t/// </remarks>\n\t\t\tpublic void Delete() {\n\t\t\t\tif ((rowState&RowState.Added)==RowState.Added) {\n\t\t\t\t\tDetach();\n\t\t\t\t} else {\n\t\t\t\t\trowState = RowState.Deleted;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Commits all the changes made to this row since the last time AcceptChanges was called.\n\t\t\t/// </summary>\n\t\t\t/// <remarks>\n\t\t\t/// If the <see cref=\"State\"/> of the row was Added or Modified, the  <see cref=\"State\"/> becomes Unchanged. \n\t\t\t/// If the <see cref=\"State\"/> was Deleted, the row is removed (<see cref=\"State\"/> becomes Detached).\n\t\t\t/// </remarks>\n\t\t\tpublic void AcceptChanges() {\n\t\t\t\tif ((rowState&RowState.Deleted)==RowState.Deleted) {\n\t\t\t\t\tDetach();\n\t\t\t\t} else if (rowState!=RowState.Detached) { \n\t\t\t\t\trowState = RowState.Unchanged;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal void Detach() {\n\t\t\t\trs = null;\n\t\t\t\trowState = RowState.Detached;\n\t\t\t}\n\n\t\t\tvoid CheckIfDetached() {\n\t\t\t\tif (rowState==RowState.Detached)\n\t\t\t\t\tthrow new InvalidOperationException();\n\t\t\t}\n\n\t\t\tobject GetValue(int columnIndex) {\n\t\t\t\treturn values[columnIndex];\n\t\t\t}\n\t\t\tvoid SetValue(int columnIndex, object val) {\n\t\t\t\tvalues[columnIndex] = val;\n\t\t\t\trowState |= RowState.Modified;\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets the data stored in the column specified by index.\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"columnIndex\">column index</param>\n\t\t\t/// <returns>An object that contains column value for this row.</returns>\n\t\t\tpublic object this[int columnIndex] {\n\t\t\t\tget {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\treturn GetValue(columnIndex);\n\t\t\t\t}\n\t\t\t\tset {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\tSetValue(columnIndex, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets the data stored in the specified <see cref=\"RecordSet.Column\"/>.\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"column\">data column</param>\n\t\t\t/// <returns>An object that contains column value for this row.</returns>\n\t\t\tpublic object this[Column column] {\n\t\t\t\tget {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\treturn GetValue(rs.columns.GetOrdinal(column));\n\t\t\t\t}\n\t\t\t\tset {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\tSetValue(rs.columns.GetOrdinal(column), value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets or sets the data stored in the column specified by name.\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"columnName\">The name of the column.</param>\n\t\t\t/// <returns>An object that contains column value for this row.</returns>\n\t\t\tpublic object this[string columnName] {\n\t\t\t\tget {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\treturn GetValue(rs.columns.GetOrdinal(columnName));\n\t\t\t\t}\n\t\t\t\tset {\n\t\t\t\t\tCheckIfDetached();\n\t\t\t\t\tSetValue(rs.columns.GetOrdinal(columnName), value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Provides strongly-typed access to each of the column values in the specified row. The Field<T> method also supports nullable types. \n\t\t\t/// </summary>\n\t\t\t/// <typeparam name=\"T\">A generic parameter that specifies the return type of the column.</typeparam>\n\t\t\t/// <param name=\"columnName\">The name of the column to return the value of.</param>\n\t\t\t/// <returns>The value, of type T. If value is null or DBNull, default(T) is returned.</returns>\n\t\t\tpublic T Field<T>(string columnName) {\n\t\t\t\tvar v = this[columnName];\n\t\t\t\tvar typeCode = Type.GetTypeCode(typeof(T));\n\t\t\t\tif (v!=null && !DBNull.Value.Equals(v)) {\n\t\t\t\t\treturn (T)Convert.ChangeType( v, typeCode, System.Globalization.CultureInfo.InvariantCulture );\n\t\t\t\t}\n\t\t\t\treturn default(T);\n\t\t\t}\n\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets the state of a <see cref=\"RecordSet.Row\"/> object.\n\t\t/// </summary>\n\t\t[Flags]\n\t\tpublic enum RowState {\n\t\t\tDetached = 1,\n\t\t\tUnchanged = 2,\n\t\t\tAdded = 4,\n\t\t\tDeleted = 8,\n\t\t\tModified = 16\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Represents a collection of <see cref=\"RecordSet.Column\"/> objects for a <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic sealed class ColumnCollection : \n\t\t\t#if NET_STANDARD\n\t\t\tIReadOnlyList<Column>\n\t\t\t#else \n\t\t\tICollection<Column>\n\t\t\t#endif\n\t\t{\n\t\t\t\n\t\t\tinternal Column[] Columns;\n\t\t\tDictionary<Column,int> ColToIdx;\n\t\t\tDictionary<string,int> ColNameToIdx;\n\n\t\t\tinternal ColumnCollection(Column[] columns) {\n\t\t\t\tColumns = columns;\n\t\t\t\tColToIdx = new Dictionary<Column, int>(columns.Length);\n\t\t\t\tColNameToIdx = new Dictionary<string, int>(columns.Length);\n\t\t\t\tfor (int i=0; i<columns.Length; i++) {\n\t\t\t\t\tColToIdx[columns[i]] = i;\n\t\t\t\t\tColNameToIdx[columns[i].Name] = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinternal int GetOrdinal(Column c) {\n\t\t\t\tint idx;\n\t\t\t\tif (ColToIdx.TryGetValue(c, out idx))\n\t\t\t\t\treturn idx;\n\t\t\t\tthrow new ArgumentException(\"Column with name '\"+c.Name+\"' does not exist.\");\n\t\t\t}\n\n\t\t\tpublic int GetOrdinal(string columnName) {\n\t\t\t\tint idx;\n\t\t\t\tif (ColNameToIdx.TryGetValue(columnName, out idx))\n\t\t\t\t\treturn idx;\n\t\t\t\tthrow new ArgumentException(\"Column with name '\"+columnName+\"' does not exist.\");\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets the total number of elements in a collection.\n\t\t\t/// </summary>\n\t\t\tpublic int Count {\n\t\t\t\tget {\n\t\t\t\t\treturn Columns.Length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets the <see cref=\"RecordSet.Column\"/> from the collection at the specified index.\n\t\t\t/// </summary>\n\t\t\tpublic Column this[int ordinal] {\n\t\t\t\tget {\n\t\t\t\t\treturn Columns[ordinal];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Gets the <see cref=\"RecordSet.Column\"/> from the collection with the specified name.\n\t\t\t/// </summary>\n\t\t\tpublic Column this[string columnName] {\n\t\t\t\tget {\n\t\t\t\t\treturn Columns[GetOrdinal(columnName)];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// <summary>\n\t\t\t/// Checks whether the collection contains a column with the specified name.\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"columnName\">the name of the column.</param>\n\t\t\t/// <returns>true if a column exists with this name; otherwise, false.</returns>\n\t\t\tpublic bool Contains(string columnName) {\n\t\t\t\treturn ColNameToIdx.ContainsKey(columnName);\n\t\t\t}\n\n\t\t\tpublic IEnumerator<Column> GetEnumerator() {\n\t\t\t\treturn ((IEnumerable<Column>)Columns).GetEnumerator();\n\t\t\t}\n\n\t\t\tIEnumerator IEnumerable.GetEnumerator() {\n\t\t\t\treturn Columns.GetEnumerator();\n\t\t\t}\n\n\t\t\t#if !NET_STANDARD\n\t\t\tbool ICollection<Column>.IsReadOnly {\n\t\t\t\tget {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid ICollection<Column>.Add(Column item) {\n\t\t\t\tthrow new NotSupportedException(\"ColumnCollection is readonly\");\n\t\t\t}\n\n\t\t\tvoid ICollection<Column>.Clear() {\n\t\t\t\tthrow new NotSupportedException(\"ColumnCollection is readonly\");\n\t\t\t}\n\n\t\t\tbool ICollection<Column>.Contains(Column item) {\n\t\t\t\tthrow new NotImplementedException();\n\t\t\t}\n\n\t\t\tvoid ICollection<Column>.CopyTo(Column[] array, int arrayIndex) {\n\t\t\t\tthrow new NotImplementedException();\n\t\t\t}\n\n\t\t\tbool ICollection<Column>.Remove(Column item) {\n\t\t\t\tthrow new NotSupportedException(\"ColumnCollection is readonly\");\n\t\t\t}\n\t\t\t#endif\n\n\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/RecordSetReader.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Data.Common;\nusing System.Linq;\nusing System.Text;\nusing System.Data;\n\nnamespace NReco.Data {\n\t\n\t/// <summary>\n\t/// The <see cref=\"RecordSetReader\"/> obtains the contents of one <see cref=\"RecordSet\"/> as form of read-only, forward-only result set. \n\t/// </summary>\n\tpublic class RecordSetReader : DbDataReader {\n\n\t\tRecordSet RS;\n\t\tbool isOpen = true;\n\t\tRecordSet.Row currentRow = null;\n\t\tint currentRowIdx = -1;\n\t\tbool EOR = false;\n\n\t\tpublic RecordSetReader(RecordSet rs) {\n\t\t\tRS = rs;\n\t\t}\n\n\t\tvoid EnsureOpen() {\n\t\t\tif (!isOpen)\n\t\t\t\tthrow new InvalidOperationException(\"Data reader is closed.\");\n\t\t}\n\n\t\tvoid EnsureRow() {\n\t\t\tEnsureOpen();\n\t\t\tif (currentRow==null) {\n\t\t\t\tthrow new InvalidOperationException(\"Invalid data reader.\");\n\t\t\t}\n\t\t}\n\n\t\tpublic override object this[string name] {\n\t\t\tget {\n\t\t\t\tEnsureRow();\n\t\t\t\treturn currentRow[name];\n\t\t\t}\n\t\t}\n\n\t\tpublic override object this[int ordinal] {\n\t\t\tget {\n\t\t\t\tEnsureRow();\n\t\t\t\tif (currentRow==null)\n\t\t\t\t\tthrow new InvalidOperationException(\"Invalid data reader.\");\n\t\t\t\treturn currentRow[ordinal];\n\t\t\t}\n\t\t}\n\n\t\tpublic override int Depth {\n\t\t\tget {\n\t\t\t\tEnsureOpen();\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int FieldCount {\n\t\t\tget {\n\t\t\t\tEnsureOpen();\n\t\t\t\treturn RS.Columns.Count;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HasRows {\n\t\t\tget {\n\t\t\t\tEnsureOpen();\n\t\t\t\treturn RS.Count>0;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool IsClosed {\n\t\t\tget {\n\t\t\t\treturn !isOpen;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int RecordsAffected {\n\t\t\tget {\n\t\t\t\tEnsureOpen();\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\t#if NET_STANDARD\n\t\tprotected override void Dispose(bool disposing) {\n\t\t#else\n\t\tpublic override void Close() {\n\t\t#endif\n\t\t\tif (IsClosed)\n\t\t\t\treturn;\n\t\t\tisOpen = false;\n\t\t\tRS = null;\n\t\t}\n\n\t\tpublic override bool GetBoolean(int ordinal) {\n\t\t\treturn (bool)this[ordinal];\n\t\t}\n\n\t\tpublic override byte GetByte(int ordinal) {\n\t\t\treturn (byte)this[ordinal];\n\t\t}\n\n\t\tlong GetArray<T>(int ordinal, long dataOffset, T[] buffer, int bufferOffset, int length) {\n\t\t\tvar arr = (T[])this[ordinal];\n\t\t\tvar copyCnt = Math.Min(arr.Length - (int)dataOffset, length);\n\t\t\tif (copyCnt>0) {\n\t\t\t\tArray.Copy(arr, (int)dataOffset, buffer, bufferOffset, copyCnt);\n\t\t\t}\n\t\t\treturn copyCnt;\t\t\t\n\t\t}\n\n\t\tpublic override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) {\n\t\t\treturn GetArray<byte>(ordinal, dataOffset, buffer, bufferOffset, length);\n\t\t}\n\n\t\tpublic override char GetChar(int ordinal) {\n\t\t\treturn (char)this[ordinal];\n\t\t}\n\n\t\tpublic override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) {\n\t\t\treturn GetArray<char>(ordinal, dataOffset, buffer, bufferOffset, length);\n\t\t}\n\n\t\tpublic override DateTime GetDateTime(int ordinal) {\n\t\t\treturn (DateTime)this[ordinal];\n\t\t}\n\n\t\tpublic override decimal GetDecimal(int ordinal) {\n\t\t\treturn (decimal)this[ordinal];\n\t\t}\n\n\t\tpublic override double GetDouble(int ordinal) {\n\t\t\treturn (double)this[ordinal];\n\t\t}\n\n\t\tpublic override IEnumerator GetEnumerator() {\n\t\t\tEnsureOpen();\n\t\t\treturn new DbEnumerator(this, false);\n\t\t}\n\n\t\tpublic override string GetDataTypeName(int ordinal) {\n\t\t\treturn GetFieldType(ordinal).Name;\n\t\t}\n\n\t\tpublic override Type GetFieldType(int ordinal) {\n\t\t\tEnsureOpen();\n\t\t\treturn RS.Columns[ordinal].DataType;\n\t\t}\n\n\t\tpublic override float GetFloat(int ordinal) {\n\t\t\treturn (float)this[ordinal];\n\t\t}\n\n\t\tpublic override Guid GetGuid(int ordinal) {\n\t\t\treturn (Guid)this[ordinal];\n\t\t}\n\n\t\tpublic override short GetInt16(int ordinal) {\n\t\t\treturn (short)this[ordinal];\n\t\t}\n\n\t\tpublic override int GetInt32(int ordinal) {\n\t\t\treturn (int)this[ordinal];\n\t\t}\n\n\t\tpublic override long GetInt64(int ordinal) {\n\t\t\treturn (long)this[ordinal];\n\t\t}\n\n\t\tpublic override string GetName(int ordinal) {\n\t\t\treturn RS.Columns[ordinal].Name;\n\t\t}\n\n\t\tpublic override int GetOrdinal(string name) {\n\t\t\tEnsureOpen();\n\t\t\treturn RS.Columns.GetOrdinal(name);\n\t\t}\n\n\t\tpublic override string GetString(int ordinal) {\n\t\t\treturn (string)this[ordinal];\n\t\t}\n\n\t\tpublic override object GetValue(int ordinal) {\n\t\t\treturn this[ordinal];\n\t\t}\n\n\t\tpublic override int GetValues(object[] values) {\n\t\t\tif (values==null)\n\t\t\t\tthrow new ArgumentNullException(\"values\");\n\t\t\tEnsureRow();\n\t\t\tif (values.Length<RS.Columns.Count)\n\t\t\t\tthrow new ArgumentException(\"Target values array is too small.\");\n\t\t\tcurrentRow.ItemArray.CopyTo(values, 0);\n\t\t\treturn RS.Columns.Count;\n\t\t}\n\n\t\tpublic override bool IsDBNull(int ordinal) {\n\t\t\tvar v = this[ordinal];\n\t\t\treturn v==null || DBNull.Value.Equals(v);\n\t\t}\n\n\t\tpublic override bool NextResult() {\n\t\t\t// current impl doesn't support multiple result sets\n\t\t\treturn false; \n\t\t}\n\n\t\tpublic override bool Read() {\n\t\t\tEnsureOpen();\n\t\t\tif (EOR)\n\t\t\t\treturn false;\n\t\t\tcurrentRowIdx++;\n\t\t\tif (currentRowIdx>=RS.Count) {\n\t\t\t\tEOR = true;\n\t\t\t\tcurrentRow = null;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcurrentRow = RS[currentRowIdx];\n\t\t\treturn true;\n\t\t}\n\n\t\tDataTable _SchemaTable = null;\n\n\t\tpublic override DataTable GetSchemaTable() {\n\t\t\treturn _SchemaTable ?? (_SchemaTable = BuildSchemaTable());\n\t\t}\n\n\t\tinternal DataTable BuildSchemaTable() {\n\t\t\tvar schemaTable = new DataTable(\"SchemaTable\");\n\n\t\t\tvar ColumnName = new DataColumn(SchemaTableColumn.ColumnName, typeof(string));\n\t\t\tvar ColumnOrdinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(int));\n\t\t\tvar ColumnSize = new DataColumn(SchemaTableColumn.ColumnSize, typeof(int));\n\t\t\tvar NumericPrecision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(short));\n\t\t\tvar NumericScale = new DataColumn(SchemaTableColumn.NumericScale, typeof(short));\n\n\t\t\tvar DataType = new DataColumn(SchemaTableColumn.DataType, typeof(Type));\n\t\t\tvar DataTypeName = new DataColumn(\"DataTypeName\", typeof(string));\n\n\t\t\tvar IsLong = new DataColumn(SchemaTableColumn.IsLong, typeof(bool));\n\t\t\tvar AllowDBNull = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(bool));\n\n\t\t\tvar IsUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(bool));\n\t\t\tvar IsKey = new DataColumn(SchemaTableColumn.IsKey, typeof(bool));\n\t\t\tvar IsAutoIncrement = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));\n\n\t\t\tvar BaseCatalogName = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));\n\t\t\tvar BaseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(string));\n\t\t\tvar BaseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(string));\n\t\t\tvar BaseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(string));\n\n\t\t\tvar BaseServerName = new DataColumn(SchemaTableOptionalColumn.BaseServerName, typeof(string));\n\t\t\tvar IsAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(bool));\n\t\t\tvar IsExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(bool));\n\n\t\t\tvar columns = schemaTable.Columns;\n\n\t\t\tcolumns.Add(ColumnName);\n\t\t\tcolumns.Add(ColumnOrdinal);\n\t\t\tcolumns.Add(ColumnSize);\n\t\t\tcolumns.Add(NumericPrecision);\n\t\t\tcolumns.Add(NumericScale);\n\t\t\tcolumns.Add(IsUnique);\n\t\t\tcolumns.Add(IsKey);\n\t\t\tcolumns.Add(BaseServerName);\n\t\t\tcolumns.Add(BaseCatalogName);\n\t\t\tcolumns.Add(BaseColumnName);\n\t\t\tcolumns.Add(BaseSchemaName);\n\t\t\tcolumns.Add(BaseTableName);\n\t\t\tcolumns.Add(DataType);\n\t\t\tcolumns.Add(DataTypeName);\n\t\t\tcolumns.Add(AllowDBNull);\n\t\t\tcolumns.Add(IsAliased);\n\t\t\tcolumns.Add(IsExpression);\n\t\t\tcolumns.Add(IsAutoIncrement);\n\t\t\tcolumns.Add(IsLong);\n\n\t\t\tfor (int i = 0; i < RS.Columns.Count; i++) {\n\t\t\t\tvar schemaRow = schemaTable.NewRow();\n\n\t\t\t\tschemaRow[ColumnName] = RS.Columns[i].Name;\n\t\t\t\tschemaRow[ColumnOrdinal] = i;\n\t\t\t\tschemaRow[ColumnSize] = DBNull.Value;\n\t\t\t\tschemaRow[NumericPrecision] = DBNull.Value;\n\t\t\t\tschemaRow[NumericScale] = DBNull.Value;\n\t\t\t\tschemaRow[BaseServerName] = DBNull.Value;\n\t\t\t\tschemaRow[BaseCatalogName] = DBNull.Value;\n\t\t\t\tschemaRow[BaseColumnName] = RS.Columns[i].Name;\n\t\t\t\tschemaRow[BaseSchemaName] = DBNull.Value;\n\t\t\t\tschemaRow[BaseTableName] = DBNull.Value;\n\t\t\t\tschemaRow[DataType] = RS.Columns[i].DataType;\n\t\t\t\tschemaRow[DataTypeName] = RS.Columns[i].DataType.Name;\n\t\t\t\tschemaRow[IsAliased] = false;\n\t\t\t\tschemaRow[IsExpression] = false;\n\t\t\t\tschemaRow[IsLong] = DBNull.Value;\n\n\t\t\t\tschemaRow[IsKey] = RS.PrimaryKey!=null ? Array.IndexOf( RS.PrimaryKey, RS.Columns[i])>=0 : false;\n\t\t\t\tschemaRow[AllowDBNull] = RS.Columns[i].AllowDBNull;\n\t\t\t\tschemaRow[IsAutoIncrement] = RS.Columns[i].AutoIncrement;\n\n\t\t\t\tschemaTable.Rows.Add(schemaRow);\n\t\t\t}\n\t\t\treturn schemaTable;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Relex/RelexBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Linq;\nusing System.Collections;\nusing System.Globalization;\nusing System.Text;\n\nnamespace NReco.Data.Relex {\n\t\n\t/// <summary>\n\t/// Relex expression builder by <see cref=\"Query\"/> structure. \n\t/// </summary>\n\tpublic class RelexBuilder {\n\t\t\n\t\tpublic string BuildRelex(QNode node) {\n\t\t\tInternalBuilder builder = new InternalBuilder();\n\t\t\treturn builder.BuildExpression(node);\n\t\t}\n\n        public string BuildRelex(Query node) {\n            InternalBuilder builder = new InternalBuilder();\n            return builder.BuildQueryString(node, false);\n        }\n\t\t\n\t\tclass InternalBuilder : SqlExpressionBuilder {\n\n\t\t\tpublic override string BuildExpression(QNode node) {\n\t\t\t\tif (node is Query)\n\t\t\t\t\treturn BuildQueryString((Query)node, false);\n\t\t\t\treturn base.BuildExpression(node);\n\t\t\t}\n\n\t\t\tprotected override string BuildGroup(QGroupNode node) {\n\t\t\t\tvar grp = base.BuildGroup(node);\n\t\t\t\tif (!String.IsNullOrEmpty( node.Name ) ) {\n\t\t\t\t\treturn String.Format(\"(<{0}> {1})\", node.Name, grp);\n\t\t\t\t} else return grp;\n\t\t\t}\n\n\t\t\tpublic string BuildQueryString(Query q, bool isNested) {\n\t\t\t\tstring rootExpression = BuildExpression(q.Condition);\n\t\t\t\tif (rootExpression != null && rootExpression.Length > 0)\n\t\t\t\t\trootExpression = String.Format(\"({0})\", rootExpression);\n\t\t\t\tstring fieldExpression = q.Fields != null ? \n\t\t\t\t\tString.Join(\",\", q.Fields.Select(v=>(string)v).ToArray() ) : \"*\";\n\t\t\t\tif (q.Sort != null && q.Sort.Length > 0) {\n\t\t\t\t\tfieldExpression = String.Format(\"{0};{1}\", fieldExpression, \n\t\t\t\t\t\tString.Join(\",\", q.Sort.Select(v=>(string)v).ToArray()));\n\t\t\t\t}\n\t\t\t\tstring limitExpression = isNested || (q.RecordOffset==0 && q.RecordCount==Int32.MaxValue) ? \n\t\t\t\t\tString.Empty : String.Format(\"{{{0},{1}}}\", q.RecordOffset, q.RecordCount);\n\t\t\t\tvar tblName = q.Table.ToString();\n\t\t\t\tif (!DataHelper.IsSimpleIdentifier(q.Table.Name) || !DataHelper.IsSimpleIdentifier(q.Table.Alias))\n\t\t\t\t\ttblName = BuildValue(tblName)+\":table\";\n\t\t\t\treturn String.Format(\"{0}{1}[{2}]{3}\", tblName, rootExpression,\n\t\t\t\t\tfieldExpression, limitExpression);\n\t\t\t}\n\n\t\t\tstatic readonly string[] stringConditions = new string[] {\n\t\t\t\t\t\"=\", \">\", \">=\", \"<\", \"<=\", \" in \", \" like \", \"=\"\n\t\t\t};\n\t\t\tstatic readonly Conditions[] enumConditions = new Conditions[] {\n\t\t\t\t\tConditions.Equal, Conditions.GreaterThan, \n\t\t\t\t\tConditions.GreaterThan|Conditions.Equal,\n\t\t\t\t\tConditions.LessThan, Conditions.LessThan|Conditions.Equal,\n\t\t\t\t\tConditions.In, Conditions.Like, Conditions.Null\n\t\t\t};\n\n\t\t\tprotected override string BuildCondition(QConditionNode node) {\n\t\t\t\tstring lvalue = BuildValue(node.LValue);\n\t\t\t\tstring rvalue = BuildValue(node.RValue);\n\t\t\t\tConditions condition = (node.Condition | Conditions.Not) ^ Conditions.Not;\n\t\t\t\tstring res = null;\n\t\t\t\tfor (int i=0; i<enumConditions.Length; i++)\n\t\t\t\t\tif (enumConditions[i]==condition) {\n\t\t\t\t\t\tres = stringConditions[i];\n\t\t\t\t\t\tbreak; // first match\n\t\t\t\t\t}\n\t\t\t\tif (res==null)\n\t\t\t\t\tthrow new ArgumentException(\"Invalid conditions set\", condition.ToString());\n\t\t\t\tif ((node.Condition & Conditions.Not)==Conditions.Not)\n\t\t\t\t\tres = \"!\" + res;\n\t\t\t\tif ((node.Condition & Conditions.Null) == Conditions.Null)\n\t\t\t\t\trvalue = \"null\";\n\t\t\t\tstring result = String.Format(\"{0}{1}{2}\", lvalue, res, rvalue);\n\t\t\t\tif ( !String.IsNullOrEmpty( node.Name ) )\n\t\t\t\t\tresult = String.Format(\"(<{0}> {1})\", node.Name, result);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t\n\n\t\t\tpublic override string BuildValue(IQueryValue value) {\n\t\t\t\tif (value is Query)\n\t\t\t\t\treturn BuildQueryString((Query)value, true);\n\t\t\t\tif (value is QRawSql)\n\t\t\t\t\treturn BuildValue(((QRawSql)value).SqlText) + \":sql\";\n\t\t\t\tif ( (value is QField) && !DataHelper.IsSimpleIdentifier( ((QField)value).Name ) )\n\t\t\t\t\treturn \"\\\"\"+base.BuildValue(value).Replace(\"\\\"\", \"\\\"\\\"\")+\"\\\":field\";\n\t\t\t\treturn base.BuildValue(value);\n\t\t\t}\n\n\t\t\tprotected override string BuildValue(QConst qConst) {\n\t\t\t\tif (qConst is QVar qVar && !qVar.HasValue) {\n\t\t\t\t\treturn BuildValue(qVar.Name) + \":var\";\n\t\t\t\t}\n\n\t\t\t\tobject constValue = qConst.Value;\n\t\t\t\tif (constValue == null)\n\t\t\t\t\treturn \"null\";\n\t\t\t\t\n\t\t\t\t// special processing for arrays\n\t\t\t\tif (constValue is IList)\n\t\t\t\t\treturn BuildValue((IList)constValue);\n\t\t\t\tif (constValue is string && qConst.Type==TypeCode.String)\n\t\t\t\t\treturn BuildValue((string)constValue);\n\t\t\t\t\n\t\t\t\tTypeCode constTypeCode = qConst.Type;\n\t\t\t\tstring typeSuffix = constTypeCode!=TypeCode.Empty && constTypeCode!=TypeCode.Object ? \":\"+constTypeCode.ToString() : String.Empty;\n\t\t\t\treturn BuildValue( Convert.ToString(constValue, CultureInfo.InvariantCulture ) ) + typeSuffix;\n\t\t\t}\n\n\t\t\tprotected override string BuildValue(IList list) {\n\t\t\t\tstring[] paramNames = new string[list.Count];\n\t\t\t\t// in relexes only supported arrays that can be represented as comma-delimeted string \n\t\t\t\tfor (int i = 0; i < list.Count; i++)\n\t\t\t\t\tparamNames[i] = Convert.ToString(list[i]);\n\t\t\t\treturn BuildValue( String.Join(\",\", paramNames) ) + \":string[]\"; // TODO: array type suggestion logic!\n\t\t\t}\t\t\t\n\t\t\t\n\t\t\tprotected override string BuildValue(string str) {\n\t\t\t\treturn \"\\\"\"+str.Replace(\"\\\"\", \"\\\"\\\"\")+\"\\\"\";\n\t\t\t}\n\n\t\t}\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Relex/RelexParser.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Linq;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Globalization;\n\nnamespace NReco.Data.Relex\n{\n\t\n\t/// <summary>\n\t/// Parses relex expression to <see cref=\"Query\"/> structure.\n\t/// </summary>\n\tpublic class RelexParser\n\t{\n\n\t\t/// <summary>\n\t\t/// Allows raw sql constants like \"select 1\":sql. True by default.\n\t\t/// </summary>\n\t\tpublic bool AllowRawSql { get; set; } = true;\n\n\t\tstatic readonly string[] nameGroups = new string[] { \"and\", \"or\"};\n\t\tstatic readonly string[] delimiterGroups = new string[] { \"&&\", \"||\"};\n\t\tstatic readonly QGroupType[] enumGroups = new QGroupType[] { QGroupType.And, QGroupType.Or };\n\t\t\n\t\tstatic readonly string[] delimiterConds = new string[] {\n\t\t\t\"==\", \"=\",\n\t\t\t\"<>\", \"!=\",\n\t\t\t\">\", \">=\",\n\t\t\t\"<\", \"<=\"};\n\t\tstatic readonly string[] nameConds = new string[] {\n\t\t\t\"in\", \"like\" };\n\t\t\t\n\t\tstatic readonly string nullField = \"null\";\n\t\t\n\t\tstatic readonly Conditions[] enumDelimConds = new Conditions[] {\n\t\t\tConditions.Equal, Conditions.Equal,\n\t\t\tConditions.Not|Conditions.Equal, Conditions.Not|Conditions.Equal,\n\t\t\tConditions.GreaterThan, Conditions.GreaterThan|Conditions.Equal,\n\t\t\tConditions.LessThan, Conditions.LessThan|Conditions.Equal\n\t\t};\n\n\t\tstatic readonly Conditions[] enumNameConds = new Conditions[] {\n\t\t\tConditions.In, Conditions.Like\n\t\t};\n\n\t\t\n\t\tstatic readonly char[] delimiters = new char[] {\n\t\t\t'(', ')', '[', ']', ';', ':', ',', '=', '<', '>', '!', '&', '|', '*', '{', '}'};\n\t\tstatic readonly char charQuote = '\"';\n\t\tstatic readonly char[] specialNameChars = new char[] {\n\t\t\t'.', '-', '_' };\n\t\tstatic readonly char[] arrayValuesSeparators = new char[] {\n\t\t\t'\\0', ';', ',', '\\t' }; // order is important!\n\t\t\n\t\tstatic readonly string[] typeNames;\n\t\tstatic readonly string[] arrayTypeNames;\n\n\t\t\n\t\tpublic enum LexemType {\n\t\t\tUnknown,\n\t\t\tName,\n\t\t\tDelimiter,\n\t\t\tQuotedConstant,\n\t\t\tConstant,\n\t\t\tStop\n\t\t}\n\t\t\n\t\tstatic RelexParser() {\n\t\t\ttypeNames = Enum.GetNames(typeof(TypeCode));\n\t\t\tarrayTypeNames = new string[typeNames.Length];\n\t\t\tfor (int i=0; i<typeNames.Length; i++) {\n\t\t\t\ttypeNames[i] = typeNames[i].ToLower();\n\t\t\t\tarrayTypeNames[i] = typeNames[i] + \"[]\";\n\t\t\t}\n\n\t\t}\n\t\t\n\t\tpublic RelexParser() {\n\t\t}\n\t\t\n\t\tprotected LexemType GetLexemType(string s, int startIdx, out int endIdx) {\n\t\t\tLexemType lexemType = LexemType.Unknown;\n\t\t\tendIdx = startIdx;\n\t\t\twhile (endIdx<s.Length) {\n\t\t\t\tif (Array.IndexOf(delimiters,s[endIdx])>=0) {\n\t\t\t\t\tif (lexemType==LexemType.Unknown) {\n\t\t\t\t\t\tendIdx++;\n\t\t\t\t\t\treturn LexemType.Delimiter;\n\t\t\t\t\t}\n\t\t\t\t\tif (lexemType!=LexemType.QuotedConstant)\n\t\t\t\t\t\treturn lexemType;\n\t\t\t\t} else if (Char.IsSeparator(s[endIdx])) {\n\t\t\t\t\tif (lexemType!=LexemType.QuotedConstant && lexemType!=LexemType.Unknown)\n\t\t\t\t\t\treturn lexemType; // done\n\t\t\t\t} else if (Char.IsLetter(s[endIdx])) {\n\t\t\t\t\tif (lexemType==LexemType.Unknown)\n\t\t\t\t\t\tlexemType=LexemType.Name;\n\t\t\t\t} else if (Char.IsDigit(s[endIdx])) {\n\t\t\t\t\tif (lexemType==LexemType.Unknown)\n\t\t\t\t\t\tlexemType=LexemType.Constant;\n\t\t\t\t} else if (Array.IndexOf(specialNameChars,s[endIdx])>=0) {\n\t\t\t\t\tif (lexemType==LexemType.Unknown)\n\t\t\t\t\t\tlexemType=LexemType.Constant;\n\t\t\t\t\tif (lexemType!=LexemType.Name && lexemType!=LexemType.Constant && lexemType!=LexemType.QuotedConstant)\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1}\", startIdx, s ) );\n\t\t\t\t} else if (s[endIdx]==charQuote) {\n\t\t\t\t\tif (lexemType==LexemType.Unknown)\n\t\t\t\t\t\tlexemType = LexemType.QuotedConstant;\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (lexemType==LexemType.QuotedConstant) {\n\t\t\t\t\t\t\t// check for \"\" combination\n\t\t\t\t\t\t\tif ( ( (endIdx+1)<s.Length && s[endIdx+1]!=charQuote) ) {\n\t\t\t\t\t\t\t\tendIdx++;\n\t\t\t\t\t\t\t\treturn lexemType;\n\t\t\t\t\t\t\t} else\n\t\t\t\t\t\t\t\tif ((endIdx+1)<s.Length) endIdx++; // skip next quote\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (Char.IsControl(s[endIdx]) && lexemType!=LexemType.Unknown && lexemType!=LexemType.QuotedConstant)\n\t\t\t\t\treturn lexemType;\n\t\t\t\t\n\t\t\t\t// goto next char\n\t\t\t\tendIdx++;\n\t\t\t}\n\t\t\t\n\t\t\tif (lexemType==LexemType.Unknown) return LexemType.Stop;\n\t\t\tif (lexemType==LexemType.Constant)\n\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\tString.Format(\"Unterminated constant (position: {0}, expression: {1}\", startIdx, s ) );\n\t\t\treturn lexemType;\n\t\t}\n\n\t\tprotected string GetLexem(string s, int startIdx, int endIdx, LexemType lexemType) {\n\t\t\tstring lexem = GetLexem(s, startIdx, endIdx);\n\t\t\tif (lexemType!=LexemType.QuotedConstant)\n\t\t\t\treturn lexem;\n\t\t\t// remove first and last chars\n\t\t\tstring constant = lexem.Substring(1, lexem.Length-2); \n\t\t\t// replace \"\" with \"\n\t\t\treturn constant.Replace( \"\\\"\\\"\", \"\\\"\" );\n\t\t}\n\t\t\n\t\tprotected string GetLexem(string s, int startIdx, int endIdx) {\n\t\t\treturn s.Substring(startIdx, endIdx-startIdx).Trim();\n\t\t}\n\n\t\t\n\t\tprotected void GetAllDelimiters(string s, int startIdx, out int endIdx) {\n\t\t\tendIdx = startIdx;\n\t\t\twhile ((endIdx+1)<s.Length && Array.IndexOf(delimiters, s[endIdx])>=0 )\n\t\t\t\tendIdx++;\n\t\t}\n\t\t\n\t\tprotected bool GetGroupType(LexemType lexemType, string s, int startIdx, ref int endIdx, ref QGroupType groupType) {\n\t\t\tstring lexem = GetLexem(s, startIdx, endIdx).ToLower();\n\t\t\tif (lexemType==LexemType.Name) {\n\t\t\t\tint idx = Array.IndexOf(nameGroups, lexem);\n\t\t\t\tif (idx<0) return false;\n\t\t\t\tgroupType = enumGroups[idx];\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (lexemType==LexemType.Delimiter) {\n\t\t\t\t// read all available delimiters...\n\t\t\t\tGetAllDelimiters(s, endIdx, out endIdx);\n\t\t\t\tlexem = GetLexem(s, startIdx, endIdx);\n\t\t\t\t\n\t\t\t\tint idx = Array.IndexOf(delimiterGroups, lexem);\n\t\t\t\tif (idx<0) return false;\n\t\t\t\tgroupType = enumGroups[idx];\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprotected bool GetCondition(LexemType lexemType, string s, int startIdx, ref int endIdx, ref Conditions conditions) {\n\t\t\tstring lexem = GetLexem(s, startIdx, endIdx).ToLower();\n\t\t\tif (lexemType==LexemType.Name) {\n\t\t\t\tint idx = Array.IndexOf(nameConds, lexem);\n\t\t\t\tif (idx>=0) {\n\t\t\t\t\tconditions = enumNameConds[idx];\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (lexemType==LexemType.Delimiter) {\n\t\t\t\t// read all available delimiters...\n\t\t\t\tGetAllDelimiters(s, endIdx, out endIdx);\n\t\t\t\tlexem = GetLexem(s, startIdx, endIdx);\n\n\t\t\t\tint idx = Array.IndexOf(delimiterConds, lexem);\n\t\t\t\tif (idx<0) {\n\t\t\t\t\tif (lexem==\"!\") {\n\t\t\t\t\t\tint newEndIdx;\n\t\t\t\t\t\tConditions innerConditions = Conditions.Equal;\n\t\t\t\t\t\t\n\t\t\t\t\t\tLexemType newLexemType = GetLexemType(s, endIdx, out newEndIdx);\n\t\t\t\t\t\tif (GetCondition(newLexemType, s, endIdx, ref newEndIdx, ref innerConditions)) {\n\t\t\t\t\t\t\tendIdx = newEndIdx;\n\t\t\t\t\t\t\tconditions = innerConditions|Conditions.Not;\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tconditions = enumDelimConds[idx];\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\t\n\t\tpublic virtual Query Parse(string relEx) {\n\t\t\tint endIdx;\n\t\t\tIQueryValue qValue = ParseInternal(relEx, 0, out endIdx );\n\t\t\tif (!(qValue is Query)) \n\t\t\t\tthrow new RelexParseException(\"Invalid expression: result is not a query\");\n\t\t\tQuery q = (Query)qValue;\n\t\t\treturn q;\n\t\t}\n\t\t\n\t\tpublic virtual QNode ParseCondition(string relExCondition) {\n\t\t\tint endIdx;\n\t\t\tif (String.IsNullOrEmpty(relExCondition))\n\t\t\t\treturn null;\n\t\t\tQNode node = ParseConditionGroup(relExCondition, 0, out endIdx);\n\t\t\tvar stopLexemType = GetLexemType(relExCondition, endIdx, out var stopEndIdx);\n\t\t\tif (stopLexemType!=LexemType.Stop)\n\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, relExCondition));\n\t\t\treturn node;\n\t\t}\n\t\t\n\t\tprotected virtual IQueryValue ParseTypedConstant(string typeCodeString, string constant) {\n\t\t\ttypeCodeString = typeCodeString.ToLower();\n\t\t\t// sql type\n\t\t\tif (typeCodeString == \"sql\") {\n\t\t\t\tif (!AllowRawSql)\n\t\t\t\t\tthrow new RelexParseException(\"Raw sql constants are not allowed\");\n\t\t\t\treturn new QRawSql(constant);\n\t\t\t}\n\t\t\t// var type\n\t\t\tif (typeCodeString == \"var\")\n\t\t\t\treturn new QVar(constant);\n\t\t\t// var type\n\t\t\tif (typeCodeString == \"field\")\n\t\t\t\treturn new QField(constant);\n\n\t\t\t// simple type\n\t\t\tint typeNameIdx = Array.IndexOf(typeNames, typeCodeString);\n\t\t\tif (typeNameIdx>=0) {\n\t\t\t\tTypeCode typeCode = (TypeCode)Enum.Parse(typeof(TypeCode), typeCodeString, true);\n\t\t\t\ttry {\n\t\t\t\t\tobject typedConstant = Convert.ChangeType(constant, typeCode, CultureInfo.InvariantCulture);\n\t\t\t\t\treturn new QConst(typedConstant);\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tthrow new InvalidCastException(\n\t\t\t\t\t\t String.Format(\"Cannot parse typed constant \\\"{0}\\\":{1}\",constant, typeCodeString),ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// array\n\t\t\ttypeNameIdx = Array.IndexOf(arrayTypeNames, typeCodeString);\n\t\t\tif (typeNameIdx>=0) {\n\t\t\t\tTypeCode typeCode = (TypeCode)Enum.Parse(typeof(TypeCode), typeNames[typeNameIdx], true);\n\t\t\t\tstring[] arrayValues = SplitArrayValues(constant);\n\t\t\t\tobject[] array = new object[arrayValues.Length];\n\t\t\t\tfor (int i=0; i<array.Length; i++)\n\t\t\t\t\tarray[i] = Convert.ChangeType(arrayValues[i], typeCode, CultureInfo.InvariantCulture);\n\t\t\t\treturn new QConst(array);\n\t\t\t}\n\n\t\t\tthrow new InvalidCastException(\n\t\t\t\tString.Format(\"Cannot parse typed constant \\\"{0}\\\":{1}\",\n\t\t\t\t\tconstant, typeCodeString) );\n\t\t}\n\t\t\n\t\tprotected string[] SplitArrayValues(string str) {\n\t\t\tfor (int i=0; i<arrayValuesSeparators.Length; i++)\n\t\t\t\tif (str.IndexOf(arrayValuesSeparators[i])>=0)\n\t\t\t\t\treturn str.Split(arrayValuesSeparators[i]);\n\t\t\treturn str.Split( arrayValuesSeparators );\n\t\t}\n\t\t\n\t\t\n\t\tprotected virtual IQueryValue ParseInternal(string input, int startIdx, out int endIdx) {\n\t\t\tLexemType lexemType = GetLexemType(input, startIdx, out endIdx);\n\t\t\tstring lexem = GetLexem(input, startIdx, endIdx);\n\t\t\t\t\t\t\n\t\t\tif (lexemType==LexemType.Constant)\n\t\t\t\treturn (QConst)lexem;\n\t\t\t\n\t\t\tif (lexemType==LexemType.QuotedConstant) {\n\t\t\t\t// remove first and last chars\n\t\t\t\tstring constant = lexem.Substring(1, lexem.Length-2); \n\t\t\t\t// replace \"\" with \"\n\t\t\t\tconstant = constant.Replace( \"\\\"\\\"\", \"\\\"\" );\n\t\t\t\t// typed?\n\t\t\t\tint newEndIdx;\n\t\t\t\tif ( GetLexemType(input, endIdx, out newEndIdx)==LexemType.Delimiter &&\n\t\t\t\t\t GetLexem(input, endIdx, newEndIdx)==\":\" ) {\n\t\t\t\t\tint typeEndIdx;\n\t\t\t\t\tif (GetLexemType(input, newEndIdx, out typeEndIdx)==LexemType.Name) {\n\t\t\t\t\t\tstring typeCodeString = GetLexem(input, newEndIdx, typeEndIdx);\n\t\t\t\t\t\tendIdx = typeEndIdx;\n\t\t\t\t\t\t// read [] at the end if specified\n\t\t\t\t\t\tif (GetLexemType(input, endIdx, out newEndIdx)==LexemType.Delimiter &&\n\t\t\t\t\t\t\tGetLexem(input, endIdx, newEndIdx)==\"[\")\n\t\t\t\t\t\t\tif (GetLexemType(input, newEndIdx, out typeEndIdx)==LexemType.Delimiter &&\n\t\t\t\t\t\t\t\tGetLexem(input, newEndIdx, typeEndIdx)==\"]\") {\n\t\t\t\t\t\t\t\tendIdx = typeEndIdx;\n\t\t\t\t\t\t\t\ttypeCodeString += \"[]\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tif (typeCodeString!=\"table\") {\n\t\t\t\t\t\t\treturn ParseTypedConstant(typeCodeString, constant);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlexem = constant;\n\t\t\t\t\t\t\tlexemType = LexemType.Name;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn (QConst)constant;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (lexemType==LexemType.Name) {\n\t\t\t\tint nextEndIdx;\n\t\t\t\t\n\t\t\t\t// query\n\t\t\t\tstring tableName = lexem;\n\t\t\t\tQNode rootCondition = null;\n\t\t\t\tQField[] fields = null;\n                QSort[] sort = null;\n\t\t\t\t\n\t\t\t\tLexemType nextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\tstring nextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\tif (nextLexemType==LexemType.Delimiter && nextLexem==\"(\") {\n\t\t\t\t\t// compose conditions\n\t\t\t\t\trootCondition = ParseConditionGroup(input, nextEndIdx, out endIdx);\n\t\t\t\t\t// read ')'\n\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\tif (nextLexemType!=LexemType.Delimiter || GetLexem(input, endIdx,nextEndIdx)!=\")\")\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t\t\t\t\n\t\t\t\t\t// read next lexem\n\t\t\t\t\tnextLexemType = GetLexemType(input, nextEndIdx, out endIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, nextEndIdx, endIdx);\n\t\t\t\t\tnextEndIdx = endIdx;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (nextLexemType==LexemType.Delimiter && nextLexem==\"[\") {\n\t\t\t\t\tnextLexemType = GetLexemType(input, nextEndIdx, out endIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, nextEndIdx, endIdx, nextLexemType);\n\t\t\t\t\tnextEndIdx = endIdx;\n\t\t\t\t\t\n\t\t\t\t\tvar fieldsList = new List<QField>();\n                    var sortList = new List<QSort>();\n\t\t\t\t\tvar curFldBuilder = new StringBuilder();\n\t\t\t\t\tcurFldBuilder.Append(nextLexem);\n                    bool sortPart = false;\n\t\t\t\t\tAction pushFld = () => {\n\t\t\t\t\t\tif (curFldBuilder.Length > 0) {\n\t\t\t\t\t\t\tif (sortPart) {\n\t\t\t\t\t\t\t\tsortList.Add(curFldBuilder.ToString());\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfieldsList.Add(curFldBuilder.ToString());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurFldBuilder.Clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n                    do {\n\t\t\t\t\t\tLexemType prevLexemType = nextLexemType;\n\t\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx, nextLexemType);\n\t\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t\t\tif (nextLexemType == LexemType.Delimiter && nextLexem == \"]\") {\n\t\t\t\t\t\t\tpushFld();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (nextLexemType == LexemType.Stop) {\n\t\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\t\tString.Format(\"Invalid syntax - unclosed bracket (position: {0}, expression: {1})\", endIdx, input));\n\t\t\t\t\t\t}\n                        // handle sort separator\n                        if (nextLexemType == LexemType.Delimiter && nextLexem == \";\") {\n\t\t\t\t\t\t\tpushFld();\n\t\t\t\t\t\t\tsortPart = true;\n\t\t\t\t\t\t} else if (nextLexemType == LexemType.Delimiter && nextLexem == \",\") {\n\t\t\t\t\t\t\tpushFld();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (prevLexemType != LexemType.Delimiter && \n\t\t\t\t\t\t\t\t\t(nextLexem.Equals(QSort.Asc,StringComparison.OrdinalIgnoreCase) ||\n\t\t\t\t\t\t\t\t\t nextLexem.Equals(QSort.Desc, StringComparison.OrdinalIgnoreCase))) {\n\t\t\t\t\t\t\t\tcurFldBuilder.Append(' ');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurFldBuilder.Append(nextLexem);\n                        }\n                    } while (true);\n\t\t\t\t\tif (fieldsList.Count != 1 || fieldsList[0] != \"*\")\n\t\t\t\t\t\tfields = fieldsList.ToArray();\n\t\t\t\t\tif (sortList.Count > 0)\n\t\t\t\t\t\tsort = sortList.ToArray();\n\t\t\t\t} else {\n\t\t\t\t\treturn (QField)lexem;\n\t\t\t\t}\n\t\t\t\tendIdx = nextEndIdx;\n\n\t\t\t\tQuery q = new Query( tableName, rootCondition);\n\t\t\t\t\n\t\t\t\t// limits?\n\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\tif (nextLexemType==LexemType.Delimiter && nextLexem==\"{\") {\n\t\t\t\t\t// read start record\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\t\tif (nextLexemType!=LexemType.Constant)\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t\t\t\tq.RecordOffset = Int32.Parse(nextLexem);\n\t\t\t\t\t// read comma\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\t\tif (nextLexemType!=LexemType.Delimiter || nextLexem!=\",\")\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t\t\t\t\t\n\t\t\t\t\t// read record count\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\t\tif (nextLexemType!=LexemType.Constant)\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t\t\t\tq.RecordCount = Int32.Parse(nextLexem);\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t// read close part '}'\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t\tnextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\t\tnextLexem = GetLexem(input, endIdx, nextEndIdx);\n\t\t\t\t\tif (nextLexemType!=LexemType.Delimiter || nextLexem!=\"}\")\n\t\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\tq.Select(fields);\n                if (sort != null)\n\t\t\t\t\tq.OrderBy(sort);\n\t\t\t\treturn q;\n\t\t\t}\n\t\t\t\n\t\t\tthrow new RelexParseException(\n\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t}\n\n\t\tprotected string ParseNodeName(string input, int startIdx, out int endIdx) {\n\t\t\tstring nodeName = null;\n\t\t\t// check for node name - starts with '<'\n\t\t\tLexemType lexemType = GetLexemType(input, startIdx, out endIdx);\n\t\t\tstring lexem = GetLexem(input, startIdx, endIdx);\n\t\t\tif (lexemType==LexemType.Delimiter && lexem==\"<\") {\n\t\t\t\tstartIdx = endIdx;\n\t\t\t\tlexemType = GetLexemType(input, startIdx, out endIdx);\n\t\t\t\tif (lexemType!=LexemType.Name && lexemType!=LexemType.Constant && lexemType!=LexemType.QuotedConstant)\n\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\tString.Format(\"Invalid syntax - node name expected (position: {0}, expression: {1})\", startIdx, input ) );\n\t\t\t\tnodeName = GetLexem(input, startIdx, endIdx);\n\t\t\t\tstartIdx = endIdx;\n\t\t\t\t// read closing delimiter '>'\n\t\t\t\tlexemType = GetLexemType(input, startIdx, out endIdx);\n\t\t\t\tlexem = GetLexem(input, startIdx, endIdx);\n\t\t\t\tif (lexemType!=LexemType.Delimiter || lexem!=\">\")\n\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", startIdx, input ) );\n\t\t\t} else {\n\t\t\t\tendIdx = startIdx; \n\t\t\t}\n\n\t\t\treturn nodeName;\n\t\t}\n\t\t\n\t\tprotected QNode ParseConditionGroup(string input, int startIdx, out int endIdx) {\n\t\t\tint nextEndIdx;\n\t\t\tLexemType lexemType = GetLexemType(input, startIdx, out nextEndIdx);\n\t\t\tstring lexem = GetLexem(input, startIdx, nextEndIdx);\n\n\t\t\t// handle not\n\t\t\tvar isNot = false;\n\t\t\tif (lexemType==LexemType.Name && lexem.Equals(\"not\", StringComparison.OrdinalIgnoreCase)) {\n\t\t\t\tisNot = true;\n\t\t\t\tstartIdx = nextEndIdx;\n\t\t\t\tlexemType = GetLexemType(input, startIdx, out nextEndIdx);\n\t\t\t\tlexem = GetLexem(input, startIdx, nextEndIdx);\n\t\t\t}\n\n\t\t\tQNode node;\n\t\t\tif (lexemType==LexemType.Delimiter && lexem==\"(\") {\n\t\t\t\tstring nodeName = ParseNodeName(input, nextEndIdx, out endIdx);\n\t\t\t\tnextEndIdx = endIdx;\n\n\t\t\t\t// check for empty group\n\t\t\t\tlexemType = GetLexemType(input, nextEndIdx, out endIdx);\n\t\t\t\tif (lexemType==LexemType.Delimiter && GetLexem(input,nextEndIdx,endIdx)==\")\") {\n\t\t\t\t\tnode = null;\n\t\t\t\t\t// push back\n\t\t\t\t\tendIdx = nextEndIdx;\n\t\t\t\t} else\n\t\t\t\t\tnode = ParseConditionGroup(input, nextEndIdx, out endIdx);\n\n\t\t\t\tif (nodeName!=null) {\n\t\t\t\t\tif (node==null)\n\t\t\t\t\t\tnode = new QGroupNode(QGroupType.And);\n\t\t\t\t\tif (node is QNode)\n\t\t\t\t\t\t((QNode)node).Name = nodeName;\n\t\t\t\t}\n\n\t\t\t\t// read ')'\n\t\t\t\tlexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\t\tif (lexemType!=LexemType.Delimiter || GetLexem(input,endIdx,nextEndIdx)!=\")\")\n\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", endIdx, input ) );\n\t\t\t\tendIdx = nextEndIdx;\n\t\t\t} else {\n\t\t\t\tnode = ParseCondition(input, startIdx, out nextEndIdx);\n\t\t\t\tendIdx = nextEndIdx;\n\t\t\t}\n\t\t\tif (isNot)\n\t\t\t\tnode = new QNegationNode(node);\n\n\t\t\t// check for group\n\t\t\tlexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\tQGroupType groupType = QGroupType.And;\n\t\t\tif (GetGroupType(lexemType, input, endIdx, ref nextEndIdx, ref groupType))\n\t\t\t\treturn ComposeGroupNode(node, ParseConditionGroup(input, nextEndIdx, out endIdx), groupType);\n\n\t\t\treturn node;\t\t\n\t\t}\n\n\t\tprotected QGroupNode ComposeGroupNode(QNode node1, QNode node2, QGroupType groupType) {\n\t\t\tQGroupNode group1 = node1 as QGroupNode, group2 = node2 as QGroupNode;\n\t\t\tif (group1 != null && group1.GroupType != groupType)\n\t\t\t\tgroup1 = null;\n\t\t\tif (group2 != null && group2.GroupType != groupType)\n\t\t\t\tgroup2 = null;\n\n\t\t\t// don't corrupt named groups\n\t\t\tif (group1 != null && group1.Name != null || group2 != null && group2.Name != null)\n\t\t\t\tgroup1 = group2 = null;\n\n\t\t\tif (group1 == null) {\n\t\t\t\tif (group2 == null) {\n\t\t\t\t\tQGroupNode group = new QGroupNode(groupType);\n\t\t\t\t\tgroup.Nodes.Add(node1);\n\t\t\t\t\tgroup.Nodes.Add(node2);\n\t\t\t\t\treturn group;\t\t\t\t\n\t\t\t\t} else {\n\t\t\t\t\tgroup2.Nodes.Insert(0, node1);\n\t\t\t\t\treturn group2;\t\t\t\t\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (group2 == null)\n\t\t\t\t\tgroup1.Nodes.Add(node2);\n\t\t\t\telse\n\t\t\t\t\tforeach (QNode qn in group2.Nodes)\n\t\t\t\t\t\tgroup1.Nodes.Add(qn);\n\t\t\t\treturn group1;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected QNode ParseCondition(string input, int startIdx, out int endIdx) {\n\t\t\t\n\t\t\tIQueryValue leftValue = ParseInternal(input, startIdx, out endIdx); \n\t\t\t\n\t\t\tint nextEndIdx;\n\t\t\tConditions conditions = Conditions.Equal;\n\n\t\t\tLexemType nextLexemType = GetLexemType(input, endIdx, out nextEndIdx);\n\t\t\tif (!GetCondition(nextLexemType, input, endIdx, ref nextEndIdx, ref conditions))\n\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\tString.Format(\"Invalid syntax (position: {0}, expression: {1})\", startIdx, input ) );\n\n\t\t\tIQueryValue rightValue = ParseInternal(input, nextEndIdx, out endIdx);\n\t\t\tQNode node;\n\t\t\tif (IsNullValue(rightValue)) {\n\t\t\t\tif ( (conditions & Conditions.Equal)!=0 )\n\t\t\t\t\tnode = new QConditionNode( leftValue, Conditions.Null | (conditions & ~Conditions.Equal), null);\n\t\t\t\telse\n\t\t\t\t\tthrow new RelexParseException(\n\t\t\t\t\t\tString.Format(\"Invalid syntax - such condition cannot be used with 'null' (position: {0}, expression: {1})\", startIdx, input ) );\n\t\t\t} else\n\t\t\t\tnode = new QConditionNode( leftValue, conditions, rightValue);\n\t\t\t\n\t\t\treturn node;\n\t\t}\n\t\t\n\t\tprotected bool IsNullValue(IQueryValue value) {\n\t\t\treturn ((value is QField) && ((QField)value).Name.ToLower()==nullField);\n\t\t}\n\t\t\n\n\t}\n\n\t/// <summary>\n\t/// </summary>\n\tpublic class RelexParseException : Exception {\n\t\tpublic RelexParseException() : base() {}\n\t\tpublic RelexParseException(string message) : base(message) {}\n\t\tpublic RelexParseException(string message, Exception innerException) : base(message, innerException) {}\n\t}\n}\n\n"
  },
  {
    "path": "src/NReco.Data/Result/DataReaderMapperContext.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016-2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Data;\n\nnamespace NReco.Data {\n\t\t\n\t/// <summary>\n\t/// Represents context for custom <see cref=\"DataReaderResult\"/> data mapping to POCO models.\n\t/// </summary>\n\tpublic interface IDataReaderMapperContext {\n\n\t\t/// <summary>\n\t\t/// Data reader with current record's data.\n\t\t/// </summary>\n\t\tIDataReader DataReader { get; }\n\n\t\t/// <summary>\n\t\t/// Target POCO model type.\n\t\t/// </summary>\n\t\tType ObjectType { get; }\n\t\t\t\n\t\t/// <summary>\n\t\t/// Performs default data mapping to specified object (data annotations are used if present).\n\t\t/// </summary>\n\t\tvoid MapTo(object o);\n\n\t\t/// <summary>\n\t\t/// Creates model of specified type and performs default mapping to this object.\n\t\t/// </summary>\n\t\tobject MapTo(Type t);  \n\t}\n\n\tinternal sealed class DataReaderMapperContext : IDataReaderMapperContext {\n\t\t\t\n\t\tpublic IDataReader DataReader { get; private set; }\n\t\t\t\n\t\tpublic Type ObjectType { get; private set; }\n\n\t\tDataMapper Mapper;\n\n\t\tinternal DataReaderMapperContext(DataMapper mapper, IDataReader rdr, Type toType) {\n\t\t\tMapper = mapper;\n\t\t\tDataReader = rdr;\n\t\t\tObjectType =toType;\n\t\t}\n\n\t\tpublic void MapTo(object o) {\n\t\t\tvar t = o.GetType();\n\t\t\tvar schema = Mapper.GetSchema(t);\n\t\t\tMapper.MapTo(DataReader, o, t, schema);\n\t\t}\n\n\t\tpublic object MapTo(Type t) {\n\t\t\treturn Mapper.MapTo(DataReader, t);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "src/NReco.Data/Result/DataReaderResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Represents <see cref=\"IDataReader\"/> result that can be mapped to POCO model, dictionary, <see cref=\"RecordSet\"/> or <see cref=\"DataTable\"/>.\n\t/// </summary>\n\tpublic class DataReaderResult : IQueryModelResult, IQueryDictionaryResult, IQueryRecordSetResult\t, IQueryDataTableResult\n\t{\n\n\t\tIDataReader DataReader;\n\t\tint RecordOffset;\n\t\tint RecordCount;\n\t\tDataMapper DtoMapper;\n\t\tFunc<IDataReaderMapperContext, object> CustomMappingHandler = null;\n\t\tstring FirstFieldName = null;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the DbDataAdapter with specified <see cref=\"IDataReader\"/> instance.\n\t\t/// </summary>\n\t\t/// <param name=\"dataReader\">data reader instance</param>\n\t\tpublic DataReaderResult(IDataReader dataReader) : this(dataReader, 0, Int32.MaxValue) {\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the DbDataAdapter with specified <see cref=\"IDataReader\"/> instance.\n\t\t/// </summary>\n\t\t/// <param name=\"dataReader\">data reader instance</param>\n\t\t/// <param name=\"offset\">first record offset</param>\n\t\t/// <param name=\"count\">max number of records to read</param>\n\t\tpublic DataReaderResult(IDataReader dataReader, int offset, int count) {\n\t\t\tDataReader = dataReader;\n\t\t\tRecordOffset = offset;\n\t\t\tRecordCount = count;\n\t\t\tDtoMapper = DataMapper.Instance;\n\t\t}\n\n\t\tinternal DataReaderResult(IDataReader dataReader, int offset, int count, string firstField) : this(dataReader,offset,count) {\n\t\t\tFirstFieldName = firstField;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Configures custom mapping handler for POCO models.\n\t\t/// </summary>\n\t\tpublic DataReaderResult SetMapper(Func<IDataReaderMapperContext, object> handler) {\n\t\t\tCustomMappingHandler = handler;\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns the first record from the query result. \n\t\t/// </summary>\n\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\tpublic T Single<T>() {\n\t\t\tvar res = new SingleDataReaderResult<T>(Read<T>);\n\t\t\tExecuteReader(res, 1);\n\t\t\treturn res.Result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns the first record from the query result. \n\t\t/// </summary>\n\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\tpublic Task<T> SingleAsync<T>() {\n\t\t\treturn SingleAsync<T>(CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns the first record from the query result. \n\t\t/// </summary>\n\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\tpublic Task<T> SingleAsync<T>(CancellationToken cancel) {\n\t\t\treturn ExecuteReaderAsync<T>(\n\t\t\t\tnew SingleDataReaderResult<T>(Read<T>), 1, cancel\n\t\t\t);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a list with all query results.\n\t\t/// </summary>\n\t\t/// <returns>list with query results</returns>\n\t\tpublic List<T> ToList<T>() {\n\t\t\tvar res = new ListDataReaderResult<T>(Read<T>);\n\t\t\tExecuteReader(res, RecordCount);\n\t\t\treturn res.Result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns a list with all query results.\n\t\t/// </summary>\n\t\tpublic Task<List<T>> ToListAsync<T>() {\n\t\t\treturn ToListAsync<T>(CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns a list with all query results.\n\t\t/// </summary>\n\t\tpublic Task<List<T>> ToListAsync<T>(CancellationToken cancel) {\n\t\t\treturn ExecuteReaderAsync<List<T>>(\n\t\t\t\tnew ListDataReaderResult<T>(Read<T>), RecordCount, cancel\n\t\t\t);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns dictionary with first record values.\n\t\t/// </summary>\n\t\t/// <returns>dictionary with field values or null if query returns zero records.</returns>\n\t\tpublic Dictionary<string, object> ToDictionary() {\n\t\t\tvar res = new SingleDataReaderResult<Dictionary<string, object>>(ReadDictionary);\n\t\t\tExecuteReader(res, 1);\n\t\t\treturn res.Result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns dictionary with first record values.\n\t\t/// </summary>\n\t\tpublic Task<Dictionary<string, object>> ToDictionaryAsync() {\n\t\t\treturn ToDictionaryAsync(CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns dictionary with first record values.\n\t\t/// </summary>\n\t\tpublic Task<Dictionary<string, object>> ToDictionaryAsync(CancellationToken cancel) {\n\t\t\treturn ExecuteReaderAsync<Dictionary<string, object>>(\n\t\t\t\tnew SingleDataReaderResult<Dictionary<string, object>>(ReadDictionary), 1, cancel\n\t\t\t);\n\t\t}\n\n\n\t\t/// <summary>\n\t\t/// Returns a list of dictionaries with all query results.\n\t\t/// </summary>\n\t\tpublic List<Dictionary<string, object>> ToDictionaryList() {\n\t\t\treturn ToList<Dictionary<string, object>>();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously a list of dictionaries with all query results.\n\t\t/// </summary>\n\t\tpublic Task<List<Dictionary<string, object>>> ToDictionaryListAsync() {\n\t\t\treturn ToDictionaryListAsync(CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously a list of dictionaries with all query results.\n\t\t/// </summary>\n\t\tpublic Task<List<Dictionary<string, object>>> ToDictionaryListAsync(CancellationToken cancel) {\n\t\t\treturn ExecuteReaderAsync<List<Dictionary<string, object>>>(\n\t\t\t\tnew ListDataReaderResult<Dictionary<string, object>>(ReadDictionary), RecordCount, cancel\n\t\t\t);\n\t\t}\n\n\n\n\t\t/// <summary>\n\t\t/// Returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic RecordSet ToRecordSet() {\n\t\t\tvar res = new RecordSetDataReaderResult();\n\t\t\tExecuteReader(res, RecordCount);\n\t\t\treturn res.Result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic Task<RecordSet> ToRecordSetAsync() {\n\t\t\treturn ToRecordSetAsync(CancellationToken.None);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tpublic Task<RecordSet> ToRecordSetAsync(CancellationToken cancel) {\n\t\t\treturn ExecuteReaderAsync<RecordSet>(new RecordSetDataReaderResult(), RecordCount, cancel);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns all query results as <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tpublic DataTable ToDataTable() => ToDataTable(null);\n\n\t\t/// <summary>\n\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// Columns mapping is not supported; you can generate SELECT command with <see cref=\"DbCommandBuilder\"/> and use\n\t\t/// it with <see cref=\"System.Data.Common.DbDataAdapter\"/> implementation if you need full support of <see cref=\"DataTable\"/> features.\n\t\t/// </remarks>\n\t\tpublic DataTable ToDataTable(DataTable tbl) {\n\t\t\tvar res = new DataTableDataReaderResult(tbl ?? new DataTable());\n\t\t\tExecuteReader(res, RecordCount);\n\t\t\treturn res.Result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tpublic Task<DataTable> ToDataTableAsync(CancellationToken cancel = default(CancellationToken))\n\t\t\t=> ToDataTableAsync(null, cancel);\n\n\t\t/// <summary>\n\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tpublic Task<DataTable> ToDataTableAsync(DataTable tbl, CancellationToken cancel = default(CancellationToken)) {\n\t\t\treturn ExecuteReaderAsync<DataTable>(new DataTableDataReaderResult(tbl ?? new DataTable()), RecordCount, cancel);\n\t\t}\n\n\t\tprivate T ChangeType<T>(object o, TypeCode typeCode) {\n\t\t\tif (DataHelper.IsNullOrDBNull(o)) {\n\t\t\t\treturn default(T);\n\t\t\t}\n\t\t\treturn (T)Convert.ChangeType(o, typeCode, System.Globalization.CultureInfo.InvariantCulture);\n\t\t}\n\n\t\tprivate Dictionary<string, object> ReadDictionary(IDataReader rdr) {\n\t\t\tvar dictionary = new Dictionary<string, object>(rdr.FieldCount);\n\t\t\tfor (int i = 0; i < rdr.FieldCount; i++)\n\t\t\t\tdictionary[rdr.GetName(i)] = rdr.GetValue(i);\n\t\t\treturn dictionary;\n\t\t}\n\n\t\tprivate T Read<T>(IDataReader rdr) {\n\t\t\tvar undelyingType = Nullable.GetUnderlyingType(typeof(T));\n\t\t\tvar typeCode = Type.GetTypeCode(undelyingType ?? typeof(T));\n\t\t\t// handle primitive single-value result\n\t\t\tif (typeCode!=TypeCode.Object || typeof(T)==typeof(object)) {\n\t\t\t\tif (rdr.FieldCount==1) {\n\t\t\t\t\treturn ChangeType<T>(rdr[0], typeCode);\n\t\t\t\t} else if (rdr.FieldCount>1) {\n\t\t\t\t\tvar firstFld = FirstFieldName;\n\t\t\t\t\tvar val = firstFld!=null ? rdr[firstFld] : rdr[0];\n\t\t\t\t\treturn ChangeType<T>(val, typeCode);\n\t\t\t\t} else {\n\t\t\t\t\treturn default(T);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// T is a dto\n\t\t\t// special handling for dictionaries\n\t\t\tvar type = typeof(T);\n\t\t\tif (type==typeof(IDictionary) || type==typeof(IDictionary<string, object>) || type==typeof(Dictionary<string, object>)) {\n\t\t\t\treturn (T)((object)ReadDictionary(rdr));\n\t\t\t}\n\t\t\t// handle as poco model\n\t\t\tif (CustomMappingHandler!=null) {\n\t\t\t\tvar mappingContext = new DataReaderMapperContext(DtoMapper, rdr, type);\n\t\t\t\tvar mapResult = CustomMappingHandler(mappingContext);\n\t\t\t\tif (mapResult==null)\n\t\t\t\t\tthrow new NullReferenceException(\"Custom mapping handler returns null\");\n\t\t\t\tif (!(mapResult is T))\n\t\t\t\t\tthrow new InvalidCastException($\"Custom mapping handler returns incompatible object type '{mapResult.GetType()}' (expected '{type}')\");\n\t\t\t\treturn (T)mapResult;\n\t\t\t}\n\t\t\treturn DtoMapper.MapTo<T>(rdr);\n\t\t}\n\n\t\tvoid ExecuteReader<T>(IDataReaderResult<T> result, int recordCount) {\n\t\t\tint index = 0;\n\t\t\tint processed = 0;\n\t\t\tresult.Init(DataReader);\n\t\t\twhile (DataReader.Read() && processed < recordCount) {\n\t\t\t\tif (index>=RecordOffset) {\n\t\t\t\t\tprocessed++;\n\t\t\t\t\tresult.Read(DataReader);\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\tresult.End();\n\t\t}\n\n\t\tasync Task<T> ExecuteReaderAsync<T>(IDataReaderResult<T> result, int recordCount, CancellationToken cancel) {\n\t\t\tint index = 0;\n\t\t\tint processed = 0;\n\n\t\t\tresult.Init(DataReader);\n\t\t\twhile ((await DataReader.ReadAsync(cancel)) && processed < recordCount) {\n\t\t\t\tif (index>=RecordOffset) {\n\t\t\t\t\tprocessed++;\n\t\t\t\t\tresult.Read(DataReader);\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\tresult.End();\n\t\t\treturn result.Result;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Result/IQueryDataTableResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nusing System.Data;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Represents query result that can be mapped to <see cref=\"DataTable\"/>.\n\t/// </summary>\n\t/// <remarks>This interface is not available in netstandard1.5 build.</remarks>\n\tpublic interface IQueryDataTableResult {\n\n\t\t/// <summary>\n\t\t/// Returns all query results as <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tDataTable ToDataTable();\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns all query results as <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tTask<DataTable> ToDataTableAsync(CancellationToken cancel = default(CancellationToken));\n\n\t\t/// <summary>\n\t\t/// Loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tDataTable ToDataTable(DataTable tbl);\n\n\t\t/// <summary>\n\t\t/// Asynchronously loads all query results into specified <see cref=\"DataTable\"/>.\n\t\t/// </summary>\n\t\tTask<DataTable> ToDataTableAsync(DataTable tbl, CancellationToken cancel = default(CancellationToken));\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Result/IQueryDictionaryResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Represents query result that can be mapped to dictionary.\n\t/// </summary>\n\tpublic interface IQueryDictionaryResult {\n\n\t\t/// <summary>\n\t\t/// Returns dictionary with first record values.\n\t\t/// </summary>\n\t\t/// <returns>dictionary with field values or null if query returns zero records.</returns>\n\t\tDictionary<string, object> ToDictionary();\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns dictionary with first record values.\n\t\t/// </summary>\n\t\tTask<Dictionary<string, object>> ToDictionaryAsync(CancellationToken cancel = default(CancellationToken));\n\n\t\t/// <summary>\n\t\t/// Returns a list of dictionaries with all query results.\n\t\t/// </summary>\n\t\tList<Dictionary<string, object>> ToDictionaryList();\n\n\t\t/// <summary>\n\t\t/// Asynchronously a list of dictionaries with all query results.\n\t\t/// </summary>\n\t\tTask<List<Dictionary<string, object>>> ToDictionaryListAsync(CancellationToken cancel = default(CancellationToken));\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Result/IQueryModelResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Represents query result that can be mapped to POCO model.\n\t/// </summary>\n\tpublic interface IQueryModelResult {\n\n\t\t/// <summary>\n\t\t/// Returns the first record from the query result. \n\t\t/// </summary>\n\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\tT Single<T>();\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns the first record from the query result. \n\t\t/// </summary>\n\t\t/// <returns>depending on T, single value or all fields values from the first record</returns>\n\t\tTask<T> SingleAsync<T>(CancellationToken cancel = default(CancellationToken));\n\n\t\t/// <summary>\n\t\t/// Returns a list with all query results.\n\t\t/// </summary>\n\t\t/// <returns>list with query results</returns>\n\t\tList<T> ToList<T>();\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns a list with all query results.\n\t\t/// </summary>\n\t\tTask<List<T>> ToListAsync<T>(CancellationToken cancel = default(CancellationToken));\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/Result/IQueryRecordSetResult.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2017 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Represents query result that can be mapped to <see cref=\"RecordSet\"/>.\n\t/// </summary>\n\tpublic interface IQueryRecordSetResult {\n\n\t\t/// <summary>\n\t\t/// Returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tRecordSet ToRecordSet();\n\n\t\t/// <summary>\n\t\t/// Asynchronously returns all query results as <see cref=\"RecordSet\"/>.\n\t\t/// </summary>\n\t\tTask<RecordSet> ToRecordSetAsync(CancellationToken cancel = default(CancellationToken));\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/SqlExpressionBuilder.cs",
    "content": "#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Text;\nusing System.Linq;\n\nnamespace NReco.Data\n{\n\t/// <summary>\n\t/// Generaic SQL expressions builder.\n\t/// </summary>\n\tpublic class SqlExpressionBuilder : ISqlExpressionBuilder\n\t{\n\t\t\n\t\tpublic SqlExpressionBuilder()\n\t\t{\n\t\t}\n\t\t\n\t\tpublic virtual string BuildTableName(QTable tbl) {\n\t\t\tvar tblName = BuildIdentifier( tbl.Name );\n\t\t\tif (!String.IsNullOrEmpty(tbl.Alias))\n\t\t\t\ttblName += \" \" + BuildIdentifier(tbl.Alias);\n\t\t\treturn tblName;\n\t\t}\n\n\t\tpublic virtual string BuildExpression(QNode node) {\n\t\t\tif (node==null) return null;\n\n\t\t\tif (node is QRawSqlNode qRawSql) {\n\t\t\t\treturn qRawSql.GetSqlText( (o) => BuildValue(new QConst(o)) );\n\t\t\t}\n\t\t\tif (node is QGroupNode qGrp)\n\t\t\t\treturn BuildGroup(qGrp);\n\t\t\tif (node is QConditionNode qCnd)\n\t\t\t\treturn BuildCondition(qCnd);\n\t\t\tif (node is QNegationNode qNot)\n\t\t\t\treturn BuildNegation(qNot);\n\t\t\t\n\t\t\tthrow new ArgumentException(\"Cannot build node with such type\", node.GetType().ToString() );\n\t\t}\n\t\t\n\t\tprotected virtual string BuildGroup(QGroupNode node) {\n\t\t\t// do not render empty group\n\t\t\tif (node.Nodes==null || node.Nodes.Count==0) return null;\n\n\t\t\t// if group contains only one node ignore group rendering logic\n\t\t\tif (node.Nodes.Count==1)\n\t\t\t\treturn BuildExpression( node.Nodes[0] );\n\n\t\t\tvar subNodes = new List<string>();\n\t\t\tforeach (QNode childNode in node.Nodes) {\n\t\t\t\tstring childNodeExpression = BuildExpression( childNode );\n\t\t\t\tif (childNodeExpression!=null)\n\t\t\t\t\tsubNodes.Add( \"(\"+childNodeExpression+\")\" ); \n\t\t\t}\n\t\t\t\n\t\t\treturn String.Join(\n\t\t\t\t\" \"+node.GroupType.ToString()+\" \",\n\t\t\t\tsubNodes.ToArray() );\n\t\t}\n\t\t\n\t\tprotected virtual string BuildNegation(QNegationNode node) {\n\t\t\tif (node.Nodes.Count==0) return null;\n\t\t\tstring expression = BuildExpression(node.Nodes[0]);\n\t\t\tif (expression==null) return null;\n\t\t\treturn String.Format(\"NOT({0})\", expression);\n\t\t}\n\n\t\tprotected virtual string BuildCondition(QConditionNode node) {\n\t\t\tConditions condition = node.Condition & (\n\t\t\t\tConditions.Equal | Conditions.GreaterThan |\n\t\t\t\tConditions.In | Conditions.LessThan |\n\t\t\t\tConditions.Like | Conditions.Null\n\t\t\t\t);\n\t\t\tstring lvalue = BuildConditionLValue(node);\n\t\t\tstring rvalue = BuildConditionRValue(node);\n\t\t\tstring res = null;\n\t\t\t\n\t\t\tswitch (condition) {\n\t\t\t\tcase Conditions.GreaterThan:\n\t\t\t\t\tres = String.Format(\"{0}>{1}\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase Conditions.LessThan:\n\t\t\t\t\tres = String.Format(\"{0}<{1}\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase (Conditions.LessThan | Conditions.Equal):\n\t\t\t\t\tres = String.Format(\"{0}<={1}\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase (Conditions.GreaterThan | Conditions.Equal):\n\t\t\t\t\tres = String.Format(\"{0}>={1}\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase Conditions.Equal:\n\t\t\t\t\tres = String.Format(\"{0}{2}{1}\", lvalue, rvalue, (node.Condition & Conditions.Not)!=0 ? \"<>\" : \"=\" );\n\t\t\t\t\tbreak;\n\t\t\t\tcase Conditions.Like:\n\t\t\t\t\tres = String.Format(\"{0} LIKE {1}\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase Conditions.In:\n\t\t\t\t\tres = String.IsNullOrWhiteSpace(rvalue) ? \"0=1\" : String.Format(\"{0} IN ({1})\", lvalue, rvalue );\n\t\t\t\t\tbreak;\n\t\t\t\tcase Conditions.Null:\n\t\t\t\t\tres = String.Format(\"{0} IS {1} NULL\", lvalue, (node.Condition & Conditions.Not)!=0 ? \"NOT\" : \"\" );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new ArgumentException(\"Invalid conditions set\", condition.ToString() );\n\t\t\t}\n\t\t\t\t\n\t\t\tif ( (node.Condition & Conditions.Not)!=0\n\t\t\t\t&& (condition & Conditions.Null)==0\n\t\t\t\t&& (condition & Conditions.Equal)==0 )\n\t\t\t\treturn String.Format(\"NOT ({0})\", res);\n\t\t\treturn res;\n\t\t}\n\t\t\n\t\tprotected virtual string BuildConditionLValue(QConditionNode node) {\n\t\t\treturn BuildValue( node.LValue);\n\t\t}\n\n\t\tprotected virtual string BuildConditionRValue(QConditionNode node) {\n\t\t\tif ( (node.Condition & Conditions.In)==Conditions.In && IsMultivalueConst( node.RValue ) ) {\n\t\t\t\tvar multiValue = ((QConst)node.RValue).Value as IList;\n\t\t\t\treturn BuildValue(multiValue);\n\t\t\t}\n\t\t\treturn BuildValue( node.RValue);\n\t\t}\n\n\t\tbool IsMultivalueConst(IQueryValue val) {\n\t\t\treturn val is QConst && ((QConst)val).Value is IList;\n\t\t}\n\n\t\tpublic virtual string BuildValue(IQueryValue value) {\n\t\t\tif (value==null) return null;\n\n\t\t\tif (value is QAggregateField qAggrFld)\n\t\t\t\treturn BuildValue(qAggrFld);\n\n\t\t\tif (value is QField qFld)\n\t\t\t\treturn BuildValue(qFld);\n\t\t\t\n\t\t\tif (value is QConst qConst)\n\t\t\t\treturn BuildValue(qConst);\n\n\t\t\tif (value is QRawSql qRawSql) {\n\t\t\t\treturn qRawSql.GetSqlText( (o) => BuildValue(new QConst(o)) );\n\t\t\t}\n\n\t\t\tthrow new NotSupportedException( \"Unknown query value: \"+ value.GetType().ToString() );\n\t\t}\n\n\t\tprotected virtual string BuildValue(QConst value) {\n\t\t\tobject constValue = value.Value;\n\t\t\tif (constValue==null)\n\t\t\t\treturn \"NULL\";\n\n\t\t\tif (constValue is string)\n\t\t\t\treturn BuildValue( (string)constValue );\n\n\t\t\tif (constValue is DateTime dt)\n\t\t\t\treturn BuildValue( dt.ToString(\"yyyy-MM-dd HH:mm:ss\", System.Globalization.CultureInfo.InvariantCulture) );\n\n\t\t\treturn Convert.ToString(constValue, System.Globalization.CultureInfo.InvariantCulture);\n\t\t}\n\t\t\n\t\tprotected virtual string BuildValue(IList list) {\n\t\t\tstring[] vals = new string[list.Count];\n\t\t\tfor (int i=0; i<list.Count; i++)\n\t\t\t\tvals[i] = BuildValue( new QConst(list[i]) );\n\t\t\treturn String.Join(\",\", vals);\n\t\t}\n\t\t\n\t\tprotected virtual string BuildValue(string str) {\n\t\t\treturn \"'\"+str.Replace(@\"'\", @\"\\'\")+\"'\";\n\t\t}\n\t\t\n\t\tprotected virtual string BuildValue(QField fieldValue) {\n\t\t\tif (!String.IsNullOrEmpty(fieldValue.Expression))\n\t\t\t\treturn fieldValue.Expression;\n\t\t\tvar name = BuildIdentifier(fieldValue.Name);\n\t\t\tif (!String.IsNullOrEmpty(fieldValue.Prefix))\n\t\t\t\tname = BuildIdentifier(fieldValue.Prefix)+\".\"+name;\n\t\t\treturn name;\n\t\t}\n\n\t\tprotected virtual string BuildValue(QAggregateField aggrFldValue) {\n\t\t\treturn QAggregateField.GetAggrExpr(aggrFldValue.AggregateFunction, \n\t\t\t\taggrFldValue.Arguments.Select(f=> BuildValue(f)).ToArray() );\n\t\t}\n\n\t\tprotected virtual string BuildIdentifier(string name) {\n\t\t\treturn name;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data/StringTemplate.cs",
    "content": "﻿#region License\n/*\n * NReco Data library (http://www.nrecosite.com/)\n * Copyright 2016 Vitaliy Fedorchenko\n * Distributed under the MIT license\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\n\nnamespace NReco.Data {\n\n\t/// <summary>\n\t/// Conditional string template parser.\n\t/// </summary>\n\t/// <remarks>\n\t/// StringTemplate replaces all tokens started with '@' (token name should have only aphanumeric or '_-' chars). \n\t/// Token processing can be avoided by specifying @@ before any alphanumeric charachter, for example: <code>@@Test</code> \n\t/// (result: <code>@Test</code>). Special symbols used for formatting syntax ('@', '[', ']',';', '{', '}') can be escaped in the following way:\n\t/// <list>\n\t/// <item>\\; or ;; = ;</item>\n\t/// <item>\\] or ]] = ]</item>\n\t/// <item>\\[ = [</item>\n\t/// <item>\\{ or {{ = {</item>  \n\t/// <item>\\} or }} = }</item>  \t \n\t/// <item>\\@ = @</item>  \n\t/// <item>\\\\ = \\</item> \n\t/// </list>\n\t/// </remarks>\n\t/// <example>\n\t/// <code>\n\t/// var strTpl = new StringTemplate(\"@Name[Hello, {0}; Hi all]!\");\n\t/// Console.Write( strTpl.FormatTemplate( new Dictionary&lt;string,object&gt;() { {\"Name\", \"John\"} } ) );  // Hi, John!\n\t/// Console.Write( strTpl.FormatTemplate( new Dictionary&lt;string,object&gt;() ) );  // Hi, all!\n\t/// </code>\n\t/// </example>\n\tpublic class StringTemplate {\n\t\tprotected string Template;\n\n\t\tprotected char[] ExtraNameChars = new [] {'_','-'};\n\n\t\t/// <summary>\n\t\t/// Get or set max recursion level of token replacement (for cases when token value contains token definitions). \n\t\t/// </summary>\n\t\t/// <remarks>Default recursion level is 1 (this means that tokens inside token values are not replaced)</remarks>\n\t\tpublic int RecursionLevel { get; set; }\n\n\t\t/// <summary>\n\t\t/// Get or set flag that determines replacement behaviour when token is not defined (true by default)\n\t\t/// </summary>\n\t\tpublic bool ReplaceMissedTokens { get;set; }\n\n\t\t/// <summary>\n\t\t/// Determines whether to replace nested tokens (like <code>@token1[ @token2={0} ]</code> ). \n\t\t/// </summary>\n\t\tpublic bool ReplaceNestedTokens { get; set; } = false;\n\n\t\tpublic StringTemplate(string tpl) {\n\t\t\tTemplate = tpl;\n\t\t\tRecursionLevel = 1;\n\t\t\tReplaceMissedTokens = true;\n\t\t}\n\n\t\tpublic StringTemplate(string tpl, int recursionLevel) {\n\t\t\tTemplate = tpl;\n\t\t\tRecursionLevel = recursionLevel;\n\t\t\tReplaceMissedTokens = true;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Replaces the format items in a specified string with the string representations of corresponding objects in a specified dictionary.\n\t\t/// </summary>\n\t\tpublic string FormatTemplate(IDictionary<string,object> props) {\n\t\t\treturn FormatTemplate((token) => {\n\t\t\t\treturn props.ContainsKey(token) ? new TokenResult(props[token]) : TokenResult.NotDefined;\n\t\t\t});\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Replaces the format items in a specified string with the string representations of corresponding objects returned by value handler.\n\t\t/// </summary>\n\t\tpublic string FormatTemplate(Func<string,TokenResult> valueHandler) {\n\t\t\tvar sb = new StringBuilder();\n\t\t\tstring tpl = Template;\n\t\t\tfor (int i = 0; i < RecursionLevel; i++) {\n\t\t\t\tsb.Clear();\n\t\t\t\tvar replacedCount = ReplaceTokens(tpl, valueHandler, sb);\n\t\t\t\ttpl = sb.ToString();\n\t\t\t\tif (replacedCount == 0)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn tpl;\n\t\t}\n\n\t\tprotected int ReplaceTokens(string tpl, Func<string,TokenResult> valueHandler, StringBuilder sb) {\n\t\t\tint pos = 0;\n\t\t\tint matchedTokensCount = 0;\n\t\t\twhile (pos < tpl.Length) {\n\t\t\t\tvar c = tpl[pos];\n\t\t\t\tif (c == '@') {\n\t\t\t\t\tint endPos;\n\t\t\t\t\tvar name = ReadName(tpl, pos + 1, out endPos);\n\t\t\t\t\tif (name != null) {\n\t\t\t\t\t\tvar tokenValue = resolveTokenValue(name, nested:false, endPos, out endPos);\n\t\t\t\t\t\tif (tokenValue!=null) {\n\t\t\t\t\t\t\tsb.Append(tokenValue);\n\t\t\t\t\t\t\tpos = endPos;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// check for @@ combination\n\t\t\t\t\t\tif ((pos + 1) < tpl.Length && tpl[pos+1]=='@') {\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsb.Append(c);\n\t\t\t\tpos++;\n\t\t\t}\n\t\t\treturn matchedTokensCount;\n\n\t\t\tstring resolveTokenValue(string name, bool nested, int startPos, out int endPos) {\n\t\t\t\tTokenResult tokenRes;\n\t\t\t\ttry {\n\t\t\t\t\ttokenRes = valueHandler(name);\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tthrow new Exception(String.Format(\"Evaluation of token {0} at position {1} failed: {2}\",\n\t\t\t\t\t\tname, pos, ex.Message), ex);\n\t\t\t\t}\n\t\t\t\tif (ReplaceMissedTokens || tokenRes.Defined) {\n\t\t\t\t\tobject callRes = tokenRes.Value;\n\t\t\t\t\tstring[] formatOptions;\n\t\t\t\t\tstring tokenValue = String.Empty;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tformatOptions = ReadFormatOptions(tpl, nested, startPos, out endPos, resolveTokenValue);\n\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\tthrow new Exception(String.Format(\"Parse error (format options of token {0}) at {1}: {2}\",\n\t\t\t\t\t\t\tname, pos, ex.Message), ex);\n\t\t\t\t\t}\n\t\t\t\t\tif (tokenRes.Applicable) {\n\t\t\t\t\t\tvar fmtNotEmpty = formatOptions != null && formatOptions.Length > 0 ? formatOptions[0] : \"{0}\";\n\t\t\t\t\t\tvar fmtEmpty = formatOptions != null && formatOptions.Length > 1 ? formatOptions[1] : \"\";\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\ttokenValue = callRes != null && Convert.ToString(callRes) != String.Empty ?\n\t\t\t\t\t\t\t\t\tFormatToken(fmtNotEmpty, callRes) : FormatToken(fmtEmpty, callRes);\n\t\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\t\tthrow new Exception(String.Format(\"Format of token {0} at position {1} failed: {2}\",\n\t\t\t\t\t\t\t\tname, pos, ex.Message), ex);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmatchedTokensCount++;\n\t\t\t\t\tif (nested) {\n\t\t\t\t\t\t// this is nested token and resolved value will be parsed\n\t\t\t\t\t\t// by String.Format in the 'parent' token.\n\t\t\t\t\t\t// If nested token format returns '{' or '}' they should be escaped \n\t\t\t\t\t\ttokenValue = escapeFormatBrackets(tokenValue);\n\t\t\t\t\t}\n\t\t\t\t\treturn tokenValue;\n\t\t\t\t}\n\t\t\t\tendPos = startPos;\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}\n\n\t\tprotected virtual string FormatToken(string fmt, object firstArg) {\n\t\t\treturn String.Format(fmt, firstArg);\n\t\t}\n\n\t\tbool isDoubleChar(char c, string s, int pos) {\n\t\t\treturn (s[pos] == c) && (pos + 1) < s.Length && s[pos + 1] == c;\n\t\t}\n\n\t\tprivate delegate string ResolveTokenValue(string name, bool nested, int startPos, out int endPos);\n\n\t\tbool isBackslashEscapedChar(char c) {\n\t\t\tswitch (c) {\n\t\t\t\tcase ';':\n\t\t\t\tcase ']':\n\t\t\t\tcase '[':\n\t\t\t\tcase '\\\\':\n\t\t\t\tcase '@':\n\t\t\t\tcase '{':\n\t\t\t\tcase '}':\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tstring escapeFormatBrackets(string s) {\n\t\t\tvar sb = new StringBuilder(s.Length + 10);\n\t\t\tchar c;\n\t\t\tfor (var i = 0; i < s.Length; i++) {\n\t\t\t\tc = s[i];\n\t\t\t\tif (c=='{' || c=='}') {\n\t\t\t\t\tsb.Append(c); // double\n\t\t\t\t}\n\t\t\t\tsb.Append(c);\n\t\t\t}\n\t\t\treturn sb.ToString();\n\t\t}\n\n\t\tprivate string[] ReadFormatOptions(string s, bool nested, int start, out int newStart, ResolveTokenValue resolveNestedTokenValue ) {\n\t\t\tnewStart = start;\n\t\t\tif (start >= s.Length || s[start] != '[')\n\t\t\t\treturn null;\n\t\t\tstart++;\n\t\t\tvar opts = new List<string>();\n\t\t\tvar pSb = new StringBuilder();\n\t\t\twhile (start < s.Length) {\n\t\t\t\tvar isEscapedChar =\n\t\t\t\t\t((s[start] == '\\\\') && (start + 1) < s.Length && isBackslashEscapedChar(s[start + 1]))\n\t\t\t\t\t||\n\t\t\t\t\tisDoubleChar(';', s, start)\n\t\t\t\t\t||\n\t\t\t\t\t(isDoubleChar(']', s, start) && !nested)  // double-escape doesn't work inside nested b/c this can be closing braket of outer token\n\t\t\t\t\t||\n\t\t\t\t\t(ReplaceNestedTokens && isDoubleChar('@', s, start));\n\t\t\t\tif (isEscapedChar) {\n\t\t\t\t\t// process escaped special char\n\t\t\t\t\tvar escapedChar = s[start + 1];\n\t\t\t\t\tpSb.Append(escapedChar);\n\t\t\t\t\tif (escapedChar == '{' || escapedChar == '}') {\n\t\t\t\t\t\t// if this is escaped curved bracket let's keep it as escaped\n\t\t\t\t\t\t// for String.Format (doubled)\n\t\t\t\t\t\tpSb.Append(escapedChar);\n\t\t\t\t\t}\n\t\t\t\t\tstart++;\n\t\t\t\t} else if (s[start] == ']') {\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (s[start] == ';') {\n\t\t\t\t\topts.Add(pSb.ToString());\n\t\t\t\t\tpSb.Clear();\n\t\t\t\t} else if (ReplaceNestedTokens && s[start]=='@') {\n\t\t\t\t\t// nested token\n\t\t\t\t\tvar nestedTokenName = ReadName(s, start + 1, out var endPos);\n\t\t\t\t\tif (nestedTokenName!=null) {\n\t\t\t\t\t\tvar nestedTokenValue = resolveNestedTokenValue(nestedTokenName, nested:true, endPos, out endPos);\n\t\t\t\t\t\tif (nestedTokenValue!=null) {\n\t\t\t\t\t\t\tpSb.Append(nestedTokenValue);\n\t\t\t\t\t\t\tstart = endPos;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpSb.Append(s[start]); // not a nested token, handle as a usual char\n\t\t\t\t} else {\n\t\t\t\t\tpSb.Append(s[start]);\n\t\t\t\t}\n\t\t\t\tstart++;\n\t\t\t}\n\t\t\topts.Add(pSb.ToString());\n\t\t\tif (start>=s.Length || s[start] != ']')\n\t\t\t\tthrow new FormatException(\"Invalid format options (no closing ']')\");\n\t\t\tif (opts.Count > 2)\n\t\t\t\tthrow new FormatException(\"Too many format options\");\n\t\t\tnewStart = start + 1;\n\t\t\treturn opts.ToArray();\n\t\t}\n\n\t\tprotected string ReadName(string s, int start, out int newStart) {\n\t\t\tnewStart = start;\n\t\t\t// should start with letter\n\t\t\tif (start >= s.Length || (!Char.IsLetter(s[start]) && s[start]!='(') )\n\t\t\t\treturn null;\n\t\t\tif (s[start] == '(') {\n\t\t\t\t// rest of the name: any chars except ')'\n\t\t\t\twhile (start < s.Length && s[start]!=')')\n\t\t\t\t\tstart++;\n\t\t\t\tif (start >= s.Length)\n\t\t\t\t\treturn null; // no closing bracket\n\t\t\t\tvar name = s.Substring(newStart + 1, start - newStart - 1);\n\t\t\t\tnewStart = start + 1; // for closing bracket\n\t\t\t\treturn name;\n\t\t\t} else {\n\t\t\t\t// rest of the name: letters or digits or '_' or '-'\n\t\t\t\twhile (start < s.Length && (Char.IsLetterOrDigit(s[start]) || Array.IndexOf(ExtraNameChars, s[start]) >= 0))\n\t\t\t\t\tstart++;\n\n\t\t\t\tvar name = s.Substring(newStart, start - newStart);\n\t\t\t\tnewStart = start;\n\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Represents token evaluation result.\n\t\t/// </summary>\n\t\tpublic sealed class TokenResult {\n\n\t\t\t/// <summary>\n\t\t\t/// Token value\n\t\t\t/// </summary>\n\t\t\tpublic object Value { get; private set; }\n\n\t\t\t/// <summary>\n\t\t\t/// Determines if token is defined.\n\t\t\t/// </summary>\n\t\t\tpublic bool Defined { get; private set; }\n\t\t\t\n\t\t\t/// <summary>\n\t\t\t/// Determines if token result is applicable.\n\t\t\t/// </summary>\n\t\t\t/// <remarks>If token is not applicable neither \"has value\" nor \"empty value\" is used (token replaced to empty string)</remarks>\n\t\t\tpublic bool Applicable { get; private set; }\n\n\t\t\tpublic static readonly TokenResult NotDefined = new TokenResult(null) { Defined = false };\n\t\t\tpublic static readonly TokenResult NotApplicable = new TokenResult(null) { Defined = true, Applicable = false };\n\n\t\t\tpublic TokenResult(object val) {\n\t\t\t\tValue = val;\n\t\t\t\tDefined = true;\n\t\t\t\tApplicable = true;\n\t\t\t}\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/DataReaderResultTests.cs",
    "content": "using System;\nusing System.Data;\n\nusing Xunit;\nnamespace NReco.Data.Tests\n{\n\n\tpublic class DataReaderResultTests\n\t{\n\t\t[Fact]\n\t\tpublic void ReadToDictionary() {\n\t\t\tvar rs = RecordSetTests.generateRecordSet();\n\n\t\t\tvar firstRecord = new DataReaderResult(new RecordSetReader(rs)).ToDictionary();\n\t\t\tAssert.NotNull(firstRecord);\n\t\t\tAssert.Equal(0, firstRecord[\"id\"]);\n\t\t\tAssert.Equal(4, firstRecord.Count);\n\n\t\t\tvar allRecords = new DataReaderResult(new RecordSetReader(rs)).ToDictionaryList();\n\t\t\tAssert.Equal(100, allRecords.Count);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void ReadToRecordSet() {\n\t\t\tvar rs = RecordSetTests.generateRecordSet();\n\n\t\t\tvar allRecords = new DataReaderResult(new RecordSetReader(rs)).ToRecordSet();\n\t\t\tAssert.Equal(4, allRecords.Columns.Count);\n\t\t\tAssert.Equal(0, allRecords[0][\"id\"]);\n\t\t\tAssert.Equal(100, allRecords.Count);\n\n\t\t\tvar allRecordsAsyncRes = new DataReaderResult(new RecordSetReader(rs)).ToRecordSetAsync().Result;\n\t\t\tAssert.Equal(100, allRecordsAsyncRes.Count);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void ReadToModel() {\n\t\t\tvar rs = RecordSetTests.generateRecordSet();\n\n\t\t\tvar secondId = new DataReaderResult(new RecordSetReader(rs), 1, 1).Single<int>();\n\t\t\tAssert.Equal(1, secondId);\n\n\t\t\tvar firstRecord = new DataReaderResult(new RecordSetReader(rs)).Single<TestModel>();\n\t\t\tAssert.NotNull(firstRecord);\n\t\t\tAssert.Equal(0, firstRecord.id);\n\n\t\t\tvar allRecords = new DataReaderResult(new RecordSetReader(rs)).ToList<TestModel>();\n\t\t\tAssert.Equal(100, allRecords.Count);\n\t\t}\n\n\t\tpublic class TestModel {\n\t\t\tpublic int id { get; set; }\n\t\t\tpublic string name { get; set; }\n\t\t\tpublic decimal amount { get; set; }\n\t\t\tpublic DateTime added_date { get; set; }\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void ReadToDataTable() {\n\t\t\tvar rs = RecordSetTests.generateRecordSet();\n\n\t\t\tvar tblWithOneRow = new DataReaderResult(new RecordSetReader(rs), 0, 1).ToDataTable();\n\t\t\tAssert.Equal(1, tblWithOneRow.Rows.Count);\n\t\t\tAssert.Equal(4, tblWithOneRow.Columns.Count);\n\t\t\tAssert.Equal(0, tblWithOneRow.Rows[0][\"id\"]);\n\t\t\tAssert.Equal(\"Name0\", tblWithOneRow.Rows[0][\"name\"]);\n\n\t\t\tvar tblAll = new DataReaderResult(new RecordSetReader(rs) ).ToDataTable();\n\t\t\tAssert.Equal(100, tblAll.Rows.Count);\n\n\t\t\t// load into specified DataTable\n\t\t\tvar ds = new DataSet();\n\t\t\tvar testTbl = ds.Tables.Add(\"test\");\n\t\t\tvar idCol = testTbl.Columns.Add(\"id\", typeof(int));\n\t\t\tidCol.AllowDBNull = false;\n\t\t\ttestTbl.PrimaryKey = new[] { idCol };\n\t\t\tnew DataReaderResult(new RecordSetReader(rs)).ToDataTable(testTbl);\n\t\t\tAssert.Equal(4, testTbl.Columns.Count);  // missed cols are added automatically\n\t\t\tAssert.Equal(100, testTbl.Rows.Count);\n\t\t\tAssert.Equal(\"Name20\", testTbl.Rows.Find(20)[\"name\"] );\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/DbBatchCommandBuilderTests.cs",
    "content": "using System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Data.SqlClient;\n\nusing Xunit;\nusing NReco.Data;\n\nnamespace NReco.Data.Tests {\n\n\tpublic class DbBatchCommandBuilderTests {\n\n\n\t\t[Fact]\n\t\tpublic void BatchInsertCommand() {\n\t\t\tvar dbFactory = new DbFactory( SqlClientFactory.Instance );\n\t\t\tvar cmdGenerator = new DbBatchCommandBuilder(dbFactory);\n\t\t\t\n\t\t\tAssert.Throws<InvalidOperationException>( () => { cmdGenerator.EndBatch(); });\n\n\t\t\tcmdGenerator.BeginBatch();\n\n\t\t\tcmdGenerator.GetInsertCommand( \"test\", new { FieldA = \"A\", FieldB = 0 } );\n\t\t\tcmdGenerator.GetInsertCommand( \"test\", new { FieldC = \"C\", FieldD = 1 } );\n\t\t\t\n\t\t\tvar batchCmd = cmdGenerator.EndBatch();\n\n\t\t\tAssert.Equal(\n\t\t\t\t@\"INSERT INTO test (FieldA,FieldB) VALUES (@p0,@p1);INSERT INTO test (FieldC,FieldD) VALUES (@p2,@p3)\",\n\t\t\t\tbatchCmd.CommandText);\n\t\t\tAssert.Equal(4, batchCmd.Parameters.Count);\n\t\t\t\n\t\t}\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/DbCommandBuilderTests.cs",
    "content": "using System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Data.SqlClient;\n\nusing Xunit;\nusing NReco.Data;\n\nnamespace NReco.Data.Tests {\n\n\tpublic class DbCommandBuilderTests : IClassFixture<SqliteDbFixture> {\n\n\t\tSqliteDbFixture SqliteDb;\n\n\t\tpublic DbCommandBuilderTests(SqliteDbFixture sqliteDb) {\n\t\t\tSqliteDb = sqliteDb;\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void Sqlite_Select() {\n\t\t\tvar cmdBuilder = new DbCommandBuilder(SqliteDb.DbFactory);\n\n\t\t\tvar countCmd = cmdBuilder.GetSelectCommand( new Query(\"contacts\").Select(QField.Count) );\n\t\t\tcountCmd.Connection = SqliteDb.DbConnection;\n\t\t\tSqliteDb.OpenConnection( () => {\n\t\t\t\tAssert.Equal(5, Convert.ToInt32( countCmd.ExecuteScalar() ) );\n\t\t\t});\n\t\t}\n\n\t\tQNode createTestQuery() {\n\t\t\treturn  (\n\t\t\t\t\t\t(QField)\"name\" % (QConst)\"Anna\" | new QNegationNode( (QField)\"age\" >= (QConst)18 )\n\t\t\t\t\t) & (\n\t\t\t\t\t\t(QField)\"weight\" == (QConst)54.3\n\t\t\t\t\t\t&\n\t\t\t\t\t\tnew QConditionNode(\n\t\t\t\t\t\t\t(QField)\"type\",\n\t\t\t\t\t\t\tConditions.In, \n\t\t\t\t\t\t\t(QConst)new string[] {\"Str1\", \"Str2\"}\n\t\t\t\t\t\t)\n\t\t\t\t\t) | (\n\t\t\t\t\t\t(QField)\"name\"!=(QConst)\"Petya\"\n\t\t\t\t\t\t&\n\t\t\t\t\t\tnew QConditionNode(\n\t\t\t\t\t\t\t(QField)\"type\", Conditions.Not|Conditions.Null,\tnull)\n\t\t\t\t\t);\t\t\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void Select_Speed() {\n\t\t\tvar dbFactory = new DbFactory( SqlClientFactory.Instance );\n\t\t\tvar cmdGenerator = new DbCommandBuilder(dbFactory);\n\t\t\t\n\t\t\tQuery q = new Query( \"test\" );\n\t\t\tq.Condition = createTestQuery();\n\t\t\tq.Fields = new QField[] { \"name\", \"age\" };\n\n\t\t\t// SELECT TEST\n\t\t\tvar stopwatch = new System.Diagnostics.Stopwatch();\n\t\t\tstopwatch.Start();\n\t\t\tfor (int i=0; i<10000; i++) {\n\t\t\t\tIDbCommand cmd = cmdGenerator.GetSelectCommand( q );\t\n\t\t\t}\n\t\t\tstopwatch.Stop();\n\n\t\t\tConsole.WriteLine(\"Speedtest for select command generation (10000 times): {0}\", stopwatch.Elapsed); \n\t\t}\n\n\n\t\t[Fact]\n\t\tpublic void InsertUpdateDelete_Speed() {\n\t\t\tvar dbFactory = new DbFactory( SqlClientFactory.Instance );\n\t\t\tvar cmdGenerator = new DbCommandBuilder(dbFactory);\n\n\t\t\tvar testData = new Dictionary<string,object> {\n\t\t\t\t{\"name\", \"Test\" },\n\t\t\t\t{\"age\", 20 },\n\t\t\t\t{\"created\", DateTime.Now }\n\t\t\t};\n\t\t\tvar testQuery = new Query(\"test\", (QField)\"id\" == (QConst)5 );\n\t\t\tvar stopwatch = new Stopwatch();\n\n\t\t\tint iterations = 0;\n\t\t\tstopwatch.Start();\n\t\t\twhile (iterations < 500) {\n\t\t\t\titerations++;\n\t\t\t\tvar insertCmd = cmdGenerator.GetInsertCommand( \"test\", testData);\n\t\t\t\tvar updateCmd = cmdGenerator.GetUpdateCommand( testQuery, testData);\n\t\t\t\tvar deleteCmd = cmdGenerator.GetDeleteCommand( testQuery );\n\t\t\t}\n\n\t\t\tstopwatch.Stop();\n\t\t\tConsole.WriteLine(\"Speedtest for DbCommandGenerator Insert+Update+Delete commands ({1} times): {0}\", stopwatch.Elapsed, iterations);\n\t\t}\n\t\t\n\t\t\n\t\t[Fact]\n\t\tpublic void BuildCommands() {\n\t\t\tvar dbFactory = new DbFactory( SqlClientFactory.Instance );\n\t\t\tvar cmdGenerator = new DbCommandBuilder(dbFactory);\n\t\t\t\n\t\t\tvar q = new Query( new QTable(\"test\",\"t\") );\n\t\t\tq.Condition = createTestQuery();\n\t\t\tq.Fields = new QField[] { \"name\", \"t.age\", new QField(\"age_months\", \"t.age*12\") };\n\n\t\t\t// SELECT TEST with prefixes and expressions\n\t\t\tIDbCommand cmd = cmdGenerator.GetSelectCommand( q );\t\n\t\t\tstring masterSQL = \"SELECT name,t.age,t.age*12 as age_months FROM test t WHERE (((name LIKE @p0) Or (NOT(age>=@p1))) And ((weight=@p2) And (type IN (@p3,@p4)))) Or ((name<>@p5) And (type IS NOT NULL))\";\n\t\t\t\n\t\t\tAssert.Equal( masterSQL, cmd.CommandText.Trim() );\n\n\t\t\t// SELECT WITH TABLE ALIAS TEST\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts.a\",\n\t\t\t\t\t\tnew QConditionNode( (QField)\"a.id\", Conditions.In, \n\t\t\t\t\t\t\tnew Query(\"dbo.accounts.b\", (QField)\"a.id\"!=(QField)\"b.id\" ) ) ) );\n\t\t\tmasterSQL = \"SELECT * FROM accounts a WHERE a.id IN (SELECT * FROM dbo.accounts b WHERE a.id<>b.id)\";\n\t\t\tAssert.Equal( masterSQL, cmd.CommandText);\n\n\t\t\t// SELECT AGGREGATE\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts\", (QField)\"active\" == (QConst)true).Select(\"name\", new QAggregateField(\"qty_sum\", \"sum\", \"qty\") ));\n\t\t\tmasterSQL = \"SELECT name,sum(qty) as qty_sum FROM accounts WHERE active=@p0 GROUP BY name\";\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\n\n\t\t\t// SELECT RAW SQL\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts\", new QRawSqlNode(\"1=2\")));\n\t\t\tmasterSQL = \"SELECT * FROM accounts WHERE 1=2\";\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts\", new QRawSqlNode(\"CUSTOM_FUNC({0},{1})\", new object[] { 1, 2 }) ));\n\t\t\tmasterSQL = \"SELECT * FROM accounts WHERE CUSTOM_FUNC(@p0,@p1)\";\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts\", (QField)\"id\" == new QRawSql(\"1\") ));\n\t\t\tmasterSQL = \"SELECT * FROM accounts WHERE id=1\";\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\t\t\tcmd = cmdGenerator.GetSelectCommand(\n\t\t\t\t\tnew Query(\"accounts\", (QField)\"id\" == new QRawSql(\"FUNC({0})\", new object[] { 1 })));\n\t\t\tmasterSQL = \"SELECT * FROM accounts WHERE id=FUNC(@p0)\";\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\n\t\t\tvar testData = new Dictionary<string,object> {\n\t\t\t\t{\"name\", \"Test\" },\n\t\t\t\t{\"age\", 20 },\n\t\t\t\t{\"weight\", 75.6 },\n\t\t\t\t{\"type\", \"staff\" }\n\t\t\t};\n\n\t\t\t// INSERT TEST\n\t\t\tcmd = cmdGenerator.GetInsertCommand( \"test\", testData );\n\t\t\tmasterSQL = \"INSERT INTO test (name,age,weight,type) VALUES (@p0,@p1,@p2,@p3)\";\n\t\t\t\n\t\t\tAssert.Equal( cmd.CommandText, masterSQL);\n\t\t\tAssert.Equal( cmd.Parameters.Count, 4);\n\t\t\t\n\t\t\t// UPDATE TEST\n\t\t\tcmd = cmdGenerator.GetUpdateCommand( new Query(\"test\", (QField)\"name\"==(QConst)\"test\"), testData );\n\t\t\tmasterSQL = \"UPDATE test SET name=@p0,age=@p1,weight=@p2,type=@p3 WHERE name=@p4\";\n\t\t\t\n\t\t\tAssert.Equal( cmd.CommandText, masterSQL);\n\t\t\tAssert.Equal( cmd.Parameters.Count, 5);\n\t\t\t\n\t\t\t// UPDATE TEST (by query)\n\t\t\tvar changes = new Dictionary<string,IQueryValue>() {\n\t\t\t\t{ \"age\", (QConst)21 }, { \"name\", (QConst)\"Alexandra\" } };\n\t\t\tcmd = cmdGenerator.GetUpdateCommand(new Query(\"test\", (QField)\"id\" == (QConst)1), changes);\n\t\t\tmasterSQL = \"UPDATE test SET age=@p0,name=@p1 WHERE id=@p2\";\n\n\t\t\tAssert.Equal(masterSQL, cmd.CommandText);\n\t\t\tAssert.Equal(3, cmd.Parameters.Count);\n\t\t\t\n\t\t\t// DELETE BY QUERY TEST\n\t\t\tcmd = cmdGenerator.GetDeleteCommand( new Query(\"test\", (QField)\"id\"==(QConst)5 ) );\n\t\t\tmasterSQL = \"DELETE FROM test WHERE id=@p0\";\n\t\t\t\n\t\t\tAssert.Equal( cmd.CommandText, masterSQL);\n\t\t\tAssert.Equal( cmd.Parameters.Count, 1);\n\n\t\t\t// ------- escape identifiers asserts --------\n\t\t\tdbFactory.IdentifierFormat = \"[{0}]\";\n\t\t\tAssert.Equal( \n\t\t\t\t\"SELECT [name],[t].[age],t.age*12 as [age_months] FROM [test] [t] WHERE ((([name] LIKE @p0) Or (NOT([age]>=@p1))) And (([weight]=@p2) And ([type] IN (@p3,@p4)))) Or (([name]<>@p5) And ([type] IS NOT NULL))\",\t\n\t\t\t\tcmdGenerator.GetSelectCommand( q ).CommandText.Trim() );\n\t\t\tAssert.Equal(\n\t\t\t\t\"INSERT INTO [test] ([name],[age],[weight],[type]) VALUES (@p0,@p1,@p2,@p3)\",\n\t\t\t\tcmdGenerator.GetInsertCommand( \"test\", testData ).CommandText );\n\t\t\tAssert.Equal(\n\t\t\t\t\"UPDATE [test] SET [name]=@p0,[age]=@p1,[weight]=@p2,[type]=@p3 WHERE [name]=@p4\",\n\t\t\t\tcmdGenerator.GetUpdateCommand( new Query(\"test\", (QField)\"name\"==(QConst)\"test\"), testData ).CommandText );\n\t\t\tAssert.Equal(\n\t\t\t\t\"DELETE FROM [test] WHERE [id]=@p0\",\n\t\t\t\tcmdGenerator.GetDeleteCommand( new Query(\"test\", (QField)\"id\"==(QConst)5 ) ).CommandText );\t\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void DataView() {\n\t\t\tvar dbFactory = new DbFactory( SqlClientFactory.Instance );\n\t\t\tvar cmdGenerator = new DbCommandBuilder(dbFactory);\n\n\t\t\tcmdGenerator.Views = new Dictionary<string,DbDataView>() {\n\t\t\t\t{ \"persons_view\", \n\t\t\t\t\tnew DbDataView(\n\t\t\t\t\t\t@\"SELECT @columns FROM persons p LEFT JOIN countries c ON (c.id=p.country_id) @where[ WHERE {0}] @orderby[ ORDER BY {0}]\") {\n\t\t\t\t\t\t\tFieldMapping = new Dictionary<string,string>() {\n\t\t\t\t\t\t\t\t{\"id\", \"p.id\"},  \n\t\t\t\t\t\t\t\t{\"count(*)\", \"count(p.id)\" },\n\t\t\t\t\t\t\t\t{\"*\", \"p.*\" },\n\t\t\t\t\t\t\t\t{\"expired\", \"CASE WHEN DATEDIFF(dd, p.added_date, NOW() )>30 THEN 1 ELSE 0 END\" } \n\t\t\t\t\t\t\t}\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t} };\n\t\t\t\n\t\t\t// simple count query test\n\t\t\tAssert.Equal(\n\t\t\t\t\"SELECT count(p.id) as cnt FROM persons p LEFT JOIN countries c ON (c.id=p.country_id)\",\n\t\t\t\tcmdGenerator.GetSelectCommand( new Query(\"persons_view\").Select(QField.Count) ).CommandText.Trim()\n\t\t\t);\n\t\t\t\n\t\t\t// field mapping in select columns\n\t\t\tAssert.Equal(\n\t\t\t\t\"SELECT p.id as id,name,CASE WHEN DATEDIFF(dd, p.added_date, NOW() )>30 THEN 1 ELSE 0 END as expired FROM persons p LEFT JOIN countries c ON (c.id=p.country_id)\",\n\t\t\t\tcmdGenerator.GetSelectCommand( new Query(\"persons_view\")\n\t\t\t\t\t.Select(\"id\", \"name\", \"expired\") ).CommandText.Trim()\n\t\t\t);\n\n\t\t\t// field mapping in conditions\n\t\t\tAssert.Equal(\n\t\t\t\t\"SELECT p.* FROM persons p LEFT JOIN countries c ON (c.id=p.country_id)  WHERE (p.id>@p0) And (CASE WHEN DATEDIFF(dd, p.added_date, NOW() )>30 THEN 1 ELSE 0 END=@p1)\",\n\t\t\t\tcmdGenerator.GetSelectCommand( new Query(\"persons_view\",\n\t\t\t\t\t(QField)\"id\">(QConst)5 & (QField)\"expired\"==new QConst(true)\n\t\t\t\t) ).CommandText.Trim()\n\t\t\t);\n\t\t}\n\t\t\n\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/DbDataAdapterTests.cs",
    "content": "using System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing System.Linq;\n\nusing Xunit;\nusing System.Threading;\n\nnamespace NReco.Data.Tests {\n\n\tpublic class DbDataAdapterTests : IClassFixture<SqliteDbFixture> {\n\n\t\tSqliteDbFixture SqliteDb;\n\t\tDbDataAdapter DbAdapter;\n\n\t\tpublic DbDataAdapterTests(SqliteDbFixture sqliteDb) {\n\t\t\tSqliteDb = sqliteDb;\n\t\t\t\n\t\t\tvar cmdBuilder = new DbCommandBuilder(SqliteDb.DbFactory);\n\t\t\tcmdBuilder.Views[\"contacts_view\"] = new DbDataView(\n\t\t\t\t@\"SELECT @columns FROM contacts c\n\t\t\t\t  LEFT JOIN companies cc ON (cc.id=c.company_id)\n\t\t\t\t@where[ WHERE {0}] @orderby[ ORDER BY {0}]\"\n\t\t\t) {\n\t\t\t\tFieldMapping = new Dictionary<string,string>() {\n\t\t\t\t\t{\"id\", \"c.id\"},\n\t\t\t\t\t{\"*\", \"c.*, cc.title as company_title\"}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tDbAdapter = new DbDataAdapter(sqliteDb.DbConnection, cmdBuilder );\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void Select() {\n\t\t\t// count: table\n\t\t\tAssert.Equal(5, DbAdapter.Select(new Query(\"contacts\").Select(QField.Count) ).Single<int>() );\n\t\t\t// count for schema-qualified query\n\t\t\tAssert.Equal(5, DbAdapter.Select( new Query( new QTable( \"main.contacts\",null) ).Select(QField.Count) ).Single<int>() );\n\n\t\t\t// select single that is null\n\t\t\tAssert.False( DbAdapter.Select( new Query(\"companies\", (QField)\"id\">(QConst)1000).Select(new QField(\"sum\", \"sum(size)\")) ).Single<int?>().HasValue );\n\t\t\tAssert.Equal(0, DbAdapter.Select(new Query(\"companies\", (QField)\"id\" > (QConst)1000).Select(new QField(\"sum\", \"sum(size)\"))).Single<int>() );\n\n\t\t\t// count: data view\n\t\t\tAssert.Equal(5, DbAdapter.Select(new Query(\"contacts_view\").Select(QField.Count) ).Single<int>() );\n\n\t\t\tvar johnContactQuery = DbAdapter.Select(new Query(\"contacts\", new QConditionNode((QField)\"name\",Conditions.Like,(QConst)\"%john%\") ) );\n\t\t\tvar johnDict = johnContactQuery.ToDictionary();\n\t\t\tAssert.Equal(\"John Doe\", johnDict[\"name\"]);\n\t\t\tAssert.Equal(4, johnDict.Count);\n\n\t\t\tvar johnModel = johnContactQuery.Single<ContactModel>();\n\t\t\tAssert.Equal(\"John Doe\", johnModel.name);\n\n\t\t\tvar contactsWithHighScoreQuery = DbAdapter.Select(\n\t\t\t\tnew Query(\"contacts_view\", (QField)\"score\" > (QConst)4 ).OrderBy(\"name desc\")\n\t\t\t);\n\n\t\t\tvar contactsWithHighDicts = contactsWithHighScoreQuery.ToDictionaryList();\n\t\t\tAssert.Equal(2, contactsWithHighDicts.Count );\n\n\t\t\tvar contactsWithHightRS = contactsWithHighScoreQuery.ToRecordSet();\n\t\t\tAssert.Equal(2, contactsWithHightRS.Count );\n\t\t\tAssert.Equal(5, contactsWithHightRS.Columns.Count );\n\t\t\tAssert.Equal(\"Viola Garrett\", contactsWithHightRS[0][\"name\"] );\n\n\t\t\t// check in\n\t\t\tvar contactsWithFourAndFiveScore = DbAdapter.Select(\n\t\t\t\tnew Query(\"contacts_view\", new QConditionNode( (QField)\"score\", Conditions.In, new QConst(new[] {4,5}) ) ).OrderBy(\"name desc\")\n\t\t\t);\n\t\t\tAssert.Equal(4, contactsWithFourAndFiveScore.ToRecordSet().Count);\n\n\t\t\t// select to annotated object\n\t\t\tvar companies = DbAdapter.Select(new Query(\"companies\").OrderBy(\"id\")).ToList<CompanyModelAnnotated>();\n\t\t\tAssert.Equal(2, companies.Count);\n\t\t\tAssert.Equal(\"Microsoft\", companies[0].Name);\n\n\t\t\t// select to datatable\n\t\t\tvar companiesTbl = DbAdapter.Select(new Query(\"companies\").OrderBy(\"id\")).ToDataTable();\n\t\t\tAssert.Equal(2, companiesTbl.Rows.Count);\n\t\t\tAssert.Equal(\"Microsoft\", companiesTbl.Rows[0][\"title\"]);\n\n\t\t\t// select aggregate\n\t\t\tvar contactsSummaryTbl = DbAdapter.Select(\n\t\t\t\tnew Query(\"contacts\").Select(\n\t\t\t\t\tQField.Count,\n\t\t\t\t\tnew QAggregateField(\"avg_score\", \"avg\", \"score\"),\n\t\t\t\t\t\"company_id\"\n\t\t\t\t)).ToDataTable();\n\n\t\t\tAssert.Equal(2, contactsSummaryTbl.Rows.Count);\n\t\t\tAssert.Equal(3, contactsSummaryTbl.Columns.Count);\n\t\t\tvar companyOneRow = contactsSummaryTbl.Rows.Cast<DataRow>().Where(r => r[\"company_id\"].ToString() == \"1\").FirstOrDefault();\n\t\t\tAssert.NotNull(companyOneRow);\n\t\t\tAssert.Equal(4M, Convert.ToDecimal( companyOneRow[\"avg_score\"] ) );\n\t\t\tAssert.Equal(3, Convert.ToInt32( companyOneRow[\"cnt\"] ));\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void Select_OffsetCount() {\n\t\t\t// pagination\n\t\t\tvar pageContactsQ = new Query(\"contacts\") { RecordOffset = 1, RecordCount = 2 }.OrderBy(\"id\");\n\t\t\tcheck(DbAdapter.Select(pageContactsQ).ToRecordSet());\n\t\t\tcheck(DbAdapter.Select(pageContactsQ).ToRecordSetAsync().GetAwaiter().GetResult());\n\n\t\t\tDbAdapter.Select(pageContactsQ).ExecuteReader<bool>(rdr => {\n\t\t\t\tvar rs = RecordSet.FromReader(rdr);\n\t\t\t\tcheck(rs);\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\tDbAdapter.Select(pageContactsQ).ExecuteReaderAsync<bool>( (rdr,cToken) => {\n\t\t\t\tvar rs = RecordSet.FromReader(rdr);\n\t\t\t\tcheck(rs);\n\t\t\t\treturn Task.FromResult(true);\n\t\t\t}, CancellationToken.None).GetAwaiter().GetResult();\n\n\t\t\tvoid check(RecordSet rs) {\n\t\t\t\tAssert.Equal(2, rs.Count);\n\t\t\t\tAssert.Equal(\"Morris Scott\", rs[0][\"name\"]);\n\t\t\t\tAssert.Equal(\"Bill Glover\", rs[1][\"name\"]);\n\t\t\t}\n\t\t}\n\n\t\t[Fact]\n\t\tpublic async Task Select_Async() {\n\t\t\t// count: table\n\t\t\tAssert.Equal(5, await DbAdapter.Select(new Query(\"contacts\").Select(QField.Count) ).SingleAsync<int>() );\n\t\t\t\n\t\t\tvar contactsWithHighScoreQuery = DbAdapter.Select(\n\t\t\t\tnew Query(\"contacts_view\", (QField)\"score\" > (QConst)4 ).OrderBy(\"name desc\")\n\t\t\t);\n\t\t\t\n\t\t\t// dictionary\n\t\t\tvar contactsWithHighDicts = await contactsWithHighScoreQuery.ToDictionaryListAsync();\n\t\t\tAssert.Equal(2, contactsWithHighDicts.Count );\t\n\t\t\t\n\t\t\t// recordset\n\t\t\tvar contactsWithHighRS = await contactsWithHighScoreQuery.ToRecordSetAsync();\n\t\t\tAssert.Equal(2, contactsWithHighRS.Count );\n\n\t\t\t// datatable\n\t\t\tvar contactsWithHighTbl = await contactsWithHighScoreQuery.ToDataTableAsync();\n\t\t\tAssert.Equal(2, contactsWithHighTbl.Rows.Count);\n\t\t\tAssert.Equal(5, contactsWithHighTbl.Columns.Count);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void SelectRawSql() {\n\t\t\t//no params\n\t\t\tAssert.Equal(5, DbAdapter.Select(\"select count(*) from contacts\").Single<int>() );\n\t\t\t// simple param\n\t\t\tAssert.Equal(5, DbAdapter.Select(\"select count(*) from contacts where id<{0}\", 100).Single<int>() );\n\t\t\tAssert.Equal(1, DbAdapter.Select(\"select count(*) from contacts where id>{0} and id<{1}\", 1, 3).Single<int>() );\n\n\t\t\t// custom db param\n\t\t\tvar customParam = new Microsoft.Data.Sqlite.SqliteParameter(\"test\", \"%John%\");\n\t\t\tAssert.Equal(1, DbAdapter.Select(\"select company_id from contacts where name like @test\", customParam).Single<int>() );\n\n\t\t\t// select raw SQL\n\t\t\tvar companyId = 1;\n\t\t\tAssert.Equal(\"Microsoft\", DbAdapter.Select(\"select title from companies where id={0}\", companyId).Single<string>());\n\t\t\tAssert.Equal(\"select title from companies where id=@p0\", SqliteDb.DbFactory.SqlLog.Last());\n\n\t\t\t// select raw SQL interpolated string\n\t\t\tAssert.Equal(\"Microsoft\", DbAdapter.Select( $\"select title from companies where id={companyId}\").Single<string>());\n\t\t\t// ensure that parametrized command is generated\n\t\t\tAssert.Equal(\"select title from companies where id=@p0\", SqliteDb.DbFactory.SqlLog.Last());\n\t\t}\n\t\t\n\t\t[Fact]\n\t\tpublic void Select_CustomMapper() {\n\t\t\t\n\t\t\tvar res = DbAdapter\n\t\t\t\t.Select(new Query(\"contacts_view\", (QField)\"name\" == (QConst)\"Morris Scott\") )\n\t\t\t\t.SetMapper( (context)=> {\n\t\t\t\t\tif (context.ObjectType==typeof(ContactModel)) {\n\t\t\t\t\t\tvar contact = (ContactModel)context.MapTo(context.ObjectType);\n\t\t\t\t\t\tcontact.Company = new CompanyModelAnnotated();\n\t\t\t\t\t\tcontact.Company.Id = Convert.ToInt32( context.DataReader[\"company_id\"] );\n\t\t\t\t\t\tcontact.Company.Name = (string)context.DataReader[\"company_title\"];\n\t\t\t\t\t\treturn contact;\n\t\t\t\t\t}\n\t\t\t\t\t// default handler\n\t\t\t\t\treturn context.MapTo(context.ObjectType);\n\t\t\t\t})\n\t\t\t\t.Single<ContactModel>();\n\t\t\tAssert.NotNull(res.Company);\n\t\t\tAssert.Equal(1, res.Company.Id.Value);\n\t\t\tAssert.Equal(\"Microsoft\", res.Company.Name);\n\t\t}\n\n\n\t\t[Fact]\n\t\tpublic void InsertUpdateDelete_Dictionary() {\n\t\t\t// insert\n\t\t\tobject recordId = null;\n\t\t\tSqliteDb.OpenConnection( () => { \n\t\t\t\tAssert.Equal(1,\n\t\t\t\t\tDbAdapter.Insert(\"main.companies\", new Dictionary<string,object>() {\n\t\t\t\t\t\t{\"title\", \"Test Inc\"},\n\t\t\t\t\t\t{\"country\", \"Norway\"},\n\t\t\t\t\t\t{\"logo_image\", null}\n\t\t\t\t\t}) );\t\t\t\t\n\t\t\t\trecordId = DbAdapter.CommandBuilder.DbFactory.GetInsertId(DbAdapter.Connection, DbAdapter.Transaction); \n\t\t\t} );\n\t\t\t// update - schema qualified\n\t\t\tAssert.Equal(1, \n\t\t\t\tDbAdapter.Update( new Query( new QTable(\"main.companies\", null), (QField)\"id\"==new QConst(recordId) ), \n\t\t\t\t\tnew Dictionary<string,object>() {\n\t\t\t\t\t\t{\"title\", \"Megacorp\"}\n\t\t\t\t\t}\n\t\t\t\t) );\n\t\t\t// update\n\t\t\tAssert.Equal(1, \n\t\t\t\tDbAdapter.Update( new Query(\"companies\", (QField)\"id\"==new QConst(recordId) ), \n\t\t\t\t\tnew Dictionary<string,object>() {\n\t\t\t\t\t\t{\"title\", \"Megacorp Inc\"}\n\t\t\t\t\t}\n\t\t\t\t) );\n\n\t\t\tvar norwayCompanyQ = new Query(\"companies\", (QField)\"country\"==(QConst)\"Norway\" );\n\n\t\t\tAssert.Equal(\"Megacorp Inc\", DbAdapter.Select(norwayCompanyQ).ToDictionary()[\"title\"]);\n\n\t\t\t// cleanup\n\t\t\tAssert.Equal(1, DbAdapter.Delete( norwayCompanyQ ) );\n\n\t\t\t// delete - schema qualified (affects 0 records)\n\t\t\tAssert.Equal(0, DbAdapter.Delete( new Query( new QTable(\"main.companies\",null), (QField)\"country\"==(QConst)\"bla\" ) ) );\n\t\t}\n\n\t\t// test for issue #48\n\t\t[Fact]\n\t\tpublic async Task Insert_InTransaction() {\n\t\t\tSqliteDb.OpenConnection(() => {\n\t\t\t\tvar tr = SqliteDb.DbConnection.BeginTransaction();\n\t\t\t\tDbAdapter.Transaction = tr;\n\t\t\t\t// insert\n\t\t\t\tvar newCompany = new CompanyModelAnnotated();\n\t\t\t\tnewCompany.Id = 5000; // should be ignored\n\t\t\t\tnewCompany.Name = null;\n\t\t\t\tDbAdapter.Insert(newCompany);\n\t\t\t\tAssert.True(newCompany.Id.HasValue && newCompany.Id.Value != 5000);\n\n\t\t\t\tAssert.Equal(1, DbAdapter.Select(new Query(\"companies\", (QField)\"title\" == DBNull.Value).Select(QField.Count)).Single<int>());\n\n\t\t\t\ttr.Rollback(); // do not save\n\t\t\t});\n\t\t}\n\n\t\t[Fact]\n\t\tpublic async Task InsertUpdateDelete_DictionaryAsync() {\n\t\t\t// insert\n\t\t\tDbAdapter.Connection.Open();\n\t\t\tAssert.Equal(1,\n\t\t\t\tawait DbAdapter.InsertAsync(\"companies\", new Dictionary<string,object>() {\n\t\t\t\t\t{\"title\", \"Test Inc\"},\n\t\t\t\t\t{\"country\", \"Norway\"}\n\t\t\t\t}).ConfigureAwait(false) );\t\t\t\t\n\t\t\tobject recordId = DbAdapter.CommandBuilder.DbFactory.GetInsertId(DbAdapter.Connection, DbAdapter.Transaction); \n\t\t\tDbAdapter.Connection.Close();\n\n\t\t\t// update\n\t\t\tAssert.Equal(1, \n\t\t\t\tawait DbAdapter.UpdateAsync( new Query(\"companies\", (QField)\"id\"==new QConst(recordId) ), \n\t\t\t\t\tnew Dictionary<string,object>() {\n\t\t\t\t\t\t{\"title\", \"Megacorp Inc\"}\n\t\t\t\t\t}\n\t\t\t\t).ConfigureAwait(false) );\n\n\t\t\tvar norwayCompanyQ = new Query(\"companies\", (QField)\"country\"==(QConst)\"Norway\" );\n\n\t\t\tAssert.Equal(\"Megacorp Inc\", DbAdapter.Select(norwayCompanyQ).ToDictionary()[\"title\"]);\n\n\t\t\t// cleanup\n\t\t\tAssert.Equal(1, await DbAdapter.DeleteAsync( norwayCompanyQ ).ConfigureAwait(false) );\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void InsertUpdateDelete_RecordSet() {\n\t\t\t\n\t\t\tvar companyRS = DbAdapter.Select(new Query(\"companies\")).ToRecordSet();\n\t\t\tcompanyRS.SetPrimaryKey(\"id\");\n\t\t\tcompanyRS.Columns[\"id\"].AutoIncrement = true;\n\n\t\t\tvar newCompany1Row = companyRS.Add();\n\t\t\tnewCompany1Row[\"title\"] = \"Test Inc\";\n\t\t\tnewCompany1Row[\"country\"] = \"Ukraine\";\n\n\t\t\tvar newCompany2Row = companyRS.Add();\n\t\t\tnewCompany2Row[\"title\"] = \"Cool Inc\";\n\t\t\tnewCompany2Row[\"country\"] = \"France\";\n\n\t\t\tAssert.Equal(4, companyRS.Count );\n\t\t\tAssert.Equal(2, DbAdapter.Update(\"companies\", companyRS) );\n\n\t\t\tAssert.True( newCompany1Row.Field<int>(\"id\")>0 );\n\t\t\tAssert.True( newCompany2Row.Field<int>(\"id\")>0 );\n\t\t\t\n\t\t\tAssert.Equal(RecordSet.RowState.Unchanged, newCompany1Row.State);\n\n\t\t\tnewCompany2Row[\"title\"] = \"Awesome Corp\";\n\t\t\tAssert.Equal(1, DbAdapter.Update(\"main.companies\", companyRS));\n\t\t\tAssert.Equal(RecordSet.RowState.Unchanged, newCompany2Row.State);\n\n\t\t\t// cleanup\n\t\t\tnewCompany1Row.Delete();\n\t\t\tnewCompany2Row.Delete();\n\t\t\tDbAdapter.Update(\"companies\", companyRS);\n\n\t\t\tAssert.Equal(2, companyRS.Count);\n\t\t\tAssert.Equal(2, DbAdapter.Select(new Query(\"companies\").Select(QField.Count) ).Single<int>() );\n\t\t}\n\n\t\t[Fact]\n\t\tpublic async Task InsertUpdateDeleteAsync_RecordSet() {\n\t\t\tvar companyRS = await DbAdapter.Select(new Query(\"companies\")).ToRecordSetAsync().ConfigureAwait(false);\n\t\t\tAssert.Equal(2, companyRS.Count);\n\t\t\tcompanyRS.SetPrimaryKey(\"id\");\n\t\t\tcompanyRS.Columns[\"id\"].AutoIncrement = true;\n\t\t\t\n\t\t\tvar newCompany1Row = companyRS.Add();\n\t\t\tnewCompany1Row[\"title\"] = \"Test Inc\";\n\t\t\tnewCompany1Row[\"country\"] = \"Ukraine\";\n\n\t\t\tAssert.Equal(1, DbAdapter.UpdateAsync(\"companies\", companyRS).GetAwaiter().GetResult() );\n\n\t\t\tAssert.NotNull(newCompany1Row[\"id\"]);\n\t\t\tAssert.Equal( RecordSet.RowState.Unchanged, newCompany1Row.State );\n\n\t\t\tnewCompany1Row[\"title\"] = \"Mega Corp\";\n\t\t\tvar newCompany2Row = companyRS.Add();\n\t\t\tnewCompany2Row[\"title\"] = \"Cool Inc\";\n\t\t\tnewCompany2Row[\"country\"] = \"France\";\n\t\t\t\n\t\t\tAssert.Equal(2, DbAdapter.UpdateAsync(\"companies\", companyRS).GetAwaiter().GetResult() );\n\t\t\t\n\t\t\tAssert.Equal(2, await DbAdapter.DeleteAsync(new Query(\"companies\", (QField)\"id\">= new QConst(newCompany1Row[\"id\"]) )) );\t\t\t\t\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void InsertUpdateDelete_PocoModel() {\n\t\t\t// insert\n\t\t\tvar newCompany = new CompanyModelAnnotated();\n\t\t\tnewCompany.Id = 5000; // should be ignored\n\t\t\tnewCompany.Name = \"Test Super Corp\";\n\t\t\tnewCompany.registered = false; // should be ignored\n\t\t\tnewCompany.Logo = new byte[] { 1,2,3 }; // lets assume this is sample binary data\n\t\t\tDbAdapter.Insert(newCompany);\n\t\t\t\n\t\t\tAssert.True(newCompany.Id.HasValue);\n\t\t\tAssert.NotEqual(5000, newCompany.Id.Value);\n\n\t\t\tAssert.Equal(\"Test Super Corp\", DbAdapter.Select(new Query(\"companies\", (QField)\"id\"==(QConst)newCompany.Id.Value).Select(\"title\") ).Single<string>() );\n\t\t\t\n\t\t\tnewCompany.Name = \"Super Corp updated\";\n\t\t\tAssert.Equal(1, DbAdapter.Update( newCompany) );\n\n\t\t\tAssert.Equal(newCompany.Name, DbAdapter.Select(new Query(\"companies\", (QField)\"id\"==(QConst)newCompany.Id.Value).Select(\"title\") ).Single<string>() );\n\n\t\t\tAssert.Equal(1, DbAdapter.Delete( newCompany ) );\n\t\t}\n\t\t\n\t\t[Fact]\n\t\tpublic async Task InsertUpdateDelete_PocoModelAsync() {\n\t\t\t// insert\n\t\t\tvar newCompany = new CompanyModelAnnotated();\n\t\t\tnewCompany.Id = 5000; // should be ignored\n\t\t\tnewCompany.Name = \"Test Super Corp\";\n\t\t\tnewCompany.registered = false; // should be ignored\n\t\t\tAssert.Equal(1, await DbAdapter.InsertAsync(newCompany).ConfigureAwait(false) );\n\t\t\t\n\t\t\tAssert.True(newCompany.Id.HasValue);\n\t\t\tAssert.NotEqual(5000, newCompany.Id.Value);\n\n\t\t\tAssert.Equal(\"Test Super Corp\", DbAdapter.Select(new Query(\"companies\", (QField)\"id\"==(QConst)newCompany.Id.Value).Select(\"title\") ).Single<string>() );\n\t\t\t\n\t\t\tnewCompany.Name = \"Super Corp updated\";\n\t\t\tAssert.Equal(1, await DbAdapter.UpdateAsync( newCompany).ConfigureAwait(false) );\n\n\t\t\tAssert.Equal(newCompany.Name, DbAdapter.Select(new Query(\"companies\", (QField)\"id\"==(QConst)newCompany.Id.Value).Select(\"title\") ).Single<string>() );\n\n\t\t\tAssert.Equal(1, await DbAdapter.DeleteAsync( newCompany ).ConfigureAwait(false) );\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void Select_MultipleResultSets() {\n\t\t\tvar batchCmdBuilder = new DbBatchCommandBuilder(DbAdapter.CommandBuilder.DbFactory);\n\t\t\tbatchCmdBuilder.BeginBatch();\n\t\t\tbatchCmdBuilder.GetSelectCommand(new Query(\"companies\"));\n\t\t\tbatchCmdBuilder.GetSelectCommand(new Query(\"contacts\"));\n\t\t\tvar selectMultipleCmd = batchCmdBuilder.EndBatch();\n\n\t\t\t(var companies, var contacts) = DbAdapter.Select(selectMultipleCmd).ExecuteReader( (rdr) => {\n\t\t\t\tvar companiesRes = new DataReaderResult(rdr).ToList<CompanyModelAnnotated>();\n\t\t\t\trdr.NextResult();\n\t\t\t\tvar contactsRes = new DataReaderResult(rdr).ToList<ContactModel>();\n\t\t\t\treturn (companiesRes, contactsRes);\n\t\t\t});\n\t\t\tAssert.Equal(2, companies.Count);\n\t\t\tAssert.Equal(5, contacts.Count);\n\t\t}\n\n\n\t\tpublic class ContactModel {\n\t\t\tpublic int? id { get; set; }\n\t\t\tpublic string name { get; set; }\n\t\t\tpublic int? company_id { get; set; }\n\n\t\t\t// property is used in custom POCO mapping handler test\n\t\t\tpublic CompanyModelAnnotated Company { get; set; }\n\t\t}\n\n\t\t[Table(\"companies\")]\n\t\tpublic class CompanyModelAnnotated {\n\t\t\t\n\t\t\t[DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n\t\t\t[Key]\n\t\t\t[Column(\"id\")]\n\t\t\tpublic int? Id { get; set; }\n\t\t\t\n\t\t\t[Column(\"title\")]\n\t\t\t[DatabaseGenerated(DatabaseGeneratedOption.None)]\n\t\t\tpublic string Name { get; set; }\n\t\t\t\n\t\t\t[Column(\"logo_image\")]\n\t\t\tpublic byte[] Logo { get; set; }\n\n\t\t\t[NotMapped]\n\t\t\tpublic bool registered { get; set; }\n\t\t}\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/NReco.Data.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <IsPackable>false</IsPackable>  \n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\NReco.Data\\NReco.Data.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.5.3\" />\n    <PackageReference Include=\"xunit\" Version=\"2.6.1\" />\n    <PackageReference Include=\"System.Data.SqlClient\" Version=\"4.8.6\" />\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.*\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/NReco.Data.Tests/QueryTests.cs",
    "content": "using System;\nusing System.ComponentModel;\nusing Xunit;\nusing NReco.Data;\n\nnamespace NReco.Data.Tests\n{\n\n\tpublic class QueryTests\n\t{\n\t\t[Fact]\n\t\tpublic void QSort() {\n\n\t\t\tQSort fld = (QSort)\"name\";\n\t\t\tAssert.Equal( fld.Field.Name, \"name\");\n\t\t\tAssert.Equal( fld.SortDirection, ListSortDirection.Ascending);\n\t\t\t\n\t\t\tfld = (QSort)\"email desc \";\n\t\t\tAssert.Equal( fld.Field.Name, \"email\");\n\t\t\tAssert.Equal( fld.SortDirection, ListSortDirection.Descending);\n\t\t\t\n\t\t\tfld = (QSort)\"email  desc \";\n\t\t\tAssert.Equal( fld.Field.Name, \"email\");\n\t\t\tAssert.Equal( fld.SortDirection, ListSortDirection.Descending);\n\n\t\t\tfld = (QSort)\"  email  desc \";\n\t\t\tAssert.Equal( fld.Field.Name, \"email\");\n\t\t\tAssert.Equal( fld.SortDirection, ListSortDirection.Descending);\t\t\t\n\t\t\t\n\t\t\tfld = (QSort)\"position asc\";\n\t\t\tAssert.Equal( fld.Field.Name, \"position\");\n\t\t\tAssert.Equal( fld.SortDirection, ListSortDirection.Ascending);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void QField() {\n\t\t\tvar f = new QField(\"simple\");\n\t\t\tAssert.Equal(\"simple\", f.Name);\n\t\t\tAssert.Null(f.Expression);\n\t\t\tAssert.Null(f.Prefix);\n\n\t\t\tf = new QField(\"t.field\");\n\t\t\tAssert.Equal(\"field\", f.Name);\n\t\t\tAssert.Null(f.Expression);\n\t\t\tAssert.Equal(\"t\", f.Prefix);\n\n\t\t\tf = new QField(\"dbo.t.field\");\n\t\t\tAssert.Equal(\"field\", f.Name);\n\t\t\tAssert.Null(f.Expression);\n\t\t\tAssert.Equal(\"dbo.t\", f.Prefix);\n\n\t\t\tf = new QField(\"sum(field)\");\n\t\t\tAssert.Equal(\"sum(field)\", f.Name);\n\t\t\tAssert.Equal(\"sum(field)\", f.Expression);\n\t\t\tAssert.Null(f.Prefix);\n\n\t\t\tf = new QField(\"sum(t.field)\");\n\t\t\tAssert.Equal(\"sum(t.field)\", f.Name);\n\t\t\tAssert.Equal(\"sum(t.field)\", f.Expression);\n\t\t\tAssert.Null(f.Prefix);\n\n\t\t\tf = new QField(\"sum(field) as  fld_test\");\n\t\t\tAssert.Equal(\"fld_test\", f.Name);\n\t\t\tAssert.Equal(\"sum(field)\", f.Expression);\n\t\t\tAssert.Null(f.Prefix);\n\n\t\t\tf = new QField(\"CAST(field as nvarchar)\");\n\t\t\tAssert.Equal(\"CAST(field as nvarchar)\", f.Name);\n\t\t\tAssert.Equal(\"CAST(field as nvarchar)\", f.Expression);\n\t\t\tAssert.Null(f.Prefix);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void QAggregateField() {\n\t\t\tvar f = new QAggregateField(\"amount_sum\", \"sum\", (QField)\"amount\");\n\t\t\tAssert.Equal(\"sum(amount)\", f.Expression);\n\t\t\tAssert.Equal(\"amount_sum\", f.Name);\n\n\t\t\t// custom sql template\n\t\t\tvar f1 = new QAggregateField(\"amount_sum\", \"COUNT(DISTINCT {0})\", (QField)\"amount\");\n\t\t\tAssert.Equal(\"COUNT(DISTINCT amount)\", f1.Expression);\n\t\t\tAssert.Equal(\"amount_sum\", f1.Name);\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void SetVars() {\n\t\t\tvar qVar1 = new QVar(\"$var1\");\n\t\t\tvar qVar2 = new QVar(\"$var2\");\n\t\t\tvar q = new Query(\"test\",\n\t\t\t\t\t(QField)\"name\" == qVar1 &\n\t\t\t\t\t(\n\t\t\t\t\t\t(QConst)1 != (QConst)2\n\t\t\t\t\t\t|\n\t\t\t\t\t\tnew Query(\"test2\", (QField)\"id\" > qVar2 )\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\tq.SetVars( (v) => {\n\t\t\t\tswitch (v.Name) {\n\t\t\t\t\tcase \"$var1\": v.Set(\"John\"); break;\n\t\t\t\t\tcase \"$var2\": v.Set(2); break;\n\t\t\t\t}\n\t\t\t});\n\t\t\tAssert.Equal(\"John\", qVar1.Value);\n\t\t\tAssert.Equal(2, qVar2.Value);\n\n\t\t\tq.SetVars( (v) => v.Unset() );\n\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var v = qVar1.Value; } );\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var v = qVar2.Value; } );\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/RecordSetTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nusing Xunit;\nusing NReco.Data;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\n\nnamespace NReco.Data.Tests\n{\n\n\tpublic class RecordSetTests\n\t{\n\n\t\tpublic static RecordSet generateRecordSet() {\n\t\t\tvar testRS = new RecordSet(new[] {\n\t\t\t\t\tnew RecordSet.Column(\"id\", typeof(int)),\n\t\t\t\t\tnew RecordSet.Column(\"name\", typeof(string)),\n\t\t\t\t\tnew RecordSet.Column(\"amount\", typeof(decimal)),\n\t\t\t\t\tnew RecordSet.Column(\"added_date\", typeof(DateTime))\n\t\t\t});\n\t\t\tfor (int i = 0; i<100; i++) {\n\t\t\t\ttestRS.Add(new object[] {\n\t\t\t\t\ti, \"Name\"+i.ToString(), i%20, new DateTime(2000, 1, 1).AddMonths(i)\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn testRS;\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void CrudOperations() {\n\t\t\t\n\t\t\tvar rs = new RecordSet(\n\t\t\t\tnew[] {\n\t\t\t\t\tnew RecordSet.Column(\"id\", typeof(int)),\n\t\t\t\t\tnew RecordSet.Column(\"name\", typeof(string)),\n\t\t\t\t\tnew RecordSet.Column(\"age\", typeof(int))\n\t\t\t\t}\n\t\t\t);\n\n\t\t\t// columns collection\n\t\t\tAssert.Equal(3, rs.Columns.Count);\n\t\t\tAssert.Equal(1, rs.Columns.GetOrdinal(\"name\"));\n\t\t\tAssert.Equal(\"age\", rs.Columns[2].Name);\n\t\t\tAssert.Equal(\"name\", rs.Columns[\"name\"].Name);\n\n\t\t\tAssert.Throws<ArgumentException>( () => {\n\t\t\t\trs.Add( new object[2]);\n\t\t\t});\n\t\t\tAssert.Throws<ArgumentException>( () => {\n\t\t\t\trs.Add( new object[4]);\n\t\t\t});\n\n\t\t\tAction<int,string,int> addRow = (id, name, age) => {\n\t\t\t\tvar r = rs.Add();\n\t\t\t\tr[\"id\"] = id;\n\t\t\t\tr[\"name\"] = name;\n\t\t\t\tr[\"age\"] = age;\n\t\t\t};\n\t\t\taddRow(1, \"John\", 25);\n\t\t\taddRow(2, \"Mary\", 28);\n\t\t\taddRow(3, \"Ray\", 32);\n\n\t\t\tAssert.Equal(3, rs.Count);\n\t\t\tAssert.Equal( RecordSet.RowState.Added, rs[0].State & RecordSet.RowState.Added  );\n\n\t\t\trs.AcceptChanges();\n\t\t\tAssert.Equal(3, rs.Count);\n\t\t\tAssert.Equal( RecordSet.RowState.Unchanged, rs[0].State );\n\n\t\t\trs[2].Delete();\n\t\t\tAssert.Equal( RecordSet.RowState.Deleted, rs[2].State);\n\t\t\trs.AcceptChanges();\n\t\t\tAssert.Equal(2, rs.Count);\n\n\t\t\t// add values array\n\t\t\trs.Add(new object[] {4, \"Adam\", 45});\n\t\t\tAssert.Equal(3, rs.Count);\n\n\t\t\t// add dictionary\n\t\t\trs.Add(new Dictionary<string,object>() {\n\t\t\t\t{\"name\", \"Gomer\"}\n\t\t\t});\n\t\t\tAssert.Equal(4, rs.Count);\n\n\t\t\t// typed accessor\n\t\t\tAssert.Equal( \"Gomer\", rs[3].Field<string>(\"name\") );\n\t\t\tAssert.Equal( null, rs[3].Field<int?>(\"age\") );\n\t\t\tAssert.Equal( 45, rs[2].Field<int?>(\"age\") );\n\n\t\t\trs[0][\"name\"] = \"Bart\";\n\t\t\tAssert.Equal( RecordSet.RowState.Modified, rs[0].State & RecordSet.RowState.Modified );\n\t\t\trs[0].AcceptChanges();\n\t\t\tAssert.Equal( RecordSet.RowState.Unchanged, rs[0].State );\n\t\t\tAssert.Equal( \"Bart\", rs[0][\"name\"] );\n\n\n\t\t\tAssert.Throws<ArgumentException>( () => {\n\t\t\t\tvar t = rs[0][\"test\"];\n\t\t\t});\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void RecordSetReader() {\n\t\t\tvar testRS = generateRecordSet();\n\n\t\t\tvar rdr = new RecordSetReader(testRS);\n\n\t\t\tAssert.True( rdr.HasRows );\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var o = rdr[0]; });\n\t\t\t\n\t\t\tAssert.True( rdr.Read() );\n\t\t\tAssert.Equal( 4, rdr.FieldCount );\n\t\t\tAssert.Equal(\"id\", rdr.GetName(0));\n\t\t\tAssert.Equal(2, rdr.GetOrdinal(\"amount\"));\n\t\t\tAssert.Equal(\"added_date\", rdr.GetName(3));\n\t\t\tAssert.Throws<IndexOutOfRangeException>( () => { var o = rdr.GetName(4); });\n\n\t\t\tAssert.Equal(0, rdr.GetInt32(0) );\n\t\t\tAssert.Equal(0, rdr[0]);\n\t\t\tAssert.Equal(\"Name0\", rdr[1]);\n\t\t\tAssert.Equal(0, rdr[2]);\n\t\t\tAssert.Equal(1, rdr.GetDateTime(3).Month);\n\n\t\t\tint cnt = 1;\n\t\t\twhile (rdr.Read()) {\n\t\t\t\tAssert.Equal(cnt, rdr[0] );\n\t\t\t\tcnt++;\n\t\t\t}\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var o = rdr[0]; });\n\n\t\t\trdr.Dispose();\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var o = rdr.FieldCount; });\n\t\t\tAssert.Throws<InvalidOperationException>( () => { var o = rdr.GetOrdinal(\"id\"); });\n\n\t\t\tAssert.Equal(100, cnt);\n\n\t\t\t// read RS from RecordSetReader\n\t\t\tvar testRSCopy = RecordSet.FromReader( new RecordSetReader(testRS) );\n\t\t\tAssert.Equal( testRS.Count, testRSCopy.Count );\n\t\t\tAssert.Equal( testRS.Columns.Count, testRSCopy.Columns.Count );\n\n\t\t\tvar testRSCopyOneRec = RecordSet.FromReader(new RecordSetReader(testRS), 1);\n\t\t\tAssert.Equal(1, testRSCopyOneRec.Count);\n\n\t\t\t// read into initialized RecordSet\n\t\t\tvar newRS = new RecordSet(\n\t\t\t\tnew[] {\n\t\t\t\t\tnew RecordSet.Column(\"id\", typeof(int)),\n\t\t\t\t\tnew RecordSet.Column(\"name\", typeof(string))\n\t\t\t\t}\n\t\t\t);\n\t\t\tnewRS.Load( new RecordSetReader(testRS) );\n\t\t\tAssert.Equal(testRS.Count, newRS.Count);\n\t\t\tAssert.Equal(\"Name99\", newRS[99].Field<string>(\"name\"));\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void RecordSet_FromModel() {\n\t\t\t\n\t\t\tvar rs1 = RecordSet.FromModel<PersonModel>();\n\n\t\t\tAssert.Equal( 5, rs1.Columns.Count );\n\t\t\tAssert.Equal( 1, rs1.PrimaryKey.Length );\n\t\t\tAssert.Equal(\"id\", rs1.PrimaryKey[0].Name );\n\t\t\tAssert.True(rs1.PrimaryKey[0].AutoIncrement );\n\t\t\tAssert.True(rs1.PrimaryKey[0].ReadOnly );   \n\t\t\t\n\t\t\tAssert.Equal(\"first_name\", rs1.Columns[1].Name );\n\t\t\t\n\t\t\tvar rs2 = RecordSet.FromModel( new PersonModel() { Id = 9, FirstName = \"John\" }, RecordSet.RowState.Modified );\n\t\t\tAssert.Equal(1, rs2.Count);\n\t\t\tAssert.Equal(9, rs2[0].Field<int>(\"id\") );\n\t\t\tAssert.Equal(\"John\", rs2[0].Field<string>(\"first_name\") );\n\t\t\tAssert.Equal(RecordSet.RowState.Modified, rs2[0].State );\n\t\t}\n\n\n\t\t[Table(\"persons\")]\n\t\tpublic class PersonModel {\n\t\t\t\n\t\t\t[DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n\t\t\t[Key]\n\t\t\t[Column(\"id\")]\n\t\t\tpublic int? Id { get; set; }\n\t\t\t\n\t\t\t[Column(\"first_name\")]\n\t\t\tpublic string FirstName { get; set; }\n\n\t\t\t[Column(\"last_name\")]\n\t\t\tpublic string LastName { get; set; }\n\t\t\t\n\t\t\t[Column(\"birthday\")]\n\t\t\tpublic DateTime? BirthDay { get; set; }\n\n\t\t\t// not annotated field\n\t\t\tpublic bool Active;\n\n\t\t\t[NotMapped]\n\t\t\tpublic string Name { \n\t\t\t\tget { return $\"{FirstName} {LastName}\"; }\n\t\t\t}\n\t\t}\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/RelexTests.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.IO;\nusing System.Xml;\nusing System.Data;\nusing System.Data.SqlClient;\n\nusing NReco.Data.Relex;\n\nusing Xunit;\n\nnamespace NReco.Data.Tests\n{\n\n\tpublic class RelexTests\n\t{\n\t\tstring[] oldRelExSamples = new string[] {\n\t\t\t\"expenses(expense_report_id = 5)[id, unit_uid, money_equivalent]\",\n\t\t\t\"tokens(id in custompage_to_token(left_uid=5 or left_uid=6)[right_uid] and type=6)[value]\",\n\t\t\t\"users(id>1 or id<=1)[*]\",\n\t\t\t\"users( id=null and id!=null )[*]\" // test for compatibility\n\t\t};\n\n\t\tstring[] oldRelExCommandTexts = new string[] {\n\t\t\t@\"SELECT id,unit_uid,money_equivalent FROM expenses WHERE expense_report_id=@p0\",\n\t\t\t@\"SELECT value FROM tokens WHERE (id IN (SELECT right_uid FROM custompage_to_token WHERE (left_uid=@p0) Or (left_uid=@p1))) And (type=@p2)\",\n\t\t\t@\"SELECT * FROM users WHERE (id>@p0) Or (id<=@p1)\",\n\t\t\t@\"SELECT * FROM users WHERE (id IS  NULL) And (id IS NOT NULL)\"\n\t\t};\n\n\n\t\tstring[] relExSamples = new string[] {\n\t\t\t\"accounts(login = \\\"Mike\\\" or id<=parent_id)[*]\",\n\t\t\t\"accounts(login = \\\"vit\\\"\\\"alik\\\" or id<=5)[*]\",\n\t\t\t\"accounts(1=2)[max(id),min(id)]\",\n\t\t\t\"users(id=\\\"\\\")[*]\",\n\t\t\t\"users_view[count]\",\n\t\t\t\"users( (id>\\\"1\\\" and id<\\\"5\\\") or (name like \\\"AAA\\\" and age<\\\"25\\\") )[*]\",\n\t\t\t\"users( (<idGroup> id>\\\"1\\\" and id<\\\"5\\\") or age<\\\"25\\\":int32 )[*]\",\n\t\t\t\"users( id in \\\"1,2,3\\\":int32[] and id !in \\\"4,5\\\":int32[] and id!=0 )[*]\",\n\t\t\t\"users( id=null and id!=null )[count(*)]\",\n\t\t\t\n\t\t\t\"users( (id!=1 and id!=2) and id!=3)[name]\",\n\t\t\t\"users( (<grname> id!=1 and id!=2) and id!=3)[name]\",\n\t\t\t\"users( (id!=1 and id!=2) and (id!=3))[name]\",\n\t\t\t\"users( (id!=1 and id!=2) and (id!=3 and id!=4))[name]\",\n\t\t\t\"users( (id!=1 and id!=2) and (id!=3 and (id!=4)))[name]\",\n\t\t\t\"users( (id!=1 and id!=2) and (( (id!=3 and (id!=4))) ))[name]\",\n\t\t\t\"users( (id!=1 and id!=2) or (id!=3))[name]\",\n\t\t\t\"users( 1=1 )[name;name,login]\",\n\t\t\t\"users( 1=1 )[name;\\\"name desc\\\"]\",\n\t\t\t\"users( 1=1 )[name;name desc,id asc,time]\",\n\t\t\t\"users( \\\"id\\\":field = 5 )[*]\",\n\t\t\t\"users( \\\"[user id]\\\":sql = 1 )[name, \\\"[last name]\\\"]\",\n\t\t\t\"\\\"company users.u\\\":table[\\\"u.User ID\\\"]\",\n\t\t\t\"users( (id!=1 and id!=2) or not(id=3))[name]\",\n\t\t\t\"users( not id=1 and id!=2 )[name]\",\n\t\t};\n\n\t\tstring[] relExCommandTexts = new string[] {\n\t\t\t@\"SELECT * FROM accounts WHERE (login=@p0) Or (id<=parent_id)\",\n\t\t\t@\"SELECT * FROM accounts WHERE (login=@p0) Or (id<=@p1)\",\n\t\t\t@\"SELECT max(id),min(id) FROM accounts WHERE @p0=@p1\",\n\t\t\t@\"SELECT * FROM users WHERE id=@p0\",\n\t\t\t@\"SELECT count FROM users_view\",\n\t\t\t@\"SELECT * FROM users WHERE ((id>@p0) And (id<@p1)) Or ((name LIKE @p2) And (age<@p3))\",\n\t\t\t@\"SELECT * FROM users WHERE ((id>@p0) And (id<@p1)) Or (age<@p2)\",\n\t\t\t@\"SELECT * FROM users WHERE (id IN (@p0,@p1,@p2)) And (NOT (id IN (@p3,@p4))) And (id<>@p5)\",\n\t\t\t@\"SELECT count(*) FROM users WHERE (id IS  NULL) And (id IS NOT NULL)\",\n\t\t\t\n\t\t\t@\"SELECT name FROM users WHERE (id<>@p0) And (id<>@p1) And (id<>@p2)\",\n\t\t\t@\"SELECT name FROM users WHERE ((id<>@p0) And (id<>@p1)) And (id<>@p2)\",\n\t\t\t@\"SELECT name FROM users WHERE (id<>@p0) And (id<>@p1) And (id<>@p2)\",\n\t\t\t@\"SELECT name FROM users WHERE (id<>@p0) And (id<>@p1) And (id<>@p2) And (id<>@p3)\",\n\t\t\t@\"SELECT name FROM users WHERE (id<>@p0) And (id<>@p1) And (id<>@p2) And (id<>@p3)\",\n\t\t\t@\"SELECT name FROM users WHERE (id<>@p0) And (id<>@p1) And (id<>@p2) And (id<>@p3)\",\n\t\t\t@\"SELECT name FROM users WHERE ((id<>@p0) And (id<>@p1)) Or (id<>@p2)\",\n\t\t\t@\"SELECT name FROM users WHERE @p0=@p1 ORDER BY name asc,login asc\",\n\t\t\t@\"SELECT name FROM users WHERE @p0=@p1 ORDER BY name desc\",\n\t\t\t@\"SELECT name FROM users WHERE @p0=@p1 ORDER BY name desc,id asc,time asc\",\n\t\t\t@\"SELECT * FROM users WHERE id=@p0\",\n\t\t\t@\"SELECT name,[last name] FROM users WHERE [user id]=@p0\",\n\t\t\t@\"SELECT u.[User ID] FROM [company users] u\",\n\t\t\t@\"SELECT name FROM users WHERE ((id<>@p0) And (id<>@p1)) Or (NOT(id=@p2))\",\n\t\t\t@\"SELECT name FROM users WHERE (NOT(id=@p0)) And (id<>@p1)\",\n\t\t};\n\n\t\tstring[] relExInvalidSyntaxSamples = new string[] {\n\t\t\t\"users[id\",\n\t\t\t\"1 and 2\",\n\t\t\t\"users(a=1 andd b=2)[*]\"\n\t\t};\n\n\t\tstring[] relExConditionInvalidSyntaxSamples = new string[] {\n\t\t\t\"1 and \",\n\t\t\t\"a=1 andd b=2\"\n\t\t};\n\n\t\t[Fact]\n\t\tpublic void test_Parse() {\n\t\t\tvar relExParser = new RelexParser();\n\t\t\t\n\t\t\t// generate SQL by query\n\t\t\tvar dbFactory = new TestRelExDbFactory();\n\t\t\tvar cmdGenerator = new DbCommandBuilder(dbFactory);\n\n\t\t\tfor (int i=0; i<oldRelExSamples.Length; i++) {\n\t\t\t\tstring relEx = oldRelExSamples[i];\n\t\t\t\tQuery q = relExParser.Parse(relEx);\n\t\t\t\tIDbCommand cmd = cmdGenerator.GetSelectCommand( q );\n\n\t\t\t\tAssert.Equal(oldRelExCommandTexts[i], cmd.CommandText.Trim() );\n\t\t\t}\n\t\t\t\n\t\t\tfor (int i=0; i<relExSamples.Length; i++) {\n\t\t\t\tstring relEx = relExSamples[i];\n\t\t\t\tQuery q = relExParser.Parse(relEx);\n\t\t\t\tIDbCommand cmd = cmdGenerator.GetSelectCommand( q );\n\t\t\t\t\n\t\t\t\tAssert.Equal( relExCommandTexts[i], cmd.CommandText.Trim() );\n\t\t\t}\n\n\t\t\t// test for named nodes\n\t\t\tstring relexWithNamedNodes = @\"users( (<idGroup> id=null and id!=null) and (<ageGroup> age>5 or age<2) and (<emptyGroup>) )[count(*)]\";\n\t\t\tQuery qWithGroups = relExParser.Parse(relexWithNamedNodes);\n\t\t\tAssert.NotEqual(null, FindNodeByName(qWithGroups.Condition, \"idGroup\") );\n\t\t\tAssert.NotEqual(null, FindNodeByName(qWithGroups.Condition, \"ageGroup\") );\n\t\t\tAssert.NotEqual(null, FindNodeByName(qWithGroups.Condition, \"emptyGroup\") );\n\t\t\n\t\t\t// just a parse test for real complex relex\n\t\t\tstring sss = \"sourcename( ( ((\\\"False\\\"=\\\"True\\\") or (\\\"False\\\"=\\\"True\\\")) and \\\"contact-of\\\" in agent_to_agent_role( left_uid in agent_accounts(agent_accounts.id=\\\"\\\")[agent_id] and (right_uid=agent_institutions.id) )[role_uid] ) or ( ((agent_institutions.id in events( events.id in event_assignments( person_id in agent_accounts (agent_accounts.id=\\\"\\\")[agent_id] )[event_id] )[client_institution_id]) or (agent_institutions.id in events( events.id in event_assignments( person_id in agent_accounts (agent_accounts.id=\\\"\\\")[agent_id] )[event_id] )[supplier_institution_id])) and (\\\"False\\\"=\\\"True\\\") ) or ( (agent_institutions.id in agent_to_agent_role( (left_uid in agent_to_agent_role( left_uid in agent_accounts(agent_accounts.id=\\\"\\\")[agent_id] and role_uid='contact-of' )[right_uid]) and role_uid='supplier-of')[right_uid] ) or (agent_institutions.id in events( events.supplier_institution_id in agent_to_agent_role( (agent_to_agent_role.role_uid='contact-of') and (agent_to_agent_role.left_uid in agent_accounts(agent_accounts.id=\\\"\\\")[agent_id]) )[agent_to_agent_role.right_uid] )[events.client_institution_id]) or (agent_institutions.id in events( events.client_institution_id in agent_to_agent_role( (agent_to_agent_role.role_uid='contact-of') and (agent_to_agent_role.left_uid in agent_accounts(agent_accounts.id=\\\"\\\")[agent_id]) )[agent_to_agent_role.right_uid] )[events.supplier_institution_id]) ) or (\\\"False\\\"=\\\"True\\\") or ( (\\\"False\\\"=\\\"True\\\") and (agent_institutions.id in agent_to_agent_role( role_uid='supplier-of' and right_uid = \\\"\\\" )[left_uid]) ) or (\\\"False\\\"=\\\"True\\\") )[*]\";\n\t\t\trelExParser.Parse(sss);\n\n\n\t\t\tvar complexSortAndFields = \"users.u( u.id=1 )[\\\"name+','\\\";id asc,id desc,\\\"sum(id)\\\"]\";\n\t\t\tvar complexQ = relExParser.Parse(complexSortAndFields);\n\t\t\tAssert.Equal(1, complexQ.Fields.Length);\n\t\t\tAssert.Equal(3, complexQ.Sort.Length);\n\n\t\t\tforeach (var invalidRelex in relExInvalidSyntaxSamples)\n\t\t\t\tAssert.Throws<RelexParseException>(() => {\n\t\t\t\t\trelExParser.Parse(invalidRelex);\n\t\t\t\t});\n\t\t\tforeach (var invalidRelexCnd in relExConditionInvalidSyntaxSamples)\n\t\t\t\tAssert.Throws<RelexParseException>(() => {\n\t\t\t\t\trelExParser.ParseCondition(invalidRelexCnd);\n\t\t\t\t});\n\t\t\t\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void test_RelexParseSpeed() {\n\t\t\tvar relExParser = new RelexParser();\n\n\t\t\tvar stopwatch = new System.Diagnostics.Stopwatch();\n\t\t\tstopwatch.Start();\n\t\t\tvar iterations = 1000;\n\t\t\tfor (int iter = 0; iter < iterations; iter++) {\n\t\t\t\tfor (int i = 0; i < relExSamples.Length; i++) {\n\t\t\t\t\tstring relEx = relExSamples[i];\n\t\t\t\t\tQuery q = relExParser.Parse(relEx);\n\t\t\t\t}\n\t\t\t}\n\t\t\tstopwatch.Stop();\n\t\t\tConsole.WriteLine(\"Speedtest for relex parse ({1} times): {0}\", stopwatch.Elapsed, iterations * relExSamples.Length); \n\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void test_RelexVar() {\n\t\t\tvar relExParser = new RelexParser();\n\t\t\tvar cnd = relExParser.ParseCondition(\"\\\"hey:%{0}\\\":var = \\\"hey\\\" \");\n\t\t\tAssert.True(cnd is QConditionNode);\n\t\t\tAssert.True(((QConditionNode)cnd).LValue is QVar);\n\t\t\t((QVar)((QConditionNode)cnd).LValue).Set(\"yeh\");\n\n\t\t\tAssert.Equal(\"\\\"%yeh\\\"=\\\"hey\\\"\", new RelexBuilder().BuildRelex(cnd) );\n\t\t}\n\n\t\tprotected QNode FindNodeByName(QNode node, string name) {\n\t\t\tif (node.Name!=null && node.Name==name)\n\t\t\t\treturn node;\n\t\t\tif (node.Nodes!=null)\n\t\t\t\tforeach (QNode cNode in node.Nodes) {\n\t\t\t\t\tQNode r = FindNodeByName(cNode, name);\n\t\t\t\t\tif (r!=null) return r;\n\t\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tQuery[] querySamples = new [] {\n\t\t\tnew Query(\"users\", (QField)\"id\"==(QConst)5 ).Select(\"id\",\"name\"),\n\t\t\tnew Query(\"users\", \n\t\t\t\tnew QConditionNode( (QField)\"company_id\", Conditions.In,\n\t\t\t\t\tnew Query(\"companies.c\").Select(\"c.id\") )\t\n\t\t\t),\n\t\t\tnew Query(\"Purchase Orders\", (QField)\"PO Number\" == (QConst) \"1111\" ),\n\t\t\tnew Query(\"accounts\", (QField)\"id\"==new QVar(\"id\")) {\n\t\t\t\tRecordOffset = 10\n\t\t\t}\n\t\t};\n\t\tstring[] queryToRelexResults = new [] {\n\t\t\t\"users(id=\\\"5\\\":Int32)[id,name]\",\n\t\t\t\"users(company_id in companies.c[c.id])[*]\",\n\t\t\t\"\\\"Purchase Orders\\\":table(\\\"PO Number\\\":field=\\\"1111\\\")[*]\",\n\t\t\t\"accounts(id=\\\"id\\\":var)[*]{10,2147483647}\"\n\t\t};\n\t\t\n\t\t[Fact]\n\t\tpublic void test_RelexBuilder() {\n\t\t\tvar relexBuilder = new RelexBuilder();\n\t\t\tfor (int i=0; i<querySamples.Length; i++) {\n\t\t\t\tAssert.Equal( queryToRelexResults[i], relexBuilder.BuildRelex(querySamples[i]) );\n\t\t\t}\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void test_GetLexem() {\n\t\t\tTestRelExQueryParser relExParser = new TestRelExQueryParser();\n\t\t\t\n\t\t\tstring expression = relExSamples[0];\n\t\t\tint startIdx = 0;\n\t\t\tint endIdx = 0;\n\t\t\tRelexParser.LexemType lexemType;\n\n\t\t\tvar testLexemTypeSeq = new string[] {\n\t\t\t\t\"Name\", \"accounts\",\n\t\t\t\t\"Delimiter\", \"(\",\n\t\t\t\t\"Name\", \"login\",\n\t\t\t\t\"Delimiter\", \"=\",\n\t\t\t\t\"QuotedConstant\", \"\\\"Mike\\\"\",\n\t\t\t\t\"Name\", \"or\",\n\t\t\t\t\"Name\", \"id\",\n\t\t\t\t\"Delimiter\", \"<\",\n\t\t\t\t\"Delimiter\", \"=\",\n\t\t\t\t\"Name\", \"parent_id\",\n\t\t\t\t\"Delimiter\", \")\",\n\t\t\t\t\"Delimiter\", \"[\",\n\t\t\t\t\"Delimiter\", \"*\",\n\t\t\t\t\"Delimiter\", \"]\"\n\t\t\t};\n\n\t\t\tint idx = 0;\n\t\t\twhile ( (lexemType=relExParser.TestGetLexemType(expression,startIdx, out endIdx))!=RelexParser.LexemType.Stop) {\n\t\t\t\tvar testLexemType = testLexemTypeSeq[idx*2];\n\t\t\t\tvar testLexemVal = testLexemTypeSeq[idx*2+1];\n\t\t\t\tAssert.Equal(testLexemType, lexemType.ToString() );\n\t\t\t\tAssert.Equal(testLexemVal, expression.Substring(startIdx, endIdx-startIdx).Trim() );\n\t\t\t\tstartIdx = endIdx;\n\n\t\t\t\tidx++;\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic class TestRelExDbFactory : DbFactory {\n\t\t\t\n\t\t\tpublic TestRelExDbFactory() : base(SqlClientFactory.Instance) {\n\t\t\t\tIdentifierFormat = \"[{0}]\";\n\t\t\t}\n\n\t\t\tprotected override string ApplyIdentifierFormat(string name) {\n\t\t\t\tif (IsSimpleIdentifier(name) || (name.StartsWith(\"[\") && name.EndsWith(\"]\") ))\n\t\t\t\t\treturn name;\n\t\t\t\treturn base.ApplyIdentifierFormat(name);\n\t\t\t}\n\n\t\t\tbool IsSimpleIdentifier(string s) {\n\t\t\t\tfor (int i=0; i<s.Length; i++) {\n\t\t\t\t\tvar ch = s[i];\n\t\t\t\t\tif (!Char.IsLetterOrDigit(ch) && ch!='-' && ch!='_')\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\t\t\t\n\t\t\t}\n\t\t}\n\n\t\t\n\t\tpublic class TestRelExQueryParser : RelexParser {\n\t\t\t\n\t\t\tpublic RelexParser.LexemType TestGetLexemType(string s, int startIdx, out int endIdx) {\n\t\t\t\treturn GetLexemType(s, startIdx, out endIdx);\n\t\t\t}\n\t\t\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/SqliteDbFixture.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.IO;\n\nusing System.Data;\nusing System.Data.Common;\nusing Microsoft.Data.Sqlite;\nusing System.Threading;\n\nnamespace NReco.Data.Tests\n{\n    public class SqliteDbFixture : IDisposable\n    {\n\t\tpublic SqliteConnection DbConnection;\t\n\t\tpublic SqlLogDbFactory DbFactory;\n\n\t\tpublic string DbFileName;\n\n\t\tpublic SqliteDbFixture() {\n\t\t\tDbFileName = Path.GetTempFileName()+\".sqlite\";\n\n\t\t\tDbConnection = new SqliteConnection( $\"Data Source={DbFileName}\" );\n\t\t\tDbFactory = new SqlLogDbFactory(Microsoft.Data.Sqlite.SqliteFactory.Instance) {\n\t\t\t\tLastInsertIdSelectText = \"SELECT last_insert_rowid()\"\n\t\t\t};\n\t\t\tCreateDb();\n\t\t}\n\n\t\tvoid CreateDb() {\n\t\t\tExecute(@\"CREATE TABLE [companies]  (\n\t\t\t\t\t[id] INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\t\t\t\t[title] TEXT,\n\t\t\t\t\t[country] TEXT,\n\t\t\t\t\t[size] INTEGER,\n\t\t\t\t\t[registered] TEXT,\n\t\t\t\t\t[logo_image] BLOB\n\t\t\t\t)\");\n\t\t\tExecute(@\"INSERT INTO [companies] (title,country,size,registered) VALUES ('Microsoft', 'USA', 118000, '1975-04-04')\");\n\t\t\tExecute(@\"INSERT INTO [companies] (title,country,size,registered) VALUES ('Atlassian', 'Australia', 1259, '2002')\");\n\n\t\t\tExecute(@\"CREATE TABLE [contacts]  (\n\t\t\t\t\t[id] INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\t\t\t\t[name] TEXT,\n\t\t\t\t\t[company_id] INTEGER,\n\t\t\t\t\t[score] INTEGER\n\t\t\t\t)\");\n\t\t\tExecute(@\"INSERT INTO [contacts] (name,company_id,score) VALUES ('John Doe', 1, 5)\");\t\t\t\n\t\t\tExecute(@\"INSERT INTO [contacts] (name,company_id,score) VALUES ('Morris Scott', 1, 4)\");\t\n\t\t\tExecute(@\"INSERT INTO [contacts] (name,company_id,score) VALUES ('Bill Glover', 1, 3)\");\n\n\t\t\tExecute(@\"INSERT INTO [contacts] (name,company_id,score) VALUES ('Edward Jordan', 2, 4)\");\n\t\t\tExecute(@\"INSERT INTO [contacts] (name,company_id,score) VALUES ('Viola Garrett', 2, 5)\");\n\t\t}\n\n\t\tvoid Execute(string sql) {\n\t\t\tvar cmd = new SqliteCommand(sql);\n\t\t\tcmd.Connection = DbConnection;\n\t\t\tOpenConnection( () => cmd.ExecuteNonQuery() );\n\t\t}\n\n\t\tpublic void OpenConnection( Action a ) {\n\t\t\tDbConnection.Open();\n\t\t\ttry {\n\t\t\t\ta();\n\t\t\t} finally {\n\t\t\t\tDbConnection.Close();\n\t\t\t}\t\t\t\n\t\t}\n\n\t\tpublic void Dispose() {\n\t\t\tSqliteConnection.ClearPool(DbConnection);\n\t\t\tDbConnection.Dispose();\n\t\t\tif (File.Exists(DbFileName))\n\t\t\t\tFile.Delete(DbFileName);\n\t\t}\n\n\t\t// collects SQL command texts of executed queries.\n\t\tpublic class SqlLogDbFactory : DbFactory {\n\n\t\t\tpublic List<string> SqlLog { get; private set; } = new List<string>();\n\n\t\t\tpublic SqlLogDbFactory(DbProviderFactory dbPrvFactory) : base(dbPrvFactory) {\n\n\t\t\t}\n\n\t\t\tpublic override IDbCommand CreateCommand() {\n\t\t\t\tvar realCmd = (DbCommand)base.CreateCommand();\n\t\t\t\treturn new SqlLogDbCommand(realCmd, this);\n\t\t\t}\n\n\t\t\tpublic class SqlLogDbCommand : DbCommand {\n\t\t\t\tDbCommand DbCmd;\n\t\t\t\tSqlLogDbFactory LogDbFactory;\n\n\t\t\t\tinternal SqlLogDbCommand(DbCommand realCmd, SqlLogDbFactory logDbFactory) {\n\t\t\t\t\tDbCmd = realCmd;\n\t\t\t\t\tLogDbFactory = logDbFactory;\n\t\t\t\t}\n\n\t\t\t\tpublic override string CommandText { get => DbCmd.CommandText; set => DbCmd.CommandText = value; }\n\t\t\t\tpublic override int CommandTimeout { get => DbCmd.CommandTimeout; set => DbCmd.CommandTimeout = value; }\n\t\t\t\tpublic override CommandType CommandType { get => DbCmd.CommandType; set => DbCmd.CommandType = value; }\n\t\t\t\tpublic override bool DesignTimeVisible { get => DbCmd.DesignTimeVisible; set => DbCmd.DesignTimeVisible = value; }\n\t\t\t\tpublic override UpdateRowSource UpdatedRowSource { get => DbCmd.UpdatedRowSource; set => DbCmd.UpdatedRowSource = value; }\n\t\t\t\tprotected override DbConnection DbConnection { get => DbCmd.Connection; set => DbCmd.Connection = value; }\n\t\t\t\tprotected override DbParameterCollection DbParameterCollection => DbCmd.Parameters;\n\t\t\t\tprotected override DbTransaction DbTransaction { get => DbCmd.Transaction; set => DbCmd.Transaction = value; }\n\n\t\t\t\tpublic override void Cancel() {\n\t\t\t\t\tDbCmd.Cancel();\n\t\t\t\t}\n\n\t\t\t\tpublic override void Prepare() {\n\t\t\t\t\tDbCmd.Prepare();\n\t\t\t\t}\n\n\t\t\t\tprotected override DbParameter CreateDbParameter() {\n\t\t\t\t\treturn DbCmd.CreateParameter();\n\t\t\t\t}\n\n\t\t\t\tT ExecuteWithLogging<T>(Func<T> exec) {\n\t\t\t\t\tLogDbFactory.SqlLog.Add(CommandText);\n\t\t\t\t\treturn exec();\n\t\t\t\t}\n\n\t\t\t\tTask<T> ExecuteWithLogging<T>(Func<Task<T>> exec) {\n\t\t\t\t\tLogDbFactory.SqlLog.Add(CommandText);\n\t\t\t\t\treturn exec();\n\t\t\t\t}\n\n\t\t\t\tpublic override int ExecuteNonQuery() {\n\t\t\t\t\treturn ExecuteWithLogging(DbCmd.ExecuteNonQuery);\n\t\t\t\t}\n\n\t\t\t\tpublic override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken) {\n\t\t\t\t\treturn ExecuteWithLogging(() => DbCmd.ExecuteNonQueryAsync(cancellationToken));\n\t\t\t\t}\n\n\t\t\t\tpublic override object ExecuteScalar() {\n\t\t\t\t\treturn ExecuteWithLogging(DbCmd.ExecuteScalar);\n\t\t\t\t}\n\n\t\t\t\tpublic override Task<object> ExecuteScalarAsync(CancellationToken cancellationToken) {\n\t\t\t\t\treturn ExecuteWithLogging(() => DbCmd.ExecuteScalarAsync(cancellationToken));\n\t\t\t\t}\n\n\t\t\t\tprotected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) {\n\t\t\t\t\treturn ExecuteWithLogging(() => DbCmd.ExecuteReader(behavior));\n\t\t\t\t}\n\n\t\t\t\tprotected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) {\n\t\t\t\t\treturn ExecuteWithLogging(() => DbCmd.ExecuteReaderAsync(behavior, cancellationToken));\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t}\n\n\n\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.Tests/StringTemplateTests.cs",
    "content": "using System;\nusing System.ComponentModel;\nusing System.Collections.Generic;\n\nusing Xunit;\n\nnamespace NReco.Data.Tests\n{\n\n\tpublic class StringTemplateTests {\n\t\t[Fact]\n\t\tpublic void FormatTemplate() {\n\t\t\tvar testStr = \"TEST @SqlOrderBy[order by {0};order by u.id desc] TEST\";\n\t\t\tvar strTpl = new StringTemplate(testStr);\n\t\t\tstrTpl.ReplaceMissedTokens = false;\n\t\t\tAssert.Equal(testStr, strTpl.FormatTemplate(new Dictionary<string, object>()));\n\t\t\tstrTpl.ReplaceMissedTokens = true;\n\t\t\tAssert.Equal(\"TEST order by u.id desc TEST\", strTpl.FormatTemplate(new Dictionary<string, object>()));\n\n\t\t\tAssert.Equal(\"TEST order by name TEST\", strTpl.FormatTemplate(\n\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t{\"SqlOrderBy\", \"name\"}\n\t\t\t\t}));\n\n\n\t\t\tAssert.Equal(\"1+2\",\n\t\t\t\tnew StringTemplate(\"@A[{0}+@B]\", 2).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tAssert.Equal(\"No replace: @Test\",\n\t\t\t\tnew StringTemplate(\"No replace: @@Test\").FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"Test\", \"bla\"}\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tAssert.Equal(\n\t\t\t\t\"and 1=2\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"@class_id[and id in metadata_property_to_class(class_id=\\\"class_id\\\":var)[property_id]];and 1=2]\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"class_id\", \"\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\n\t\t\tAssert.Equal(\n\t\t\t\t\"{ $and: [ {\\\"_id\\\":{$exists:true}},  { \\\"borough\\\" : \\\"1\\\" },   { \\\"cuisine\\\" : { $regex : \\\"2\\\" } },   ] }\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"{ $and: [ {\\\"_id\\\":{$exists:true}}, @borough[ {{ \\\"borough\\\" : {0} }}, ] @cuisine[ {{ \\\"cuisine\\\" : {{ $regex : {0} }} }}, ]  ] }\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"borough\", \"\\\"1\\\"\"},\n\t\t\t\t\t\t{\"cuisine\", \"\\\"2\\\"\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\n\t\t\tAssert.Equal(\n\t\t\t\t\"zzz@WAW;[]\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"zzz@A[@WAW;;[]]]\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"A\", \"1\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\t\t\tAssert.Equal(\n\t\t\t\t\"zzz [] \",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"zzz@A[\\\\;; [\\\\] ]\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"A\", \"\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\n\t\t\t// placeholder syntax @(name)\n\t\t\tAssert.Equal(\n\t\t\t\t\"@(AAA\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"@(AAA\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() { { \"AAA\", \"BBB\" } }\n\t\t\t\t)\n\t\t\t);\n\t\t\tAssert.Equal(\n\t\t\t\t\"BBB\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"@(AAA)\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() { { \"AAA\", \"BBB\" } }\n\t\t\t\t)\n\t\t\t);\n\t\t\tAssert.Equal(\n\t\t\t\t\"AAA_BBB\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\"@(123)_@aaa\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"123\", \"AAA\"},\n\t\t\t\t\t\t{\"aaa\", \"BBB\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\t\t\tAssert.Equal(\n\t\t\t\t\" _B_\",\n\t\t\t\tnew StringTemplate(\n\t\t\t\t\t\" @(A)[_{0}_]\").FormatTemplate(\n\t\t\t\t\tnew Dictionary<string, object>() {\n\t\t\t\t\t\t{\"A\", \"B\"}\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t);\n\n\t\t}\n\n\t\t[Fact]\n\t\tpublic void NestedTokens() {\n\t\t\tAssert.Equal(\"1+(2) \",\n\t\t\t\t(new StringTemplate(\"@A[{0}+@B[({0})] ]\") {\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2\",\n\t\t\t\t(new StringTemplate(\"@A[@B]\") {\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"@1\",\n\t\t\t\t(new StringTemplate(\"@A[@{0}]\") {\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"3+2+1\",\n\t\t\t\t(new StringTemplate(\"@A[@B[@C+{0}]+{0}]\") {\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}, {\"C\", 3}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2]\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[1;2\\]]]\") {\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", null}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2]\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[1;2]\\]]\") { // escaped \\] in nested\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", null}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2]\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[1;2]]]]\") {  // double ]] in outer\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", null}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2-]]\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[1;2]]-]]\") {  // external ]] remains ]]\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", null}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"2[\\\\]\",\n\t\t\t\t(new StringTemplate(@\"@A[@B\\[\\\\\\]]\") {  // backslash escaped \n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tAssert.Equal(\"{ 2 }\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[{{ {0} }}]]\") {  // escaped { inside nested\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tAssert.Equal(\"{0}\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[\\{0\\}]]\") {  // escaped { inside nested\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}\n\t\t\t\t})\n\t\t\t);\n\t\t\tAssert.Equal(\"{[{}]}\",\n\t\t\t\t(new StringTemplate(@\"@A[@B[\\{@C[\\[\\{\\}\\]]\\}]]\") {  // escaped { inside nested\n\t\t\t\t\tReplaceNestedTokens = true\n\t\t\t\t}).FormatTemplate(new Dictionary<string, object>() {\n\t\t\t\t\t{\"A\", 1}, {\"B\", 2}, {\"C\", 3}\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/NReco.Data.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26114.2\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"NReco.Data\", \"NReco.Data\\NReco.Data.csproj\", \"{42A98B2C-6070-4CDC-A760-795CC1BE66B1}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"NReco.Data.Tests\", \"NReco.Data.Tests\\NReco.Data.Tests.csproj\", \"{DC35C7B5-853C-4953-91F0-820E1437CE74}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{42A98B2C-6070-4CDC-A760-795CC1BE66B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{42A98B2C-6070-4CDC-A760-795CC1BE66B1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{42A98B2C-6070-4CDC-A760-795CC1BE66B1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{42A98B2C-6070-4CDC-A760-795CC1BE66B1}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DC35C7B5-853C-4953-91F0-820E1437CE74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DC35C7B5-853C-4953-91F0-820E1437CE74}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DC35C7B5-853C-4953-91F0-820E1437CE74}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DC35C7B5-853C-4953-91F0-820E1437CE74}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E138270B-84B3-4A0C-82E6-CE283F9D53EA}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  }
]