pagarme / pagarme-php Goto Github PK
View Code? Open in Web Editor NEW:blue_heart: Pagar.me's PHP API
:blue_heart: Pagar.me's PHP API
Ao criar contas bancárias não existe a possibilidade de informar o tipo de conta (conta_corrente, conta_poupanca, conta_corrente_conjunta, conta_poupanca_conjunta) conforme em https://docs.pagar.me/api/#criando-uma-conta-bancaria.
Embora a funcionalidade esteja OK via cURL, não está funcionando através do código PHP indicado na documentação, que faz uso dessa biblioteca:
require("pagarme-php/Pagarme.php");
Pagarme::setApiKey("ak_test_grXijQ4GicOa2BLGZrDRTR5qNQxJW0");
$plan = PagarMe_Plan::findById("12785");
$plan->setName("plano silver");
A resposta é válida, mas o nome não é alterado.
Estou utilizando a lib pelo composer e a versão esta desatualizada.
V1.1.0 - 2015-11-13 16:08 UTC
Nessa versão não tem o método validateRequestSignature
, provavelmente muitas outras melhorias pois tem vários commits a partir dessa data.
A versão dev-master esta atualizada, porém como esta em desenvolvimento pode esta instável.
Ao tentar criar uma assinatura é necessário ter populado um objeto de Address do Customer, pois quando se é populado os dados para envio para o endpoint da API de subscriptions, é feito o acesso ao objeto, conforme código abaixo:
https://github.com/pagarme/pagarme-php/blob/V3/lib/Subscription/Request/SubscriptionCreate.php#L67
O Ambiente não interfere pois o erro ocorre quando se tenta acessar um método no atributo address e o mesmo esta nulo, o mesmo erro deve acontecer phone. Ja que o mesmo também esta nulo
Criar uma assinatura, pode ser por boleto ou cartão sem passar o endereço do costumer.
Deveria criar uma assinatura sem a obrigatoriedade do endereço, ja que pelo Documentação o endereço somente é obrigatório quando for usar o antifraude, e como dito na Documentação quando vai usar o recurso de Subscription o mesmo não utiliza o antifraude, segue o trecho onde isso é mencionado:
OBS: As transações criadas pelas assinaturas não passam pelo antifraude, devido a ocorrência de fraudes nesse tipo de serviço serem praticamente nulas.
https://docs.pagar.me/api/?shell#objeto-subscription
Quando se tenta criar uma subscription sem preenchimento de endereço ocorre o seguinte erro:
FatalThrowableError in SubscriptionCreate.php line 100: Call to a member function getStreet() on null
A forma de correção mais simples seria a verificação se os métodos citados abaixo tem o retorno nulo, antes de adicionar eles ao payload de envio:
https://github.com/pagarme/pagarme-php/blob/V3/lib/Subscription/Request/SubscriptionCreate.php#L67
https://github.com/pagarme/pagarme-php/blob/V3/lib/Subscription/Request/SubscriptionCreate.php#L68
IMHO the SplitRuleCollection
could implement the Countable
. Today I need to calculate how many Payables
a transaction created, so I had to get the Transaction
and then iterate over the SplitRules
to get how many splits the transaction have.
$transaction = $pagarme->transaction->get($transactionId);
$splitRulesQtt = 0;
foreach ($transaction->getSplitRules() as $splitRule) {
$splitRulesQtt++;
}
$payablesQtt = $transaction->getInstallments() * $splitRulesQtt;
Proposal
class SplitRuleCollection implements \ArrayAccess, \Iterator, \Countable
{
// ... Existing code
/**
* Count the number of items in the collection.
*
* @return int
*/
public function count()
{
return count($this->rules);
}
}
Change the whole code from chargeback to refund
Hoje, para realizar uma transação, temos 2 formas distintas para compor um objeto \PagarMe\Sdk\Customer\Customer
:
\PagarMe\Sdk\Customer\CustomerHandler->get()
, que nos retorna uma estrutura de objetos completa;A classe \PagarMe\Sdk\Transaction\Request\TransactionCreate
sofreu alterações para esse problema, gerando instâncias de Address e Phone caso esses dados sejam arrays ao invés de objetos.
\PagarMe\Sdk\Transaction\Request\TransactionCreate
/**
* @return array
*/
public function getPayload()
{
$customer = $this->transaction->getCustomer();
$address = $customer->getAddress();
if (is_array($address)) {
$address = new \PagarMe\Sdk\Customer\Address($address);
}
$phone = $customer->getPhone();
if (is_array($phone)) {
$phone = new \PagarMe\Sdk\Customer\Phone($phone);
}
Para que isso seja resolvido, precisamos encontrar uma forma mais limpa e consistente para manipulação desses dados, cogitando manter as duas interfaces de entrada de dados (array e objeto) ou mantendo somente uma (objeto).
Estou trabalhando na migração da v1.1 para a v3 desse SDK e estou tomando erro quando tento criar transações. A versão 1.1 funciona perfeitamente.
Unknown Error (0): Invalid resource type: boolean in /media/sf_scire/system/vendor/guzzlehttp/streams/src/Stream.php on line 85
Meu código:
$address = new \PagarMe\Sdk\Customer\Address([
'street' => $customer->address,
'street_number' => $customer->addrNumber,
'complementary' => $customer->complement,
'neighborhood' => $customer->neighborhood,
'city' => $customer->city,
'state' => $customer->state,
'zipcode' => $customer->zip,
]);
$phone = new \PagarMe\Sdk\Customer\Phone([
'ddd' => $customer->ddd,
'number' => $customer->phone,
]);
$customer = $pagarMe->customer()->create(
$customer->name,
$customer->email,
$customer->documentNumber,
$address,
$phone
);
$transaction = $pagarMe->transaction()->boletoTransaction(
$orderValue,
$customer,
postbackUrl()
);
Quando a assinatura está em teste, ao recuperá-la, como não tem transação, o SubscriptionBuilder tenta setar a current_transaction com buildTransaction fornecendo um valor vazio.
O que eu fiz foi verificar se a current_transaction do Subscription não é vazia antes de tentar executar o buildTransaction:
$subscriptionData->current_transaction = $subscriptionData->current_transaction ? $this->buildTransaction($subscriptionData->current_transaction) : [];
Lack installation instructions and tips on how to contribute to the project.
Não há classe para trabalhar com os Recebíveis (objeto Payable)
Hoje, como desenvolvedor, gostaria de fazer a captura de uma transação diretamente pelo token gerado na autorização (modelo checkout pagar.me).
Transação capturada sem a necessidade de buscar a transação na API.
I think it is really dangerous to use "dev-master" as a composer requirement on my production environment.
Can you create a tag?
Thanks =)
Versão: 3.0.1
https://github.com/pagarme/pagarme-php/tree/V3/
A busca de transação (transactionId) não está funcionando corretamente pois a busca só aceita dígitos porém no ambiente de homologação temos transações do tipo "test_transaction_SltLsBdOI6GYCPexmfKqJllShSfwME".
Seria excelente usar os recursos de template para Issue e Pull Request neste repositório, assim podemos nos beneficiar de um formato padrão para detalhamento de problema/melhorias.
As Issues e Pull Requests criados atualmente não seguem um padrão e muitas vezes carecem de informação, o que dificulta investigação e priorização deles.
Criar um arquivo .github/ISSUE_TEMPLATE.md
e um arquivo .github/PULL_REQUEST_TEMPLATE.md
contendo um modelo para criação de Issue e Pull Request.
Boa tarde,
estou tendo este erro quase em qualquer request que eu faço atráves do sdk, porém, eu consigo realizar o mesmo request pelo browser, sem problemas.
Pelo pouco que sei, entendo que o response do curl está sendo erro 500. Porém, como disse o mesmo request pelo browser está ok.
Aguardo resposta, abraço.
Fui até o fundo desta situação e descobri que o problema está na classe Request.php, linha 22.
O método parent::getApiKey() já esta retornando um array, resultando em um array_merge defeituoso:
api_key => api_key => ak_test......; Após um dump na instância RestClient, reparem no endpoint montado.
Alterando a linha 22 da classe Request.php para:
o endpoint é montado corretamente e o restante do sdk funciona corretamente.
Espero que considerem está situação... Obrigado.
Olá,
Estou tentando usar a API do PagarMe, como ensinado na documentação aqui (aliás, a documentação básica está aparentemente errada, já que usando Composer, não consigo seguir os passos daqui: https://docs.pagar.me/transactions/).
Entretanto, ao criar um Address e Phone, passando para o Customer e tentando criar uma transação acontece o seguinte erro: Cannot use object of type PagarMe\Sdk\Customer\Address as array in C:\Projects\pagarmetest\vendor\pagarme\pagarme-php\lib\Transaction\Request\TransactionCreate.php
.
O erro é meio óbvio pois olhando o código é simples de corrigir aparentemente:
<?php
'address' => [
'street' => $address['street'],
'street_number' => $address['street_number'],
'complementary' => isset($address['complementary']) ? $address['complementary']: null,
'neighborhood' => $address['neighborhood'],
'zipcode' => $address['zipcode']
]
Como podem ver, o código está tentando utilizar o $address como se fosse um array, mas ele é uma instância de \PagarMe\Sdk\Customer\Address
.
Alterando para (por exemplo) $address->getAddress(), já corrige o problema, mas eu realmente não sei por que este código foi escrito assim.
Alguma coisa que preciso fazer?
O código inteiro é este:
<?php
$pagarMe = new PagarMe("xxx");
$card = $pagarMe->card()->create('xxx', 'JOHN DOVE', '0722');
$address = new \PagarMe\Sdk\Customer\Address([
'street' => 'xxx',
'streetNumber' => 'xx',
'neighborhood' => 'xxx',
'zipcode' => 'xxx',
'complementary' => '',
'city' => 'xxx',
'state' => 'xxx',
'country' => 'xxx',
]);
$phone = new \PagarMe\Sdk\Customer\Phone(['ddd' => '47', 'number' => '99999999', 'ddi' => '55']);
$customer = $pagarMe->customer()->create(
'John Dove',
'[email protected]',
'09130141095',
$address,
$phone,
'15021994',
'M'
);
$transaction = $pagarMe->transaction()->creditCardTransaction(
1000,
$card,
$customer,
1,
true,
'http://requestb.in/pkt7pgpk',
['idProduto' => 13933139]
);
Ps.: Esse código é só um exemplo que estou tentando fazer pois estou apenas testando a API para uso posterior
Hoje só podemos adicionar metadata numa transação no momento de sua criação, como demonstrado na documentação. Seria interessante ter a opção para inserir metadata numa transação no ato de sua captura pelo Checkout Pagar.me, assim como é disponibilizado pela API.
Adicionar metadata na etapa de captura de uma transação pelo modo token do Checkout Pagar.me.
Recurso não implementado.
Adicionar a manipulação de metadata no objeto PagarMe\Sdk\Transaction\Request\TransactionCapture
.
Como faço para utilizar as regras de split nas transações utilizando cartão de crédito? O código abaixo está ignorando as informações de "split_rules"
$pagarme->transaction()->creditCardTransaction(
intval($itemPrice*100),
$card,
$customer,
1,
true,
null,
['item' => $itemName],
[
'split_rules' => array(
array(
'recipient_id' => 're_cizsf7yqb00nefv6esyivk11k',
'charge_processing_fee' => false,
'liable' => true,
'percentage' => '80',
),
array(
'recipient_id' => 're_cizk96xvh049bws6ey9wf92tq',
'charge_processing_fee' => true,
'liable' => false,
'percentage' => '20',
)
)
]
);
Hi,
https://github.com/pagarme/pagarme-php/blob/master/lib/Pagarme/CardHashCommon.php
This class has a confusing name. CardHash
implies a cryptographic hash (e.g. SHA256
) is being used, but you're encrypting with RSA. Interestingly, you're not specifying the padding client-side, so you're encrypting with PKCS1v1.5 padding. (This is OpenSSL's default.)
If your server-side API is actually decrypting PKCS1v1.5 padded ciphertexts, this is actually vulnerable to Bleichenbacher's 1998 Padding Oracle Attack. (I have no way of confirming this without an API key, of course.)
See ZF2015-10 for an example of how this is usually mitigated.
See also: this blog post on Cryptographic right answers.
Should send 'X-Live' or not in the header
Digging into the SDK and the api documentation (https://docs.pagar.me/api/#objeto-payable) I noticed that there's no mention about the recipient_id
on the Payable
return object.
I checked on the api and it return this info. Follow the object that I got from the api call:
[{
"object": "payable",
"id": 107xxxxx,
"status": "waiting_funds",
"amount": 6492,
"fee": 0,
"anticipation_fee": 0,
"installment": 12,
"transaction_id": 132xxxx,
"split_rule_id": "sr_cizhajmq400c5zg6e0xxxxxxx",
"bulk_anticipation_id": null,
"recipient_id": "re_ciy67slew0220kn6evxxxxxxx",
"payment_date": "2018-02-20T03:00:00.000Z",
"original_payment_date": null,
"type": "credit",
"payment_method": "credit_card",
"date_created": "2017-02-22T18:28:23.527Z"
}]
PS.: I added some x
characters into the id
, transaction_id
, split_rule_id
and recipient_id
to "hide" the original data.
There's any intention in adding this on the SDK? Is the documentation incomplete yet?
Thanks in advance.
Ao tentar rodar o composer require pagarme/pagarme-php
foi notificado que a versão necessário do Guzzle é conflitante com a versão necessário do Guzzle para o Laravel.
Atualizar a versão necessário do Guzzle na biblioteca do Pagarme para uma versão compatível com a do Laravel 5.4.
Não encontrei na v3 opção de criar uma assinatura utilizando o card hash ou criar um cartão utilizando o card hash.
I was looking into the pagar.me docs and I noticed that on the payables endpoint it is possible to fetch a list of payables using any property as filter.
Said that, I need the ability to fetch those payables with the SDK V3. I know that it's possible to fetch it using the elasticsearch advanced search, but I think it could be a good idea to have an specific method (under payables domain) to get those data and not using the elastic search stuff.
Ao utilizar o SDK V3, para qualquer ação com cartão, o objeto retornado com ele não vem o atributo expiration_date, onde o mesmo esta no exemplo de retorno https://docs.pagar.me/api/?shell#retornando-um-cartao-salvo e quando se faz um CURL para o endpoint de consulta de cartão o mesmo atributo é retornado
Qualquer uso do SDK V3, pois a classe não tem esse atributo para ser populado
Usando qualquer um dos passos da wiki, listados abaixo:
/** @var $card \PagarMe\Sdk\Card\Card */
$card = $pagarMe->card()->create(
'4242424242424242',
'JOHN DOVE',
'0722'
);
/** @var $card \PagarMe\Sdk\Card\Card */
$card = $pagarMe->card()->get('card_ci6y37h16wrxsmzyi');
O Objeto Card, deve ter o atributo expirationDate
Atualmente o objeto Card não tem o atributo, expiration_date, referente ao retorno do endpoint
Adicionar o atributo ao objeto para o mesmo ser populado
Seria um grande diferencial para o pacote de integração estar em formato do composer, assim poderia ser incluido mais facilmente em Frameworks que trabalham com o composer!
Atualmente existem muitos Frameworks utilizando: Laravel, Synfony, Zend 2 entre outros.
<?php
require __DIR__.'/vendor/autoload.php';
date_default_timezone_set('America/Sao_Paulo');
$pagarMe = new \PagarMe\Sdk\PagarMe('API_KEY');
$card = new \PagarMe\Sdk\Card\Card([
'id' => 'card_cizri9czn00csfi6e1ygzw9vz',
'cvv' => '122'
]);
//tentativa 1
$customer = new \PagarMe\Sdk\Customer\Customer(
[
'address' => new \PagarMe\Sdk\Customer\Address([]),
'phone' => new \PagarMe\Sdk\Customer\Phone([])
]
);
//tentativa 2
$customer = new \PagarMe\Sdk\Customer\Customer(
[
'address' => [],
'phone' => []
]
);
$transaction = $pagarMe->transaction()->creditCardTransaction(
1000,
$card,
$customer,
1,
true,
'www.asd.com.br',
['idProduto' => 13933139],
[]
);
Mas são enviado os dados do customer, mas com valores null e a API acaba verificando e barrrando, mesmo com antifraude.
Talvez seja problema da API?
Obrigado
Some subscription tests are failing, fix it.
Importei a api v3 no meu projeto e já estou com um problema ao setar a apiKey: Class 'PagarMe\Sdk\Client' not found in PagarMe.php on line 134
Hi,
I was testing an integration and an Exception was raised without any message about the error.
I extracted the error object from the lib and obtained this:
In PHPUnit I have this:
1) Test\PagarmeServiceTest::testGetTransactionByIdWithSuccess
PagarMe_Exception:
/var/www/myapp/vendor/pagarme/pagarme-php/lib/Pagarme/Exception.php:26
/var/www/myapp/vendor/pagarme/pagarme-php/lib/Pagarme/TransactionCommon.php:45
/var/www/myapp/vendor/pagarme/pagarme-php/lib/Pagarme/Transaction.php:6
Estou recebendo um erro 500 no arquivo Request.php ao tentar criar um cartão.
Esta é a versão certa.. pois tentei usar a libv2.. e funcionou.. porém não esta disponivel ainda os metodos para planos e assinaturas.
BUG: URL da rota de deletar bulk_anticipation
está incorreta.
A URL neste arquivo (https://github.com/pagarme/pagarme-php/blob/V3/lib/BulkAnticipation/Request/BulkAnticipationDelete.php#L54) contém um /delete
no final. O correto seria sem. Por conta disso as antecipações em status building
não são deletadas.
bulk_anticipation
com o build
definido como true
bulk_anticipation
com o status building
$client->bulkAnticipation()->delete($bulkAnticipation)
Espera-se que retorne 200 e a antecipação seja cancelada.
Uma exceção é lançada e a antecipação não é deletada, mantendo "presos" todos os payables
utilizados na antecipação pelos próximos 5 minutos.
Remover o /delete
no endpoint da API, assim como indicado na documentação: https://docs.pagar.me/api/#deletando-uma-antecipacao-building
Versão: 3.0.1
https://github.com/pagarme/pagarme-php/tree/V3/
Ao rodar o código abaixo não estou conseguindo recuperar o "boleto_url" e "boleto_barcode" porem o pedido aparece corretamente lá no Dashboard, parece que os getters estão faltando na classe BoletoTransaction.
$this->pagarMe = new PagarMe($apiKey);
$transaction = $this->pagarMe->transaction()->boletoTransaction($amount, $customer, $this->helper->getNotificationUrl());
Não há classe para trabalhar com o endpoint Search.
Criei a classe e o método search(), que recebe o $type, $query e $search_type de acordo com a documentação. Além dele, o método searchTransactionByMetadata() para pesquisar metadados em transações.
Estou utilizando o branch master (v2) e estou com problema ao criar uma assinatura, pois não tenho retorno dos dados após a assinatura criada, assim como acontece na criação do plano. Poderiam ter colocado na documentação o retorno das requisições.
With booleans, only strict comparison (with
!==
operator) should be used to lower bug risks and to improve performances.
public function __construct(GuzzleClient $client, $apiKey, $timeout = null)
{
$this->client = $client;
$this->apiKey = $apiKey;
if ($timeout != null) {
$this->setDefaultTimeout($timeout);
}
}
/**
Posted from SensioLabsInsight
Ao criar uma transação, não consigo enviar o parâmetro soft_descriptor disponível na API. Segue exemplo das tentativas:
['softDescriptor' => TESTE]
//OU
['soft_descriptor' => TESTE]
$extraAttributes = ['soft_descritor' => $soft_descriptor]
No JSON de retorno da API, o esperado era:
"soft_descriptor":"TESTE",
Segue o JSON retornado:
"soft_descriptor":null,
E ai pessoal, to tentando implementar o PagarMe e estou enfrentando um problema aqui, estou em ambiante de teste, executando uma transação de teste, tudo ocorre normal no front-end, o problema é quando o tenho que capturar a transação no backend, veja bem:
Na linha 26 do Request.php onde a requisiçao é feita, em vez de eu receber um JSON com uma respota de sucesso ou erro eu estou recebendo uma página de 500 internal error, gerando uma excessão na linha 29 do Request.php primeiramente eu achei que o erro era da minha parte, eu chequei e testei todas as variáveis aqui e não estou conseguindo achar o erro, será que vocês poderiam me ajudar?
Atualmente, via SDK, não é possível criar um Card
através do card_hash
gerado via Pagarme.js, apenas com os dados completos do cartão. Gostaria de realizar essa operação para evitar trafegar dados de cartão "abertos" via rede.
A criação via hash é possível usando a API REST, passando o parâmetro card_hash
no lugar dos dados do cartão, mas a funcionalidade não é exposta na SDK PHP.
Sugiro a criação de um método createFromHash(string $card_hash)
que permita essa operação.
Posso abrir um PR com esse objetivo, se for interessante.
Obrigado!
Ao criar uma assinatura utilizando o card_hash (release 3.1.0), o postbackUrl não é salvo, ficando sempre null.
Versão 3.0
Ao executar o método implementado e referenciado na issue: #116
public function getBoletoUrl() { return $this->boletoUrl; }
public function getBoletoBarcode() { return $this->boletoBarcode; }
Está retornando erros, pois a propriedade boletoUrl e boletoBarcode não existem no objeto em questão.
Isto acontece por conta do método fill da trait Fillable implementada na class AbstractTransaction: fill()
Este método checa se a propriedade existe antes de setar como field do objeto.
Na api v2 existia uma forma de validar as notificações recebidas utilizando: PagarMe::validateRequestSignature(file_get_contents('php://input'), $_SERVER['HTTP_X_HUB_SIGNATURE'])
Qual a forma de validar utilizando a api v3?
Obs.: Não achei na documentação.
Ao tentar criar uma antecipação e passar o building como "true" ainda sim a antecipação é criada como pendente.
building
como true$bulk->getStatus()
não é building
Que o status da bulk_anticipation
seja building
O status da bulk_anticipation
é pending
Alterar a linha https://github.com/pagarme/pagarme-php/blob/V3/lib/BulkAnticipation/Request/BulkAnticipationCreate.php#L69 e trocar de building
para build
. Não se o correto é true
como valor ou como string, porém uma string true funciona.
This library is using an old Guzzle version, having problems together with other libraries (like facebook/graph-sdk (beta)
/ intercom-php
).
In Use: 5.3
Latest: 6.2.3
Your requirements could not be resolved to an installable set of packages.
Fix: Please update to 6.x.
Guzzle Upgrade Guide
https://github.com/guzzle/guzzle/blob/master/UPGRADING.md
Essa V3 do SDK já está disponível para rodar em produção? É que não vi na Wiki alguma menção sobre o card_hash e também na criação de um cartão o CVV não é informado.
<?php
require("pagarme-php/Pagarme.php");
Pagarme::setApiKey("ak_test_TSgC3nvXtdYnDoGKgNLIOfk3TFfkl9");
$transaction = new PagarMe_Transaction(array(
"amount" => 4400,
"metadata" => array(
"order_id" => "2235451",
"event_id" => "17533",
"products_amount" => 40,
"payment_type_id" => 18,
"installment_amount" => 0
),
"payment_method" => "credit_card",
"async" => false,
"card" => array(
"card_number" => "5232840325291779",
"card_holder_name" => "Joao G F E MIRANDA",
"card_expiration_month" => 6,
"card_expiration_year" => 2019,
"card_cvv" => 123
),
"installments" => 1
));
$transaction->charge();
$status = $transaction->status;
echo $status;
?>
This throws an exception:
Fatal error: Uncaught exception 'PagarMe_Exception' with message 'Data de expiração inválida ' in /Users/joaofaria/new/php-poc/pagarme-php/lib/Pagarme/Model.php:24
Pelo que foi analisado no seguinte trecho de código:
$customerData->address = new Address(
get_object_vars($customerData->addresses[0])
);
$customerData->phone = new Phone($customerData->phones[0]);
A SDK está tratando os dados como um único objeto para Address
e para Phone
e a API utiliza um array de objetos.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.