SlideShare a Scribd company logo
1 of 22
Download to read offline
Why you shouldn’t
edit SilverStripe
core files
(and how to do it anyway)
By Loz Calver / @kinglozzer
What do you mean “editing
core files”?
Modifying someone else’s code
Code outside the scope of “your project”
Applies to framework, cms and any other modules
Why would I edit core files?
Bugs - SilverStripe isn’t (quite) perfect
Security
need urgent/immediate fix
email us!
Missing/upcoming features - time delay between minor versions
Clients!
security@silverstripe.org
Why shouldn’t I edit core files?
Other developers don’t know what you’ve done
Updates are harder
(you should all be keeping up to date!)
eventually you’ll get bored or frustrated and give up
You might accidentally introduce other issues
How can I avoid editing core?
Workaround 1: Extensions
Example 1: adding database fields & extra methods
MyMemberExtension.php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
'DateOfBirth' => 'SS_Datetime'
);
public function SayHi() {
return "Hi " . $this->owner->Name;
}
}
_config.yml
Member:
extensions:
- MyMemberExtension
Workaround 1: Extensions
Example 2: augmenting database queries
BlogPostFilter.php
<?php
class BlogPostFilter extends DataExtension {
public function augmentSQL(SQLQuery &$query) {
$stage = Versioned::current_stage();
if ($stage == 'Live' || !Permission::check('VIEW_DRAFT_CONTENT')) {
$sqlNow = Convert::raw2sql(SS_Datetime::now());
$query->addWhere(sprintf('"PublishDate" < '%s'', $sqlNow));
}
}
}
_config.yml
BlogPost:
extensions:
- BlogPostFilter
Workaround 1: Extensions
Pros
Can be used to add things to built-in classes
Reusable: package them up, release them as modules!
Cons/Caveats
Reliant on extension points
Extensions have limited power
Workaround 2: Injector
Example: adding an extension hook
ManyManyListWithHook.php
<?php
class ManyManyListWithHook extends ManyManyList {
public function add($item, $extraFields = null) {
parent::add($item, $extraFields);
if($item instanceof DataObject) {
$item->extend('onAfterManyManyAdd', $this);
}
}
}
_config.yml
Injector:
ManyManyList:
class: ManyManyListWithHook
Credit to / module@camspiers silverstripe-cacheinclude
Workaround 2: Injector
Example: using the extension hook
MemberExtension.php
<?php
class MemberExtension extends Extension {
public function onAfterManyManyAdd(ManyManyList $list) {
Debug::log('Member added to many_many relation');
}
}
_config.yml
Member:
extensions:
- MemberExtension
Workaround 2: Injector
Pros
Can “replace” an entire class
Super powerful
Cons/Caveats
With great power comes great responsibility
Must be instantiated with one of:
Class::create()
Injector::inst()->get('Class')
Injector::inst()->create('Class')
Injector::inst()->createWithArgs('Class')
When all else fails, fork it!
Create a fork, apply your fix
Use Git to periodically rebase from “upstream”
Composer helps to make this easier!
Example
composer.json
{
"require": {
"silverstripe/cms": "3.1.15",
"silverstripe/framework": "3.1.15"
},
"repositories": [
{
"type": "vcs",
"url": "git@github.com:kinglozzer/sapphire.git"
}
]
}
Example
composer.json
{
"require": {
"silverstripe/cms": "3.1.15",
"silverstripe/framework": "dev-hotfix"
},
"repositories": [
{
"type": "vcs",
"url": "git@github.com:kinglozzer/sapphire.git"
}
]
}
Not quite...
Fixed!
composer.json
{
"require": {
"silverstripe/cms": "3.1.15",
"silverstripe/framework": "dev-hotfix"
},
"repositories": [
{
"type": "vcs",
"url": "git@github.com:kinglozzer/sapphire.git"
}
]
}
Fixed!
composer.json
{
"require": {
"silverstripe/cms": "3.1.15",
"silverstripe/framework": "dev-hotfix as 3.1.15"
},
"repositories": [
{
"type": "vcs",
"url": "git@github.com:kinglozzer/sapphire.git"
}
]
}
Forking
Pros
Easier to:
keep track of modifications made
re-apply changes during updates - rebase/cherry-pick
create a PR!
Cons/Caveats
While easier, it’s still extra effort!
Slows down composer updates
Summary
Use extensions where possible
For simple additions/fixes to methods, Injector should be okay
For anything else you can’t work around, fork as last resort
Use Composer!
Thanks/questions
Feedback welcomed!
@kinglozzer @kinglozzer lozcalver@bigfork.co.uk

