SlideShare une entreprise Scribd logo
1  sur  103
Télécharger pour lire hors ligne
1/103
Me
Nikita Shilnikov
• github.com/flash-gordon
2/103
Me
Nikita Shilnikov
• github.com/flash-gordon
3/103
Me
Nikita Shilnikov
• github.com/flash-gordon
• dry-rb and rom-rb core team member
4/103
DI in Ruby
5/103
What, why, how
6/103
What?
7/103
Inversion of Control
8/103
Event-based programming
(JavaScript)
9/103
Dependency Injection
10/103
class CreateUser
def call(name)
user_repo.create(name: name)
end
end
11/103
class CreateUser
def call(name)
user_repo.create(name: name)
end
end
12/103
undefined local variable or method user_repo
13/103
undefined local variable or method user_repo
14/103
Local variable
def call(user_repo, name)
user_repo.create(name: name)
end
15/103
Method
def user_repo
# dependency resolution
end
def call(name)
user_repo.create(name: name)
end
16/103
Constant (or singleton)
def user_repo
UserRepo.new
end
17/103
Constant
Pros:
• Dumb simple
• Easy to follow
• You don't need a method
Cons:
• High coupling
• Hard to test (?)
• Less extendable
18/103
Method
attr_accessor :user_repo
def initialize(user_repo)
@user_repo = user_repo
end
19/103
Method
let(:fake_repo) { FakeRepo.new }
let(:create_user) { CreateUser.new(fake_repo) }
example do
create_user.(name: 'Jade')
end
20/103
Why?
21/103
22/103
S O L I D
23/103
Dependency
Inversion Principle
24/103
Dependency Inversion Principle
A. High-level modules should not depend on low-level
modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should
depend on abstractions.
25/103
26/103
Think about
interfaces
27/103
Think about interfaces
• External services (network)
• Message queues
• Background jobs
28/103
Harder to write, easier to use and
support
29/103
Not harder in Ruby
30/103
How?
31/103
class CreateUser
attr_reader :user_repo
def initialize(user_repo)
@user_repo = user_repo
end
end
32/103
Container
Container = { user_repo: UserRepo.new }
def initialize(user_repo = nil)
@user_repo = user_repo || Container[:user_repo]
end
33/103
create_user = CreateUser.new(UserRepo.new)
34/103
create_user = CreateUser.new(UserRepo.new)
create_user = CreateUser.new
35/103
create_user = CreateUser.new(UserRepo.new)
create_user = CreateUser.new
create_user = CreateUser.new(FakeRepo.new)
36/103
create_user = CreateUser.new(UserRepo.new)
create_user = CreateUser.new
create_user = CreateUser.new(FakeRepo.new)
before { Container[:user_repo] = FakeRepo.new }
let(:create_user) { CreateUser.new }
example { create_user.(name: 'Jade') }
37/103
Loading order problem
38/103
Loading order
Container = {
user_repo: UserRepo.new,
create_user: CreateUser.new(?)
}
39/103
Loading order
Conainter = {
user_repo: -> { UserRepo.new },
create_user: -> { CreateUser.new }
}
40/103
Loading order
Conainter = {
user_repo: -> { UserRepo.new },
create_user: -> { CreateUser.new }
}
user = Container[:create_user].call.call(name: 'Jade')
41/103
dry-container
42/103
dry-container
Container = Dry::Container.new
Container.register(:user_repo) { UserRepo.new }
Container.register(:create_user) { CreateUser.new }
43/103
dry-container
Container[:create_user]
44/103
dry-container
Container[:create_user]
CreateUser.new
45/103
dry-container
Container[:create_user]
CreateUser.new
Container[:user_repo]
UserRepo.new
46/103
dry-container
Container[:create_user]
CreateUser.new
Container[:user_repo]
UserRepo.new
47/103
dry-container
Dir['repositories/*.rb'].each do |path|
key = path.sub('repositories/', '').sub('.rb', '')
class_name = Inflecto.camelize(key)
Container.register(key) do
require path
Inflecto.contantize(class_name).new
end
end
48/103
dry-container
Dir['repositories/*.rb'].each do |path|
key = path.sub('repositories/', '').sub('.rb', '')
class_name = Inflecto.camelize(key)
Container.register(key) do
require path
Inflecto.contantize(class_name).new
end
end
49/103
dry-container
Dir['repositories/*.rb'].each do |path|
key = path.sub('repositories/', '').sub('.rb', '')
class_name = Inflecto.camelize(key)
Container.register(key) do
require path
Inflecto.contantize(class_name).new
end
end
50/103
dry-container
Container.enable_stubs!
around do |ex|
Container.stub(:user_repo, FakeRepo.new) { ex.run }
end
51/103
dry-container
Container.register('user_repo', memoize: true) {
UserRepo.new
}
52/103
class CreateUser
attr_reader :user_repo, :user_created_worker
def initialize(user_repo: Container[:user_repo], user_created_worker: Container[:user_created_worker])
@user_repo = user_repo
@user_created_worker = user_created_worker
end
end
53/103
Boilerplate!
54/103
dry-auto_inject
55/103
• Needs a container
• Creates a constructor
56/103
dry-auto_inject
Import = Dry::AutoInject(Container)
57/103
dry-auto_inject
class CreateUserWithAccount
include Import['repo.user_repo', 'workers.user_created']
def call(name)
user = user_repo.create(name: name)
user_created.(user.user_id)
user
end
end
58/103
dry-auto_inject
class CreateUserWithAccount
include Import['repo.user_repo', 'workers.user_created']
def call(name)
user = user_repo.create(name: name)
user_created.(user.user_id)
user
end
end
59/103
dry-auto_inject
Plays nice with inheritance
60/103
dry-auto_inject
Compatible with existing constructors
61/103
dry-auto_inject
class CreateUserFromParams
attr_reader :params
def initialize(params)
@param = params
end
def create
UserRepo.new.create(params)
end
end
62/103
dry-auto_inject
class CreateUserFromParams
include Import['user_repo']
attr_reader :params
def initialize(params, **other)
super(other)
@param = params
end
end
63/103
Cost
• One line with explicitly defined dependencies
64/103
Benefits
• You don't need to think about building objects
• All code is built on the same principles
• It's far easier to write testable code
• You, most likely, will write functional-ish code
• Speeds up tests in a natural way
65/103
What if?
66/103
dry-system
67/103
dry-system
Container + injector + loading mechanism
68/103
dry-system
• Extends $LOAD_PATH
• Uses require to load files
• Registers dependencies automatically
• Builds dependencies using name conventions
• Can split an application into sub-apps
69/103
dry-system
class Application < Dry::System::Container
configure do |config|
config.root = Pathname('./app')
end
end
70/103
dry-system
class Application < Dry::System::Container
configure do |config|
config.root = Pathname('./app')
config.auto_register = 'lib'
end
load_paths!('lib')
end
71/103
dry-system
Application.register('utils.logger', Logger.new($stdout))
Application.finalize!
Application['utils.logger']
72/103
dry-system
Import = Application.injector
class CreateUser
include Import['repos.user_repo', 'utils.logger']
def call(name)
# ...
end
end
73/103
Stateful components
Application.finalize(:persistence) do |container|
start do
require 'sequel'
conn = Sequel.connect(ENV['DB_URL'])
container.register('persistence.db', conn)
end
stop do
db.disconnect
end
end
74/103
Stateful components
before(:all) do
Application.start(:persistence)
end
75/103
dry-system
• May not play nice with Rails (but who knows)
• Good for new projects
76/103
Future
• Instrumenting code
• Debugging tools
77/103
Application graph
78/103
Application graph
79/103
Application graph
• web.services.create_user [640ms]
• user_repo.create [10ms]
• web.view.user_created [215ms]
• external.billing.create_user [278ms]
80/103
Bonus
81/103
Singleton container
Import = Dry::AutoInject(Container)
class CreateUser
include Import['repo.user_repo']
end
82/103
Sharing the context
logger = TaggedLogger.new(env['X-Request-ID'])
83/103
Sharing the context
Application.finalize!
logger = TaggedLogger.new(env['X-Request-ID'])
Application.register('logger', logger) # => Error
84/103
Sharing the context
Application.register_abstract('logger')
Application.finalize!
85/103
Sharing the context
Application.register_abstract('logger')
Application.finalize!
logger = TaggedLogger.new(env['X-Request-ID'])
AppWithLogger = Application.provide(logger: logger)
86/103
Sharing the context
AppWithLogger[:create_user] # => #<CreateUser logger=#<Logger>>
87/103
Sharing the context
Import = Dry::AutoInject(Application)
class CreateUser
include Import['logger']
end
88/103
Passing the container as a dependency
Container.register('create_user') {
CreateUser.new
}
89/103
Passing the container as a dependency
Container.register('create_user') { |app_with_logger|
CreateUser.new(container: app_with_logger)
}
90/103
Zero global state
(literally)
91/103
92/103
Cons:
• Can't be memoized
• Can violate boundaries
93/103
Cons:
• Can't be memoized
• Can violate boundaries
Pros:
94/103
Cons:
• Can't be memoized
• Can violate boundaries
Pros:
• Reduces code duplcation
95/103
Cons:
• Can't be memoized
• Can violate boundaries
Pros:
• Reduces code duplcation
• Simplifies context sharing
96/103
Cons:
• Can't be memoized
• Can violate boundaries
Pros:
• Reduces code duplcation (no need to pass arguments)
• Simplifies context sharing
• Kills global state
97/103
Recap
98/103
Recap
• DI is a way to implement the dependency inversion
principle
• This makes your code easier to test and write
• Can break an application into sub-apps
• Can remove the global state as a whole (100% FP)
• Can be done in Ruby in one evening
• Doesn't have any major disadvantages *
99/103
DI 101
• Replace hard dependencies with interfaces (plain Ruby)
• Put dependencies into a container (dry-container)
• Inject dependencies automatically (dry-auto_inject)
• Organize application code in modules (dry-system)
100/103
Caveats
• Don't put every single thing into a container
• Make dependencies pure (aka thread-safe)
• Keep interfaces simple
• Injecting a dozen of deps at once is bad, m'kay?
• Fear new abstractions
101/103
Try it!
102/103
Thank you
• github.com/flash-gordon
• dry-rb.org
• dry-rb/dry-container
• dry-rb/dry-auto_inject
• dry-rb/dry-system
• dry-rb/dry-web-blog
103/103

