text:
//
// Copyright (c) 2012 Krueger Systems, Inc.
// Copyright (c) 2013 Øystein Krog (oystein.krog@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using JetBrains.Annotations;
using SQLite.Net.Attributes;
using SQLite.Net.Interop;

namespace SQLite.Net
{
    /// <summary>
    ///     Represents an open connection to a SQLite database.
    /// </summary>
    [PublicAPI]
    public class SQLiteConnection : IDisposable
    {
        internal static readonly IDbHandle NullHandle = default(IDbHandle);

        /// <summary>
        ///     Used to list some code that we want the MonoTouch linker
        ///     to see, but that we never want to actually execute.
        /// </summary>
#pragma warning disable 649
        private static bool _preserveDuringLinkMagic;
#pragma warning restore 649
        private readonly Random _rand = new Random();
        private readonly IDictionary<string, TableMapping> _tableMappings;
        private TimeSpan _busyTimeout;
        private long _elapsedMilliseconds;
        private IDictionary<TableMapping, ActiveInsertCommand> _insertCommandCache;
        private bool _open;
        private IStopwatch _sw;
        private int _transactionDepth;

        static SQLiteConnection()
        {
            if (_preserveDuringLinkMagic)
            {
                // ReSharper disable once UseObjectOrCollectionInitializer
                var ti = new ColumnInfo();
                ti.Name = "magic";
            }
        }

        /// <summary>
        ///     Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
        /// </summary>
        /// <param name="sqlitePlatform"></param>
        /// <param name="databasePath">
        ///     Specifies the path to the database file.
        /// </param>
        /// <param name="storeDateTimeAsTicks">
        ///     Specifies whether to store DateTime properties as ticks (true) or strings (false). You
        ///     absolutely do want to store them as Ticks in all new projects. The option to set false is
        ///     only here for backwards compatibility. There is a *significant* speed advantage, with no
        ///     down sides, when setting storeDateTimeAsTicks = true.
        /// </param>
        /// <param name="serializer">
        ///     Blob serializer to use for storing undefined and complex data structures. If left null
        ///     these types will thrown an exception as usual.
        /// </param>
        /// <param name="tableMappings">
        ///     Exisiting table mapping that the connection can use. If its null, it creates the mappings,
        ///     if and when required. The mappings are also created when an unknown type is used for the first
        ///     time.
        /// </param>
        /// <param name="extraTypeMappings">
        ///     Any extra type mappings that you wish to use for overriding the default for creating
        ///     column definitions for SQLite DDL in the class Orm (snake in Swedish).
        /// </param>
        /// <param name="resolver">
        ///     A contract resovler for resolving interfaces to concreate types during object creation
        /// </param>
        [PublicAPI]
        public SQLiteConnection(
            ISQLitePlatform sqlitePlatform,
            string databasePath,
            bool storeDateTimeAsTicks = true,
            IBlobSerializer serializer = null,
            IDictionary<string, TableMapping> tableMappings = null,
            IDictionary<Type, string> extraTypeMappings = null,
            IContractResolver resolver = null)
            : this(sqlitePlatform, databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks,
                serializer, tableMappings, extraTypeMappings, resolver)
        {
        }

        /// <summary>
        ///     Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
        /// </summary>
        /// <param name="sqlitePlatform"></param>
        /// <param name="databasePath">
        ///     Specifies the path to the database file.
        /// </param>
        /// <param name="openFlags"></param>
        /// <param name="storeDateTimeAsTicks">
        ///     Specifies whether to store DateTime properties as ticks (true) or strings (false). You
        ///     absolutely do want to store them as Ticks in all new projects. The option to set false is
        ///     only here for backwards compatibility. There is a *significant* speed advantage, with no
        ///     down sides, when setting storeDateTimeAsTicks = true.
        /// </param>
        /// <param name="serializer">
        ///     Blob serializer to use for storing undefined and complex data structures. If left null
        ///     these types will thrown an exception as usual.
        /// </param>
        /// <param name="tableMappings">
        ///     Exisiting table mapping that the connection can use. If its null, it creates the mappings,
        ///     if and when required. The mappings are also created when an unknown type is used for the first
        ///     time.
        /// </param>
        /// <param name="extraTypeMappings">
        ///     Any extra type mappings that you wish to use for overriding the default for creating
        ///     column definitions for SQLite DDL in the class Orm (snake in Swedish).
        /// </param>
        /// <param name="resolver">
        ///     A contract resovler for resolving interfaces to concreate types during object creation
        /// </param>
        [PublicAPI]
        public SQLiteConnection([JetBrains.Annotations.NotNull] ISQLitePlatform sqlitePlatform, string databasePath, SQLiteOpenFlags openFlags,
            bool storeDateTimeAsTicks = true, [CanBeNull] IBlobSerializer serializer = null, [CanBeNull] IDictionary<string, TableMapping> tableMappings = null,
            [CanBeNull] IDictionary<Type, string> extraTypeMappings = null, IContractResolver resolver = null)
        {
            if (sqlitePlatform == null)
            {
                throw new ArgumentNullException("sqlitePlatform");
            }
            ExtraTypeMappings = extraTypeMappings ?? new Dictionary<Type, string>();
            Serializer = serializer;
            Platform = sqlitePlatform;
            Resolver = resolver ?? ContractResolver.Current;

            _tableMappings = tableMappings ?? new Dictionary<string, TableMapping>();

            if (string.IsNullOrEmpty(databasePath))
            {
                throw new ArgumentException("Must be specified", "databasePath");
            }

            DatabasePath = databasePath;

            IDbHandle handle;
            var databasePathAsBytes = GetNullTerminatedUtf8(DatabasePath);
            var r = Platform.SQLiteApi.Open(databasePathAsBytes, out handle, (int) openFlags, IntPtr.Zero);

            Handle = handle;
            if (r != Result.OK)
            {
                throw SQLiteException.New(r, string.Format("Could not open database file: {0} ({1})", DatabasePath, r));
            }

            if (handle == null)
            {
                throw new NullReferenceException("Database handle is null");
            }

            Handle = handle;

            _open = true;

            StoreDateTimeAsTicks = storeDateTimeAsTicks;

            BusyTimeout = TimeSpan.FromSeconds(0.1);
        }

        [CanBeNull, PublicAPI]
        public IBlobSerializer Serializer { get; private set; }

        [CanBeNull, PublicAPI]
        public IDbHandle Handle { get; private set; }

        [JetBrains.Annotations.NotNull, PublicAPI]
        public string DatabasePath { get; private set; }

        [PublicAPI]
        public bool TimeExecution { get; set; }

        [CanBeNull]
        [PublicAPI]
        public ITraceListener TraceListener { get; set; }

        [PublicAPI]
        public bool StoreDateTimeAsTicks { get; private set; }

        [JetBrains.Annotations.NotNull, PublicAPI]
        public IDictionary<Type, string> ExtraTypeMappings { get; private set; }

        [JetBrains.Annotations.NotNull, PublicAPI]
        public IContractResolver Resolver { get; private set; }

        /// <summary>
        ///     Sets a busy handler to sleep the specified amount of time when a table is locked.
        ///     The handler will sleep multiple times until a total time of <see cref="BusyTimeout" /> has accumulated.
        /// </summary>
        [PublicAPI]
        public TimeSpan BusyTimeout
        {
            get { return _busyTimeout; }
            set
            {
                _busyTimeout = value;
                if (Handle != NullHandle)
                {
                    Platform.SQLiteApi.BusyTimeout(Handle, (int) _busyTimeout.TotalMilliseconds);
                }
            }
        }

        /// <summary>
        ///     Returns the mappings from types to tables that the connection
        ///     currently understands.
        /// </summary>
        [PublicAPI]
        [JetBrains.Annotations.NotNull]
        public IEnumerable<TableMapping> TableMappings
        {
            get { return _tableMappings.Values; }
        }

        /// <summary>
        ///     Whether <see cref="BeginTransaction" /> has been called and the database is waiting for a <see cref="Commit" />.
        /// </summary>
        [PublicAPI]
        public bool IsInTransaction
        {
            get { return _transactionDepth > 0; }
        }

        [JetBrains.Annotations.NotNull, PublicAPI]
        public ISQLitePlatform Platform { get; private set; }

        [PublicAPI]
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        [PublicAPI]
        public void EnableLoadExtension(int onoff)
        {
            var r = Platform.SQLiteApi.EnableLoadExtension(Handle, onoff);
            if (r != Result.OK)
            {
                var msg = Platform.SQLiteApi.Errmsg16(Handle);
                throw SQLiteException.New(r, msg);
            }
        }

        [JetBrains.Annotations.NotNull]
        private static byte[] GetNullTerminatedUtf8(string s)
        {
            var utf8Length = Encoding.UTF8.GetByteCount(s);
            var bytes = new byte[utf8Length + 1];
            Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0);
            return bytes;
        }

        /// <summary>
        ///     Retrieves the mapping that is automatically generated for the given type.
        /// </summary>
        /// <param name="type">
        ///     The type whose mapping to the database is returned.
        /// </param>
        /// <param name="createFlags">
        ///     Optional flags allowing implicit PK and indexes based on naming conventions
        /// </param>
        /// <returns>
        ///     The mapping represents the schema of the columns of the database and contains
        ///     methods to set and get properties of objects.
        /// </returns>
        [PublicAPI]
        public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
        {
            TableMapping map;
            return _tableMappings.TryGetValue(type.FullName, out map) ? map : CreateAndSetMapping(type, createFlags, _tableMappings);
        }

