1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2014-06-30 00:04:32 -04:00
parent 85594d3cdd
commit bae88e739c
2482 changed files with 198730 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
import gplx.stores.*;
import java.sql.*;
class Mysql_engine extends Db_engine_sql_base {
@Override public String Key() {return Db_connect_mysql.KeyDef;}
@Override public Sql_cmd_wtr SqlWtr() {return Sql_cmd_wtr_.BackslashSensitive;}
@Override public Db_engine MakeEngine(Db_connect connectInfo) {
Mysql_engine rv = new Mysql_engine();
rv.ctor_SqlEngineBase(connectInfo);
return rv;
}
@Override public DataRdr NewDataRdr(ResultSet rdr, String commandText) {return Mysql_rdr.new_(rdr, commandText);}
@gplx.Internal @Override protected Connection NewDbCon() {
Db_connect_mysql connUrl = (Db_connect_mysql)dbInfo;
return NewDbCon("jdbc:mysql://localhost/" + connUrl.Database() + "?characterEncoding=UTF8", connUrl.Uid(), connUrl.Pwd());
}
@gplx.Internal protected static final Mysql_engine _ = new Mysql_engine(); Mysql_engine() {}
}
class Mysql_rdr extends Db_data_rdr {
//PATCH:MYSQL:byte actually returned as int by Jdbc ResultSet (or MYSQL impmentation); convert to byte
@Override public byte ReadByte(String key) {return ReadByteOr(key, Byte.MAX_VALUE);}
@Override public byte ReadByteOr(String key, byte or) {
Object val = Read(key);
return val == null ? or : ((Integer)val).byteValue();
}
public static Mysql_rdr new_(ResultSet rdr, String commandText) {
Mysql_rdr rv = new Mysql_rdr();
rv.ctor_db_data_rdr(rdr, commandText);
return rv;
} Mysql_rdr() {}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
import gplx.stores.*;
import java.sql.*;
class Postgres_engine extends Db_engine_sql_base {
@Override public String Key() {return Db_connect_postgres.KeyDef;}
@Override public Sql_cmd_wtr SqlWtr() {return Sql_cmd_wtr_.BackslashSensitive;}
@Override public Db_engine MakeEngine(Db_connect connectInfo) {
Postgres_engine rv = new Postgres_engine();
rv.ctor_SqlEngineBase(connectInfo);
return rv;
}
@Override public DataRdr NewDataRdr(ResultSet rdr, String commandText) {return Db_data_rdr_.new_(rdr, commandText);}
@gplx.Internal @Override protected Connection NewDbCon() {
Db_connect_postgres connUrl = (Db_connect_postgres)dbInfo;
return NewDbCon("jdbc:" + connUrl.Key_of_db_connect() + "://localhost/" + connUrl.Database(), connUrl.Uid(), connUrl.Pwd());
}
@gplx.Internal protected static final Postgres_engine _ = new Postgres_engine(); Postgres_engine() {}
}

View File

@@ -0,0 +1,96 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
import gplx.stores.*;
import java.sql.*;
class Sqlite_engine extends Db_engine_sql_base {
@Override public String Key() {return Db_connect_sqlite.KeyDef;}
@Override public Db_engine MakeEngine(Db_connect connectInfo) {
Sqlite_engine rv = new Sqlite_engine();
rv.ctor_SqlEngineBase(connectInfo);
return rv;
}
@Override public DataRdr NewDataRdr(ResultSet rdr, String commandText) {return Sqlite_rdr.new_(rdr, commandText);}
static boolean loaded = false;
@gplx.Internal @Override protected Connection NewDbCon() {
if (!loaded) {
try {
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {throw Err_.new_("could not load sqlite jdbc driver");}
loaded = true;
}
Db_connect_sqlite connUrl = (Db_connect_sqlite)dbInfo;
return NewDbCon("jdbc:sqlite://" + String_.Replace(connUrl.Database(), "\\", "/"), "", "");
}
private boolean pragma_needed = true;
@Override public void Txn_bgn() {
// Execute(Db_qry_sql.xtn_("PRAGMA ENCODING=\"UTF-8\";"));
// Execute(Db_qry_sql.xtn_("PRAGMA journal_mode = OFF;")); // will cause out of memory
// Execute(Db_qry_sql.xtn_("PRAGMA journal_mode = MEMORY;"));
if (pragma_needed) {
Execute(Db_qry_sql.xtn_("PRAGMA synchronous = OFF;"));
pragma_needed = false;
}
// Execute(Db_qry_sql.xtn_("PRAGMA temp_store = MEMORY;"));
// Execute(Db_qry_sql.xtn_("PRAGMA locking_mode = EXCLUSIVE;"));
// Execute(Db_qry_sql.xtn_("PRAGMA cache_size=4000;")); // too many will also cause out of memory
Execute(Db_qry_sql.xtn_("BEGIN TRANSACTION;"));
}
@gplx.Internal protected static final Sqlite_engine _ = new Sqlite_engine(); Sqlite_engine() {}
}
class Sqlite_rdr extends Db_data_rdr { @Override public float ReadFloat(String key) {return ReadFloatOr(key, Float.NaN);}
@Override public float ReadFloatOr(String key, float or) {
Object val = Read(key);
Double d = ((Double)val);
return val == null ? or : d.floatValue();
}
@Override public DecimalAdp ReadDecimal(String key) {return ReadDecimalOr(key, null);}
@Override public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) {
Object val = Read(key);
Double d = ((Double)val);
return val == null ? or : DecimalAdp_.double_(d);
}
@Override public DateAdp ReadDate(String key) {return ReadDateOr(key, null);}
@Override public DateAdp ReadDateOr(String key, DateAdp or) {
Object val = Read(key);
return val == null ? or : DateAdp_.parse_fmt((String)val, "M/dd/yyyy hh:mm tt");
}
@Override public boolean ReadBool(String key) {return ReadBoolOr(key, false);}
@Override public boolean ReadBoolOr(String key, boolean or) {
Object val = Read(key);
return val == null ? or : Int_.cast_(val) == 1;
}
@Override public byte ReadByte(String key) {return ReadByteOr(key, Byte_.Zero);}
@Override public byte ReadByteOr(String key, byte or) {
Object val = Read(key);
return val == null ? or : (byte)Int_.cast_(val);
}
@Override public long ReadLong(String key) {return ReadLongOr(key, Long_.MinValue);}
@Override public long ReadLongOr(String key, long or) {
Object val = Read(key);
if (val == null) return or;
Number n = (Number)val;
return n.longValue();
}
public static Sqlite_rdr new_(ResultSet rdr, String commandText) {
Sqlite_rdr rv = new Sqlite_rdr();
rv.ctor_db_data_rdr(rdr, commandText);
return rv;
} Sqlite_rdr() {}
}

View File

@@ -0,0 +1,91 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
public class Sqlite_engine_ {
public static void Db_attach(Db_provider p, String alias, String url) {
String s = String_.Format("ATTACH '{0}' AS {1};", url, alias);
Db_qry qry = Db_qry_sql.xtn_(s);
p.Exec_qry(qry);
}
public static void Db_detach(Db_provider p, String alias) {
String s = String_.Format("DETACH '{0}';", alias);
Db_qry qry = Db_qry_sql.xtn_(s);
p.Exec_qry(qry);
}
public static void Tbl_create_and_delete(Db_provider p, String tbl_name, String tbl_sql) {
Tbl_delete(p, tbl_name);
Db_qry qry = Db_qry_sql.ddl_(tbl_sql);
p.Exec_qry(qry);
}
public static void Tbl_create(Db_provider p, String tbl_name, String tbl_sql) {
Db_qry qry = Db_qry_sql.ddl_(tbl_sql);
p.Exec_qry(qry);
}
public static void Tbl_delete_many(Db_provider p, String... tbls) {
int len = tbls.length;
for (int i = 0; i < len; i++)
Tbl_delete(p, tbls[i]);
}
public static void Tbl_delete(Db_provider p, String tbl) {
Db_qry qry = Db_qry_sql.ddl_("DROP TABLE IF EXISTS " + tbl + ";");
p.Exec_qry(qry);
}
public static void Tbl_rename(Db_provider p, String src, String trg) {
Db_qry qry = Db_qry_sql.ddl_(String_.Format("ALTER TABLE {0} RENAME TO {1};", src, trg));
p.Exec_qry(qry);
}
public static void Pragma_page_size_4096(Db_provider p) {Pragma_page_size(p, 4096);}
public static void Pragma_page_size(Db_provider p, int val) {
Db_qry qry = Db_qry_sql.ddl_("PRAGMA page_size = " + Int_.XtoStr(val) + ";");
p.Exec_qry(qry);
}
public static void Idx_create(Db_provider p, Db_idx_itm... idxs) {Idx_create(Gfo_usr_dlg_.Null, p, "", idxs);}
public static void Idx_create(Gfo_usr_dlg usr_dlg, Db_provider p, String file_id, Db_idx_itm... idxs) {
int len = idxs.length;
p.Txn_mgr().Txn_end_all(); // commit any pending transactions
for (int i = 0; i < len; i++) {
p.Txn_mgr().Txn_bgn_if_none();
String index = idxs[i].Xto_sql();
usr_dlg.Prog_many("", "", "creating index: ~{0} ~{1}", file_id, index);
p.Exec_qry(Db_qry_sql.ddl_(index));
p.Txn_mgr().Txn_end_all();
}
}
public static Db_provider Provider_load_or_fail_(Io_url url) {
boolean exists = Io_mgr._.ExistsFil(url);
if (!exists) throw Err_.new_fmt_("db does not exist; url=~{0}", url.Raw());
Db_connect connect = Db_connect_sqlite.load_(url);
return Db_provider_.new_(connect);
}
public static Db_provider Provider_load_or_make_(Io_url url) {return Provider_load_or_make_(url, Bool_obj_ref.n_());}
public static Db_provider Provider_load_or_make_(Io_url url, Bool_obj_ref created) {
boolean exists = Io_mgr._.ExistsFil(url);
created.Val_(!exists);
Db_connect connect = exists ? Db_connect_sqlite.load_(url) : Db_connect_sqlite.make_(url);
Db_provider p = Db_provider_.new_(connect);
if (!exists)
Pragma_page_size(p, 4096);
return p;
}
public static final int Stmt_arg_max = 999; // 999 is max number of variables allowed by sqlite
public static final boolean Supports_read_binary_stream = false;
public static final boolean Supports_indexed_by = true;
public static String X_date_to_str(DateAdp v) {return v == Date_null ? "" : v.XtoStr_fmt_iso_8561();}
public static final DateAdp Date_null = null;
public static final byte Wildcard_byte = Byte_ascii.Hash;
}

View File

@@ -0,0 +1,129 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
import org.junit.*;
public class db_CrudOps_tst {
CrudOpsFxt fx = new CrudOpsFxt();
@Test public void Mysql() {if (Tfds.SkipDb) return;
fx.RunAll(Db_provider_fxt.Mysql());
}
@Test public void Tdb() {if (Tfds.SkipDb) return;
fx.RunAll(Db_provider_fxt.Tdb("100_dbs_crud_ops.dsv"));
}
@Test public void Postgres() {if (Db_provider_fxt.SkipPostgres) return;
fx.RunAll(Db_provider_fxt.Postgres());
}
@Test public void Sqlite() {if (Tfds.SkipDb) return;
fx.Fx().DmlAffectedAvailable_(false);
fx.RunAll(Db_provider_fxt.Sqlite());
}
}
class CrudOpsFxt {
public Db_provider_fxt Fx() {return fx;} Db_provider_fxt fx = new Db_provider_fxt();
void Init() {fx.ini_DeleteAll("dbs_crud_ops");}
public void RunAll(Db_provider provider) {
fx.Provider_(provider);
Insert_hook();
UpdateOne_hook();
UpdateMany_hook();
DeleteOne_hook();
DeleteMany_hook();
SelectLike_hook();
SelectLikeForFileName_hook();
InsertUnicode_hook();
Backslash_hook();
fx.Rls();
}
public void Insert_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecRdrTbl(1, "dbs_crud_ops");
fx.tst_RowAry(0, 1, "John Doe");
}
public void UpdateOne_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 2).Arg_("name", "John Doe"));
fx.tst_ExecDml(1, Db_qry_.update_common_("dbs_crud_ops", Db_crt_.eq_("id", 2), KeyVal_.new_("name", "Jane Smith")));
fx.tst_ExecRdrTbl(2, "dbs_crud_ops");
fx.tst_RowAry(0, 1, "John Doe");
fx.tst_RowAry(1, 2, "Jane Smith");
}
public void UpdateMany_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 2).Arg_("name", "John Doe"));
fx.tst_ExecDml(2, Db_qry_.update_common_("dbs_crud_ops", Db_crt_.eq_("name", "John Doe"), KeyVal_.new_("name", "Jane Smith")));
fx.tst_ExecRdrTbl(2, "dbs_crud_ops");
fx.tst_RowAry(0, 1, "Jane Smith");
fx.tst_RowAry(1, 2, "Jane Smith");
}
public void DeleteOne_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 2).Arg_("name", "Jane Smith"));
fx.tst_ExecDml(1, Db_qry_.delete_("dbs_crud_ops", Db_crt_.eq_("id", 2)));
fx.tst_ExecRdrTbl(1, "dbs_crud_ops");
fx.tst_RowAry(0, 1, "John Doe");
}
public void DeleteMany_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 2).Arg_("name", "Jane Smith"));
fx.tst_ExecDml(2, Db_qry_.delete_tbl_("dbs_crud_ops"));
fx.tst_ExecRdrTbl(0, "dbs_crud_ops");
}
public void SelectLike_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "John Doe"));
fx.tst_ExecRdr(1, Db_qry_.select_cols_("dbs_crud_ops", Db_crt_.like_("name", "John%")));
fx.tst_RowAry(0, 1, "John Doe");
}
public void SelectLikeForFileName_hook() {
this.Init();
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "file%"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "file|%"));
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 1).Arg_("name", "file test"));
fx.tst_ExecRdr(1, Db_qry_.select_cols_("dbs_crud_ops", Db_crt_.like_("name", "file|%")));
fx.tst_RowAry(0, 1, "file%");
}
public void InsertUnicode_hook() {
this.Init();
String val = "Ω";
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 3).Arg_obj_type_("name", val, Db_val_type.Tid_nvarchar));
Db_qry_select select = Db_qry_.select_val_("dbs_crud_ops", "name", Db_crt_.eq_("id", 3));
Tfds.Eq(val, ExecRdr_val(select));
fx.tst_ExecDml(1, Db_qry_.update_("dbs_crud_ops", Db_crt_.Wildcard).Arg_obj_type_("name", val + "a", Db_val_type.Tid_nvarchar));
Tfds.Eq(val + "a", ExecRdr_val(select));
}
public void Backslash_hook() {
this.Init();
String val = "\\";
fx.tst_ExecDml(1, Db_qry_.insert_("dbs_crud_ops").Arg_("id", 3).Arg_("name", val));
Tfds.Eq(val, ExecRdr_val(Db_qry_.select_val_("dbs_crud_ops", "name", Db_crt_.eq_("id", 3))));
Tfds.Eq(val, ExecRdr_val(Db_qry_.select_val_("dbs_crud_ops", "name", Db_crt_.eq_("name", "\\"))));
}
String ExecRdr_val(Db_qry_select select) {return (String)select.ExecRdr_val(fx.Provider());}
}

