Pages

Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

Thursday, June 26, 2025

Configure NGinx to serve static files and Apache for dynamic

In CentOS 6.x
Follow the following steps for installation. 
rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
Now that the repo is installed, we need to install NGinx

yum install nginx

Configuring NGinx

Now that NGinx is installed we need to create a VirtualHost (actually NGinx calls them Server Blocks) for each site we are hosting.
nano /etc/nginx/conf.d/virtual.conf
#Insert one of these for each of the virtualhosts you have configured in Apache

server {
 listen 80;
root /path/to/site/root; 
 index index.php index.html index.htm;
server_name www.yourdomain.com yourdomain.com;
location / {
 try_files $uri $uri/ /index.php;
 }
location ~ \.php$ {

 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $remote_addr;
 proxy_set_header Host $host;
 proxy_pass http://127.0.0.1:8080;

}

location ~ /\.ht {
deny all;
}
}

This configuration tells NGinx to try and serve the requested file, but to pass the request onto Apache if it's unable to do so. Requests for PHP files should be forwarded automatically. Apache will be told who requested the file in the 'X-Forwarded-For' header.

The final section tells NGinx not to check requests for .htaccess files as no one want anyone to see the contents of these.


Configuring Apache

We want users to hit our NGinx installation (otherwise this effort is wasted) but Apache is currently sat on port 80. So we're going to move it to 8080 (given that's the port we specified in the NGinx configuration we created).

nano /etc/httpd/conf/httpd.conf
# Find the following
Listen (someIP) 80
# Change the port to
Listen 127.0.0.1 8080

# Now at the bottom of the file, you'll find your virtualhost directives,
# Change all port definitions of 80 to 8080
# Don't forget the Default virtualhost definition
# <virtualhost *:80> becomes <virtualhost *:8080>

We change the Listen address as we don't want external hosts to access Apache directly, everything should go through NGinx. Ideally, we also want to forbid outside access to port 8080 at the firewall to ensure that the point of entry to our system is restricted to the authorised route - through NGinx.

Start the Services
We've now configured Apache to listen on a different port, so all we need to do know is restart Apache (so that it moves to port 8080) and start NGinx so that it can start handling requests.

  • service httpd restart
  • service nginx start

Now if you browse to your site, nothing should have changed visibly. However, if you check the HTTP headers you should see NGinx instead of Apache, checking a phpinfo file should still show Apache as having called the PHP parser though.

 

Installation FFmpeg on Linux RHEL/CentOS 6.X

FFmpeg :

FFmpeg is simply a tool that implements a decoder and then an encoder. It is a complete, cross-platform solution to record, convert, and stream audio and video. This allows users to convert files from one format to another.

Features :

  • FFmpeg is free software licensed under the LGPL or GPL depending on your choice of configuration options.

  • FFmpeg Hosting can convert any video format to the web-optimized .flv format so that they can get streamed on the website.

  • FFmpeg provide command line tool to convert multimedia files between formats.


Steps to Installation FFmpeg on Linux RHEL/CentOS 6.X

  

Step 1 : Create FFmpeg Repository

Open repository Directory

[root@bsrtech ~]# cd /etc/yum.repos.d/

Create name with ffmpeg(any name) repositorty& open with vi command

[root@bsrtech yum.repos.d]# vim ffmpeg.repo

Step 2 : Write the following data on that file

     [ffmpeg]
name=FFmpeg RPM Repository for Red Hat Enterprise Linux
baseurl=http://apt.sw.be/redhat/el6/en/x86_64/dag/  (64 Bit OS)
#baseurl=http://apt.sw.be/redhat/el6/en/i386/dag/   (32 Bit OS)
gpgcheck=1
enabled=1


Save&Quit the file(:wq)

Stewp 3 : Copy the conf file in lib directory

 Copy /etc/ld.so.conf file in /usr/local/lib/ directory

[root@bsrtech ~]# cp -r /etc/ld.so.conf  /usr/local/lib/

Then After Run This Command