Contenu connexe

Tendances

Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting BasicsDr.Ravi
 
2-introduction_to_shell_scripting
2-introduction_to_shell_scripting2-introduction_to_shell_scripting
2-introduction_to_shell_scriptingerbipulkumar
 
Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting BasicsSudharsan S
 
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...Zyxware Technologies
 
Easiest way to start with Shell scripting
Easiest way to start with Shell scriptingEasiest way to start with Shell scripting
Easiest way to start with Shell scriptingAkshay Siwal
 
OpenGurukul : Language : Shell Scripting
OpenGurukul : Language : Shell ScriptingOpenGurukul : Language : Shell Scripting
OpenGurukul : Language : Shell ScriptingOpen Gurukul
 
Unix shell scripting basics
Unix shell scripting basicsUnix shell scripting basics
Unix shell scripting basicsManav Prasad
 
Linux Shell Scripting
Linux Shell ScriptingLinux Shell Scripting
Linux Shell ScriptingRaghu nath
 
Inheritance compiler support
Inheritance compiler supportInheritance compiler support
Inheritance compiler supportSyed Zaid Irshad
 
Perl one-liners
Perl one-linersPerl one-liners
Perl one-linersdaoswald
 
Quize on scripting shell
Quize on scripting shellQuize on scripting shell
Quize on scripting shelllebse123
 