View File

@@ -0,0 +1,79 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.dbs; import gplx.*;
import org.junit.*;
public class db_DataTypes_tst {
DataTypes_base_fxt fx = new DataTypes_base_fxt();
@Test public void Mysql() {if (Tfds.SkipDb) return;
fx.Select_FloatStr_("0.333333");
fx.RunAll(Db_provider_fxt.Mysql());
}
@Test public void Tdb() {if (Tfds.SkipDb) return;
fx.Select_FloatStr_(Float_.XtoStr(Float_.Div(1, 3)));
fx.RunAll(Db_provider_fxt.Tdb("110_dbs_multiple_data_types.dsv"));
}
@Test public void Postgres() {if (Db_provider_fxt.SkipPostgres) return;
fx.Select_FloatStr_("0.33333334");
fx.RunAll(Db_provider_fxt.Postgres());
}
@Test public void Sqlite() {if (Tfds.SkipDb) return;
fx.Select_FloatStr_("0.33333334");
fx.RunAll(Db_provider_fxt.Sqlite());
}
/*
DROP TABLE dbs_multiple_data_types;
CREATE TABLE dbs_multiple_data_types (
unique_id int
, full_name varchar(255)
, is_active bit
, last_update timestamp
, quantity float(24)
, amount decimal(12, 3)
);
INSERT INTO dbs_multiple_data_types VALUES (1, 'John Doe', B'1', '3/30/2006 10:22 PM', 0.333333343, 12.345);
*/
}
class DataTypes_base_fxt {
public Db_provider Provider() {return provider;} Db_provider provider;
public DataTypes_base_fxt() {}
public void Rls() {provider.Rls();}
public String Select_FloatStr() {return select_FloatStr;} public DataTypes_base_fxt Select_FloatStr_(String v) {select_FloatStr = v; return this;} private String select_FloatStr;
public void RunAll(Db_provider provider) {
this.provider = provider;
this.Select_hook(select_FloatStr);
provider.Rls();
}
public void Select_hook(String floatStr) {
DataRdr rdr = Db_qry_.select_tbl_("dbs_multiple_data_types").Exec_qry_as_rdr(provider);
rdr.MoveNextPeer();
Tfds.Eq(rdr.ReadInt("unique_id"), 1);
Tfds.Eq(rdr.ReadStr("full_name"), "John Doe");
Tfds.Eq(rdr.ReadBool("is_active"), true);
Tfds.Eq_date(rdr.ReadDate("last_update"), DateAdp_.parse_gplx("2006-03-30 22:22:00.000"));
Tfds.Eq(floatStr, Object_.XtoStr_OrEmpty(rdr.ReadFloat("quantity")));
Tfds.Eq_decimal(rdr.ReadDecimal("amount"), DecimalAdp_.parts_(12, 345));
}
public void UpdateDate_hook() {
provider.Exec_qry(Db_qry_.update_("dbs_multiple_data_types", Db_crt_.eq_("unique_id", 1)).Arg_obj_("last_update", DateAdpClassXtn._.XtoDb(DateAdp_.parse_gplx("20091115 220000.000"))));
DataRdr rdr = Db_qry_.select_tbl_("dbs_multiple_data_types").Exec_qry_as_rdr(provider);
rdr.MoveNextPeer();
Tfds.Eq_date(rdr.ReadDate("last_update"), DateAdp_.parse_gplx("20091115 220000.000"));
}
}