Log4j's basic application

zhaozj2021-02-16  156

Introduction log4j is an open source project, which enables developers to maximize the output of the flexible control program debugging information, which is implemented by additional profiles. And the log4j development kit is easy to get started, and some developers may be addictive. Most large development projects have their own APIs themselves for recording program logs and debugging programs. Many experience proves that the management of debugging information plays a very important role in software development. Log management usually provides the following benefits: First, it can make the context of running during the running process of the program (CONTEXT), which is convenient for our developers, once the log output is added, the program is running The logging information can be automatically generated during the process. Second, log information can be output to different places (consisters, documents, log servers, etc.) to study. Finally, in addition to playing its role during the development process, a powerful logging development package can be used as an audit tool. In order to adapt to the above law, early 1996 EU Semper (Secure Electronic Marketplace For Europe) project group decided to develop its own log management development package (Tracing API), after countless changes and function, eventually born log4j - - A very popular Java logging development kit. The issuance of this development kit follows IBM Public License, Certified by The Open Source Initiative. At the same time, Logging does have some defects, for example, it affects the speed of the program run, increasing the cost of the code, and adds many unnecessary outputs. In order to reduce the impact of these negative factors, log4j is designed to be as efficient and flexible. Because, few applications (systems) use the log log as the main function, log4j's developers try to make LOG4J easy to understand and use. This article first describes the approximate frameworks and important components of LOG4J. The author explains how to use log4j through some simple examples.

Categories, Appenders, And LayOutslog4j The most important three basic components: 1. Categories (Classifying the log information, what information is what information should be output, what log information should be ignored) 2. Appenders (Defining the LOG information output, the log information should be output to where, console, file, network device, etc.) 3. Layouts (formatting log information) software developers can implement records according to the type and priority of the log through these three components, and can control the format of log information output when the program is running, where to output anywhere (Console, log file), let us understand them again.

