1 21 22 23 package org.apache.derbyTesting.functionTests.util; 24 25 import java.sql.*; 26 import java.io.*; 27 import java.lang.reflect.*; 28 import java.util.Enumeration ; 29 import java.util.Hashtable ; 30 import java.util.Locale ; 31 import java.util.Properties ; 32 import java.util.StringTokenizer ; 33 import java.util.NoSuchElementException ; 34 import java.security.AccessController ; 35 import java.security.PrivilegedAction ; 36 import java.security.PrivilegedExceptionAction ; 37 import java.security.PrivilegedActionException ; 38 import javax.sql.DataSource ; 39 40 import org.apache.derby.iapi.reference.JDBC30Translation; 41 import org.apache.derby.iapi.services.info.JVMInfo; 42 import org.apache.derbyTesting.functionTests.harness.RunTest; 43 44 45 46 47 52 public class TestUtil { 53 54 public static boolean HAVE_DRIVER_CLASS; 56 static{ 57 try{ 58 Class.forName("java.sql.Driver"); 59 HAVE_DRIVER_CLASS = true; 60 } 61 catch(ClassNotFoundException e){ 62 HAVE_DRIVER_CLASS = false; 64 } 65 } 66 67 public static final int UNKNOWN_FRAMEWORK = -1; 68 69 72 public static final int EMBEDDED_FRAMEWORK = 0; 73 74 77 public static final int DERBY_NET_FRAMEWORK = 1; 78 79 83 84 public static final int DB2JCC_FRAMEWORK = 2; 86 89 public static final int DERBY_NET_CLIENT_FRAMEWORK = 3; 91 92 97 public static final int OLD_NET_FRAMEWORK = 4; 99 100 private static int framework = UNKNOWN_FRAMEWORK; 101 102 103 private static String XA_DATASOURCE_STRING = "XA"; 106 private static String CONNECTION_POOL_DATASOURCE_STRING = "ConnectionPool"; 107 private static String REGULAR_DATASOURCE_STRING = ""; 108 private static String JSR169_DATASOURCE_STRING = "Simple"; 109 110 112 119 public static boolean isNetFramework() 120 { 121 framework = getFramework(); 122 switch (framework) 123 { 124 case DERBY_NET_FRAMEWORK: 125 case DERBY_NET_CLIENT_FRAMEWORK: 126 case DB2JCC_FRAMEWORK: 127 case OLD_NET_FRAMEWORK: 128 return true; 129 default: 130 return false; 131 } 132 } 133 134 139 public static boolean isJCCFramework() 140 { 141 int framework = getFramework(); 142 switch (framework) 143 { 144 case DERBY_NET_FRAMEWORK: 145 case DB2JCC_FRAMEWORK: 146 case OLD_NET_FRAMEWORK: 147 return true; 148 } 149 return false; 150 } 151 152 public static boolean isDerbyNetClientFramework() 153 { 154 return (getFramework() == DERBY_NET_CLIENT_FRAMEWORK); 155 } 156 157 public static boolean isEmbeddedFramework() 158 { 159 return (getFramework() == EMBEDDED_FRAMEWORK); 160 } 161 162 170 private static int getFramework() 171 { 172 if (framework != UNKNOWN_FRAMEWORK) 173 return framework; 174 String frameworkString = (String ) AccessController.doPrivileged 175 (new PrivilegedAction () { 176 public Object run() { 177 return System.getProperty("framework"); 178 } 179 } 180 ); 181 if (frameworkString == null) 184 { 185 String useprocessFramework = RunTest.framework; 186 if (useprocessFramework != null) 187 frameworkString = useprocessFramework; 188 } 189 if (frameworkString == null || 190 frameworkString.toUpperCase(Locale.ENGLISH).equals("EMBEDDED")) 191 framework = EMBEDDED_FRAMEWORK; 192 else if (frameworkString.toUpperCase(Locale.ENGLISH).equals("DERBYNETCLIENT")) 193 framework = DERBY_NET_CLIENT_FRAMEWORK; 194 else if (frameworkString.toUpperCase(Locale.ENGLISH).equals("DERBYNET")) 195 framework = DERBY_NET_FRAMEWORK; 196 else if (frameworkString.toUpperCase(Locale.ENGLISH).indexOf("DB2JNET") != -1) 197 framework = OLD_NET_FRAMEWORK; 198 199 return framework; 200 201 } 202 203 211 public static String getJdbcUrlPrefix() 212 { 213 String hostName=getHostName(); 214 return getJdbcUrlPrefix(hostName, 1527); 215 } 216 217 220 public static String getHostName() 221 { 222 String hostName = (String ) AccessController.doPrivileged 223 (new PrivilegedAction () { 224 public Object run() { 225 return System.getProperty("hostName"); 226 } 227 } 228 ); 229 if (hostName == null) 230 hostName="localhost"; 231 return hostName; 232 } 233 234 247 public static String getJdbcUrlPrefix(String server, int port) 248 { 249 int framework = getFramework(); 250 switch (framework) 251 { 252 case EMBEDDED_FRAMEWORK: 253 return "jdbc:derby:"; 254 case DERBY_NET_FRAMEWORK: 255 case OLD_NET_FRAMEWORK: 256 return "jdbc:derby:net://" + server + ":" + port + "/"; 257 case DERBY_NET_CLIENT_FRAMEWORK: 258 return "jdbc:derby://" + server + ":" + port + "/"; 259 case DB2JCC_FRAMEWORK: 260 return "jdbc:db2://" + server + ":" + port + "/"; 261 } 262 return null; 264 265 } 266 267 270 public static void loadDriver() throws Exception 271 { 272 final String driverName; 273 framework = getFramework(); 274 switch (framework) 275 { 276 case EMBEDDED_FRAMEWORK: 277 driverName = "org.apache.derby.jdbc.EmbeddedDriver"; 278 break; 279 case DERBY_NET_FRAMEWORK: 280 case OLD_NET_FRAMEWORK: 281 case DB2JCC_FRAMEWORK: 282 driverName = "com.ibm.db2.jcc.DB2Driver"; 283 break; 284 case DERBY_NET_CLIENT_FRAMEWORK: 285 driverName = "org.apache.derby.jdbc.ClientDriver"; 286 break; 287 default: 288 driverName= "org.apache.derby.jdbc.EmbeddedDriver"; 289 break; 290 } 291 292 try { 293 AccessController.doPrivileged 294 (new PrivilegedExceptionAction () { 295 public Object run() throws Exception { 296 return Class.forName(driverName).newInstance(); 297 } 298 } 299 ); 300 } catch (PrivilegedActionException e) { 301 throw e.getException(); 302 } 303 } 304 305 306 314 public static javax.sql.DataSource getDataSource(Properties attrs) 315 { 316 String classname; 317 if(HAVE_DRIVER_CLASS) 318 { 319 classname = getDataSourcePrefix() + REGULAR_DATASOURCE_STRING + "DataSource"; 320 classname = checkForJDBC40Implementation(classname); 321 return (javax.sql.DataSource ) getDataSourceWithReflection(classname, attrs); 322 } 323 else 324 return getSimpleDataSource(attrs); 325 326 } 327 328 public static DataSource getSimpleDataSource(Properties attrs) 329 { 330 String classname = getDataSourcePrefix() + JSR169_DATASOURCE_STRING + "DataSource"; 331 return (javax.sql.DataSource ) getDataSourceWithReflection(classname, attrs); 332 } 333 334 342 public static javax.sql.XADataSource getXADataSource(Properties attrs) 343 { 344 345 String classname = getDataSourcePrefix() + XA_DATASOURCE_STRING + "DataSource"; 346 classname = checkForJDBC40Implementation(classname); 347 return (javax.sql.XADataSource ) getDataSourceWithReflection(classname, attrs); 348 } 349 350 351 359 public static javax.sql.ConnectionPoolDataSource getConnectionPoolDataSource(Properties attrs) 360 { 361 String classname = getDataSourcePrefix() + CONNECTION_POOL_DATASOURCE_STRING + "DataSource"; 362 classname = checkForJDBC40Implementation(classname); 363 return (javax.sql.ConnectionPoolDataSource ) getDataSourceWithReflection(classname, attrs); 364 } 365 366 374 public static String checkForJDBC40Implementation(String classname) { 375 String classname_ = classname; 376 if (JVMInfo.JDK_ID >= JVMInfo.J2SE_16) { 380 String classname40 = classname_ + "40"; 381 try { 382 Class.forName(classname40); 383 classname_ = classname40; 384 } catch (ClassNotFoundException e) {} 385 } 386 return classname_; 387 } 388 389 public static String getDataSourcePrefix() 390 { 391 framework = getFramework(); 392 switch(framework) 393 { 394 case OLD_NET_FRAMEWORK: 395 case DERBY_NET_FRAMEWORK: 396 case DB2JCC_FRAMEWORK: 397 return "com.ibm.db2.jcc.DB2"; 398 case DERBY_NET_CLIENT_FRAMEWORK: 399 return "org.apache.derby.jdbc.Client"; 400 case EMBEDDED_FRAMEWORK: 401 return "org.apache.derby.jdbc.Embedded"; 402 default: 403 Exception e = new Exception ("FAIL: No DataSource Prefix for framework: " + framework); 404 e.printStackTrace(); 405 } 406 return null; 407 } 408 409 410 411 static private Class [] STRING_ARG_TYPE = {String .class}; 412 static private Class [] INT_ARG_TYPE = {Integer.TYPE}; 413 static private Class [] BOOLEAN_ARG_TYPE = { Boolean.TYPE }; 414 private static Hashtable specialAttributes = null; 416 417 418 private static Object getDataSourceWithReflection(String classname, Properties attrs) 419 { 420 Object [] args = null; 421 Object ds = null; 422 Method sh = null; 423 String methodName = null; 424 425 if (specialAttributes == null) 426 { 427 specialAttributes = new Hashtable (); 428 specialAttributes.put("portNumber",INT_ARG_TYPE); 429 specialAttributes.put("driverType",INT_ARG_TYPE); 430 specialAttributes.put("retrieveMessagesFromServerOnGetMessage", 431 BOOLEAN_ARG_TYPE); 432 specialAttributes.put("retrieveMessageText", 433 BOOLEAN_ARG_TYPE); 434 } 435 436 try { 437 ds = Class.forName(classname).newInstance(); 438 439 String hostName = getHostName(); 442 if ( (!isEmbeddedFramework()) && (hostName != null ) && (attrs.getProperty("serverName") == null) ) 443 attrs.setProperty("serverName", hostName); 444 445 for (Enumeration propNames = attrs.propertyNames(); 446 propNames.hasMoreElements();) 447 { 448 String key = (String ) propNames.nextElement(); 449 Class [] argType = (Class []) specialAttributes.get(key); 450 if (argType == null) 451 argType = STRING_ARG_TYPE; 452 String value = attrs.getProperty(key); 453 if (argType == INT_ARG_TYPE) 454 { 455 args = new Integer [] 456 { new Integer (Integer.parseInt(value)) }; 457 } 458 else if (argType == BOOLEAN_ARG_TYPE) 459 { 460 args = new Boolean [] { new Boolean (value) }; 461 } 462 else if (argType == STRING_ARG_TYPE) 463 { 464 args = new String [] { value }; 465 } 466 else { 468 throw new Exception ("FAIL: getDataSourceWithReflection: Argument type " + argType[0].getName() + " not supportted for attribute: " + 469 " key:" + key + " value:" +value); 470 471 } 472 methodName = getSetterName(key); 473 474 475 sh = ds.getClass().getMethod(methodName, argType); 478 sh.invoke(ds, args); 479 } 480 481 } catch (Exception e) 482 { 483 System.out.println("Error accessing method " + methodName); 484 System.out.println(e.getMessage()); 485 e.printStackTrace(); 486 } 487 return ds; 488 } 489 490 491 public static String getSetterName(String attribute) 492 { 493 return "set" + Character.toUpperCase(attribute.charAt(0)) + attribute.substring(1); 494 } 495 496 497 public static String getGetterName(String attribute) 498 { 499 return "get" + Character.toUpperCase(attribute.charAt(0)) + attribute.substring(1); 500 } 501 502 public static void dumpSQLExceptions(SQLException sqle) { 504 TestUtil.dumpSQLExceptions(sqle, false); 505 } 506 507 public static void dumpSQLExceptions(SQLException sqle, boolean expected) { 508 String prefix = ""; 509 if (!expected) { 510 System.out.println("FAIL -- unexpected exception ****************"); 511 } 512 else 513 { 514 prefix = "EXPECTED "; 515 } 516 517 do 518 { 519 System.out.println(prefix + "SQLSTATE("+sqle.getSQLState()+"): " + sqle.getMessage()); 520 sqle = sqle.getNextException(); 521 } while (sqle != null); 522 } 523 524 525 public static String sqlNameFromJdbc(int jdbcType) { 526 switch (jdbcType) { 527 case Types.BIT : return "Types.BIT"; 528 case JDBC30Translation.SQL_TYPES_BOOLEAN : return "Types.BOOLEAN"; 529 case Types.TINYINT : return "Types.TINYINT"; 530 case Types.SMALLINT : return "SMALLINT"; 531 case Types.INTEGER : return "INTEGER"; 532 case Types.BIGINT : return "BIGINT"; 533 534 case Types.FLOAT : return "Types.FLOAT"; 535 case Types.REAL : return "REAL"; 536 case Types.DOUBLE : return "DOUBLE"; 537 538 case Types.NUMERIC : return "Types.NUMERIC"; 539 case Types.DECIMAL : return "DECIMAL"; 540 541 case Types.CHAR : return "CHAR"; 542 case Types.VARCHAR : return "VARCHAR"; 543 case Types.LONGVARCHAR : return "LONG VARCHAR"; 544 case Types.CLOB : return "CLOB"; 545 546 case Types.DATE : return "DATE"; 547 case Types.TIME : return "TIME"; 548 case Types.TIMESTAMP : return "TIMESTAMP"; 549 550 case Types.BINARY : return "CHAR () FOR BIT DATA"; 551 case Types.VARBINARY : return "VARCHAR () FOR BIT DATA"; 552 case Types.LONGVARBINARY : return "LONG VARCHAR FOR BIT DATA"; 553 case Types.BLOB : return "BLOB"; 554 555 case Types.OTHER : return "Types.OTHER"; 556 case Types.NULL : return "Types.NULL"; 557 default : return String.valueOf(jdbcType); 558 } 559 } 560 public static String getNameFromJdbcType(int jdbcType) { 561 switch (jdbcType) { 562 case Types.BIT : return "Types.BIT"; 563 case JDBC30Translation.SQL_TYPES_BOOLEAN : return "Types.BOOLEAN"; 564 case Types.TINYINT : return "Types.TINYINT"; 565 case Types.SMALLINT : return "Types.SMALLINT"; 566 case Types.INTEGER : return "Types.INTEGER"; 567 case Types.BIGINT : return "Types.BIGINT"; 568 569 case Types.FLOAT : return "Types.FLOAT"; 570 case Types.REAL : return "Types.REAL"; 571 case Types.DOUBLE : return "Types.DOUBLE"; 572 573 case Types.NUMERIC : return "Types.NUMERIC"; 574 case Types.DECIMAL : return "Types.DECIMAL"; 575 576 case Types.CHAR : return "Types.CHAR"; 577 case Types.VARCHAR : return "Types.VARCHAR"; 578 case Types.LONGVARCHAR : return "Types.LONGVARCHAR"; 579 case Types.CLOB : return "Types.CLOB"; 580 581 case Types.DATE : return "Types.DATE"; 582 case Types.TIME : return "Types.TIME"; 583 case Types.TIMESTAMP : return "Types.TIMESTAMP"; 584 585 case Types.BINARY : return "Types.BINARY"; 586 case Types.VARBINARY : return "Types.VARBINARY"; 587 case Types.LONGVARBINARY : return "Types.LONGVARBINARY"; 588 case Types.BLOB : return "Types.BLOB"; 589 590 case Types.OTHER : return "Types.OTHER"; 591 case Types.NULL : return "Types.NULL"; 592 default : return String.valueOf(jdbcType); 593 } 594 } 595 596 597 598 public static String TABLE_START_TAG = "<TABLE border=1 cellspacing=1 cellpadding=1 bgcolor=white style='width:100%'>"; 599 public static String TABLE_END_TAG = "</TABLE>"; 600 public static String TD_INVERSE = 601 "<td valign=bottom align=center style=background:#DADADA; padding:.75pt .75pt .75pt .75pt'> <p class=MsoNormal style='margin-top:6.0pt;margin-right:0in;margin-bottom: 6.0pt;margin-left:0in'><b><span style='font-size:8.5pt;font-family:Arial; color:black'>"; 602 603 public static String TD_CENTER = "<TD valign=center align=center> <p class=MsoNormal style='margin-top:6.0pt;margin-right:0in;margin-bottom:6.0pt;margin-left:0in'><b><span style='font-size:8.5pt;font-family:Arial; color:black'>"; 604 605 public static String TD_LEFT = "<TD valign=center align=left> <p class=MsoNormal style='margin-top:6.0pt;margin-right:0in;margin-bottom:6.0pt;margin-left:0in'><b><span style='font-size:8.5pt;font-family:Arial; color:black'>"; 606 607 608 public static String TD_END = "</SPAN></TD>"; 609 610 public static String END_HTML_PAGE="</BODY> </HTML>"; 611 612 613 public static void startHTMLPage(String title, String author) 614 { 615 System.out.println("<HTML> \n <HEAD>"); 616 System.out.println(" <meta http-equiv=\"Content-Type\"content=\"text/html; charset=iso-8859-1\">"); 617 System.out.println("<meta name=\"Author\" content=\"" + author + "\">"); 618 System.out.println("<title>" + title + "</title>"); 619 System.out.println("</HEAD> <BODY>"); 620 System.out.println("<H1>" + title + "</H1>"); 621 } 622 623 public static void endHTMLPage() 624 { 625 System.out.println(END_HTML_PAGE); 626 } 627 628 633 634 641 public static void printBoolArrayHTMLTable(String rowDescription, 642 String columnDescription, 643 String [] rowLabels, 644 String [] colLabels, 645 boolean[][] array, 646 String tableInfo) 647 { 648 649 System.out.println("<H2>" + tableInfo + "</H2>"); 650 651 System.out.println(TABLE_START_TAG); 652 System.out.println("<TR>"); 653 System.out.println(TD_INVERSE +columnDescription + "---><BR><BR><BR><BR><BR>"); 655 System.out.println("<---" +rowDescription); 656 System.out.println(TD_END); 657 658 659 for (int i = 0; i < colLabels.length; i++) 661 { 662 System.out.println(TD_INVERSE); 663 for (int c = 0; c < colLabels[i].length() && c < 20; c++) 664 { 665 System.out.println(colLabels[i].charAt(c) + "<BR>"); 666 } 667 System.out.println(TD_END); 668 } 669 670 System.out.println("</TR>"); 671 672 for (int i = 0; i < rowLabels.length; i ++) 674 { 675 System.out.println("<TR>"); 676 System.out.println(TD_LEFT); 677 System.out.println("<C> " + rowLabels[i] + "</C>"); 678 System.out.println(TD_END); 679 680 for (int j = 0; j < colLabels.length; j ++) 681 { 682 System.out.println(TD_CENTER); 683 System.out.println((array[i][j]) ? "Y" : "-"); 684 System.out.println(TD_END); 685 } 686 System.out.println("</TR>"); 687 } 688 689 690 System.out.println(TABLE_END_TAG); 691 System.out.println("<P><P>"); 692 693 } 694 695 703 public static String stringToHexLiteral(String s) 704 { 705 byte[] bytes; 706 String hexLiteral = null; 707 try { 708 bytes = s.getBytes("UTF-16BE"); 709 hexLiteral = convertToHexString(bytes); 710 } 711 catch (UnsupportedEncodingException ue) 712 { 713 System.out.println("This shouldn't happen as UTF-16BE should be supported"); 714 ue.printStackTrace(); 715 } 716 717 return hexLiteral; 718 } 719 720 private static String convertToHexString(byte [] buf) 721 { 722 StringBuffer str = new StringBuffer (); 723 str.append("X'"); 724 String val; 725 int byteVal; 726 for (int i = 0; i < buf.length; i++) 727 { 728 byteVal = buf[i] & 0xff; 729 val = Integer.toHexString(byteVal); 730 if (val.length() < 2) 731 str.append("0"); 732 str.append(val); 733 } 734 return str.toString() +"'"; 735 } 736 737 738 739 742 743 public static int getJDBCMajorVersion(Connection conn) 744 { 745 try { 746 conn.getClass().getMethod("setSavepoint", null); 750 DatabaseMetaData meta = conn.getMetaData(); 751 Method method = 752 meta.getClass().getMethod("getJDBCMajorVersion", null); 753 return ((Number ) method.invoke(meta, null)).intValue(); 754 } catch (Throwable t) { 755 return 2; 758 } 759 760 } 761 762 769 public static void cleanUpTest (Statement s, String [] testObjects) 770 throws SQLException { 771 772 for (int i=0; i < testObjects.length; i++) { 773 try { 774 s.execute("drop " + testObjects[i]); 775 } catch (SQLException se) { } 778 } 779 } 780 781 782 800 public static Connection getConnection(String databaseName, String connAttrs) 801 throws SQLException { 802 try { 803 Connection conn; 804 if(TestUtil.HAVE_DRIVER_CLASS) { 805 String driverName; 808 int framework = getFramework(); 809 switch (framework) 810 { 811 case EMBEDDED_FRAMEWORK: 812 driverName = "org.apache.derby.jdbc.EmbeddedDriver"; 813 break; 814 case DERBY_NET_FRAMEWORK: 815 case OLD_NET_FRAMEWORK: 816 case DB2JCC_FRAMEWORK: 817 driverName = "com.ibm.db2.jcc.DB2Driver"; 818 break; 819 case DERBY_NET_CLIENT_FRAMEWORK: 820 driverName = "org.apache.derby.jdbc.ClientDriver"; 821 break; 822 default: 823 driverName = "org.apache.derby.jdbc.EmbeddedDriver"; 824 break; 825 } 826 Class.forName(driverName).newInstance(); 828 829 String url = getJdbcUrlPrefix() + databaseName; 830 if (connAttrs != null) url += ";" + connAttrs; 831 if (framework == DERBY_NET_FRAMEWORK) 832 { 833 if (( connAttrs == null) || ((connAttrs != null) && (connAttrs.indexOf("user") < 0))) 834 url += ":" + "user=APP;password=APP;retrieveMessagesFromServerOnGetMessage=true;"; 835 } 836 conn = DriverManager.getConnection(url); 837 } 838 else { 839 Properties prop = new Properties (); 841 prop.setProperty("databaseName", databaseName); 842 if (connAttrs != null) 843 prop.setProperty("connectionAttributes", connAttrs); 844 conn = getDataSourceConnection(prop); 845 } 846 return conn; 847 } catch (ClassNotFoundException cnfe) { 848 System.out.println("FAILure: Class not found!"); 849 cnfe.printStackTrace(); 850 return null; 851 } catch (InstantiationException inste) { 852 System.out.println("FAILure: Cannot instantiate class"); 853 inste.printStackTrace(); 854 return null; 855 } catch (IllegalAccessException ille) { 856 System.out.println("FAILure: Not allowed to use class"); 857 ille.printStackTrace(); 858 return null; 859 } 860 } 861 862 public static Connection getDataSourceConnection (Properties prop) throws SQLException { 863 DataSource ds = TestUtil.getDataSource(prop); 864 try { 865 Connection conn = ds.getConnection(); 866 return conn; 867 } 868 catch (SQLException e) { 869 throw e; 870 } 871 } 872 873 public static void shutdownUsingDataSource (String dbName) throws SQLException { 874 Properties prop = new Properties (); 875 prop.setProperty("databaseName", dbName ); 876 prop.setProperty("shutdownDatabase", "shutdown" ); 877 DataSource ds = TestUtil.getDataSource(prop); 878 try { 879 Connection conn = ds.getConnection(); 880 } 881 catch (SQLException e) { 882 throw e; 883 } 884 } 885 886 public static boolean compareURL(String url) { 888 889 if(isEmbeddedFramework()) { 890 if(url.compareTo("jdbc:derby:wombat") == 0) 891 return true; 892 } else if(isNetFramework()) { 893 try { 894 StringTokenizer urlTokenizer = new StringTokenizer (url, "/"); 895 String urlStart = urlTokenizer.nextToken(); 896 urlTokenizer.nextToken(); 897 String urlEnd = urlTokenizer.nextToken(); 898 899 if(urlEnd.compareTo("wombat;create=true") != 0) 900 return false; 901 902 if(isJCCFramework() && (urlStart.compareTo("jdbc:derby:net:") == 0)) 903 return true; 904 905 if(isDerbyNetClientFramework() && (urlStart.compareTo("jdbc:derby:") == 0)) 906 return true; 907 908 } catch (NoSuchElementException nsee) { 909 return false; 911 } 912 } 913 914 return false; 915 } 916 917 } 918 919 | Popular Tags |