        private TableMapping CreateAndSetMapping(Type type, CreateFlags createFlags, IDictionary<string, TableMapping> mapTable)
        {
            var props = Platform.ReflectionService.GetPublicInstanceProperties(type);
            var map = new TableMapping(type, props, createFlags);
            mapTable[type.FullName] = map;
            return map;
        }

        /// <summary>
        ///     Retrieves the mapping that is automatically generated for the given type.
        /// </summary>
        /// <returns>
        ///     The mapping represents the schema of the columns of the database and contains
        ///     methods to set and get properties of objects.
        /// </returns>
        [PublicAPI]
        public TableMapping GetMapping<T>()
        {
            return GetMapping(typeof (T));
        }

        /// <summary>
        ///     Executes a "drop table" on the database.  This is non-recoverable.
        /// </summary>
        [PublicAPI]
        public int DropTable<T>()
        {
            var map = GetMapping(typeof (T));

            var query = string.Format("drop table if exists \"{0}\"", map.TableName);

            return Execute(query);
        }

        /// <summary>
        ///     Executes a "create table if not exists" on the database. It also
        ///     creates any specified indexes on the columns of the table. It uses
        ///     a schema automatically generated from the specified type. You can
        ///     later access this schema by calling GetMapping.
        /// </summary>
        /// <returns>
        ///     The number of entries added to the database schema.
        /// </returns>
        [PublicAPI]
        public int CreateTable<T>(CreateFlags createFlags = CreateFlags.None)
        {
            return CreateTable(typeof (T), createFlags);
        }