Introduction to shell scripting
Introduction to shell scriptingIntroduction to shell scripting
Introduction to shell scriptingCorrado Santoro
 

Tendances (20)

Unix shell scripts
Unix shell scriptsUnix shell scripts
Unix shell scripts
 
03 tk2123 - pemrograman shell-2
03   tk2123 - pemrograman shell-203   tk2123 - pemrograman shell-2
03 tk2123 - pemrograman shell-2
 
Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting Basics
 
2-introduction_to_shell_scripting
2-introduction_to_shell_scripting2-introduction_to_shell_scripting
2-introduction_to_shell_scripting
 
Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting Basics
 
Unix shell scripting
Unix shell scriptingUnix shell scripting
Unix shell scripting
 
Shell scripting
Shell scriptingShell scripting
Shell scripting
 
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...
Introduction to Bash Scripting, Zyxware Technologies, CSI Students Convention...
 
Easiest way to start with Shell scripting
Easiest way to start with Shell scriptingEasiest way to start with Shell scripting
Easiest way to start with Shell scripting
 
Ruby 1.9
Ruby 1.9Ruby 1.9
Ruby 1.9
 
OpenGurukul : Language : Shell Scripting
OpenGurukul : Language : Shell ScriptingOpenGurukul : Language : Shell Scripting
OpenGurukul : Language : Shell Scripting
 