More Related Content

What's hot

For each component in mule
For each component in muleFor each component in mule
For each component in muleRajkattamuri
 
Choice component in mule
Choice component in mule Choice component in mule
Choice component in mule Rajkattamuri
 
Introduction to django
Introduction to djangoIntroduction to django
Introduction to djangoIlian Iliev
 
Mule ESB SMTP Connector Integration
Mule ESB SMTP Connector  IntegrationMule ESB SMTP Connector  Integration
Mule ESB SMTP Connector IntegrationAnilKumar Etagowni
 
Mule Esb Data Weave
Mule Esb Data WeaveMule Esb Data Weave
Mule Esb Data WeaveMohammed246
 
Filter expression in mule
Filter expression in muleFilter expression in mule
Filter expression in muleRajkattamuri
 
Quartz component in mule
Quartz component in muleQuartz component in mule
Quartz component in mulejaveed_mhd
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecturepostrational
 
Filter expression in mule demo
Filter expression in mule demoFilter expression in mule demo
Filter expression in mule demoSudha Ch
 
Mule esb add logger to existing flow
Mule esb add logger to existing flowMule esb add logger to existing flow
Mule esb add logger to existing flowGermano Barba
 
Input and output flow using http and java component
Input and output flow using http and java componentInput and output flow using http and java component
Input and output flow using http and java componentSon Nguyen
 
( 15 ) Office 2007 Create A Membership Database
( 15 ) Office 2007   Create A Membership Database( 15 ) Office 2007   Create A Membership Database
( 15 ) Office 2007 Create A Membership DatabaseLiquidHub
 
ACL in CodeIgniter
ACL in CodeIgniterACL in CodeIgniter
ACL in CodeIgnitermirahman
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHPStephen Young
 
Junit in mule demo
Junit in mule demo Junit in mule demo
Junit in mule demo javeed_mhd
 

What's hot (18)

For each component in mule
For each component in muleFor each component in mule
For each component in mule
 
Choice component in mule
Choice component in mule Choice component in mule
Choice component in mule
 
Introduction to django
Introduction to djangoIntroduction to django
Introduction to django
 
Mule ESB SMTP Connector Integration
Mule ESB SMTP Connector  IntegrationMule ESB SMTP Connector  Integration
Mule ESB SMTP Connector Integration
 
Mule Esb Data Weave
Mule Esb Data WeaveMule Esb Data Weave
Mule Esb Data Weave
 
Filter expression in mule
Filter expression in muleFilter expression in mule
Filter expression in mule
 
Quartz component in mule
Quartz component in muleQuartz component in mule
Quartz component in mule
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecture
 
Filter expression in mule demo
Filter expression in mule demoFilter expression in mule demo
Filter expression in mule demo
 
Mule jdbc
Mule   jdbcMule   jdbc
Mule jdbc
 
Mule esb add logger to existing flow
Mule esb add logger to existing flowMule esb add logger to existing flow
Mule esb add logger to existing flow
 
Passing java arrays in oracle stored procedure from mule esb flow
Passing java arrays in oracle stored procedure from mule esb flowPassing java arrays in oracle stored procedure from mule esb flow
Passing java arrays in oracle stored procedure from mule esb flow
 
Mule esb :Data Weave
Mule esb :Data WeaveMule esb :Data Weave
Mule esb :Data Weave
 
Input and output flow using http and java component
Input and output flow using http and java componentInput and output flow using http and java component
Input and output flow using http and java component
 
( 15 ) Office 2007 Create A Membership Database
( 15 ) Office 2007   Create A Membership Database( 15 ) Office 2007   Create A Membership Database
( 15 ) Office 2007 Create A Membership Database
 