        /// <summary>
        ///     Executes a "create table if not exists" on the database. It also
        ///     creates any specified indexes on the columns of the table. It uses
        ///     a schema automatically generated from the specified type. You can
        ///     later access this schema by calling GetMapping.
        /// </summary>
        /// <param name="ty">Type to reflect to a database table.</param>
        /// <param name="createFlags">Optional flags allowing implicit PK and indexes based on naming conventions.</param>
        /// <returns>
        ///     The number of entries added to the database schema.
        /// </returns>
        [PublicAPI]
        public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
        {
            var map = GetMapping(ty, createFlags);

            var query = "create table if not exists \"" + map.TableName + "\"(\n";

            var mapColumns = map.Columns;

            if (!mapColumns.Any())
            {
                throw new Exception("Table has no (public) columns");
            }

            var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings));
            var decl = string.Join(",\n", decls.ToArray());
            query += decl;
            query += ")";

            var count = Execute(query);

            if (count == 0)
            {
                //Possible bug: This always seems to return 0?
                // Table already exists, migrate it
                MigrateTable(map);
            }

            var indexes = new Dictionary<string, IndexInfo>();
            foreach (var c in mapColumns)
            {
                foreach (var i in c.Indices)
                {
                    var iname = i.Name ?? map.TableName + "_" + c.Name;
                    IndexInfo iinfo;
                    if (!indexes.TryGetValue(iname, out iinfo))
                    {
                        iinfo = new IndexInfo
                        {
                            IndexName = iname,
                            TableName = map.TableName,
                            Unique = i.Unique,
                            Columns = new List<IndexedColumn>()
                        };
                        indexes.Add(iname, iinfo);
                    }

                    if (i.Unique != iinfo.Unique)
                    {
                        throw new Exception(
                            "All the columns in an index must have the same value for their Unique property");
                    }

                    iinfo.Columns.Add(new IndexedColumn
                    {
                        Order = i.Order,
                        ColumnName = c.Name
                    });
                }
            }

            foreach (var indexName in indexes.Keys)
            {
                var index = indexes[indexName];
                var columns = index.Columns.OrderBy(i => i.Order).Select(i => i.ColumnName).ToArray();
                count += CreateIndex(indexName, index.TableName, columns, index.Unique);
            }

            return count;
        }

        /// <summary>
        ///     Creates an index for the specified table and columns.
        /// </summary>
        /// <param name="indexName">Name of the index to create</param>
        /// <param name="tableName">Name of the database table</param>
        /// <param name="columnNames">An array of column names to index</param>
        /// <param name="unique">Whether the index should be unique</param>
        [PublicAPI]
        public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false)
        {
            const string sqlFormat = "create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")";
            var sql = string.Format(sqlFormat, tableName, string.Join("\", \"", columnNames), unique ? "unique" : "", indexName);
            return Execute(sql);
        }

        /// <summary>
        ///     Creates an index for the specified table and column.
        /// </summary>
        /// <param name="indexName">Name of the index to create</param>
        /// <param name="tableName">Name of the database table</param>
        /// <param name="columnName">Name of the column to index</param>
        /// <param name="unique">Whether the index should be unique</param>
        [PublicAPI]
        public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false)
        {
            return CreateIndex(indexName, tableName, new[] {columnName}, unique);
        }

        /// <summary>
        ///     Creates an index for the specified table and column.
        /// </summary>
        /// <param name="tableName">Name of the database table</param>
        /// <param name="columnName">Name of the column to index</param>
        /// <param name="unique">Whether the index should be unique</param>
        [PublicAPI]
        public int CreateIndex(string tableName, string columnName, bool unique = false)
        {
            return CreateIndex(tableName + "_" + columnName, tableName, columnName, unique);
        }

        /// <summary>
        ///     Creates an index for the specified table and columns.
        /// </summary>
        /// <param name="tableName">Name of the database table</param>
        /// <param name="columnNames">An array of column names to index</param>
        /// <param name="unique">Whether the index should be unique</param>
        [PublicAPI]
        public int CreateIndex(string tableName, string[] columnNames, bool unique = false)
        {
            return CreateIndex(tableName + "_" + string.Join("_", columnNames), tableName, columnNames, unique);
        }

        /// <summary>
        ///     Creates an index for the specified object property.
        ///     e.g. CreateIndex{Client}(c => c.Name);
        /// </summary>
        /// <typeparam name="T">Type to reflect to a database table.</typeparam>
        /// <param name="property">Property to index</param>
        /// <param name="unique">Whether the index should be unique</param>
        [PublicAPI]
        public void CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false)
        {
            MemberExpression mx;
            if (property.Body.NodeType == ExpressionType.Convert)
            {
                mx = ((UnaryExpression) property.Body).Operand as MemberExpression;
            }
            else
            {
                mx = (property.Body as MemberExpression);
            }
            if (mx == null)
            {
                throw new ArgumentException("Expression is not supported", "property");
            }
            var propertyInfo = mx.Member as PropertyInfo;
            if (propertyInfo == null)
            {
                throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
            }

            var propName = propertyInfo.Name;

            var map = GetMapping<T>();
            var colName = map.FindColumnWithPropertyName(propName).Name;

            CreateIndex(map.TableName, colName, unique);
        }

        [PublicAPI]
        public List<ColumnInfo> GetTableInfo(string tableName)
        {
            var query = "pragma table_info(\"" + tableName + "\")";
            return Query<ColumnInfo>(query);
        }

        private void MigrateTable(TableMapping map)
        {
            var existingCols = GetTableInfo(map.TableName);

            var toBeAdded = new List<TableMapping.Column>();

            foreach (var p in map.Columns)
            {
                var found = false;
                foreach (var c in existingCols)
                {
                    found = (string.Compare(p.Name, c.Name, StringComparison.OrdinalIgnoreCase) == 0);
                    if (found)
                    {
                        break;
                    }
                }
                if (!found)
                {
                    toBeAdded.Add(p);
                }
            }

            foreach (var p in toBeAdded)
            {
                var addCol = "alter table \"" + map.TableName + "\" add column " +
                             Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings);
                Execute(addCol);
            }
        }

        /// <summary>
        ///     Creates a new SQLiteCommand. Can be overridden to provide a sub-class.
        /// </summary>
        /// <seealso cref="SQLiteCommand.OnInstanceCreated" />
        [PublicAPI]
        protected virtual SQLiteCommand NewCommand()
        {
            return new SQLiteCommand(Platform, this);
        }

        /// <summary>
        ///     Creates a new SQLiteCommand given the command text with arguments. Place a '?'
        ///     in the command text for each of the arguments.
        /// </summary>
        /// <param name="cmdText">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the command text.
        /// </param>
        /// <returns>
        ///     A <see cref="SQLiteCommand" />
        /// </returns>
        [PublicAPI]
        public SQLiteCommand CreateCommand(string cmdText, params object[] args)
        {
            if (!_open)
            {
                throw SQLiteException.New(Result.Error, "Cannot create commands from unopened database");
            }

            var cmd = NewCommand();
            cmd.CommandText = cmdText;
            foreach (var o in args)
            {
                cmd.Bind(o);
            }
            return cmd;
        }

        /// <summary>
        ///     Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
        ///     in the command text for each of the arguments and then executes that command.
        ///     Use this method instead of Query when you don't expect rows back. Such cases include
        ///     INSERTs, UPDATEs, and DELETEs.
        ///     You can set the Trace or TimeExecution properties of the connection
        ///     to profile execution.
        /// </summary>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     The number of rows modified in the database as a result of this execution.
        /// </returns>
        [PublicAPI]
        public int Execute(string query, params object[] args)
        {
            var cmd = CreateCommand(query, args);

            if (TimeExecution)
            {
                if (_sw == null)
                {
                    _sw = Platform.StopwatchFactory.Create();
                }
                _sw.Reset();
                _sw.Start();
            }

            var r = cmd.ExecuteNonQuery();

            if (TimeExecution)
            {
                _sw.Stop();
                _elapsedMilliseconds += _sw.ElapsedMilliseconds;

                TraceListener.WriteLine("Finished in {0} ms ({1:0.0} s total)", _sw.ElapsedMilliseconds, _elapsedMilliseconds/1000.0);
            }

            return r;
        }

        [PublicAPI]
        public T ExecuteScalar<T>(string query, params object[] args)
        {
            var cmd = CreateCommand(query, args);

            if (TimeExecution)
            {
                if (_sw == null)
                {
                    _sw = Platform.StopwatchFactory.Create();
                }
                _sw.Reset();
                _sw.Start();
            }

            var r = cmd.ExecuteScalar<T>();

            if (TimeExecution)
            {
                _sw.Stop();
                _elapsedMilliseconds += _sw.ElapsedMilliseconds;

                TraceListener.WriteLine("Finished in {0} ms ({1:0.0} s total)", _sw.ElapsedMilliseconds, _elapsedMilliseconds/1000.0);
            }

            return r;
        }

        /// <summary>
        ///     Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
        ///     in the command text for each of the arguments and then executes that command.
        ///     It returns each row of the result using the mapping automatically generated for
        ///     the given type.
        /// </summary>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     An enumerable with one result for each row returned by the query.
        /// </returns>
        [PublicAPI]
        public List<T> Query<T>(string query, params object[] args) where T : class
        {
            var cmd = CreateCommand(query, args);
            return cmd.ExecuteQuery<T>();
        }

        /// <summary>
        ///     Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
        ///     in the command text for each of the arguments and then executes that command.
        ///     It returns each row of the result using the mapping automatically generated for
        ///     the given type.
        /// </summary>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     An enumerable with one result for each row returned by the query.
        ///     The enumerator will call sqlite3_step on each call to MoveNext, so the database
        ///     connection must remain open for the lifetime of the enumerator.
        /// </returns>
        [PublicAPI]
        public IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : class
        {
            var cmd = CreateCommand(query, args);
            return cmd.ExecuteDeferredQuery<T>();
        }

        /// <summary>
        ///     Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
        ///     in the command text for each of the arguments and then executes that command.
        ///     It returns each row of the result using the specified mapping. This function is
        ///     only used by libraries in order to query the database via introspection. It is
        ///     normally not used.
        /// </summary>
        /// <param name="map">
        ///     A <see cref="TableMapping" /> to use to convert the resulting rows
        ///     into objects.
        /// </param>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     An enumerable with one result for each row returned by the query.
        /// </returns>
        [PublicAPI]
        public List<object> Query(TableMapping map, string query, params object[] args)
        {
            var cmd = CreateCommand(query, args);
            return cmd.ExecuteQuery<object>(map);
        }

        /// <summary>
        ///     Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
        ///     in the command text for each of the arguments and then executes that command.
        ///     It returns each row of the result using the specified mapping. This function is
        ///     only used by libraries in order to query the database via introspection. It is
        ///     normally not used.
        /// </summary>
        /// <param name="map">
        ///     A <see cref="TableMapping" /> to use to convert the resulting rows
        ///     into objects.
        /// </param>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     An enumerable with one result for each row returned by the query.
        ///     The enumerator will call sqlite3_step on each call to MoveNext, so the database
        ///     connection must remain open for the lifetime of the enumerator.
        /// </returns>
        [PublicAPI]
        public IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args)
        {
            var cmd = CreateCommand(query, args);
            return cmd.ExecuteDeferredQuery<object>(map);
        }

        /// <summary>
        ///     Returns a queryable interface to the table represented by the given type.
        /// </summary>
        /// <returns>
        ///     A queryable object that is able to translate Where, OrderBy, and Take
        ///     queries into native SQL.
        /// </returns>
        [PublicAPI]
        public TableQuery<T> Table<T>() where T : class
        {
            return new TableQuery<T>(Platform, this);
        }

        /// <summary>
        ///     Attempts to retrieve an object with the given primary key from the table
        ///     associated with the specified type. Use of this method requires that
        ///     the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
        /// </summary>
        /// <param name="pk">
        ///     The primary key.
        /// </param>
        /// <returns>
        ///     The object with the given primary key. Throws a not found exception
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public T Get<T>(object pk) where T : class
        {
            var map = GetMapping(typeof (T));
            return Query<T>(map.GetByPrimaryKeySql, pk).First();
        }

        /// <summary>
        ///     Attempts to retrieve the first object that matches the predicate from the table
        ///     associated with the specified type.
        /// </summary>
        /// <param name="predicate">
        ///     A predicate for which object to find.
        /// </param>
        /// <returns>
        ///     The object that matches the given predicate. Throws a not found exception
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public T Get<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            return Table<T>().Where(predicate).First();
        }

        /// <summary>
        ///     Attempts to retrieve an object with the given primary key from the table
        ///     associated with the specified type. Use of this method requires that
        ///     the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
        /// </summary>
        /// <param name="pk">
        ///     The primary key.
        /// </param>
        /// <returns>
        ///     The object with the given primary key or null
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public T Find<T>(object pk) where T : class
        {
            var map = GetMapping(typeof (T));
            return Query<T>(map.GetByPrimaryKeySql, pk).FirstOrDefault();
        }

        /// <summary>
        ///     Attempts to retrieve the first object that matches the query from the table
        ///     associated with the specified type.
        /// </summary>
        /// <param name="query">
        ///     The fully escaped SQL.
        /// </param>
        /// <param name="args">
        ///     Arguments to substitute for the occurences of '?' in the query.
        /// </param>
        /// <returns>
        ///     The object that matches the given predicate or null
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public T FindWithQuery<T>(string query, params object[] args) where T : class
        {
            return Query<T>(query, args).FirstOrDefault();
        }

        /// <summary>
        ///     Attempts to retrieve an object with the given primary key from the table
        ///     associated with the specified type. Use of this method requires that
        ///     the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
        /// </summary>
        /// <param name="pk">
        ///     The primary key.
        /// </param>
        /// <param name="map">
        ///     The TableMapping used to identify the object type.
        /// </param>
        /// <returns>
        ///     The object with the given primary key or null
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public object Find(object pk, TableMapping map)
        {
            return Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault();
        }

        /// <summary>
        ///     Attempts to retrieve the first object that matches the predicate from the table
        ///     associated with the specified type.
        /// </summary>
        /// <param name="predicate">
        ///     A predicate for which object to find.
        /// </param>
        /// <returns>
        ///     The object that matches the given predicate or null
        ///     if the object is not found.
        /// </returns>
        [PublicAPI]
        public T Find<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            return Table<T>().Where(predicate).FirstOrDefault();
        }

        /// <summary>
        ///     Begins a new transaction. Call <see cref="Commit" /> to end the transaction.
        /// </summary>
        /// <example cref="System.InvalidOperationException">Throws if a transaction has already begun.</example>
        [PublicAPI]
        public void BeginTransaction()
        {
            // The BEGIN command only works if the transaction stack is empty,
            //    or in other words if there are no pending transactions.
            // If the transaction stack is not empty when the BEGIN command is invoked,
            //    then the command fails with an error.
            // Rather than crash with an error, we will just ignore calls to BeginTransaction
            //    that would result in an error.
            if (Interlocked.CompareExchange(ref _transactionDepth, 1, 0) == 0)
            {
                try
                {
                    Execute("begin transaction");
                }
                catch (Exception ex)
                {
                    var sqlExp = ex as SQLiteException;
                    if (sqlExp != null)
                    {
                        // It is recommended that applications respond to the errors listed below
                        //    by explicitly issuing a ROLLBACK command.
                        // TODO: This rollback failsafe should be localized to all throw sites.
                        switch (sqlExp.Result)
                        {
                            case Result.IOError:
                            case Result.Full:
                            case Result.Busy:
                            case Result.NoMem:
                            case Result.Interrupt:
                                RollbackTo(null, true);
                                break;
                        }
                    }
                    else
                    {
                        // Call decrement and not VolatileWrite in case we've already
                        //    created a transaction point in SaveTransactionPoint since the catch.
                        Interlocked.Decrement(ref _transactionDepth);
                    }

                    throw;
                }
            }
            else
            {
                // Calling BeginTransaction on an already open transaction is invalid
                throw new InvalidOperationException("Cannot begin a transaction while already in a transaction.");
            }
        }

        /// <summary>
        ///     Creates a savepoint in the database at the current point in the transaction timeline.
        ///     Begins a new transaction if one is not in progress.
        ///     Call <see cref="RollbackTo" /> to undo transactions since the returned savepoint.
        ///     Call <see cref="Release" /> to commit transactions after the savepoint returned here.
        ///     Call <see cref="Commit" /> to end the transaction, committing all changes.
        /// </summary>
        /// <returns>A string naming the savepoint.</returns>
        [PublicAPI]
        public string SaveTransactionPoint()
        {
            var depth = Interlocked.Increment(ref _transactionDepth) - 1;
            var retVal = "S" + _rand.Next(short.MaxValue) + "D" + depth;

            try
            {
                Execute("savepoint " + retVal);
            }
            catch (Exception ex)
            {
                var sqlExp = ex as SQLiteException;
                if (sqlExp != null)
                {
                    // It is recommended that applications respond to the errors listed below
                    //    by explicitly issuing a ROLLBACK command.
                    // TODO: This rollback failsafe should be localized to all throw sites.
                    switch (sqlExp.Result)
                    {
                        case Result.IOError:
                        case Result.Full:
                        case Result.Busy:
                        case Result.NoMem:
                        case Result.Interrupt:
                            RollbackTo(null, true);
                            break;
                    }
                }
                else
                {
                    Interlocked.Decrement(ref _transactionDepth);
                }

                throw;
            }

            return retVal;
        }

        /// <summary>
        ///     Rolls back the transaction that was begun by <see cref="BeginTransaction" /> or <see cref="SaveTransactionPoint" />
        ///     .
        /// </summary>
        [PublicAPI]
        public void Rollback()
        {
            RollbackTo(null, false);
        }

        /// <summary>
        ///     Rolls back the savepoint created by <see cref="BeginTransaction" /> or SaveTransactionPoint.
        /// </summary>
        /// <param name="savepoint">
        ///     The name of the savepoint to roll back to, as returned by <see cref="SaveTransactionPoint" />.
        ///     If savepoint is null or empty, this method is equivalent to a call to <see cref="Rollback" />
        /// </param>
        [PublicAPI]
        public void RollbackTo(string savepoint)
        {
            RollbackTo(savepoint, false);
        }

        /// <summary>
        ///     Rolls back the transaction that was begun by <see cref="BeginTransaction" />.
        /// </summary>
        /// <param name="savepoint">the savepoint name/key</param>
        /// <param name="noThrow">true to avoid throwing exceptions, false otherwise</param>
        private void RollbackTo(string savepoint, bool noThrow)
        {
            // Rolling back without a TO clause rolls backs all transactions
            //    and leaves the transaction stack empty.
            try
            {
                if (string.IsNullOrEmpty(savepoint))
                {
                    if (Interlocked.Exchange(ref _transactionDepth, 0) > 0)
                    {
                        Execute("rollback");
                    }
                }
                else
                {
                    DoSavePointExecute(savepoint, "rollback to ");
                }
            }
            catch (SQLiteException)
            {
                if (!noThrow)
                {
                    throw;
                }
            }
            // No need to rollback if there are no transactions open.
        }

        /// <summary>
        ///     Releases a savepoint returned from <see cref="SaveTransactionPoint" />.  Releasing a savepoint
        ///     makes changes since that savepoint permanent if the savepoint began the transaction,
        ///     or otherwise the changes are permanent pending a call to <see cref="Commit" />.
        ///     The RELEASE command is like a COMMIT for a SAVEPOINT.
        /// </summary>
        /// <param name="savepoint">
        ///     The name of the savepoint to release.  The string should be the result of a call to
        ///     <see cref="SaveTransactionPoint" />
        /// </param>
        [PublicAPI]
        public void Release(string savepoint)
        {
            DoSavePointExecute(savepoint, "release ");
        }

        private void DoSavePointExecute(string savePoint, string cmd)
        {
            // Validate the savepoint
            var firstLen = savePoint.IndexOf('D');
            if (firstLen >= 2 && savePoint.Length > firstLen + 1)
            {
                int depth;
                if (int.TryParse(savePoint.Substring(firstLen + 1), out depth))
                {
                    // TODO: Mild race here, but inescapable without locking almost everywhere.
                    if (0 <= depth && depth < _transactionDepth)
                    {
                        Platform.VolatileService.Write(ref _transactionDepth, depth);
                        Execute(cmd + savePoint);
                        return;
                    }
                }
            }

            throw new ArgumentException(
                "savePoint is not valid, and should be the result of a call to SaveTransactionPoint.", "savePoint");
        }

        /// <summary>
        ///     Commits the transaction that was begun by <see cref="BeginTransaction" />.
        /// </summary>
        [PublicAPI]
        public void Commit()
        {
            if (Interlocked.Exchange(ref _transactionDepth, 0) != 0)
            {
                Execute("commit");
            }
            // Do nothing on a commit with no open transaction
        }

        /// <summary>
        ///     Executes
        ///     <paramref name="action" />
        ///     within a (possibly nested) transaction by wrapping it in a SAVEPOINT. If an
        ///     exception occurs the whole transaction is rolled back, not just the current savepoint. The exception
        ///     is rethrown.
        /// </summary>
        /// <param name="action">
        ///     The <see cref="Action" /> to perform within a transaction.
        ///     <paramref name="action" />
        ///     can contain any number
        ///     of operations on the connection but should never call <see cref="BeginTransaction" /> or
        ///     <see cref="Commit" />.
        /// </param>
        [PublicAPI]
        public void RunInTransaction(Action action)
        {
            try
            {
                var savePoint = SaveTransactionPoint();
                action();
                Release(savePoint);
            }
            catch (Exception)
            {
                Rollback();
                throw;
            }
        }

        /// <summary>
        ///     Inserts all specified objects.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert.
        /// </param>
        /// <param name="runInTransaction">A boolean indicating if the inserts should be wrapped in a transaction.</param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int InsertAll(IEnumerable objects, bool runInTransaction = true)
        {
            var c = 0;
            if (runInTransaction)
            {
                RunInTransaction(() =>
                {
                    foreach (var r in objects)
                    {
                        c += Insert(r);
                    }
                });
            }
            else
            {
                foreach (var r in objects)
                {
                    c += Insert(r);
                }
            }
            return c;
        }

        /// <summary>
        ///     Inserts all specified objects.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert.
        /// </param>
        /// <param name="extra">
        ///     Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
        /// </param>
        /// <param name="runInTransaction">A boolean indicating if the inserts should be wrapped in a transaction.</param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int InsertAll(IEnumerable objects, string extra, bool runInTransaction = true)
        {
            var c = 0;
            if (runInTransaction)
            {
                RunInTransaction(() =>
                {
                    foreach (var r in objects)
                    {
                        c += Insert(r, extra);
                    }
                });
            }
            else
            {
                foreach (var r in objects)
                {
                    c += Insert(r, extra);
                }
            }
            return c;
        }

        /// <summary>
        ///     Inserts all specified objects.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert.
        /// </param>
        /// <param name="objType">
        ///     The type of object to insert.
        /// </param>
        /// <param name="runInTransaction">A boolean indicating if the inserts should be wrapped in a transaction.</param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int InsertAll(IEnumerable objects, Type objType, bool runInTransaction = true)
        {
            var c = 0;
            if (runInTransaction)
            {
                RunInTransaction(() =>
                {
                    foreach (var r in objects)
                    {
                        c += Insert(r, objType);
                    }
                });
            }
            else
            {
                foreach (var r in objects)
                {
                    c += Insert(r, objType);
                }
            }
            return c;
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int Insert(object obj)
        {
            if (obj == null)
            {
                return 0;
            }
            return Insert(obj, "", obj.GetType());
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        ///     If a UNIQUE constraint violation occurs with
        ///     some pre-existing object, this function deletes
        ///     the old object.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows modified.
        /// </returns>
        [PublicAPI]
        public int InsertOrReplace(object obj)
        {
            if (obj == null)
            {
                return 0;
            }
            return Insert(obj, "OR REPLACE", obj.GetType());
        }

        /// <summary>
        ///     Inserts all specified objects.
        ///     For each insertion, if a UNIQUE
        ///     constraint violation occurs with
        ///     some pre-existing object, this function
        ///     deletes the old object.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert or replace.
        /// </param>
        /// <returns>
        ///     The total number of rows modified.
        /// </returns>
        [PublicAPI]
        public int InsertOrReplaceAll(IEnumerable objects)
        {
            var c = 0;
            RunInTransaction(() =>
            {
                foreach (var r in objects)
                {
                    c += InsertOrReplace(r);
                }
            });
            return c;
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <param name="objType">
        ///     The type of object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int Insert(object obj, Type objType)
        {
            return Insert(obj, "", objType);
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        ///     If a UNIQUE constraint violation occurs with
        ///     some pre-existing object, this function deletes
        ///     the old object.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <param name="objType">
        ///     The type of object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows modified.
        /// </returns>
        [PublicAPI]
        public int InsertOrReplace(object obj, Type objType)
        {
            return Insert(obj, "OR REPLACE", objType);
        }

        /// <summary>
        ///     Inserts all specified objects.
        ///     For each insertion, if a UNIQUE
        ///     constraint violation occurs with
        ///     some pre-existing object, this function
        ///     deletes the old object.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert or replace.
        /// </param>
        /// <param name="objType">
        ///     The type of objects to insert or replace.
        /// </param>
        /// <returns>
        ///     The total number of rows modified.
        /// </returns>
        [PublicAPI]
        public int InsertOrReplaceAll(IEnumerable objects, Type objType)
        {
            var c = 0;
            RunInTransaction(() =>
            {
                foreach (var r in objects)
                {
                    c += InsertOrReplace(r, objType);
                }
            });
            return c;
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <param name="extra">
        ///     Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
        /// </param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int Insert(object obj, string extra)
        {
            if (obj == null)
            {
                return 0;
            }
            return Insert(obj, extra, obj.GetType());
        }

        /// <summary>
        ///     Inserts the given object and retrieves its
        ///     auto incremented primary key if it has one.
        /// </summary>
        /// <param name="obj">
        ///     The object to insert.
        /// </param>
        /// <param name="extra">
        ///     Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
        /// </param>
        /// <param name="objType">
        ///     The type of object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows added to the table.
        /// </returns>
        [PublicAPI]
        public int Insert(object obj, string extra, Type objType)
        {
            if (obj == null || objType == null)
            {
                return 0;
            }

            var map = GetMapping(objType);

            if (map.PK != null && map.PK.IsAutoGuid)
            {
                var prop = objType.GetRuntimeProperty(map.PK.PropertyName);
                if (prop != null)
                {
                    if (prop.GetValue(obj, null).Equals(Guid.Empty))
                    {
                        prop.SetValue(obj, Guid.NewGuid(), null);
                    }
                }
            }

            var replacing = string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0;

            var cols = replacing ? map.Columns : map.InsertColumns;
            var vals = new object[cols.Length];
            for (var i = 0; i < vals.Length; i++)
            {
                vals[i] = cols[i].GetValue(obj);
            }

            var insertCmd = GetInsertCommand(map, extra);
            int count;
            try
            {
                count = insertCmd.ExecuteNonQuery(vals);
            }
            catch (SQLiteException ex)
            {
                if (Platform.SQLiteApi.ExtendedErrCode(Handle) == ExtendedResult.ConstraintNotNull)
                {
                    throw NotNullConstraintViolationException.New(ex.Result, ex.Message, map, obj);
                }
                throw;
            }

            if (map.HasAutoIncPK)
            {
                var id = Platform.SQLiteApi.LastInsertRowid(Handle);
                map.SetAutoIncPK(obj, id);
            }

            return count;
        }

        private PreparedSqlLiteInsertCommand GetInsertCommand(TableMapping map, string extra)
        {
            ActiveInsertCommand cmd;
            if (_insertCommandCache == null)
            {
                _insertCommandCache = new Dictionary<TableMapping, ActiveInsertCommand>();
            }

            if (!_insertCommandCache.TryGetValue(map, out cmd))
            {
                cmd = new ActiveInsertCommand(map);
                _insertCommandCache[map] = cmd;
            }

            return cmd.GetCommand(this, extra);
        }

        /// <summary>
        ///     Updates all of the columns of a table using the specified object
        ///     except for its primary key.
        ///     The object is required to have a primary key.
        /// </summary>
        /// <param name="obj">
        ///     The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
        /// </param>
        /// <returns>
        ///     The number of rows updated.
        /// </returns>
        [PublicAPI]
        public int Update(object obj)
        {
            if (obj == null)
            {
                return 0;
            }
            return Update(obj, obj.GetType());
        }

        /// <summary>
        ///     Updates all of the columns of a table using the specified object
        ///     except for its primary key.
        ///     The object is required to have a primary key.
        /// </summary>
        /// <param name="obj">
        ///     The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
        /// </param>
        /// <param name="objType">
        ///     The type of object to insert.
        /// </param>
        /// <returns>
        ///     The number of rows updated.
        /// </returns>
        [PublicAPI]
        public int Update(object obj, Type objType)
        {
            int rowsAffected;
            if (obj == null || objType == null)
            {
                return 0;
            }

            var map = GetMapping(objType);

            var pk = map.PK;

            if (pk == null)
            {
                throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK");
            }

            var cols = from p in map.Columns
                where p != pk
                select p;
            var vals = from c in cols
                select c.GetValue(obj);
            var ps = new List<object>(vals)
            {
                pk.GetValue(obj)
            };
            var q = string.Format("update \"{0}\" set {1} where {2} = ? ", map.TableName,
                string.Join(",", (from c in cols
                    select "\"" + c.Name + "\" = ? ").ToArray()), pk.Name);
            try
            {
                rowsAffected = Execute(q, ps.ToArray());
            }
            catch (SQLiteException ex)
            {
                if (ex.Result == Result.Constraint && Platform.SQLiteApi.ExtendedErrCode(Handle) == ExtendedResult.ConstraintNotNull)
                {
                    throw NotNullConstraintViolationException.New(ex, map, obj);
                }

                throw;
            }

            return rowsAffected;
        }

        /// <summary>
        ///     Updates all specified objects.
        /// </summary>
        /// <param name="objects">
        ///     An <see cref="IEnumerable" /> of the objects to insert.
        /// </param>
        /// <param name="runInTransaction">A boolean indicating if the inserts should be wrapped in a transaction.</param>
        /// <returns>
        ///     The number of rows modified.
        /// </returns>
        [PublicAPI]
        public int UpdateAll(IEnumerable objects, bool runInTransaction = true)
        {
            var c = 0;
            if (runInTransaction)
            {
                RunInTransaction(() =>
                {
                    foreach (var r in objects)
                    {
                        c += Update(r);
                    }
                });
            }
            else
            {
                foreach (var r in objects)
                {
                    c += Update(r);
                }
            }
            return c;
        }

        /// <summary>
        ///     Deletes the given object from the database using its primary key.
        /// </summary>
        /// <param name="objectToDelete">
        ///     The object to delete. It must have a primary key designated using the PrimaryKeyAttribute.
        /// </param>
        /// <returns>
        ///     The number of rows deleted.
        /// </returns>
        [PublicAPI]
        public int Delete(object objectToDelete)
        {
            var map = GetMapping(objectToDelete.GetType());
            var pk = map.PK;
            if (pk == null)
            {
                throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK");
            }
            var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name);
            return Execute(q, pk.GetValue(objectToDelete));
        }

        /// <summary>
        ///     Deletes the object with the specified primary key.
        /// </summary>
        /// <param name="primaryKey">
        ///     The primary key of the object to delete.
        /// </param>
        /// <returns>
        ///     The number of objects deleted.
        /// </returns>
        /// <typeparam name='T'>
        ///     The type of object.
        /// </typeparam>
        [PublicAPI]
        public int Delete<T>(object primaryKey)
        {
            var map = GetMapping(typeof (T));
            var pk = map.PK;
            if (pk == null)
            {
                throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK");
            }
            var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name);
            return Execute(q, primaryKey);
        }

        /// <summary>
        ///     Deletes all the objects from the specified table.
        ///     WARNING WARNING: Let me repeat. It deletes ALL the objects from the
        ///     specified table. Do you really want to do that?
        /// </summary>
        /// <returns>
        ///     The number of objects deleted.
        /// </returns>
        /// <typeparam name='T'>
        ///     The type of objects to delete.
        /// </typeparam>
        [PublicAPI]
        public int DeleteAll<T>()
        {
            var map = GetMapping(typeof (T));
            var query = string.Format("delete from \"{0}\"", map.TableName);
            return Execute(query);
        }

        #region Backup

        public string CreateDatabaseBackup(ISQLitePlatform platform)
        {
            ISQLiteApiExt sqliteApi = platform.SQLiteApi as ISQLiteApiExt;

            if (sqliteApi == null)
            {
                return null;
            }

            string destDBPath = this.DatabasePath + "." + DateTime.UtcNow.ToString("yyyy-MM-dd_HH-mm-ss-fff");

            IDbHandle destDB;
            byte[] databasePathAsBytes = GetNullTerminatedUtf8(destDBPath);
            Result r = sqliteApi.Open(databasePathAsBytes, out destDB,
                (int) (SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite), IntPtr.Zero);

            if (r != Result.OK)
            {
                throw SQLiteException.New(r, String.Format("Could not open backup database file: {0} ({1})", destDBPath, r));
            }

            /* Open the backup object used to accomplish the transfer */
            IDbBackupHandle bHandle = sqliteApi.BackupInit(destDB, "main", this.Handle, "main");

            if (bHandle == null)
            {
                // Close the database connection
                sqliteApi.Close(destDB);

                throw SQLiteException.New(r, String.Format("Could not initiate backup process: {0}", destDBPath));
            }

            /* Each iteration of this loop copies 5 database pages from database
            ** pDb to the backup database. If the return value of backup_step()
            ** indicates that there are still further pages to copy, sleep for
            ** 250 ms before repeating. */
            do
            {
                r = sqliteApi.BackupStep(bHandle, 5);

                if (r == Result.OK || r == Result.Busy || r == Result.Locked)
                {
                    sqliteApi.Sleep(250);
                }
            } while (r == Result.OK || r == Result.Busy || r == Result.Locked);

            /* Release resources allocated by backup_init(). */
            r = sqliteApi.BackupFinish(bHandle);

            if (r != Result.OK)
            {
                // Close the database connection
                sqliteApi.Close(destDB);

                throw SQLiteException.New(r, String.Format("Could not finish backup process: {0} ({1})", destDBPath, r));
            }

            // Close the database connection
            sqliteApi.Close(destDB);

            return destDBPath;
        }

        #endregion

        ~SQLiteConnection()
        {
            Dispose(false);
        }

        [PublicAPI]
        protected virtual void Dispose(bool disposing)
        {
            Close();
        }

        [PublicAPI]
        public void Close()
        {
            if (_open && Handle != NullHandle)
            {
                try
                {
                    if (_insertCommandCache != null)
                    {
                        foreach (var sqlInsertCommand in _insertCommandCache.Values)
                        {
                            sqlInsertCommand.Dispose();
                        }
                    }
                    var r = Platform.SQLiteApi.Close(Handle);
                    if (r != Result.OK)
                    {
                        var msg = Platform.SQLiteApi.Errmsg16(Handle);
                        throw SQLiteException.New(r, msg);
                    }
                }
                finally
                {
                    Handle = NullHandle;
                    _open = false;
                }
            }
        }

        public class ColumnInfo
        {
            //			public int cid { get; set; }

            [PublicAPI]
            [Column("name")]
            public string Name { get; set; }

            //			[Column ("type")]
            //			public string ColumnType { get; set; }

            [PublicAPI]
            public int notnull { get; set; }

            //			public string dflt_value { get; set; }

            //			public int pk { get; set; }

            [PublicAPI]
            public override string ToString()
            {
                return Name;
            }
        }

        private struct IndexInfo
        {
            public List<IndexedColumn> Columns;
            public string IndexName;
            public string TableName;
            public bool Unique;
        }

        private struct IndexedColumn
        {
            public string ColumnName;
            public int Order;
        }
    }
}


text:
package com.example.multimodule.service;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

@Service
@EnableConfigurationProperties(ServiceProperties.class)
public class MyService {

    private final ServiceProperties serviceProperties;

    public MyService(ServiceProperties serviceProperties) {
        this.serviceProperties = serviceProperties;
    }

    public String message() {
        return this.serviceProperties.getMessage();
    }

}

redpajama_set_name: RedPajamaGithub


text:
package mailgun

import (
	"strconv"
	"time"
)

const iso8601date = "2006-01-02"

type Stat struct {
	Event      string         `json:"event"`
	TotalCount int            `json:"total_count"`
	CreatedAt  string         `json:"created_at"`
	Id         string         `json:"id"`
	Tags       map[string]int `json:"tags"`
}

type statsEnvelope struct {
	TotalCount int    `json:"total_count"`
	Items      []Stat `json:"items"`
}

type Accepted struct {
	Incoming int `json:"incoming"`
	Outgoing int `json:"outgoing"`
	Total    int `json:"total"`
}

type Delivered struct {
	Smtp  int `json:"smtp"`
	Http  int `json:"http"`
	Total int `json:"total"`
}

type Temporary struct {
	Espblock int `json:"espblock"`
}

type Permanent struct {
	SuppressBounce      int `json:"suppress-bounce"`
	SuppressUnsubscribe int `json:"suppress-unsubscribe"`
	SuppressComplaint   int `json:"suppress-complaint"`
	Bounce              int `json:"bounce"`
	DelayedBounce       int `json:"delayed-bounce"`
	Total               int `json:"total"`
}

type Failed struct {
	Temporary Temporary `json:"temporary"`
	Permanent Permanent `json:"permanent"`
}

type Total struct {
	Total int `json:"total"`
}

type StatsTotal struct {
	Time         string    `json:"time"`
	Accepted     Accepted  `json:"accepted"`
	Delivered    Delivered `json:"delivered"`
	Failed       Failed    `json:"failed"`
	Stored       Total     `json:"stored"`
	Opened       Total     `json:"opened"`
	Clicked      Total     `json:"clicked"`
	Unsubscribed Total     `json:"unsubscribed"`
	Complained   Total     `json:"complained"`
}

type StatsTotalResponse struct {
	End        string       `json:"end"`
	Resolution string       `json:"resolution"`
	Start      string       `json:"start"`
	Stats      []StatsTotal `json:"stats"`
}

// GetStats returns a basic set of statistics for different events.
// Events start at the given start date, if one is provided.
// If not, this function will consider all stated events dating to the creation of the sending domain.
func (m *MailgunImpl) GetStats(limit int, skip int, startDate *time.Time, event ...string) (int, []Stat, error) {
	r := newHTTPRequest(generateApiUrl(m, statsEndpoint))

	if limit != -1 {
		r.addParameter("limit", strconv.Itoa(limit))
	}
	if skip != -1 {
		r.addParameter("skip", strconv.Itoa(skip))
	}

	if startDate != nil {
		r.addParameter("start-date", startDate.Format(iso8601date))
	}

	for _, e := range event {
		r.addParameter("event", e)
	}
	r.setClient(m.Client())
	r.setBasicAuth(basicAuthUser, m.APIKey())

	var res statsEnvelope
	err := getResponseFromJSON(r, &res)
	if err != nil {
		return -1, nil, err
	} else {
		return res.TotalCount, res.Items, nil
	}
}

// GetStatsTotal returns a basic set of statistics for different events.
// https://documentation.mailgun.com/en/latest/api-stats.html#stats
func (m *MailgunImpl) GetStatsTotal(start *time.Time, end *time.Time, resolution string, duration string, event ...string) (*StatsTotalResponse, error) {
	r := newHTTPRequest(generateApiUrl(m, statsTotalEndpoint))

	if start != nil {
		r.addParameter("start", start.Format(iso8601date))
	}
	if end != nil {
		r.addParameter("end", end.Format(iso8601date))
	}

	if resolution != "" {
		r.addParameter("resolution", resolution)
	}

	if duration != "" {
		r.addParameter("duration", duration)
	}

	for _, e := range event {
		r.addParameter("event", e)
	}
	r.setClient(m.Client())
	r.setBasicAuth(basicAuthUser, m.APIKey())

	var res StatsTotalResponse
	err := getResponseFromJSON(r, &res)
	if err != nil {
		return nil, err
	} else {
		return &res, nil
	}
}


text:
<?php

declare(strict_types=1);

namespace Linio\Component\Cache\Adapter;

use Linio\Component\Cache\Exception\KeyNotFoundException;

interface AdapterInterface
{
    public function __construct(array $config);

    /**
     * @throws KeyNotFoundException
     *
     * @return mixed
     */
    public function get(string $key);

    public function getMulti(array $keys): array;

    /**
     * @param mixed $value
     */
    public function set(string $key, $value): bool;

    public function setMulti(array $data): bool;

    public function contains(string $key): bool;

    public function delete(string $key): bool;

    public function deleteMulti(array $keys): bool;

    public function flush(): bool;

    public function getNamespace(): string;

    public function setNamespace(string $namespace): void;

    public function cacheNotFoundKeys(): bool;
}


text:
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H

typedef struct {
  char *scheme;
  char *authority;
  char *path;
} grpc_uri;

/** parse a uri, return NULL on failure */
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);