[root@bsrtech ~]# ldconfig -v  (Enter)

Step 4 : Install rpmforge Repository

For 32 Bit OS


[root@bsrtech ~]#rmp -Uvh http://apt.sw.be/redhat/el6/en/i386/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.i686.rpm

For 64 Bit OS

[root@bsrtech ~]# rpm -Uvh http://apt.sw.be/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

Once Update installed Packages using yum update command

[root@bsrtech ~]# yum update

Step 5 : Now Install ffmpeg & ffmpeg-devel

   [root@bsrtech ~]# yum -y install ffmpeg ffmpeg-devel
( or )

   [root@bsrtech ~]# yum -y install ffmpeg*

After Completion use ffmpeg command to see the Full Details of FFmpeg.

[root@bsrtech ~]# ffmpeg

Simplest rules to Redirect using .htaccess

Simplest rules to Redirect using .htaccess

How to write rewrite rule (URL rewriting, mod_rewrite)
(1) Redirect site from http to https :
Add the below in .htaccess file in public_html
===================================================
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
===================================================

(2) Redirecting a domain to another domain via .htaccess
Example :- redirect shaz.com to google.com
===================================================
RewriteEngine on
RewriteCond %{HTTP_HOST} ^shaz\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.shaz\.com$
RewriteRule ^/?$ “http\:\/\/www\.google\.com\/” [R=301,L]
===================================================
(3) Redirect users to access the site with WWW
example :- redirect shaz.com to www.shaz.com
Add the below in .htaccess file
===================================================
RewriteEngine on
RewriteCond %{HTTP_HOST} ^shaz\.com$ [NC]
RewriteRule ^(.*)$ http://www.shaz.com/$1 [L,R=301]
===================================================

(4) Redirect page to another page within public_html
example :- to redirect home.html to index.php
===================================================
RewriteEngine on
RewriteRule ^home.html$ index.php
===================================================

example2 :- rewrite site shaz.com/kb/index.php to shaz.com/blog/index.html
go to kb directory and create a .htaccess file
+++++++++++++++++++++++++++++++++++++++++++++++++++
#cd public_html/kb
#touch .htaccess
#vi .htaccess
+++++++++++++++++++++++++++++++++++++++++++++++++++
===================================================
RewriteEngine on
RewriteRule ^index.php$ /blog/index.html
===================================================

Wednesday, July 8, 2015

Linux tune the VM subsystem.

Tuning the memory subsystem in Linux is a powerful but delicate task. The right settings can boost your system’s performance, but incorrect changes may cause instability or slowdowns. Always adjust one parameter at a time and monitor your system before making further changes.

Exploring /proc/sys/vm

The /proc/sys/vm directory contains files that represent kernel parameters for the virtual memory subsystem. You can read and write to these files to tune system behavior.

To view the files, use:
cd /proc/sys/vm
ls -l

Sample output:
-rw-r--r-- 1 root root 0 Oct 16 04:21 block_dump
-rw-r--r-- 1 root root 0 Oct 16 04:21 dirty_background_ratio
-rw-r--r-- 1 root root 0 Oct 16 04:21 dirty_expire_centisecs
-rw-r--r-- 1 root root 0 Oct 16 04:21 dirty_ratio
-rw-r--r-- 1 root root 0 Oct 16 04:21 dirty_writeback_centisecs
-rw-r--r-- 1 root root 0 Oct 16 04:21 drop_caches
-rw-r--r-- 1 root root 0 Oct 16 04:21 swappiness
-rw-r--r-- 1 root root 0 Oct 16 04:21 vfs_cache_pressure
...

Key Parameters and Their Effects

  1. dirty_background_ratio
    Purpose: Sets the percentage of system memory filled with “dirty” pages (pages to be written to disk) before the background writeback daemon (pdflush) starts writing them out.

Check current value:
sysctl vm.dirty_background_ratio

Default example:
vm.dirty_background_ratio = 10

