quinta-feira, 27 de novembro de 2014

Recuperar dados MySQL perdido com mysqlbinlog exemplo point-in-time-recuperação

Original post: http://anothermysqldba.blogspot.com/2014/11/recover-lost-mysql-data-with.html

Cópia de segurança ... de backup ... backup ... mas é claro .. você também precisa monitorar e testar esses backups, muitas vezes de outra forma poderiam ser inútil. Tendo seus MySQL log binário habilitado pode certamente ajudá-lo em tempos de emergência também. Os log binário do MySQL são frequentemente referenciado em relação a replicação do MySQL, por uma boa razão, eles armazenam todas as consultas ou eventos que alteram dados ( baseados em linha é um pouco diferente, mas esta um exemplo). Os logs binários têm um impacto mínimo no desempenho do servidor quando se considera as opções de recuperação que prestam. 


[anothermysqldba]> show variables like 'log_bin%'; 
+---------------------------------+--------------------------------------------+ 
| Variable_name | Value | 
+---------------------------------+--------------------------------------------+ 
| log_bin | ON | 
| log_bin_basename | /var/lib/mysql/binlogs/mysql-binlogs | 
| log_bin_index | /var/lib/mysql/binlogs/mysql-binlogs.index | 

show variables like 'binlog_format%'; 
+---------------+-------+ 
| Variable_name | Value | 
+---------------+-------+ 
| binlog_format | MIXED | 
+---------------+-------+ 


Portanto, este é apenas um exemplo simples usando mysqlbinlog para recuperar dados de um log binário e aplicá-lo de volta para o banco de dados. 

Primeiro precisamos de algo a perder. Se algo estava para acontecer com o nosso banco de dados que precisa ser capaz de recuperar os dados ou talvez seja apenas uma forma de se recuperar de alguém erro. 


CREATE TABLE `table_w_rdata` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`somedata` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
`moredata` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

Podemos fingir aqui e assumir que temos desenvolvedores / DBAs que não estão se comunicando muito bem e / ou salvar cópias de seu código. 