/** destroy a uri */
void grpc_uri_destroy(grpc_uri *uri);

#endif


text:
var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: {
    main: './src/main.js'
  },
  output: {
    path: path.resolve(__dirname, '../wwwroot/dist'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  resolve: {
    alias: {
      'public': path.resolve(__dirname, '../wwwroot/public')
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
            // the "scss" and "sass" values for the lang attribute to the right configs here.
            // other preprocessors should work out of the box, no loader config like this necessary.
            'scss': 'vue-style-loader!css-loader!sass-loader',
            'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          objectAssign: 'Object.assign'
        }
      },
      {
        test: /\.styl$/,
        loader: ['style-loader', 'css-loader', 'stylus-loader']
      },
      {
        test: /\.css$/,
        loader: ['style-loader', 'css-loader']
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  performance: {
    hints: false
  },
  devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}


text:
import mongodb from "mongodb";

export { ObjectID } from "mongodb";

export function create(config, cb) {

    let {
        host,
        port,
        database,
        journal = true,
        w       = 1
    } = config;

    const localServer = new mongodb.Server(host, port);

    const mongo = new mongodb.Db(database, localServer, {
        journal,
        w
    });

    mongo.open(function(err, db) {
        if(err) {
            return cb(err);
        }
        db.ObjectID = mongodb.ObjectID;
        return cb(null, db);
    });

}


text:
__all__ = ['getMUSICregion']
from SimulationAnalysis import readHlist
from readGadgetSnapshot import readGadgetSnapshot
from findLagrangianVolume import findLagrangianVolume

_fmt = lambda a: ', '.join(map(str, a))

def getMUSICregion(target_id, rvir_mult, hlist, snapshot_prefix, ic_prefix,\
        edges_file=None):
    halos = readHlist(hlist, ['id', 'rvir', 'x', 'y', 'z'])
    target = halos[(halos['id'] == target_id)][0]
    c = [target[ax] for ax in 'xyz']
    r = rvir_mult * target['rvir'] * 1.e-3

    header = readGadgetSnapshot(snapshot_prefix+'.0')
    box_size = header.BoxSize

    rec_cor, rec_len = findLagrangianVolume(c, r, \
            snapshot_prefix, ic_prefix, edges_file, rec_only=True)
    print 'region          = box'
    print 'ref_offset      =', _fmt(rec_cor/box_size)
    print 'ref_extent      =', _fmt(rec_len/box_size)

def main():
    from sys import argv
    from json import load
    with open(argv[1], 'r') as fp:
        d = load(fp)
    getMUSICregion(**d)

if __name__ == '__main__':
    main()


text:
layout: post
microblog: true
date: 2013-03-05 23:25 +0300
guid: http://desparoz.micro.blog/2013/03/05/t309036938256609280.html
---
Switch by @Ihnatko from iPhone to Android reminds us that an OS is a life support system for features & apps. Use that which works for you


text:
<!DOCTYPE html>

    <meta charset="UTF-8">
    <meta name=viewport content='width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no'>
    <title>评论列表</title>
    <link rel="stylesheet" type="text/css" href="../../css/base.css">
    <link rel="stylesheet" href="../../css/mui.css">
    <link rel="stylesheet" type="text/css" href="../../css/teachersay.css">
    <link rel="stylesheet" href="../../css/qqface.css">

{{comment.users ? comment.users.realname : "未知"}}

                {{comment.created_at}}

{{comment.content}}

              {{ comment.praise_count}}

          <input  type="text" placeholder="我来讲两句...">

                <textarea id="saytext" name="saytext" class="weui-textarea" placeholder="请输入留言内容" rows="3" v-model="content"></textarea>

                    <button class="cl-light-gray" @click="canCel">取消</button>
                    <button class="blue" @click="add">确定</button>


text:
from heapq import heappush, heappop
from Instance import Instance
from Instances import Instances
from operator import add,mul
from textblob import TextBlob
from NodosPalabras.Nodo import Nodo
from nltk.stem.lancaster import LancasterStemmer
import math

class RedPalabras(object):
	"""docstring for Clasificador"""
	def __init__(self):
		super(RedPalabras, self).__init__()
		self.nodosPorClase = {}
		self.clases = {}
		self.stopWords = "a|about|above|after|again|against|all|am|an|and|any|are|aren't|as|at|be|because|been|before|being|below|between|both|but|by|can't|cannot|could|couldn't|did|didn't|do|does|doesn't|doing|don't|down|during|each|few|for|from|further|had|hadn't|has|hasn't|have|haven't|having|he|he'd|he'll|he's|her|here|here's|hers|herself|him|himself|his|how|how's|i|i'd|i'll|i'm|i've|if|in|into|is|isn't|it|it's|its|itself|let's|me|more|most|mustn't|my|myself|no|nor|not|of|off|on|once|only|or|other|ought|our|ours|ourselves|out|over|own|same|shan't|she|she'd|she'll|she's|should|shouldn't|so|some|such|than|that|that's|the|their|theirs|them|themselves|then|there|there's|these|they|they'd|they'll|they're|they've|this|those|through|to|too|under|until|up|very|was|wasn't|we|we'd|we'll|we're|we've|were|weren't|what|what's|when|when's|where|where's|which|while|who|who's|whom|why|why's|with|won't|would|wouldn't|you|you'd|you'll|you're|you've|your|yours|yourself|yourselves"
		self.st = LancasterStemmer()

	"""parametros es un string de configuracion para el clasificador"""
	"""para KNN por ejemplo k=11, para una red reuronal,numero de capas
	 	nl=2... cada clasificador se puede preguntar con getCapabilities()"""
	def setParameters(self, parametros):
		raise NotImplementedError( "Should have implemented this" )

	"""data es un array de instancias"""
	def buildClassifier(self, data):
		#todas las instancias de este clasificador se asumen [texto, clase]
		self.clases = list(data.getClases())
		for clase in self.clases:
			self.nodosPorClase[clase] = {}

		for instance in data.getListInstances():
			texto = instance.getElementAtPos(0)
			clase = instance.getElementAtPos(1)
			textB = TextBlob(texto)

			nodoAnterior = None
			for palabra in textB.words:
				palabra = palabra.lower()
				if palabra in self.stopWords:
					continue
				palabra = self.st.stem(palabra)
				if palabra in self.nodosPorClase[clase]:
					if nodoAnterior is None:
						nodoAnterior = self.nodosPorClase[clase][palabra]
					else:
						nodo = self.nodosPorClase[clase][palabra]
						if nodoAnterior.isConexo(palabra):
							nodoAnterior.sumaAlPeso(palabra, 0.1)
						else:
							#nodo.setConexo(nodoAnterior)
							nodoAnterior.setConexo(nodo)
						nodoAnterior = nodo
				else:
					#se crea el nodo porque no existe en esta clase
					nodo = Nodo(palabra)
					self.nodosPorClase[clase][palabra] = nodo
					if nodoAnterior is None:
						pass
					else:
						#nodo.setConexo(nodoAnterior)
						nodoAnterior.setConexo(nodo)
					nodoAnterior = nodo

	"""se clasifica una sola instancia, retornando la clase, int"""
	def classifyInstance(self, instance):
		#todas las instancias de este clasificador se asumen [texto, clase]
		texto = instance.getElementAtPos(0)
		clase = instance.getElementAtPos(1)
		textB = TextBlob(texto)

		pesoClase = {}

		for clase in self.clases:
			pesoClase[clase] = 0
			nodoAnterior = None
			for palabra in textB.words:
				palabra = palabra.lower()
				if palabra in self.stopWords:
					continue
				palabra = self.st.stem(palabra)
				if palabra in self.nodosPorClase[clase]:
					if nodoAnterior is None:
						nodoAnterior = self.nodosPorClase[clase][palabra]
					else:
						if nodoAnterior.isConexo(palabra):
							peso = nodoAnterior.getPeso(palabra)
							pesoClase[clase] += peso
						else:
							#por ahora nada, pero se debería aplicar dikstra
							pesoClase[clase] -= 0
						nodoAnterior = self.nodosPorClase[clase][palabra]
				else:
					pesoClase[clase] -= 0
					nodoAnterior = None

		mejorClase = None
		mejorClaseN = 0
		for clase in self.clases:
			if mejorClase is None:
				mejorClase = clase
				mejorClaseN = pesoClase[clase]
			else:
				if mejorClaseN < pesoClase[clase]:
					mejorClase = clase
					mejorClaseN = pesoClase[clase]

		return mejorClase

	"""retorna un String JSON para que el Clasificador se pueda guardar en un fichero o donde sea necesario"""
	def saveClassifierToJSON(self):
		raise NotImplementedError( "Should have implemented this" )

	def restoreClassifierFromJSON(self, jsonObj):
		raise NotImplementedError( "Should have implemented this" )

	"""retorna un string con el funcionamiento del Clasificador"""
	def getCapabilities(self):
		raise NotImplementedError( "Should have implemented this" )

	"""Hace que el clasificador entre en modo debug o no"""
	def setDebug(self, value):
		raise NotImplementedError( "Should have implemented this" )


text:
<?php
namespace xml\xmlreader_004;

function test() {
  $filename = '_004.xml';

  $xmlstring = '<?xml version="1.0" encoding="UTF-8"?>
<books><book num="1" idx="2">book1</book></books>';
  file_put_contents($filename, $xmlstring);

  $reader = new \XMLReader();
  if (!$reader->open($filename)) {
    exit();
  }

  while ($reader->read()) {
    if ($reader->nodeType != \XMLReader::END_ELEMENT) {
      echo $reader->name."\n";
      if ($reader->nodeType == \XMLReader::ELEMENT && $reader->hasAttributes) {
        $attr = $reader->moveToFirstAttribute();
        while ($attr) {
          echo "   Attribute Name: ".$reader->name."\n";
          echo "   Attribute Value: ".$reader->value."\n";
          $attr = $reader->moveToNextAttribute();
        }
      }
    }
  }

  $reader->close();
  unlink($filename);
}

test();


text:
require 'active_model'

module CrazyValidators
  class AlphaNumericalityValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)

      return if value.nil?

      unless value.to_s.match(/^\w+$/)
        record.errors.add(attribute, :not_alpha_numeric, options)
      end
    end
  end
end


text:
import React from 'react';

import AirportCodes from 'airport-codes/airports.json';
import VirtualizedSelect from 'react-virtualized-select';
import _ from 'lodash';
import '!!style-loader!css-loader!../../../node_modules/react-select/dist/react-select.min.css';
import '!!style-loader!css-loader!../../../node_modules/react-virtualized-select/styles.css';
import '!!style-loader!css-loader!./LocationPicker.css';
import Label from '../Label/index';

class LocationPicker extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      options: [],
    };
  }

  onChange = (value) => {
    if (this.props.onChange) {
      this.props.onChange(value ? value.value : null);
    }
  };

  filterOptions = (options, filterString) => {
    const filterStringCaps = filterString.toUpperCase();
    return _.filter(options, (option) => option.iata === filterStringCaps || option.value.indexOf(filterStringCaps) !== -1 || option.city.indexOf(filterStringCaps) !== -1);
  };

  render() {
    const options = _.map(AirportCodes, (airport) => ({ value: airport.name.toUpperCase(), label: airport.name, iata: airport.iata.toUpperCase(), city: airport.city.toUpperCase() }));
    return (

        {this.props.label && {this.props.label}}
        <VirtualizedSelect
          filterOptions={this.filterOptions}
          options={options}
          value={this.props.value}
          onChange={this.onChange}
          clearable={false}
        />

    );
  }
}