Tuning:
Increasing this value (for example, to 20) means less frequent flushes, which may benefit systems with fast disks but can cause larger flushes at once.
sysctl -w vm.dirty_background_ratio=20

  1. swappiness
    Purpose: Controls how aggressively the kernel swaps memory pages to disk.

Check current value:
sysctl vm.swappiness

Default example:
vm.swappiness = 60

Tuning:
Lower values reduce swapping (good for desktops), higher values increase swapping (can benefit workloads with long-sleeping processes).
sysctl -w vm.swappiness=100

  1. dirty_ratio
    Purpose: Sets the percentage of system memory that can be filled with dirty pages before processes generating writes must themselves start writing data to disk.

Check current value:
sysctl vm.dirty_ratio

Default example:
vm.dirty_ratio = 40

Tuning:
Lowering this value (for example, to 25) causes data to be written to disk more frequently, reducing the risk of large data loss but possibly impacting performance.
sysctl -w vm.dirty_ratio=25

Best Practices for VM Tuning

  • Change one setting at a time.

  • Monitor system performance after each change using tools like vmstat, top, or free.

  • If performance improves, keep the new setting. If not, revert to the previous value.

  • Document your changes for future reference and troubleshooting.


Thursday, September 25, 2014

cPanel’s Built-in php.ini File

WHERE IS THE CPanel PHP.INI?

If you're using cPanel and need to tweak your PHP settings, you might be looking for the php.ini file. This file controls how PHP behaves on your server. For cPanel's default PHP installation, you can find the main php.ini file at this location:

/usr/local/cpanel/3rdparty/etc/php.ini

Understanding this location is key for anyone needing to make direct changes to global PHP configurations within a cPanel environment.


REBUILDING CPANEL'S INTERNAL PHP

Sometimes, you might need to rebuild or refresh cPanel's internal PHP installation. This can be useful for troubleshooting or applying certain updates. You can do this using a specific script provided by cPanel:

/scripts/makecppphp

Running this script will recompile or reconfigure the PHP environment that cPanel itself uses, which can resolve various issues related to its internal functions.

Tuesday, July 8, 2014

Shell In A Box – A Web-Based SSH Terminal to Access Remote Linux Servers

Shell In A Box (pronounced as shellinabox) is a web based terminal emulator . It has built-in web server that runs as a web-based SSH client on a specified port and prompt you a web terminal emulator to access and control your Linux Server SSH Shell remotely using any AJAX/JavaScript and CSS enabled browsers without the need of any additional browser 

RHEL/CentOS 6 32-64 Bit

## RHEL/CentOS 6 32-Bit ##
# wget http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
# rpm -ivh epel-release-6-8.noarch.rpm

## RHEL/CentOS 6 64-Bit ##
# wget http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
# rpm -ivh epel-release-6-8.noarch.rpm
# vi /etc/sysconfig/shellinaboxd
# TCP port that shellinboxd's webserver listens on- Which ever you need , here I am choosing port 80
PORT=80

# specify the IP address of a destination SSH server
OPTS="-s /:SSH:172.16.25.125"

# if you want to restrict access to shellinaboxd from localhost only
OPTS="-s /:SSH:172.16.25.125 --localhost-only"

Monday, December 16, 2013

Exim cheat sheet

Exim is a powerful mail transfer agent (MTA) used on many Linux servers. When emails can't be delivered immediately, they get put into a "queue." Managing this queue is crucial for server health and ensuring mail delivery. This guide provides quick commands for common Exim queue tasks.


CLEARING THE EXIM MAIL QUEUE

