PHP hook, building hooks in your application
Introduction
One of the real challenges in building any type of framework, core or application is making it possible for the developers to hook into the business logic at specific points. Since PHP is not event based, nor it works with interrupts you have to come up an alternative.
The test case
Lets assume we are the main developers of a webshop framework. Programmers can use our framework to build complete webshops. Programmers can manage the orders that are placed on the webshop with the order class. The order class is part of our framework and we don’t want it to be extended by any programmer. However we don’t want to limit to programmers in their possibilities to hook into the orders process.
For example programmers should be able to send an email to the webshopowner if an order changes from one specific delivery status to another. This functionality is not part of the default behavior in our framework and is custom for the progammers webshop implementation.
Like said before, PHP doesn’t provide interrupts or real events so we need to come up with another way to implement hooks into our application. Lets take a look at the observer pattern.
Implementing the Observer pattern
The observer pattern is a design-pattern that describes a way for objects to be notified to specific state-changes in objects of the application.
For the first implementation we can use SPL. The SPL provides in two simple objects:
SPLSubject
- attach (new observer to attach)
- detach (existing observer to detach)
- notify (notify all observers)
SPLObserver
- update (Called from the subject (i.e. when it’s value has changed).
iOrderRef = $iOrderRef;
// Get order information from the database or an other resources
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param SplObserver $oObserver
* @return void
*/
public function attach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param SplObserver $oObserver
* @return void
*/
public function detach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notify()
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function delete()
{
$this->notify();
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notify();
// ...
$this->iStatus = $iStatus;
// ...
$this->notify();
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements SplObserver
{
/**
* Previous orderstatus
* @var int
*/
protected $iPreviousOrderStatus;
/**
* Current orderstatus
* @var int
*/
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oSubject
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(SplSubject $oSubject)
{
if(!$oSubject instanceof Order) {
return;
}
if(is_null($this->iPreviousOrderStatus)) {
$this->iPreviousOrderStatus = $oSubject->getStatus();
} else {
$this->iCurrentOrderStatus = $oSubject->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oSubject->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attach(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->delete();
?>
There are several problems with the implementation above. To most important disadvantage is that we have only one update method in our observer. In this update method we don’t know when and why we are getting notified, just that something happened. We should keep track of everything that happens in the subject. (Or use debug_backtrace… just joking, don’t even think about using it that way ever!).
Taking it a step further, events
Lets take a look at the next example, we will extend the Observer implementation with some an additional parameter for the eventname that occured.
Finishing up, optional data
iOrderRef = $iOrderRef;
// Get order information from the database or something else...
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function attachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function detachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notifyObserver($sEvent, $mData=null)
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this, $sEvent, $mData);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function add($aOrder = array())
{
$this->notifyObserver('onAdd');
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notifyObserver('onBeforeUpdateStatus');
// ...
$this->iStatus = $iStatus;
// ...
$this->notifyObserver('onAfterUpdateStatus');
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements Observer_Interface
{
protected $iPreviousOrderStatus;
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oObservable
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(Observable_Interface $oObservable, $sEvent, $mData=null)
{
if(!$oObservable instanceof Order) {
return;
}
switch($sEvent) {
case 'onBeforeUpdateStatus':
$this->iPreviousOrderStatus = $oObservable->getStatus();
return;
case 'onAfterUpdateStatus':
$this->iCurrentOrderStatus = $oObservable->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oObservable->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attachObserver(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->add();
?>
Now we are able to take action on different events that occur.
Disadvantages
Although this implementation works quite well there are some drawbacks. One of those drawbacks is that we need to dispatch an event in our framework, if we don’t programmers can’t hook into our application. Triggering events everywhere give us a small performance penalty however I do think this way of working gives the programmers a nice way to hook into your application on those spots that you want them to hook in.
Just for the record
Notice that this code is just an example and can still use some improvements, for example: each observer is initialized even it will maybe never be notified, therefore I suggest to make use of lazy in some cases for loading the objects. There are other systems to hook into an application, more to follow!
Выезд нарколога на дом в Нижнем Новгороде — капельница от запоя с выездом на дом. Мы обеспечиваем быстрое и качественное лечение без необходимости посещения клиники.
Получить дополнительную информацию – [url=https://vyvod-iz-zapoya-nizhnij-novgorod13.ru/]вывод из запоя вызов на дом в нижний новгороде[/url]
JustinAxots
19 Oct 25 at 2:34 pm
Срочная наркологическая помощь в Красноярске доступна на сайте vivod-iz-zapoya-krasnoyarsk021.ru. Наркологическая клиника предлагает помощь в лечении зависимостейвключая методы кодирования от алкоголизма и специализированные программы лечения. Здесь вы найдете помощь при запое и реабилитацию наркоманов. Консультация психотерапевта также доступны. Специальные кризисные центры обеспечивают поддержку для родственников пациентов. Профилактика зависимостей и реабилитация после наркотической зависимости, важные этапы на пути к здоровью. Гарантируем анонимность и конфиденциальность.
lecheniekrasnoyarskNeT
19 Oct 25 at 2:35 pm
farmacias direct [url=http://tadalafiloexpress.com/#]cialis precio[/url] tadalafilo 5 mg precio
GeorgeHot
19 Oct 25 at 2:36 pm
Вывод из запоя в Самаре проводится с проверенными препаратами, с учётом состояния пациента и без лишнего стресса.
Узнать больше – [url=https://vyvod-iz-zapoya-v-stacionare-samara23.ru/]вывод из запоя в стационаре самара[/url]
Williamliz
19 Oct 25 at 2:37 pm
Ukrainian President Volodymyr Zelensky condemned Russian attacks on the Ukrainian regions of Kharkiv, Zaporizhzhia and Sumy on Monday, saying that the Kremlin intends to “humiliate diplomatic efforts” just hours before European leaders visit the White House.
[url=https://kra-42–at.ru]kra38 сс[/url]
“The Russian war machine continues to destroy lives despite everything,” Zelensky said in a statement, hours before he’s due to meet US President Donald Trump in the Oval Office. “That is precisely why we are seeking assistance to put an end to the killings. That is why reliable security guarantees are required. That is why Russia should not be rewarded for its participation in this war.”
[url=https://kra—42–cc.ru]kra38 сс[/url]
“Everyone seeks dignified peace and true security,” the Ukrainian president said. “And at this very moment, the Russians are attacking Kharkiv, Zaporizhzhia, the Sumy region, and Odesa, destroying residential buildings and our civilian infrastructure.”
At least seven people were killed in Russia’s attack? on Kharkiv and a further three killed in the ballistic missile strike on the city of Zaporizhzhia, with scores more injured, according to Ukrainian authorities.
“This was a demonstrative and cynical Russian strike,” Zelensky added.
kra37 at
https://kra42at.net
Danieljeove
19 Oct 25 at 2:37 pm
фрибет в мелбет [url=http://www.melbetbonusy.ru]фрибет в мелбет[/url] .
melbet_cyOi
19 Oct 25 at 2:39 pm
купить диплом физика [url=rudik-diplom6.ru]купить диплом физика[/url] .
Diplomi_xyKr
19 Oct 25 at 2:41 pm
1вин обман или нет [url=http://1win5510.ru]http://1win5510.ru[/url]
1win_uz_mosi
19 Oct 25 at 2:44 pm
[url=https://x.com/vaycasino_xcom]vaycasino Guncel Giris[/url]
ManuelBluro
19 Oct 25 at 2:44 pm
купить диплом в выборге [url=http://www.rudik-diplom9.ru]http://www.rudik-diplom9.ru[/url] .
Diplomi_cmei
19 Oct 25 at 2:44 pm
1вин ios приложение [url=https://1win5509.ru/]https://1win5509.ru/[/url]
1win_uz_fsKt
19 Oct 25 at 2:48 pm
https://tadalafiloexpress.com/# cialis precio
MickeySum
19 Oct 25 at 2:49 pm
Ukrainian President Volodymyr Zelensky condemned Russian attacks on the Ukrainian regions of Kharkiv, Zaporizhzhia and Sumy on Monday, saying that the Kremlin intends to “humiliate diplomatic efforts” just hours before European leaders visit the White House.
[url=https://kra42-at.net]kra39 cc[/url]
“The Russian war machine continues to destroy lives despite everything,” Zelensky said in a statement, hours before he’s due to meet US President Donald Trump in the Oval Office. “That is precisely why we are seeking assistance to put an end to the killings. That is why reliable security guarantees are required. That is why Russia should not be rewarded for its participation in this war.”
[url=https://kra-42-cc.net]kra40[/url]
“Everyone seeks dignified peace and true security,” the Ukrainian president said. “And at this very moment, the Russians are attacking Kharkiv, Zaporizhzhia, the Sumy region, and Odesa, destroying residential buildings and our civilian infrastructure.”
At least seven people were killed in Russia’s attack? on Kharkiv and a further three killed in the ballistic missile strike on the city of Zaporizhzhia, with scores more injured, according to Ukrainian authorities.
“This was a demonstrative and cynical Russian strike,” Zelensky added.
kra38 cc
https://kra–41—at.ru
Michaelbaf
19 Oct 25 at 2:49 pm
$MTAUR presale is flying under radar but shouldn’t—80% discount is insane value. In-game mini-games unlocked by tokens add replayability. Bullish on its 9% annual market growth projection.
minotaurus presale
WilliamPargy
19 Oct 25 at 2:50 pm
1win uz [url=www.1win5510.ru]www.1win5510.ru[/url]
1win_uz_vosi
19 Oct 25 at 2:50 pm
мелбет официальный сайт [url=https://melbetbonusy.ru/]мелбет официальный сайт[/url] .
melbet_beOi
19 Oct 25 at 2:55 pm
купить диплом геодезиста [url=https://rudik-diplom9.ru]купить диплом геодезиста[/url] .
Diplomi_yuei
19 Oct 25 at 2:55 pm
fans connect
MichaelSig
19 Oct 25 at 2:56 pm
1вин лайв ставки [url=1win5509.ru]1win5509.ru[/url]
1win_uz_crKt
19 Oct 25 at 2:56 pm
brandmetric.click – I checked this site and the layout is very clean, easy to navigate and visually appealing.
Rina Heinbach
19 Oct 25 at 2:58 pm
kuvalis.com – I found the design pretty clean and the content easy to digest.
Ashley Whyard
19 Oct 25 at 2:59 pm
My brother recommended I might like this website.
He was totally right. This post actually made my day.
You cann’t imagine just how much time I had spent for
this info! Thanks!
طراحی سایت پزشکی در اردبیل
19 Oct 25 at 3:00 pm
Программа вывода из запоя в Воронеже от «Частного Медика 24» включает не только устранение физической зависимости, но и работу по восстановлению сна, гидратацию, лекарственную поддержку, а также психотерапию, чтобы помочь справиться не просто с запоем, но и с причинами, которые к нему привели.
Получить дополнительные сведения – [url=https://vyvod-iz-zapoya-v-stacionare-voronezh23.ru/]нарколог вывод из запоя в стационаре в воронеже[/url]
Anthonyvom
19 Oct 25 at 3:00 pm
1вин вывести деньги [url=https://1win5510.ru/]https://1win5510.ru/[/url]
1win_uz_dusi
19 Oct 25 at 3:00 pm
мелбет войти [url=www.melbetbonusy.ru]www.melbetbonusy.ru[/url] .
melbet_pgOi
19 Oct 25 at 3:01 pm
cialis prezzo: cialis prezzo – tadalafil senza ricetta
RaymondNit
19 Oct 25 at 3:01 pm
https://form.jotform.com/252393820540050
Anthonycam
19 Oct 25 at 3:03 pm
Ukrainian President Volodymyr Zelensky condemned Russian attacks on the Ukrainian regions of Kharkiv, Zaporizhzhia and Sumy on Monday, saying that the Kremlin intends to “humiliate diplomatic efforts” just hours before European leaders visit the White House.
[url=https://kra42cc.com]kra40 at[/url]
“The Russian war machine continues to destroy lives despite everything,” Zelensky said in a statement, hours before he’s due to meet US President Donald Trump in the Oval Office. “That is precisely why we are seeking assistance to put an end to the killings. That is why reliable security guarantees are required. That is why Russia should not be rewarded for its participation in this war.”
[url=https://kra–41–cc.ru]kra42 сс[/url]
“Everyone seeks dignified peace and true security,” the Ukrainian president said. “And at this very moment, the Russians are attacking Kharkiv, Zaporizhzhia, the Sumy region, and Odesa, destroying residential buildings and our civilian infrastructure.”
At least seven people were killed in Russia’s attack? on Kharkiv and a further three killed in the ballistic missile strike on the city of Zaporizhzhia, with scores more injured, according to Ukrainian authorities.
“This was a demonstrative and cynical Russian strike,” Zelensky added.
kra36 cc
https://kra42cc.com
Michaelbaf
19 Oct 25 at 3:05 pm
I’m really enjoying the theme/design of your website.
Do you ever run into any web browser compatibility issues?
A couple of my blog readers have complained about my website not working correctly in Explorer but looks great in Safari.
Do you have any ideas to help fix this issue?
webpage
19 Oct 25 at 3:05 pm
купить диплом в норильске [url=www.rudik-diplom6.ru]купить диплом в норильске[/url] .
Diplomi_bzKr
19 Oct 25 at 3:07 pm
kraken marketplace
кракен онлайн
JamesDaync
19 Oct 25 at 3:08 pm
Me impressionei com BETesporte Casino, sinto um rugido de emocao. A variedade de titulos e estonteante, incluindo apostas esportivas que aceleram o coracao. Fortalece seu saldo inicial. O acompanhamento e impecavel, com suporte preciso e confiavel. Os saques sao rapidos como um drible, no entanto mais apostas gratis seriam incriveis. No fim, BETesporte Casino garante diversao constante para amantes de apostas esportivas ! Acrescentando que o site e veloz e cativante, instiga a prolongar o jogo. Um diferencial importante os eventos comunitarios envolventes, fortalece o senso de comunidade.
Ler mais|
BlazeStrikerT3zef
19 Oct 25 at 3:09 pm
купить диплом в зеленодольске [url=https://rudik-diplom15.ru]купить диплом в зеленодольске[/url] .
Diplomi_jcPi
19 Oct 25 at 3:10 pm
Sou totalmente viciado em PlayPIX Casino, leva a um universo de pura adrenalina. A variedade de titulos e estonteante, com sessoes ao vivo cheias de emocao. O bonus de boas-vindas e cativante. A assistencia e eficiente e amigavel, com suporte rapido e preciso. As transacoes sao confiaveis, no entanto ofertas mais generosas seriam bem-vindas. Resumindo, PlayPIX Casino e essencial para jogadores para entusiastas de jogos modernos ! Vale destacar a plataforma e visualmente espetacular, facilita uma imersao total. Um diferencial significativo as opcoes variadas de apostas esportivas, assegura transacoes confiaveis.
Abrir agora|
BlazeRhythmQ6zef
19 Oct 25 at 3:10 pm
1win cashback uz [url=http://1win5510.ru]http://1win5510.ru[/url]
1win_uz_ymsi
19 Oct 25 at 3:12 pm
кафе ромашково
кафе ромашково
19 Oct 25 at 3:13 pm
Thank you for every other informative website.
Where else could I am getting that kind of info written in such an ideal manner?
I have a undertaking that I am just now operating on,
and I have been on the look out for such info.
scam awareness MEXQuick
19 Oct 25 at 3:15 pm
1win uz [url=www.1win5510.ru]www.1win5510.ru[/url]
1win_uz_vwsi
19 Oct 25 at 3:16 pm
купить диплом в ейске [url=https://www.rudik-diplom13.ru]https://www.rudik-diplom13.ru[/url] .
Diplomi_zton
19 Oct 25 at 3:18 pm
официальный сайт мелбет [url=www.melbetbonusy.ru/]www.melbetbonusy.ru/[/url] .
melbet_zxOi
19 Oct 25 at 3:22 pm
Actually when someone doesn’t be aware of then its up to other people that they will assist,
so here it occurs.
https://google-chrome.ru.com/
19 Oct 25 at 3:22 pm
Это — неожиданность!
в 1910 году Эме Герлен умер, [url=https://share.google/WxFJmeYam31JAhKtv]https://share.google/WxFJmeYam31JAhKtv[/url] компанию в наследство получили сыновья Габриэля Жак и Пьер. 3. громадное значение придается дизайну флаконов: „флакон для аромата – что платье для женщин“.
Kimrex
19 Oct 25 at 3:24 pm
кракен клиент
кракен клиент
JamesDaync
19 Oct 25 at 3:26 pm
Дизайнерский ремонт: искусство преображения пространства
Дизайн интерьера играет важную роль в создании комфортной и уютной атмосферы в доме. Сегодня мы поговорим о таком понятии, как дизайнерский ремонт, который позволяет превратить обычное жилье в уникальное пространство, отражающее индивидуальность владельца.
[url=https://designapartment.ru ]дизайнерский ремонт квартиры под ключ[/url]
Что такое дизайнерский ремонт?
Дизайнерский ремонт — это комплекс работ, направленных на создание оригинального дизайна помещения. Это не просто обновление отделки, а полноценный творческий процесс, включающий разработку концепции, подбор материалов и мебели, а также реализацию проекта.
Ключевые особенности дизайнерского ремонта:
– Индивидуальный подход к каждому проекту.
– Использование качественных материалов и современных технологий.
– Создание уникального стиля, соответствующего вкусам заказчика.
– Оптимизация пространства для максимального комфорта и функциональности.
Виды дизайнерских ремонтов
[url=https://designapartment.ru ]дизайнерский ремонт цена в москве[/url]
Существует несколько видов дизайнерских ремонтов, каждый из которых имеет свои особенности и преимущества.
#1 Дизайнерский ремонт квартиры
Это наиболее распространенный вид ремонта, подходящий для тех, кто хочет обновить интерьер своей городской квартиры. Специалисты разрабатывают проект, учитывая размеры помещений, пожелания клиента и бюджет. Такой ремонт включает перепланировку, замену коммуникаций, отделочные работы и декорирование.
Пример дизайна: светлая гостиная с панорамными окнами, минималистичный дизайн кухни и спальни в стиле лофт.
#2 Дизайнерский ремонт дома
Такой ремонт предполагает полное преобразование жилого дома, начиная от фундамента и заканчивая крышей. Здесь важно учитывать архитектурные особенности здания, климатические условия региона и предпочтения владельцев. Часто используется экодизайн, натуральные материалы и энергосберегающие технологии.
Пример дизайна: просторный холл с камином, стеклянная веранда с видом на сад, спальня в пастельных тонах.
[url=https://designapartment.ru]дизайнерский ремонт апартаментов[/url]
#3 Дизайнерский ремонт виллы
Ремонт вилл требует особого подхода, поскольку такие объекты часто расположены в живописных местах и имеют большую площадь. Важно сохранить гармонию с окружающей средой, используя природные материалы и цвета. Особое внимание уделяется созданию зон отдыха, бассейнов и садов.
Пример дизайна: роскошная вилла с бассейном, открытая терраса с видами на море, спальная зона в тропическом стиле.
#4 Дизайнерский ремонт коттеджа
Коттедж отличается от обычного дома наличием придомового участка и возможностью организации дополнительных функциональных зон. Ремонт коттеджей включает работу над фасадом, ландшафтом и внутренним пространством. Стили могут варьироваться от классики до хай-тека.
Пример дизайна: двухэтажный коттедж с мансардой, гостиная-столовая в скандинавском стиле, детская комната с игровой зоной.
#5 Дизайнерский ремонт пентхауса
Пентхаус — это элитное жилье, расположенное на верхних этажах зданий с панорамными видами. Для такого типа недвижимости характерны высокие потолки, большие окна и эксклюзивные элементы декора. Проектирование пентхауса требует учета особенностей конструкции здания и пожеланий клиентов относительно приватности и удобства.
Пример дизайна: современный пентхаус с открытой планировкой, кабинет с видом на город, зона отдыха с джакузи.
Заключение
Дизайнерский ремонт — это возможность создать идеальное пространство для жизни и отдыха. Независимо от того, хотите ли вы обновить квартиру, дом, виллу, коттедж или пентхаус, профессиональный подход гарантирует вам комфорт и эстетическое удовольствие на долгие годы.
https://designapartment.ru
дизайнерский ремонт квартиры москва
WayneTut
19 Oct 25 at 3:27 pm
купить дипломы о высшем цены [url=https://www.rudik-diplom9.ru]купить дипломы о высшем цены[/url] .
Diplomi_raei
19 Oct 25 at 3:30 pm
купить диплом в лениногорске [url=www.rudik-diplom6.ru/]www.rudik-diplom6.ru/[/url] .
Diplomi_wvKr
19 Oct 25 at 3:33 pm
Кодирование от алкоголизма: верный шаг к здоровой жизни — узнайте, как современные методы помогают справиться с зависимостью, не выходя из дома. Подробности на NetLekarstvаm. Исследовать вопрос подробнее – http://infoenglish.info/forum/13-9411-1
Crystaldum
19 Oct 25 at 3:35 pm
купить диплом в перми [url=rudik-diplom13.ru]купить диплом в перми[/url] .
Diplomi_caon
19 Oct 25 at 3:38 pm
brandmetric.click – Pages load quickly and smoothly, no lag or weird behavior when switching tabs.
Keenan Decastro
19 Oct 25 at 3:41 pm
бонус мелбет [url=http://www.melbetbonusy.ru]бонус мелбет[/url] .
melbet_amOi
19 Oct 25 at 3:42 pm