LocationPicker.propTypes = {
  onChange: React.PropTypes.func,
  label: React.PropTypes.string,
  value: React.PropTypes.string,
};

export default LocationPicker;


text:
A simple application for visualizing your Freckle Data in some new and interesting ways

## The supported charts are:

* Projections
  * Average Billable/Unbillable per Day (Trend)
  * Average Billable/Unbillable per Month (Trend)
* "Hard Data"
  * Billable/Unbillable per Month over Time (Trend)
* Comparisons
  * Time logged per Project (Polar/Pie)
  * Time logged per Tag combination (Polar/Pie)
  * Unbillable/Billable time logged (Polar/Pie)

## We plan on adding

1. Time logged per Project over Time

## Date ranges

* The following date ranges are provided as a shortcut:
  * Last 2 Weeks
  * Last Month
  * Last Quarter
  * Last 6 Months
  * Last Year
* You can also specify a custom date range


text:
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (c) 2014, Apptentive, Inc. All Rights Reserved.
  ~ Please refer to the LICENSE file for the terms and conditions
  ~ under which redistribution and use of this file is permitted.
  -->
<resources>
    <string name="apptentive_ok">OK</string>
    <string name="apptentive_yes">Yes</string>
    <string name="apptentive_no">No</string>
    <string name="apptentive_skip">Skip</string>
    <string name="apptentive_you">You</string>
    <string name="apptentive_developer">Developer</string>
    <string name="apptentive_oops">Oops!</string>
    <string name="apptentive_send">Send</string>
    <string name="apptentive_give_feedback">Give Feedback</string>
    <string name="apptentive_thanks">Thanks!</string>
    <string name="apptentive_no_thanks">No thanks</string>
    <string name="apptentive_thank_you">Thank You</string>
    <string name="apptentive_were_sorry">We\'re Sorry!</string>
    <string name="apptentive_required">Required</string>
    <string name="apptentive_optional">Optional</string>
    <string name="apptentive_sending">Sending…</string>
    <string name="apptentive_version">Apptentive Version %s</string>

    <string name="apptentive_edittext_hint_email">Your Email Address</string>
    <string name="apptentive_edittext_hint_email_required">Email Address (required)</string>

    <string name="apptentive_powered_by_apptentive">Powered by Apptentive</string>
    <string name="apptentive_about_title">About Apptentive</string>
    <string name="apptentive_about_description">Apptentive is a feedback and communication service which allows the people who make this app to quickly get your feedback and better listen to you.</string>
    <string name="apptentive_about_description_link">Find out more at apptentive.com</string>
    <string name="apptentive_about_privacy">Your feedback is hosted by Apptentive and is subject to Apptentive\'s privacy policy and the privacy policy of the developer of this app.</string>
    <string name="apptentive_about_privacy_link">Visit Apptentive\'s Privacy Policy</string>

    <string name="apptentive_do_you_love_this_app">Do you love %s?</string>

    <string name="apptentive_rating_message_fs">We\'re so happy to hear that you love %s! It\'d be really helpful if you shared us with your followers! Thanks so much for spending some time with us.</string>
    <string name="apptentive_rate_this_app">Share %s</string>
    <string name="apptentive_rating_remind">Remind Me Later</string>
    <string name="apptentive_rating_error">We\'re unable to find this app in the store. Please visit the store to find and rate it.</string>

    <string name="apptentive_intro_dialog_title_no_love">@string/apptentive_were_sorry</string>
    <string name="apptentive_intro_dialog_title_default">Thanks for your feedback!</string>
    <string name="apptentive_intro_dialog_body">Please let us know how to make %s better for you!</string>
    <string name="apptentive_intro_dialog_edittext_hint">Tell us how we can help. (required)</string>

    <string name="apptentive_thank_you_dialog_body">Your response has been saved in the Message Center, where you\'ll be able to view replies and send us other messages.</string>
    <string name="apptentive_thank_you_dialog_body_message_center_disabled">Thank you for your feedback!</string>
    <string name="apptentive_thank_you_dialog_body_message_center_disabled_email_required">We\'ll be in touch via email.</string>
    <string name="apptentive_thank_you_dialog_close">Close</string>
    <string name="apptentive_thank_you_dialog_view_messages">View Messages</string>

    <string name="apptentive_dialog_email_validation_failed_title">Invalid Email Address</string>
    <string name="apptentive_dialog_email_validation_failed_body">Please enter a valid email address.</string>

    <string name="apptentive_survey_header">Survey</string>
    <string name="apptentive_survey_singleline_hint">Enter an answer…</string>
    <string name="apptentive_survey_send_response">Send Response</string>

    <string name="apptentive_message_center_title">Message Center</string>
    <string name="apptentive_message_center_compose_hint">Type a message…</string>
    <string name="apptentive_message_center_attachment_title">Send image?</string>

    <!-- This is a Java format. -->
    <string name="apptentive_message_sent_timestamp_format">MMM dd, yyyy h:mma</string>

    <string name="apptentive_message_auto_body_manual">This is our Message Center. If you have questions, suggestions, concerns, or just want to get in touch, please send us a message. We love talking with our customers!</string>
    <string name="apptentive_message_auto_body_no_love">What can we do to ensure that you love our app? We appreciate your constructive feedback.</string>

    <string name="apptentive_rating_provider_no_google_play">Google Play was not found. Please install Google Play before rating this app.</string>
    <string name="apptentive_rating_provider_no_amazon_appstore">Amazon Appstore was not found. Please install Amazon Appstore before rating this app.</string>
    <string name="apptentive_rating_provider_no_mikandi">MiKandi Market was not found. Please install MiKandi Market before rating this app.</string>