Sometimes, you need to clear out stuck or unwanted emails from the queue.

  • Remove All Mails: This command directly deletes all files from the input directory of the Exim spool, effectively clearing the entire queue. rm -rf /var/spool/exim/input/*

  • Delete All Frozen Mails: Frozen emails are those that Exim has temporarily stopped trying to deliver due to issues. exim -bpr | grep frozen | awk {'print $3'} | xargs exim -Mrm Alternatively, a more concise command: exiqgrep -z -i | xargs exim -Mrm

  • Delete Frozen Mails Older Than a Day: This is useful for clearing old, stalled messages without affecting newer ones. The 86400 represents seconds (1 day). exiqgrep -zi -o 86400 | xargs exim -Mrm You can change 86400 to any number of seconds for a different time frame.

  • Clear Spam Mails: If your logs indicate messages are marked as [SPAM]. grep -R -l [SPAM] /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

  • Clear Frozen Mails (Based on Log Entry): grep -R -l '*** Frozen' /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

  • Clear Mails for Unverified Recipients: grep -R -l 'The recipient cannot be verified' /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

  • Remove Mails from a Specific Sender (e.g., 'root'): Replace "" with the sender's email address or username, for example, root@yourhostname. exim -bp |grep ""|awk '{print $3}'|xargs exim -Mrm

  • Remove 'nobody' Mails: These often come from scripts. Replace HOSTNAME with your server's hostname.

    • From a specific sender (nobody@HOSTNAME): exiqgrep -i -f nobody@HOSTNAME | xargs exim -Mrm

    • For a specific recipient/domain (nobody@HOSTNAME): exiqgrep -i -r nobody@HOSTNAME | xargs exim -Mrm

  • Delete Mails for a Specific Domain: Replace yourdomain.com with the actual domain. exim -bp | grep "yourdomain.com" | awk {'print $3'} | xargs exim -Mrm


DELIVERING MAILS FROM THE QUEUE

If emails are stuck but should be delivered, you can force a delivery attempt.

  • Force Deliver All Mails: This command attempts to deliver all messages in the queue. The -P 40 option attempts 40 deliveries in parallel. exim -bpru |awk '{print $3}' | xargs -n 1 -P 40 exim -v -M

  • Flush the Mail Queue (Force Another Run): This tells Exim to process the queue again. exim -qff Alternatively: /usr/sbin/exim -qff exim -qf

  • Force Deliver Mails of a Particular Domain: Replace domain.com with the target domain. exim -v -Rff domain.com

  • Force Deliver a Specific Message: Replace MSGID with the message's unique ID. exim -M MSGID To view the transaction during delivery: exim -v -M MSGID


CHECKING THE EXIM MAIL QUEUE STATUS

These commands help you monitor the queue and inspect individual messages.

  • Exim Queue Summary: Provides details like count, volume, oldest, newest message, and domain breakdown. exim -bp | exiqsumm

  • Number of Frozen Mails: exim -bpr | grep frozen | wc -l

  • Total Number of Mails in Queue: exim -bpr | grep "<" | wc -l A simpler alternative: exim -bpc

  • View Mail in Queue for a User/Sender: Replace $name with the username or email address. exim -bp|grep $name

  • Check All Mails in the Queue: This lists all messages and their IDs. exim -bp

  • View Log for a Message: Replace message ID with the actual ID. exim -Mvl message ID

  • View Message Header: Replace $MSGID with the message ID. exim -Mvh $MSGID

  • View Message Body: Replace $MSGID with the message ID. exim -Mvb $MSGID


ADVANCED EXIM TOOLS

  • Simulate SMTP Transaction: This command helps debug Exim's checks, ACLs (Access Control Lists), and filters without actually sending a mail. Replace 127.0.0.1 with the IP you want to simulate from. exim -bh 127.0.0.1

  • Most Used Mailing Script Locations: This can help identify scripts sending a lot of mail. grep cwd /var/log/exim_mainlog | grep -v /var/spool | awk -F"cwd=" '{print $2}' | awk '{print $1}' | sort | uniq -c | sort -n

  • Check Syntactic Errors in Configuration: Use this when modifying Exim's configuration file. exim -C /config/file.new -bV

Wednesday, December 11, 2013

Understanding Mod_Security Database Connection Issues

You've encountered an error stating that the Mod_Security plugin can't connect to its database. Specifically, it's an "Access denied" error for the user 'modsec'@'localhost', even though a password was provided. This usually means the password Mod_Security is using to connect to the database is incorrect or the database user doesn't have the right permissions.


WHY THIS MATTERS

Mod_Security is a web application firewall that helps protect your website from various attacks. If it can't connect to its database, it might not be able to log security events or function correctly, leaving your website vulnerable.


HOW TO FIX IT

There are two main steps to resolve this, focusing on ensuring the 'modsec' user can properly access the 'modsec' database.

  1. Find the Correct Password Mod_Security is Using:

    The error indicates Mod_Security is trying to connect with a specific password. You need to find out what password it's actually configured to use.

    • Action: Run the following command in your server's terminal:

      grep dbpassword /etc/cron.hourly/modsecparse.pl
      
    • Explanation: This command searches a common Mod_Security configuration file (modsecparse.pl) for the line containing dbpassword. This line will reveal the password that Mod_Security is currently trying to use for its database connection. Let's say the output of this command shows the password is 'odu6lGYKAIyP'.

  2. Grant the Correct Permissions to the Database User:

    Once you know the password Mod_Security is configured with, you need to ensure the 'modsec' database user has the correct password and permissions in MySQL.

    • Action: Log into your MySQL server (as a root user or a user with sufficient privileges) and execute the following command. Replace 'odu6lGYKAIyP' with the actual password you found in the previous step.

      SQL
      GRANT ALL ON modsec.* TO 'modsec'@localhost IDENTIFIED BY 'odu6lGYKAIyP';
      FLUSH PRIVILEGES;
      
    • Explanation:

      • GRANT ALL ON modsec.*: This gives the 'modsec' user all permissions on all tables within the modsec database.

      • TO 'modsec'@localhost: Specifies that these permissions apply to the user 'modsec' when connecting from the 'localhost' (meaning from the same server).

      • IDENTIFIED BY 'odu6lGYKAIyP': Sets or updates the password for the 'modsec' user to 'odu6lGYKAIyP'. It's crucial that this password matches what Mod_Security is configured to use.

      • FLUSH PRIVILEGES;: This command reloads the grant tables in MySQL, applying the new permissions immediately.

Wednesday, November 20, 2013

Recovering from InnoDB Corruption in MySQL

InnoDB is a robust storage engine for MySQL, but like any system, it can encounter issues such as corruption. Understanding how to address these problems is crucial for database administrators. This guide will outline steps to recover from an InnoDB corruption using the innodb_force_recovery option.

Understanding the Error

The error log indicates an assertion failure within InnoDB, suggesting data corruption. Typical causes include hardware faults, sudden shutdowns, or bugs. The error message suggests steps for recovery and forces InnoDB into a special "recovery" mode.


130306 22:02:18 mysqld_safe Number of processes running now: 0
130306 22:02:18 mysqld_safe mysqld restarted
130306 22:02:18 [Note] Plugin 'FEDERATED' is disabled.
130306 22:02:18 InnoDB: The InnoDB memory heap is disabled
130306 22:02:18 InnoDB: Mutexes and rw_locks use GCC atomic builtins
130306 22:02:18 InnoDB: Compressed tables use zlib 1.2.3
130306 22:02:18 InnoDB: Using Linux native AIO
130306 22:02:18 InnoDB: Initializing buffer pool, size = 128.0M
130306 22:02:18 InnoDB: Completed initialization of buffer pool
130306 22:02:18 InnoDB: highest supported file format is Barracuda.
130306 22:02:18 InnoDB: 5.5.30 started; log sequence number 1629186928
130306 22:02:18 [Note] Server hostname (bind-address): '0.0.0.0'; port: 3306
130306 22:02:18 [Note] - '0.0.0.0' resolves to '0.0.0.0';
130306 22:02:18 [Note] Server socket created on IP: '0.0.0.0'.
130306 22:02:18 [Note] Event Scheduler: Loaded 0 events
130306 22:02:18 [Note] /usr/sbin/mysqld: ready for connections.
Version: '5.5.30-cll' socket: '/var/lib/mysql/mysql.sock' port: 3306 MySQL Community Server (GPL)
130306 22:02:19 InnoDB: Assertion failure in thread 47204348393792 in file trx0purge.c line 840
InnoDB: Failing assertion: purge_sys->purge_trx_no <= purge_sys->rseg->last_trx_no
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
03:02:19 UTC - mysqld got signal 6 ;

This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.

We will try our best to scrape up some info that will hopefully help diagnose the problem, but since we have already crashed, something is definitely wrong and this may fail.


Steps to Recovery

1. Stop mysqld:

First, ensure that MySQL is not running to prevent further data corruption.

service mysqld stop

2. Backup Critical Files:

Before proceeding with any recovery steps, back up the existing InnoDB data files.

mkdir /root/mysql_backup cp /var/lib/mysql/ib* /root/mysql_backup/

3. Configure MySQL for Recovery:

Edit the MySQL configuration file (/etc/my.cnf) and add the following under the [mysqld] section:

innodb_force_recovery = 4

There are different levels of innodb_force_recovery you can use, from 1 to 6. Levels 1-4 are generally considered safe, while 5 and 6 are used as a last resort.

4. Restart mysqld:

Restart the MySQL server. It will start in recovery mode due to the innodb_force_recovery setting.

service mysqld start

5. Dump All Tables:

Create a dump of all databases. This might take some time depending on the size of your databases.

mysqldump -A > /root/mysql_backup/dump.sql

6. Drop Corrupted Databases:

Identify and drop the corrupted databases. If you're unsure which ones are corrupted, you might need to drop all databases and restore them from the dump later.

mysql -u root -p -e "DROP DATABASE corrupted_db"

7. Stop mysqld:

Once again, stop the MySQL server to proceed with the next steps.

service mysqld stop

8. Remove InnoDB Data Files:

Delete the old InnoDB data files. Be cautious with this command – ensure you have backups!

rm /var/lib/mysql/ib*

9. Comment out innodb_force_recovery:

Edit /etc/my.cnf and comment out or remove the innodb_force_recovery option.

10. Restart mysqld:

Start the MySQL server. It should recreate the InnoDB data files.

service mysqld start

11. Restore Databases:

Restore the databases from the dump you created earlier.Copy code

mysql < /root/mysql_backup/dump.sql

12. Repair and Optimize:

Finally, check and repair all databases and tables.

mysqlcheck –all-databases –repair
innodb force recovery options

Mode 1 - Doesn't crash MySQL when it sees a corrupt page
Mode 2 - Doesn't run background operations
Mode 3 - Doesn't attempt to roll back transactions
Mode 4 - Doesn't calculate stats or apply stored/buffered changes
Mode 5 - Doesn't look at the undo logs during start-up
Mode 6 - Doesn't roll-forward from the redo logs (ib_logfiles) during start-up
1 (SRV_FORCE_IGNORE_CORRUPT)
Let the server run even if it detects a corrupt page. Try to make SELECT * FROM tbl_name jump
over corrupt index records and pages, which helps in dumping tables.
2 (SRV_FORCE_NO_BACKGROUND)
Prevent the main thread from running. If a crash would occur during the purge operation,
this recovery value prevents it.
3 (SRV_FORCE_NO_TRX_UNDO)
Do not run transaction rollbacks after recovery.
4 (SRV_FORCE_NO_IBUF_MERGE)
Prevent insert buffer merge operations. If they would cause a crash, do not do them.
Do not calculate table statistics.
5 (SRV_FORCE_NO_UNDO_LOG_SCAN)
Do not look at undo logs when starting the database: InnoDB treats even incomplete transactions as committed.
6 (SRV_FORCE_NO_LOG_REDO)
Do not do the log roll-forward in connection with recovery.
The database must not otherwise be used with any nonzero value of innodb_force_recovery.
As a safety measure, InnoDB prevents users from performing INSERT, UPDATE, or
DELETE operations when innodb_force_recovery is greater than 0.

**Hint : A simple query for finding all of your InnoDB tables in case you want to specifically target the corruption.
SELECT table_schema, table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE engine = 'innodb';

\