Compared to the system.out.println mode output debug information, a dedicated log control tool (Logging API) is that it is capable of shutting down some debug information output when appropriate, without affecting other people's debugging. The implementation of this capability is determined to classify these logging information based on a certain standard. Based on the above principles, the org.apache.log4j.category class implements the core of the entire log4j package, and the debug information is classified and named according to the habits of the general developers. Similar to the classification rules for Java development kits, (a category is said ing it, is aprofix of the child category name.), For example, Category named com.foo is Named Catent's Parent in COM.FOO.BAR. Just as our habit of java is a parent of java.util, and is the same as Java.util.Vector. The uppermost Category is called root category, and the root Category has two features: (1) It always exists (IT Always Exists) (2) It cannot be directly obtained in the Category class, we pass Gtroot () The method gets root category. The static method getInstance () instantiates all other category. GetInstance () gets the instance name of the instantiated category by calling the quotation. Other methods Category class are listed below: package org.apache.log4j; public Category class {// Creation & retrieval methods: public static Category getRoot (); public static Category getInstance (String name); // printing methods: public void debug (String message); public void info (String message); public void warn (String message); public void error (String message); // generic printing method: public void log (Priority p, String message);} us You can define a Category priority through the set method in the org.apache.log4j.priority class. (Set the priority level of Category and the level of the traditional UNIX Syslog definition). But log4j only encourages the following four priority: Error, Warn, Info, and Debug, these four level priorities are Error> Warn> Info> Debug. However, Org.apache.log4j.Propority provides higher flexibility, that is, users can define their priority with subclasses of the Priority class. If a category is not defined to define its own priority, it will inherit the priority defined by the closest ancestor. This ensures that all Category eventually inherits a priority (because the root Category has a default priority definition).

After we get an instance of Category, we can output debugging information by calling the following method: 1. Error () Output Error level debugging information 2.warn () Output WARN level debugging information 3.Info () Output Info level Debug Information 4. DEBUG () Output Debug Level Debug Information 5.log () The normal log information is defined, and the above five methods will determine the priority of the output information. For an example, if C is an instance of a Category class, then statement C.info ("...") is only performed when the priority is reached at the INFO-level output request (a logging request). A logging request means that it is permitted when the debug level is above or equal to this level. Otherwise, this log output request is not allowed, and a Category that is not defined priority will automatically inherit the priority from its Parent or Ancestor according to the hierarchical relationship. By the following block, you will find this rule: // Get a category instance named "com.foo" category cat = category.getInstance ("com.foo"); // now set its priority.cat.setPriority (Priority) .Info); category bart = category.getInstance ("com.foo.bar"); // this request is enabled, Because Warn> = info.cat.warn ("Low Fuel Level."); // this request is Disabled, Because Debug = info.barcat.info ("Located Nearest Gas Station); // this request is disabled, Because Debug

If the GetInstance () method is called multiple times by the same number, the reference to the Category object generated during the first call is returned. Therefore, in this way we can configure a category and do not require additional processing to get this object elsewhere. Category can create and configure it in any order. One thing worth noting is that a Parent Category back automatically found and connects to his Child's CAGETORY, even, he is defined after his Child Category. LOG4J is usually set when the program or class is initialized. The best way is to define the log4j configuration information through additional profiles, and then we will discuss this aspect. Log4j allows the name of Category to be defined by the name of the program component. This way we can define a Category for each Java class file name (including the package name of this class), which is a useful and intuitive Category instance name definition. And so that we can easily determine their respective sources from a large number of log information. Of course, that is not a hard specified, in fact, log4j does not limit what restrictions on setting Category's instance names, programmers can define the instance name of Category according to their own preferences.

Appenders and layouts implements a flexible control of the log information through Category only one of the Log4J packages, and the Log4J's Appenders class also implements outputting log information to many different output devices. Currently, log4j's appenders can achieve log information to the following output devices: 1.console2.files 3.gui Components 4.Remote Socket Servers5.nt Event loggers6.remote Unix Syslog daem a category can be referenced at the same time That is, a Category log information can be output simultaneously to multiple output devices. For an almost, if you make a root category log information to console, then natural, this root category all the log information that is allowed to output will be output to the console, then you define a child category, and This Child Category's log information is output to File appenders. We assume that this Child Category's name is C, then all the allowed LOG information of C and C's Child Category will be output to Console Appender and File Appender. At the same time, it is worth noting that we can overwrite this default setting to avoid that some rest Appenders are automatically configured in the Parent Category due to the inheritance relationship between Category. Usually, users not only need to specify the output device of log information, but they also need to configure the output format of log information, which is implemented by the Layout class associated with the appender class. Although the Appender class only implements how to output a formatted LOG information to the related output device, the Layout class can format the output of LOG information according to the user's needs. PatternLayout is part of the log4j release package that provides the same flexibility as the Printf method in the C language to let the programmer format LOG information. For example, formatting statement% R [% T]% -5p% C -% M% N will produce the following output format: 176 [main] info org.foo.bar - Located Nearest Gas Station format Description: The first one Regional "176" is equal to the program from the start of the millisecond number of milliseconds running to print out this information "[main]" is the thread "INFO" "INFO" in this LOG statement is the priority of this LOG statement The fourth area "org.foo.bar" is the content of the category name of this log information, the fifth region "LOCATED NEAREST GAS Station", the content of the log information.

The workload of the output statement that Configuration adds these log information is unmistive. The survey data shows that during program development, the code quantity required to output debug information is estimated to account for the entire application total code. % 4 of the amount. Therefore, even the most general size application also needs to include at least few thousand lines of LOG statements. In this way, it is important that the statement that we will maintain these log outputs is important. Although the LOG4J development kit can flexibly control the log output in the code, but the control of the LOG information is much flexible by the configuration file. Currently, log4j's profile supports XML format and Java Properties format. Let's take an example: Import com.foo.bar; // Import log4j classes.import org.apache.log4j.category; import org.apache.log4j.basicconfigurator; public class myapp {// define a static category variable sol it references the // Category instance named "MyApp" .static Category cat = Category.getInstance (MyApp.class.getName ()); public static void main (String [] args) {// Set up a simple configuration that logs on The console.basicconfigurator.configure (); cat.info ("Entering Application)); bar bar = new bar (); bar.doot (); cat.info (" exiting application. ");}} As seen, myApp class first introduces the relevant class in the log4j package, then defines a static Category instance named myApp, and everyone notes the name of this Category just like myApp class name. The MyApp class also uses BAR classes defined in the com.foo package: package com.foo; import org.apache.log4j.category; public class bar {static category cat = category.getInstance (bar.class.getname () ); public void doit () {cat.debug ("DID IT AGAIN!");}}

The class myApp is obtained by calling the BasicConfigurator.configure () method to get the default setting of log4j. This method sets the root category set a consolerapnder to make the log information to Console. And the output of the log information is default the% -4R [% T]%-5p% C% X -% M% N. It is also worth noting that the priority of root category is defined by default as priority.debug. MyApp program LOG output is: 0 [main] info myapp - Entering application.36 [main] debug com.foo.bar - DID IT Again! 51 [main] info myapp - exiting appli

The MyApp class gets the BasicConfigurator.configure () method to get the LOG4J's default configuration, and other classes only need to introduce the Org.log4j.category class and get a category to output LOG. The above example always outputs the same log information (unless you change the source code and recompile, this is the same as the system.out.println () function output debug information). But fortunately, log4j allows us to be slightly modified to myApp programs to control the log information at the time of the program. The following is a modified version: import com.foo.Bar; import org.apache.log4j.Category; import org.apache.log4j.PropertyConfigurator; public class MyApp {static Category cat = Category.getInstance (MyApp.class.getName ( )); public static void main (string [] args) {// BasicConfigurator replaced with propertyconfigurator.propertyConfigurator.configure (args [0]); Cat.info ("Entering Application)); bar bar = new bar (); Bar.Doit (); Cat.info ("EXITING Application.");}} The MYAPP reads the Log profile by passing the number of the PropertyConfigurator () method. The following is a simple example of a configuration file. The result of this configuration file will be the same as the Log4j's default configuration: # set root category prior to debug and its only appender to a1.log4j.rootcategory = debug, A1 # a1 is set to be a ConsoleAppender which outputs to System.out.log4j.appender.A1 org.apache.log4j.ConsoleAppender # A1 uses PatternLayout.log4j.appender.A1.layout = org.apache.log4j.PatternLayoutlog4j.appender.A1.layout.ConversionPattern = =% - 4R [% T]% -5P% C% X -% M% N

Suppose we don't need to include the log output of classes under com.foo, you can change the log configuration file to the following form: log4j.rootcategory = debug, a1log4j.Appender.a1 = org.apache.log4j.consoleAppenderlog4j.Appender.a1. Layout = org.apache.log4j.patternlayout # print the date in iso 8601 factoryLog4j.Appender.a1.Layout.conversionPattern =% D [% T]% -5p% C -% M% N # print Only Messages of Priority Warn OR Above in the package com.foo.log4j.category.com.foo = WARN Use the new profile will get the following log output: 2000-09-07 14: 07: 41, 508 [main] info myapp - Entering Application.2000-ENTERING APPLICEN 09-07 14: 07: 41, 529 [main] info myapp - exiting application. Because category com.foo.bar did not define a priority, it can only inherit priority from the package com.foo, and in the configuration file, we The priority defined for com.foo category is Warn. Therefore, the log output of the DOIT () method in the com.foo.bar class is prohibited. Below, we are in an example, the following profile makes the log information simultaneously output to the console and log file: log4j.rootcategory = debug, stdout, rlog4j.appender.stdout = org.apache.log4j.consolerappenderlog4j.Appender.stdout. Layout = org.apache.log4j.patternLayout # pattern to output the caller's file name and line number.log4j.Appender.stdout.Layout.conversionPattern =% 5P [% T] (% F:% L) -% M% NLOG4J. appender.R = org.apache.log4j.RollingFileAppenderlog4j.appender.R.File = example.loglog4j.appender.R.MaxFileSize = 100KB # Keep one backup filelog4j.appender.R.MaxBackupIndex = 1log4j.appender.R.layout = org .apache.log4j.patternlayoutlog4j.Appender.r.Layout.conversionPattern =% P% T% C -% M% N

Calling this enhanced version of the profile will see the following output information on the console: info [main] (myapp2.java: 12) - Entering Application.debug [main] (bar.java: 8) - doing it again! Info [main] (myapp2.java:15) - exitation application.

At the same time, in the above configuration file, we add the second output object FileAppender in Root Category. The log information will be output to the Example.log file at the same time. When the example.log file reaches 100KB, the example.log file will be automatically renamed EXAMPLE.LOG.1 simultaneously generate a new content empty EXAMPLE.LOG file. (In English is called Rolled over). One thing is worth emphasizing that we do not need to recompile the source when modifying the log information output. We can also simply output the log information into UNIX Syslog daem or output to NT Event Logger by modifying the log profile. Even we can also output the log information to the remote dedicated LOG server.

NESTED DIAGNOSTIC CONTEXTS currently developed many systems that need to process multiple client concurrent issues. In this typical concurrent system, different client requests are typically processed by different threads. Log Development Kit played a very important role in this case, in general, LOT4J can create different category to different threads, respectively, can distinguish those LOG outputs belong to a thread. of. But this way greatly aggravates the burden on the server. In order to save system overhead, log4j's designers use threads that deal with the same category to define a category to use them together, and then add information that can be sufficient to distinguish different client requests in the log information. This is implemented by NDC (Nested Diagnostic Context): Public Class Ndc {// Used When Printing The DiagnosticPublic static string get (); // remove the top of the context from the ndc.public static string pop (); / / Add diagnostic context for the current thread.public static void push (String message); // Remove the diagnostic context for this thread.public static void remove ();} NDC class for each thread maintains a single thread context save the stack . Everyone noticed that all methods in org.apache.log4j.ndc classes are static. Once the NDC function is used, the information in these thread context stacks will be automatically added to the log information, and the user cannot interfere. Programmers need to do just save the correct information to the NDC stack, which is implemented by the PUSH () and POP () methods. In order to further illustrate this, we give an example. Suppose we have a servlet program that requires both multiple client requests, which first establishes a new thread when receiving the client's request, and assigns a NDC stack for saving the context to save the request, the context May be a host name, IP address, or other information that can be obtained from request information and can distinguish information from request information, which is usually maintained in cookies. This allows even the servlet program that may also handle multiple clients, which can still be distinguished, because different client processing threads have different NDC stacks. This looks like a different Category as a different client request. Performance Some people object to use the LOG development kit in the program because they believe that the log process adds the overhead of the program and affects the speed of the program. This view also makes sense, because even a general size application is at least a few thousand log outputs. This is a problem that all Log development tools need to work hard. Log4j adhering to the design principle: speed and efficiency first, flexibility second. However, users still need to clearly understand the following and performance-related data: 1. Logging Performance When Logging is turned off. When log is disabled, the application still needs to do some excess system overhead on the number of methods. As shown below: Cat.debug ("Entry Number:" i "IS" String.Valueof (Entry [i])); Even if the log is disabled, the variable I and array Entry [i] is still initialized .

In order to reduce this overhead, we will change the above code segment to: if (Cat.IndebuGenabled () {cat.debug ("Entry Number:" i "IS" String.Valueof (entry [i] This is said that the program first determines whether the log function is turned on, and then decide whether these variables in the log code segment should be instantiated. However, even if the log function is turned on, the program still needs to make a redundant judgment, but In contrast, the ISDebugenabled () function execution time is only 1% of the entire log statement execution time. In log4j, all LOG information is processed primarily by the Category class, Category is designed, not interface, mainly It is to reduce the overhead of program calls, but this is at the expense of flexibility to sacrifice the interface .2. The Performance of Deciding WHENER TO log or not to log when Logging is turned on. Next, most effectilities The factor is the hierarchical relationship of Category. When the log function is opened, the log4j still needs to determine whether the log information needs to be output according to different log requests. And, some category instantiates the priority level of log information. This category must inherit the priority from his last Category. In order to get their priority settings, some category may need to search for his Parent Category or even its Ancestor Category. Log4j has done a lot in this area. The effort is to make the search to get the priority search as quickly as possible .3. Actual logging The last point may have a greater impact on performance. The formatting process of log information is. Log4j also pays more attention At this point, it is optimized. Usually, a typical formatting statement may need to use 100 to 300 microsecond processing time. Although the designer as designer as much as possible during the design process of the log4j development kit Features, but the speed has always been the factors they first consider. In order to improve the speed of operation, many parts of log4j have been overwritten more than once. EXAMPLES IN THE RELESE PACKAGE Currently Log4j's latest version number is 1.2.4. Issuance package The example of the belt is placed in an Examples directory, and the following is a brief introduction to the example of the distribution package: Trivial.java Package Sample;

import org.apache.log4j.Category; import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.NDC; public class Trivial {static Logger cat = Logger.getLogger (Trivial. Class.getName (); public static void main (string [] args) {BasicConfigurator.configure (); ndc.push ("Client # 45890"); Cat.info ("Awake Awake. Put on thy stregth.") TriVial.foo (); innertrivial.foo (); Cat.info ("exiting trivial.");} Static void foo () {ndc.push ("db"); Cat.debug ("now King David WAS Old NDC.POP ();} static class innertrival {static category cat = category.getInstance (InnerTrivial.class.getname ());

Static void foo () {cat.info ("Entered foo.");}}} Before compiling, make sure that the log4j decompressed / DIST / LIB / LOG4J-1.2.4.jar package is added to the LOG4J decompression ClassPath, then compiled, run the program, will get the following output information on the console: 0 [main] info sample.trivial Client # 45890 - Awake Awake. Put on thy stregth.10 [main] debug sample.trivial client # 45890 DB - Now King David Was Old.40 [Main] Info Sample.Trivial $ InnerTrivial Client # 45890 - Entered Foo.40 [Main] Info Sample.Trivial Client # 45890 - EXITING TRIVIAL.1) First introduced into the Log4j package Category class, Logger class (Logger class is subclass of the Category class, will gradually replace the Category class), the BasicConfigurator class, NDC class. 2) Instance a static Logger class, instance is named sample.trivial (by trivial.class.getname () method). 3) By calling the BasicConfigurator.configure () method to get the default configuration of log4j (including LOG information priority, output devices, etc.). 4) Press the thread context into the NDC stack by calling the PUSH () method of the NDC into the NDC stack. 5) Call the Logger's INFO () method outputs the INFO level log information. Note: The information in the NDC stack will be reserved unless the POP () method is called. Everyone pays that the Inner Class called InnerTrivial is defined in the Trivial class and re-acquires a category, but inNertriVial does not need to call the BasicConfigurator.configure () method to get the basic configuration to call the info () function output log information. This is because Category in the two classes has the same root category and inherits the configuration information from root category. Sort.java and Sortalgo.java give examples of how to use the configuration file. An example of using LOG4J in J2EE is given below. Use log4j in j2ee Use the log4j package in the J2EE server to note: 1) Based on the particularity of the J2EE server JAR package load mechanism, you must copy the LOG4J's JAR package to the% javahome / jre / lib / ext / directory. It doesn't work just in ClassPath. 2) Because the J2EE server strictly controls the file operation, only the% J2EE_HOME% / logs directory can be written when the log file is written, unless the server.policy file specifies the other write-written directory.

Let me give this very simple example showing how to use the log4j development kit in the J2EE server, the files involved in the example are as follows: Bonus.html

Bonus Calculation

Enter Social security Number:

enter Multiplier:

Bonus.html above accepts the social security number and insured amount entered by the user.

BonusServlet.javaimport javax.servlet *;. Import javax.servlet.http *;. Import java.io *;. Import javax.naming *;. Import javax.rmi.PortableRemoteObject; import Beans *;. Public class BonusServlet extends HttpServlet { CalcHome homecalc; public void init (ServletConfig config) throws ServletException {// Look up home interfacetry {InitialContext ctx = new InitialContext (); Object objref = ctx.lookup ( "calcs"); homecalc = (CalcHome) PortableRemoteObject.narrow (objref , CalcHome.class);} catch (Exception NamingException) {NamingException.printStackTrace ();}} public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String socsec = null; int multiplier = 0; double calc = 0.0 PrintWriter out; response.setContentType ("text / html"); string title = "ejb eXample"; out = response.getwriter (); out.println (" ); OUT. Println; Out.println ("</ Title> </ head> <body>"); try {CALC Thecalculation; // Get Multiplier and Social Security Informationstring Strmult = Req uest.getParameter ( "MULTIPLIER"); Integer integerMult = new Integer (strMult); multiplier = integerMult.intValue (); socsec = request.getParameter ( "SOCSEC"); // Calculate bonusdouble bonus = 100.00; theCalculation = homecalc.create (); calc = theCalculation.calcBonus (multiplier, bonus);} catch (Exception CreateException) {CreateException.printStackTrace ();} // Display Dataout.println ( "<H1> Bonus Calculation </ H1>"); out. Println ("<p> SOC Sec: Socsec " <p> "); Out.println (" <p> Multiplier: " Multiplier " <p> ");</p> <p>Out.println ("<p> Bonus Amount:" Calc "<p>"); Out.Println ("</ Body> </ HTML>"); out.close ();} public void destroy () {System.out.Println ("Destroy");}} Bonusservlert.java gets the social security number and amount transferred from Bonus.html, and calls the EJB program to process the data and display the result to the client.</p> <p>EJB's Home Interface: package Beans; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; public interface CalcHome extends EJBHome {Calc create () throws CreateException, RemoteException;} EJB Remote interface where: package Beans; import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Calc extends EJBObject {public double calcBonus (int multiplier, double bonus) throws RemoteException;} EJB service processing logic: package Beans; import java.rmi .RemoteException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class CalcBean implements SessionBean {public double calcBonus (int multiplier, double bonus) {double calc = (multiplier * bonus); return calc;} // These methods are described in more // detail in Lesson 2public void ejbCreate () {} public void setSessionContext (SessionContext ctx) {} public void ejbRemove () {} public void ejbActivate () {} public void ejbPassivate () {} public void ejbLoad () {} public void ejbstore () {}} After successfully released, you can join the log4j test code in your code. Want to learn more about the publishing steps of the above app, please take the article "Say 'Hello World' TO EJB". Next we use the LOG4J packet in EJB (due to the method of using the log4j in the servlet, the same method in the examples mentioned above, is not repeated). 1. First, increasing the EJB Remote interface called logtest declared method: package Beans; import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Calc extends EJBObject {public double calcBonus (int multiplier, double bonus) throws RemoteException .; public void logtest () throws RemoteException;} 2 EJB business process implemented LogTest Bean () method: package Beans; import java.rmi.RemoteException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import Org.apache.log4j.category; import org.apache.log4j.logger; import org.apache.log4j. *; import org.apache.log4j.ndc;</p> <p>public class CalcBean implements SessionBean {static Logger logger = Logger.getLogger (CalcBean.class.getName ()); public double calcBonus (int multiplier, double bonus) {logger.debug ( "Entering calcBeans () method"); logtest () Double Calc = ("EXITINT CALCBEANS () Method"); Return Calc;} public void logtest () {Logger.debug ("Enter LogTest Method"); ndc.push ("Client . # 45890 "); logger.debug (" Exiting logtest method ");} // These methods are described in more // detail in Lesson 2public void ejbCreate () {PropertyConfigurator.configure (" F: /example.properties ") ;} public void setSessionContext (SessionContext ctx) {} public void ejbRemove () {} public void ejbActivate () {} public void ejbPassivate () {} public void ejbLoad () {} public void ejbStore () {}} It is assumed that log The configuration file is f: an Example.Properties file under the disc. Next is the setting problem of the configuration file. Example.properties # Attach appender A1 to root. Set root level to Level.DEBUG.log4j.rootLogger = DEBUG, A1 # A1 is set to be a FileAppender sending its output to # a log file. However, only error messages and above will Be printed # in a1 Because A1'S Threshold Is set to level.error.</p> <p># The fact that the root level is set to Prority.DEBUG only influences # log requests made to the root logger. It has no influence on the # * appenders * attached to root. # Appender A1 writes to the file "test" in J2EE's Allow Write Dir EX LOGS DIRESTORY.LOG4J.Appender.a1 = org.apache.log4j.fileaPpenderlog4j.Appender.a1.file = E: /J2SDKEE1.3/logs/test.log</p> <p># Truncate 'test' if it aleady exists.log4j.Appender.a1.append = false</p></div><div class="text-center mt-3 text-grey"> 转载请注明原文地址:https://www.9cbs.com/read-8401.html</div><div class="plugin d-flex justify-content-center mt-3"></div><hr><div class="row"><div class="col-lg-12 text-muted mt-2"><i class="icon-tags mr-2"></i><span class="badge border border-secondary mr-2"><h2 class="h6 mb-0 small"><a class="text-secondary" href="tag-2.html">9cbs</a></h2></span></div></div></div></div><div class="card card-postlist border-white shadow"><div class="card-body"><div class="card-title"><div class="d-flex justify-content-between"><div><b>New Post</b>(<span class="posts">0</span>) </div><div></div></div></div><ul class="postlist list-unstyled"> </ul></div></div><div class="d-none threadlist"><input type="checkbox" name="modtid" value="8401" checked /></div></div></div></div></div><footer class="text-muted small bg-dark py-4 mt-3" id="footer"><div class="container"><div class="row"><div class="col">CopyRight © 2020 All Rights Reserved </div><div class="col text-right">Processed: <b>0.032</b>, SQL: <b>9</b></div></div></div></footer><script src="./lang/en-us/lang.js?2.2.0"></script><script src="view/js/jquery.min.js?2.2.0"></script><script src="view/js/popper.min.js?2.2.0"></script><script src="view/js/bootstrap.min.js?2.2.0"></script><script src="view/js/xiuno.js?2.2.0"></script><script src="view/js/bootstrap-plugin.js?2.2.0"></script><script src="view/js/async.min.js?2.2.0"></script><script src="view/js/form.js?2.2.0"></script><script> var debug = DEBUG = 0; var url_rewrite_on = 1; var url_path = './'; var forumarr = {"1":"Tech"}; var fid = 1; var uid = 0; var gid = 0; xn.options.water_image_url = 'view/img/water-small.png'; </script><script src="view/js/wellcms.js?2.2.0"></script><a class="scroll-to-top rounded" href="javascript:void(0);"><i class="icon-angle-up"></i></a><a class="scroll-to-bottom rounded" href="javascript:void(0);" style="display: inline;"><i class="icon-angle-down"></i></a></body></html><script> var forum_url = 'list-1.html'; var safe_token = 'GTRWifhhN3Z81pkJeIr6_2BvMSGp2uPeCso0IYk60JE6vEgRI036MdWtykJ7CYID6aPznqUcqxkkWvuHc_2Bfbanrg_3D_3D'; var body = $('body'); body.on('submit', '#form', function() { var jthis = $(this); var jsubmit = jthis.find('#submit'); jthis.reset(); jsubmit.button('loading'); var postdata = jthis.serializeObject(); $.xpost(jthis.attr('action'), postdata, function(code, message) { if(code == 0) { location.reload(); } else { $.alert(message); jsubmit.button('reset'); } }); return false; }); function resize_image() { var jmessagelist = $('div.message'); var first_width = jmessagelist.width(); jmessagelist.each(function() { var jdiv = $(this); var maxwidth = jdiv.attr('isfirst') ? first_width : jdiv.width(); var jmessage_width = Math.min(jdiv.width(), maxwidth); jdiv.find('img, embed, iframe, video').each(function() { var jimg = $(this); var img_width = this.org_width; var img_height = this.org_height; if(!img_width) { var img_width = jimg.attr('width'); var img_height = jimg.attr('height'); this.org_width = img_width; this.org_height = img_height; } if(img_width > jmessage_width) { if(this.tagName == 'IMG') { jimg.width(jmessage_width); jimg.css('height', 'auto'); jimg.css('cursor', 'pointer'); jimg.on('click', function() { }); } else { jimg.width(jmessage_width); var height = (img_height / img_width) * jimg.width(); jimg.height(height); } } }); }); } function resize_table() { $('div.message').each(function() { var jdiv = $(this); jdiv.find('table').addClass('table').wrap('<div class="table-responsive"></div>'); }); } $(function() { resize_image(); resize_table(); $(window).on('resize', resize_image); }); var jmessage = $('#message'); jmessage.on('focus', function() {if(jmessage.t) { clearTimeout(jmessage.t); jmessage.t = null; } jmessage.css('height', '6rem'); }); jmessage.on('blur', function() {jmessage.t = setTimeout(function() { jmessage.css('height', '2.5rem');}, 1000); }); $('#nav li[data-active="fid-1"]').addClass('active'); </script>