</resources>


text:
class WXDLLIMPEXP_FWD_CORE wxFrame;
class WXDLLIMPEXP_FWD_CORE wxWindowMac;
class WXDLLIMPEXP_FWD_CORE wxApp ;
class WXDLLIMPEXP_FWD_CORE wxKeyEvent;
class WXDLLIMPEXP_FWD_BASE wxLog;
class WXDLLIMPEXP_FWD_CORE wxMacAutoreleasePool;

// Force an exit from main loop
void WXDLLIMPEXP_CORE wxExit();

// Yield to other apps/messages
bool WXDLLIMPEXP_CORE wxYield();

// Represents the application. Derive OnInit and declare
// a new App object to start application
class WXDLLIMPEXP_CORE wxApp: public wxAppBase
{
    DECLARE_DYNAMIC_CLASS(wxApp)

    wxApp();
    virtual ~wxApp();

    virtual void WakeUpIdle();

    virtual void SetPrintMode(int mode) { m_printMode = mode; }
    virtual int GetPrintMode() const { return m_printMode; }

    // calling OnInit with an auto-release pool ready ...
    virtual bool CallOnInit();
#if wxUSE_GUI
    // setting up all MacOS Specific Event-Handlers etc
    virtual bool OnInitGui();
#endif // wxUSE_GUI