delimiter // 
CREATE PROCEDURE populate_dummydata( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @A + (RAND() * @B ))) as somedata, SUBSTR(md5(''),FLOOR( @C + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END// 
delimiter ; 
call populate_dummydata(50); 

> SELECT NOW() \G 
*************************** 1. row *************************** 
NOW(): 2014-11-27 17:32:25 
1 row in set (0.00 sec) 

> SELECT * from table_w_rdata WHERE id > 45; 
+----+----------------------------+------------------+ 
| id | somedata | moredata | 
+----+----------------------------+------------------+ 
| 46 | b204e9800998ecf8427e | 0998ecf8427e | 
| 47 | d98f00b204e9800998ecf8427e | 8ecf8427e | 
| 48 | b204e9800998ecf8427e | 800998ecf8427e | 
| 49 | 98f00b204e9800998ecf8427e | e9800998ecf8427e | 
| 50 | 98f00b204e9800998ecf8427e | 998ecf8427e | 
+----+----------------------------+------------------+ 

Enquanto um procedimento é criado é mais tarde escrito por outra pessoa de forma incorreta. 

DROP PROCEDURE IF EXISTS populate_dummydata ; 
delimiter // 
CREATE PROCEDURE populate_dummydata( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @C + (RAND() * @A ))) as somedata, SUBSTR(md5(''),FLOOR( @B + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END// 
delimiter ; 

call populate_dummydata(50); 
> SELECT NOW(); SELECT * from table_w_rdata WHERE id > 95; 
+---------------------+ 
| NOW() | 
+---------------------+ 
| 2014-11-27 17:36:28 | 
+---------------------+ 
1 row in set (0.00 sec) 

+-----+-------------------+---------------------+ 
| id | somedata | moredata | 
+-----+-------------------+---------------------+ 
| 96 | 4e9800998ecf8427e | 00998ecf8427e | 
| 97 | 9800998ecf8427e | 800998ecf8427e | 
| 98 | e9800998ecf8427e | 204e9800998ecf8427e | 
| 99 | e9800998ecf8427e | 4e9800998ecf8427e | 
| 100 | 9800998ecf8427e | 04e9800998ecf8427e | 
+-----+-------------------+---------------------+ 


A versão substituída do procedimento não está a gerar valores aleatórios como a equipe queria. O criador original do processo acabado de sair de frustração. Então o que fazer? Um pouco de tempo tem passado desde que foi criado também. Nós sabemos o nome do banco, nome da rotina e do período de tempo em geral, quando o procedimento incorreto foi criado e sorte para nós os logs bin ainda estão por aí, para que possamos ir buscá-la. 

Temos de dar uma olhada geral em torno de uma vez que quer apenas um point-in-time-recuperação deste procedure.We acontecer para encontrar o procedimento e a posição no log binário antes e depois dele. 


NOW(): 2014-11-27 19:46:17 
# mysqlbinlog --start-datetime=20141127173200 --stop-datetime=20141127173628 --database=anothermysqldba mysql-binlogs.000001 | more 

at 253053 
at 253564 

# mysql anothermysqldba --login-path =local -e "DROP PROCEDURE populate_dummydata"; 
# mysqlbinlog --start-position=253053 --stop-position=253564 --database=anothermysqldba mysql-binlogs.000001 | mysql --login-path =local anothermysqldba 


> SHOW CREATE PROCEDURE populate_dummydata\G 
*************************** 1. row *************************** 
Procedure: populate_dummydata 
sql_mode: NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 
Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `populate_dummydata`( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @A + (RAND() * @B ))) as somedata, SUBSTR(md5(''),FLOOR( @C + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END 
character_set_client: utf8 
collation_connection: utf8_general_ci 
Database Collation: latin1_swedish_ci 
1 row in set (0.00 sec) 

NOW(): 2014-11-27 19:51:03 
> call populate_dummydata(50); 
> SELECT * from table_w_rdata WHERE id > 145; 
+-----+-----------------------------+------------------+ 
| id | somedata | moredata | 
+-----+-----------------------------+------------------+ 
| 146 | 98f00b204e9800998ecf8427e | 800998ecf8427e | 
| 147 | cd98f00b204e9800998ecf8427e | 800998ecf8427e | 
| 148 | 204e9800998ecf8427e | 98ecf8427e | 
| 149 | d98f00b204e9800998ecf8427e | e9800998ecf8427e | 
| 150 | 204e9800998ecf8427e | 9800998ecf8427e | 
+-----+-----------------------------+------------------+ 


Recuperamos o nosso procedimento a partir do log binário via point-in-time-recuperação . 
Este é um exemplo simples, mas é um exemplo das ferramentas que você pode usar a avançar. 

É por isso que os logs binários são tão valiosos. 

URL úteis: 

terça-feira, 11 de novembro de 2014

systemctl e MySQL

Original post: http://anothermysqldba.blogspot.com/2014/11/systemctl-and-mysql.html

Assim, alguns usuários concluir um yum install do MySQL e esperar para ser capaz de usar o seguinte comando para iniciar o servidor MySQL :: /etc/init.d/mysql começar apenas para obter "Nenhum arquivo ou diretório"

Então este é um post rápido para ajudar a usar o comando systemctl.
É provável que você veja isto:
# systemctl list-unit-files | grep mysql 
mysqld.service disabled

Primeiro eu recomendo ir para tools.percona.com e criar um arquivo my.cnf válido.

Portanto, a solução é fácil, só precisamos ativar esse modo que o banco de dados pode começar na inicialização do servidor.

#systemctl enable mysqld.service 
ln -s '/usr/lib/systemd/system/mysqld.service' '/etc/systemd/system/mysql.service' 
ln -s '/usr/lib/systemd/system/mysqld.service' '/etc/systemd/system/multi-user.target.wants/mysqld.service' 
#systemctl start mysqld 
#systemctl list-unit-files | grep mysql 
mysql.service enabled 
mysqld.service enabled

Agora você deve ser bom para ir ...

sábado, 11 de outubro de 2014

Girando MySQL Logs lentas

Original post: http://anothermysqldba.blogspot.com/2014/10/rotating-mysql-slow-logs.html

Ao trabalhar com diferentes clientes acontecer de eu correr em grandes arquivos de log lento ao longo do tempo. Embora existam várias opiniões sobre como eles devem ser rodados. Muitas dessas opiniões usar rotação de log eo comando liberar registros, prefiro não liberar meus logs binários embora. É por isso que eu concordo com o Ronald Bradford blog de ​​anos atrás sobre como fazer isso. 
Tomei um pouco mais longe e roteirizado os passos. O script bash é construído com o MySQL 5.6 eo mysql_config_editor em mente que pode ser usado em versões mais antigas do MySQL também. 

O script fará o seguinte: 
  • Reúna atual nome do arquivo de log
  • Reúna valor de tempo de consulta longa corrente
  • Reinicia o tempo de consulta muito tempo para um valor mais alto
  • Copia o log enquanto truncando-lo também (ver post do Ronald)
  • Reinicia o tempo de consulta tempo de volta ao horário original
  • Executa uma consulta simples lento para que possa verificar o novo registro lento, se desejar
  • Remove o registro mais antigo lento para que você possa ganhar espaço de volta.
    • Você pode comentar este comando se você quiser rever o log em seu lugar.
Assim é que tudo funciona? 
Bem, vamos usar esse exemplo. 

Atualmente estou usando o mysql_config_editor sobre um arquivo .my.cnf então eu atualizei o script de acordo. 
# mysql_config_editor print --all 
[local] 
user = root 
password = ***** 
host = localhost 

Eu posso ver que este log de consultas lentas é agora 1G. 
# ls -alh mysql-slow.log 
-rw-rw---- 1 mysql mysql 1.1G Oct 11 16:08 mysql-slow.log 

Então eu executar o script 
# /root/rotate_slow_logs.sh 
# ls -alh mysql-slow.log 
-rw-rw---- 1 mysql mysql 5.8K Oct 11 16:11 mysql-slow.log 

Ok bom, funcionou e eu tenho um arquivo de log menor agora sem limpar meus logs bin ou reiniciar o MySQL. 

Este script pode ser adicionado a um crontab para que você possa rodar tão frequentemente como você gostaria. 

Aqui está o script. 
#!/bin/bash 

# THIS IS BUILT WITH MYSQL 5.6 SECURITY IN MIND. 
# SET THE LOGINPATHVALUE if you are using the mysql_config_editor 
# IF YOU ARE NOT USING THE mysql_config_editor THEN IT IS ASSUMED YOU HAVE 
# SET A .my.cnf FILE IN THE USER HOME DIR OR THIS USER HAS NO PASSWORD SET 


# PLEASE SET THIS ACCORDINGLY TO YOUR SYSTEM. 
LOGINPATHVALUE="local"; 

if [ -z "${LOGINPATHVALUE}" ]; then 
LOGINPATH=""; 
fi 

if [ -n "${LOGINPATHVALUE-unset}" ]; then 
LOGINPATH="--login-path=$LOGINPATHVALUE " 

fi 

# GATHERS THE LOG FILE NAME 
SLOWLOG=$(mysqladmin $LOGINPATH variables | grep slow | grep file | awk '/[a-zA-Z]/ {print $4}' ) 

# GATHER CURRENT VALUE 
LQT=$( mysqladmin $LOGINPATH variables | grep long_query_time | awk '/[0-9]./ {print $4}' ) 
LQTB=$(mysql $LOGINPATH -e " SELECT @@global.long_query_time *200 AS LQTB;" | awk '/[0-9]./ {print $1}' ) 
LQTC=$(mysql $LOGINPATH -e " SELECT @@global.long_query_time *2 AS LQTC;" | awk '/[0-9]./ {print $1}' ) 

# GATHER MARKER 
DATE=`date +"%m%d%Y"` 

# RESET SLOW QUERY TIME 
# SET GLOBAL long_query_time=10; 
mysql $LOGINPATH -e "SET GLOBAL long_query_time= $LQTB" 

LQTD=$( mysqladmin $LOGINPATH variables | grep long_query_time | awk '/[0-9]./ {print $4}' ) 

#MOVE THE LOG OUT 
cp $SLOWLOG $SLOWLOG.$DATE; > $SLOWLOG 

#SET THE TIMEBACK 
mysql $LOGINPATH -e "SET GLOBAL long_query_time= $LQT" 

LQTD=$( mysqladmin $LOGINPATH variables | grep long_query_time | awk '/[0-9]./ {print $4}' ) 

#PLACE A Slow query for log 
SLOWQUERY=$(mysql $LOGINPATH -e "SELECT sleep($LQTC) " ) 

# REMOVE OLD LOG 
/bin/rm -f $SLOWLOG.$DATE;


terça-feira, 23 de setembro de 2014

MySQL conexões de usuários

Original post: http://anothermysqldba.blogspot.com/2014/09/mysql-user-connections.html

Então eu me encontrei explicando as diferenças com os usuários do MySQL e como eles autenticar. Em primeiro lugar esta informação não é nova, mas pode ser encontrada aqui:
Vou apenas mostrar alguns exemplos do mundo real para explicar isso.

O MySQL utiliza o nome de usuário, bem como o acesso quando se avalia as permissões de um usuário. É por isso que a melhor prática é remover os usuários anônimos.

Para este exemplo vou começar com os seguintes usuários



MariaDB [(none)]> select user , host from mysql.user;
+---------+-----------+
| user | host |
+---------+-----------+
| root | 127.0.0.1 |
| root | ::1 |
| | centos64 |
| root | centos64 |
| | localhost |
| root | localhost |
+---------+-----------+

Eu posso entrar no servidor até pensei que não tem um nome de usuário porque o padrão para baixo para anonymous @ localhost.


# mysql -u nobody
MariaDB [(nenhum)]> selecione current_user ();
+ ---------------- +
| Current_user () |
+ ---------------- +
|localhost |
+ ---------------- +
MariaDB [(nenhum)]> show subvenções;
+ -------------------------------------- +
| Bolsas paralocalhost |
+ -------------------------------------- +
| GRANT Uso na * TO '' @ 'localhost'. |
+ -------------------------------------- +

Enquanto eu não posso fazer muita coisa que eu ainda tenho no banco de dados.

Agora, quando eu passar por um usuário conhecido:


# mysql -u root -p
MariaDB [(nenhum)]> selecione current_user;
+ ---------------- +
| Current_user |
+ ---------------- +
| Root @ localhost |
+ ---------------- +
MariaDB [(nenhum)]> show subvenções;
+----------------------------------------------------------------------------------------------------------------------------------------+
| Bolsas para root @ localhost |
+----------------------------------------------------------------------------------------------------------------------------------------+
| GRANT ALL ON * PRIVILÉGIOS * TO 'root' @ 'localhost' IDENTIFICADAS POR SENHA '* 8CD56861FDADF7A264741F27D502D1A8DAE0A8F7' WITH GRANT OPTION. |
| GRANT PROXY ON '' @ '' para 'root' @ 'localhost' WITH GRANT OPTION |
+----------------------------------------------------------------------------------------------------------------------------------------+


Atualmente, o usuário root tem quatro contas diferentes.

MariaDB [(none)]> select user , host from mysql.user where user = 'root';
+------+-----------+
| user | host |
+------+-----------+
| root | 127.0.0.1 |
| root | ::1 |
| root | centos64 |
| root | localhost |
+------+-----------+

Estas são todas as contas diferentes. Eu só preciso de um deles embora. Eu só uso a conta root através de ligações locais de acolhimento.

MariaDB [(none)]> DROP USER 'root'@'127.0.0.1';
Query OK, 0 rows affected (0.33 sec)

MariaDB [(none)]> DROP USER 'root'@'centos64';
Query OK, 0 rows affected (0.02 sec)

MariaDB [(none)]> DROP USER 'root'@'::1';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> select user , host from mysql.user where user = 'root';
+------+-----------+
| user | host |
+------+-----------+
| root | localhost |
+------+-----------+

Então, o que eu quero dizer com quatro contas diferentes? Eles toda a conta de usuário root. Sem .. Eles são raiz e tudo o host. Assim, cada conta (usuário + host) pode ter permissões diferentes.

Então, vamos fazer um exemplo próximo para mostrar a diferença.
Assim, o servidor, neste exemplo, possui duas interfaces de rede. Então, eu vou criar um usuário por todos os pontos de acesso, cada um com diferentes permissões para mostrar as diferenças. Vou ajustar a mesma senha, mas aqueles poderia ser diferente também.

MariaDB [(none)]> GRANT SELECT ON *.* TO 'anothermysqldba'@'10.0.2.15' IDENTIFIED BY '<cleartext password>';
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE , DROP, RELOAD, SHUTDOWN, PROCESS, FILE, INDEX, ALTER ON *.* TO 'anothermysqldba'@'192.168.0.%' IDENTIFIED BY '<cleartext password>';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'anothermysqldba'@'localhost' IDENTIFIED BY '<cleartext password>' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(nenhum)]> selecione usuário, host de mysql.user onde user = 'anothermysqldba';
+ ----------------- + ------------- +
| Usuário | anfitrião |
+ ----------------- + ------------- +
| Anothermysqldba | 10.0.2.15 |
| Anothermysqldba |. 192.168.0% |
| Anothermysqldba | localhost |
+ ----------------- + ------------- +

Então o que isso significa? Mesmo que os nomes de usuário são os mesmos, porque o MySQL usa o acolhimento, bem como para validar um usuário a cada ponto de acesso do usuário, como permissões diferentes.

Enquanto você pode confiar em alguns de seus desenvolvedores, este é muitas vezes uma boa idéia para limitar alguns dos seu acesso se eles estão trabalhando remotamente ou através de seus scripts. Se eles precisam fazer algo que não envolve você e eles têm de ssh para o servidor em si e login para realizar outras tarefas. Este é, naturalmente, dependente da relação de trabalho e fluxo de sua empresa e / ou aplicações.

Usando o 10.0.2.15 anfitrião o usuário só tem acesso select.

# mysql -h 10.0.2.15 -u anothermysqldba -p
MariaDB [(nenhum)]> selecione current_user ();
+ --------------------------- +
| Current_user () |
+ --------------------------- +
| Anothermysqldba@10.0.2.15 |
+ --------------------------- +
MariaDB [(nenhum)]> show subvenções;
+-------------------------------------------------------------------------------------------------------------------------+
| Bolsas para anothermysqldba@10.0.2.15 |
+-------------------------------------------------------------------------------------------------------------------------+
| GRANT SELECIONE ON * TO 'anothermysqldba'@'10.0.2.15 »identificados através de senha' * 31360D7EE84BE965C0E759179FC61B6943BCA64F '. |
+-------------------------------------------------------------------------------------------------------------------------+

Usando o host 192.168.0.26 o usuário tem mais acesso. Essa conta também é definido para acessar através de qualquer coisa sob o 192.168.0 / 255 (%) de sub-rede.

# mysql -h 192.168.0.26 -u anothermysqldba -p
MariaDB [(nenhum)]> selecione current_user ();
+ + -----------------------------
| Current_user () |
+ + -----------------------------
| Anothermysqldba@192.168.0.% |
+ + -----------------------------
MariaDB [(nenhum)]> show subvenções;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Bolsas para anothermysqldba@192.168.0.% |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, processo e arquivo, INDEX, ALTER ON * TO 'anothermysqldba'@'192.168.0.% »identificados através de senha' * 31360D7EE84BE965C0E759179FC61B6943BCA64F '. |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Então, como você vai assumir o usuário localhost tem a conta de acesso completo.

# mysql -u anothermysqldba -p
MariaDB [(nenhum)]> selecione current_user ();
+ --------------------------- +
| Current_user () |
+ --------------------------- +
| Anothermysqldba @ localhost |
+ --------------------------- +
1 row in set (0.00 sec)

MariaDB [(nenhum)]> show subvenções;
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| Bolsas para anothermysqldba @ localhost |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT ALL ON * PRIVILÉGIOS * TO 'anothermysqldba' @ 'localhost' IDENTIFICADAS POR SENHA '* 31360D7EE84BE965C0E759179FC61B6943BCA64F' WITH GRANT OPTION. |
+---------------------------------------------------------------------------------------------------------------------------------------------------+

Agora, como eu disse antes, é melhor prática para remover os usuários anônimos. Usando o mysql_secure_installation para instalação vai ajudar com a sua também.

Por que isso importa?

# mysql -u anothremysqldba -p
MariaDB [(nenhum)]> selecione current_user ();
+ ---------------- +
| Current_user () |
+ ---------------- +
|localhost |
+ ---------------- +
1 row in set (0.00

O exemplo simples ... está acima e apenas evitar erros simples. Um erro de digitação permitido o acesso ao banco de dados, não deve permitir isso.

Então, retire em seguida e testar novamente.

MariaDB [(none)]> DROP USER ''@'localhost';
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> DROP USER ''@'centos64';
Query OK, 0 rows affected (0.00 sec)

# Mysql-u anothremysqldba -p
Digite a senha:
ERROR 1045 (28000): Acesso negado para o usuário 'anothremysqldba' @ 'localhost' (senha usada: SIM

Então, o que significa se o seu banco de dados é criado com a maioria com% como o nome ou ip estrita endereços e não curingas?

Esta seria uma decisão de segurança e de negócios de sua parte. Pessoalmente não é uma opção válida na minha opinião. Nada mais que um curinga (%) permite que um ponto de acesso robusto, mas se o firewall tem uma falha que também abre o acesso ao controle remoto de usuários da rede. Um endereço IP estrita por usuário também é bastante rigorosa na minha opinião, mas isso depende do usuário. Por exemplo, mesmo com uma conta que tenha sido criada para replicação Prefiro ainda usar o endereço IP com uma ie%.: 192.168.0%. Endereços IP mudam (mesmo mudanças estáticos para usuários remotos do DBA muitas vezes não é dito) e que muitas vezes resulta em pessoas que vêm para o DBA com queixas sobre falhas de acesso.

Certa vez trabalhei com uma pessoa que limitava a cada acesso do usuário bloqueado para um endereço IP estático. Essa pessoa teve que alterar constantemente declarações de concessão. As pessoas têm de ser capazes de trabalhar de forma fácil e eficaz, enquanto você pode garantir a segurança em sua extremidade.