Unix shell scripting basics
Unix shell scripting basicsUnix shell scripting basics
Unix shell scripting basics
 
Linux Shell Scripting
Linux Shell ScriptingLinux Shell Scripting
Linux Shell Scripting
 
Slides
SlidesSlides
Slides
 
PHP Tips & Tricks
PHP Tips & TricksPHP Tips & Tricks
PHP Tips & Tricks
 
Inheritance compiler support
Inheritance compiler supportInheritance compiler support
Inheritance compiler support
 
Perl one-liners
Perl one-linersPerl one-liners
Perl one-liners
 
Shell Script
Shell ScriptShell Script
Shell Script
 
Quize on scripting shell
Quize on scripting shellQuize on scripting shell
Quize on scripting shell
 
Introduction to shell scripting
Introduction to shell scriptingIntroduction to shell scripting
Introduction to shell scripting
 

Similaire à DIY DI in Ruby

Codeigniter4の比較と検証
Codeigniter4の比較と検証Codeigniter4の比較と検証
Codeigniter4の比較と検証ME iBotch
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java DevelopersYakov Fain
 
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the b
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the bfinalprojtemplatev5finalprojtemplate.gitignore# Ignore the b
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the bChereCheek752
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitsmueller_sandsmedia
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]Raul Fraile
 
Migrating to Openshift - Reyhan Fabianto
Migrating to Openshift - Reyhan FabiantoMigrating to Openshift - Reyhan Fabianto
Migrating to Openshift - Reyhan FabiantoDevOpsDaysJKT
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
GLRB - Decent exposure
GLRB - Decent exposureGLRB - Decent exposure
GLRB - Decent exposureMatt Yoho
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Building communication platforms for the IoT
Building communication platforms for the IoTBuilding communication platforms for the IoT
Building communication platforms for the IoTTroels Brødsgaard
 
Beyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with PuppetBeyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with Puppetlutter
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Julien Truffaut
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On RailsJohn Wilker
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Ralf Eggert
 

Similaire à DIY DI in Ruby (20)

Ruby meetup-dry
Ruby meetup-dryRuby meetup-dry
Ruby meetup-dry
 
Codeigniter4の比較と検証
Codeigniter4の比較と検証Codeigniter4の比較と検証
Codeigniter4の比較と検証
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
 
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the b
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the bfinalprojtemplatev5finalprojtemplate.gitignore# Ignore the b
finalprojtemplatev5finalprojtemplate.gitignore# Ignore the b
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
Vagrant for real
Vagrant for realVagrant for real
Vagrant for real
 
Migrating to Openshift - Reyhan Fabianto
Migrating to Openshift - Reyhan FabiantoMigrating to Openshift - Reyhan Fabianto
Migrating to Openshift - Reyhan Fabianto
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
GLRB - Decent exposure
GLRB - Decent exposureGLRB - Decent exposure
GLRB - Decent exposure
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Building communication platforms for the IoT
Building communication platforms for the IoTBuilding communication platforms for the IoT
Building communication platforms for the IoT
 
Beyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with PuppetBeyond Golden Containers: Complementing Docker with Puppet
Beyond Golden Containers: Complementing Docker with Puppet
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!Implicit parameters, when to use them (or not)!
Implicit parameters, when to use them (or not)!
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
 

Dernier

Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....ShaimaaMohamedGalal
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 

Dernier (20)

Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 

DIY DI in Ruby