    virtual int OnRun();

    virtual bool ProcessIdle();

    // implementation only
    void OnIdle(wxIdleEvent& event);
    void OnEndSession(wxCloseEvent& event);
    void OnQueryEndSession(wxCloseEvent& event);

protected:
    int                   m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
    wxMacAutoreleasePool* m_macPool;

public:

    static bool           sm_isEmbedded;
    // Implementation
    virtual bool Initialize(int& argc, wxChar **argv);
    virtual void CleanUp();

    // the installed application event handler
    WXEVENTHANDLERREF    MacGetEventHandler() { return m_macEventHandler ; }
    WXEVENTHANDLERREF    MacGetCurrentEventHandlerCallRef() { return m_macCurrentEventHandlerCallRef ; }
    void MacSetCurrentEvent( WXEVENTREF event , WXEVENTHANDLERCALLREF handler )
    { m_macCurrentEvent = event ; m_macCurrentEventHandlerCallRef = handler ; }

    // adding a CFType object to be released only at the end of the current event cycle (increases the
    // refcount of the object passed), needed in case we are in the middle of an event concering an object
    // we want to delete and cannot do it immediately
    // TODO change semantics to be in line with cocoa (make autrelease NOT increase the count)
    void                  MacAddToAutorelease( void* cfrefobj );
    void                  MacReleaseAutoreleasePool();

public:
    static wxWindow*      s_captureWindow ;
    static long           s_lastModifiers ;