ACL in CodeIgniter
ACL in CodeIgniterACL in CodeIgniter
ACL in CodeIgniter
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHP
 
Junit in mule demo
Junit in mule demo Junit in mule demo
Junit in mule demo
 

Similar to Why you shouldn’t edit silver stripe core files (and how to do it anyway)

Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 3camp
 
Built-in query caching for all PHP MySQL extensions/APIs
Built-in query caching for all PHP MySQL extensions/APIsBuilt-in query caching for all PHP MySQL extensions/APIs
Built-in query caching for all PHP MySQL extensions/APIsUlf Wendel
 
Codebits 2012 - Fast relational web site construction.
Codebits 2012 - Fast relational web site construction.Codebits 2012 - Fast relational web site construction.
Codebits 2012 - Fast relational web site construction.Nelson Gomes
 
Starting with PHP and Web devepolment
Starting with PHP and Web devepolmentStarting with PHP and Web devepolment
Starting with PHP and Web devepolmentRajib Ahmed
 
PyCon US 2012 - State of WSGI 2
PyCon US 2012 - State of WSGI 2PyCon US 2012 - State of WSGI 2
PyCon US 2012 - State of WSGI 2Graham Dumpleton
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn Cleveley
 
Drupal 8 meets to symphony
Drupal 8 meets to symphonyDrupal 8 meets to symphony
Drupal 8 meets to symphonyBrahampal Singh
 
Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's CodeWildan Maulana
 
Having Fun Building Web Applications (Day 2 slides)
Having Fun Building Web Applications (Day 2 slides)Having Fun Building Web Applications (Day 2 slides)
Having Fun Building Web Applications (Day 2 slides)Clarence Ngoh
 
WordPress Structure and Best Practices
WordPress Structure and Best PracticesWordPress Structure and Best Practices
WordPress Structure and Best Practicesmarkparolisi
 
WordPress plugin #1
WordPress plugin #1WordPress plugin #1
WordPress plugin #1giwoolee
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsPython RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsSolution4Future
 

Similar to Why you shouldn’t edit silver stripe core files (and how to do it anyway) (20)

Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
 
Built-in query caching for all PHP MySQL extensions/APIs
Built-in query caching for all PHP MySQL extensions/APIsBuilt-in query caching for all PHP MySQL extensions/APIs
Built-in query caching for all PHP MySQL extensions/APIs
 
CodeIgniter & MVC
CodeIgniter & MVCCodeIgniter & MVC
CodeIgniter & MVC
 
Codebits 2012 - Fast relational web site construction.
Codebits 2012 - Fast relational web site construction.Codebits 2012 - Fast relational web site construction.
Codebits 2012 - Fast relational web site construction.
 
Starting with PHP and Web devepolment
Starting with PHP and Web devepolmentStarting with PHP and Web devepolment
Starting with PHP and Web devepolment
 
PyCon US 2012 - State of WSGI 2
PyCon US 2012 - State of WSGI 2PyCon US 2012 - State of WSGI 2
PyCon US 2012 - State of WSGI 2
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
Drupal 8 meets to symphony
Drupal 8 meets to symphonyDrupal 8 meets to symphony
Drupal 8 meets to symphony
 
Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
 
Having Fun Building Web Applications (Day 2 slides)
Having Fun Building Web Applications (Day 2 slides)Having Fun Building Web Applications (Day 2 slides)
Having Fun Building Web Applications (Day 2 slides)
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
 
WordPress Structure and Best Practices
WordPress Structure and Best PracticesWordPress Structure and Best Practices
WordPress Structure and Best Practices
 
WordPress plugin #1
WordPress plugin #1WordPress plugin #1
WordPress plugin #1
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsPython RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutions
 
Php
PhpPhp
Php
 

Recently uploaded

SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Buds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in NoidaBuds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in Noidabntitsolutionsrishis
 

Recently uploaded (20)

SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Buds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in NoidaBuds n Tech IT Solutions: Top-Notch Web Services in Noida
Buds n Tech IT Solutions: Top-Notch Web Services in Noida
 

Why you shouldn’t edit silver stripe core files (and how to do it anyway)