    int                   m_nCmdShow;

    // mac specifics
protected:
#if wxOSX_USE_COCOA
    // override for support of custom app controllers
    virtual WX_NSObject   OSXCreateAppController();
#endif

private:
    virtual bool        DoInitGui();
    virtual void        DoCleanUp();

    WXEVENTHANDLERREF     m_macEventHandler ;
    WXEVENTHANDLERCALLREF m_macCurrentEventHandlerCallRef ;
    WXEVENTREF            m_macCurrentEvent ;

public:
    static long           s_macAboutMenuItemId ;
    static long           s_macPreferencesMenuItemId ;
    static long           s_macExitMenuItemId ;
    static wxString       s_macHelpMenuTitleName ;

    WXEVENTREF            MacGetCurrentEvent() { return m_macCurrentEvent ; }

    // For embedded use. By default does nothing.
    virtual void          MacHandleUnhandledEvent( WXEVENTREF ev );

    bool    MacSendKeyDownEvent( wxWindow* focus , long keyval , long modifiers , long when , wxChar uniChar ) ;
    bool    MacSendKeyUpEvent( wxWindow* focus , long keyval , long modifiers , long when , wxChar uniChar ) ;
    bool    MacSendCharEvent( wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar ) ;
    void    MacCreateKeyEvent( wxKeyEvent& event, wxWindow* focus , long keymessage , long modifiers , long when , wxChar uniChar ) ;
#if wxOSX_USE_CARBON
    // we only have applescript on these
    virtual short         MacHandleAEODoc(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
    virtual short         MacHandleAEGURL(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
    virtual short         MacHandleAEPDoc(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
    virtual short         MacHandleAEOApp(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
    virtual short         MacHandleAEQuit(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
    virtual short         MacHandleAERApp(const WXAPPLEEVENTREF event , WXAPPLEEVENTREF reply) ;
#endif
    // in response of an openFiles message with Cocoa and an
    // open-document apple event
    virtual void         MacOpenFiles(const wxArrayString &fileNames) ;
    // called by MacOpenFiles for each file.
    virtual void         MacOpenFile(const wxString &fileName) ;
    // in response of a get-url apple event
    virtual void         MacOpenURL(const wxString &url) ;
    // in response of a print-document apple event
    virtual void         MacPrintFiles(const wxArrayString &fileNames) ;
    // called by MacPrintFiles for each file
    virtual void         MacPrintFile(const wxString &fileName) ;
    // in response of a open-application apple event
    virtual void         MacNewFile() ;
    // in response of a reopen-application apple event
    virtual void         MacReopenApp() ;

    // Notice that this is just a placeholder and doesn't work yet!
    //
    // Override this to return false from a non-bundled console app in order to
    // stay in background instead of being made a foreground application as
    // happens by default.
    virtual bool         OSXIsGUIApplication() { return true; }

#if wxOSX_USE_COCOA_OR_IPHONE
    // immediately before the native event loop launches
    virtual void         OSXOnWillFinishLaunching();
    // immediately when the native event loop starts, no events have been served yet
    virtual void         OSXOnDidFinishLaunching();
    // OS asks to terminate app, return no to stay running
    virtual bool         OSXOnShouldTerminate();
    // before application terminates
    virtual void         OSXOnWillTerminate();

private:
    bool                m_onInitResult;
    bool                m_inited;
    wxArrayString       m_openFiles;
    wxArrayString       m_printFiles;
    wxString            m_getURL;

public:
    bool                OSXInitWasCalled() { return m_inited; }
    void                OSXStoreOpenFiles(const wxArrayString &files ) { m_openFiles = files ; }
    void                OSXStorePrintFiles(const wxArrayString &files ) { m_printFiles = files ; }
    void                OSXStoreOpenURL(const wxString &url ) { m_getURL = url ; }
#endif

    // Hide the application windows the same as the system hide command would do it.
    void MacHideApp();

    DECLARE_EVENT_TABLE()
};

#endif
    // _WX_APP_H_