SlideShare uma empresa Scribd logo
1 de 100
Baixar para ler offline
ScalaBlitz 
Efficient Collections Framework
What’s a Blitz?
Blitz-chess is a style of 
rapid chess play.
Blitz-chess is a style of 
rapid chess play.
Knights have horses.
Horses run fast.
def mean(xs: Array[Float]): Float = 
xs.par.reduce(_ + _) / xs.length
With Lists, operations 
can only be executed 
from left to right
1 2 4 8
1 2 4 8 
Not your typical list.
Bon app.
Apparently not enough
No amount of 
documentation is 
apparently enough
The reduceLeft 
guarantees operations are 
executed from left to right
Parallel and sequential 
collections sharing operations
There are several 
problems here
How we see users
How users 
see the docs
Bending the truth.
And sometimes we 
were just slow
So, we have a new API now 
def findDoe(names: Array[String]): Option[String] = 
{ 
names.toPar.find(_.endsWith(“Doe”)) 
}
Wait, you renamed a 
method? 
def findDoe(names: Array[String]): Option[String] = 
{ 
names.toPar.find(_.endsWith(“Doe”)) 
}
Yeah, par already exists. 
But, toPar is different. 
def findDoe(names: Array[String]): Option[String] = 
{ 
names.toPar.find(_.endsWith(“Doe”)) 
}
def findDoe(names: Array[String]): Option[String] = { 
names.toPar.find(_.endsWith(“Doe”)) 
} 
implicit class ParOps[Repr](val r: Repr) extends AnyVal { 
def toPar = new Par(r) 
}
def findDoe(names: Array[String]): Option[String] = { 
ParOps(names).toPar.find(_.endsWith(“Doe”)) 
} 
implicit class ParOps[Repr](val r: Repr) extends AnyVal { 
def toPar = new Par(r) 
}
def findDoe(names: Array[String]): Option[String] = { 
ParOps(names).toPar.find(_.endsWith(“Doe”)) 
} 
implicit class ParOps[Repr](val r: Repr) extends AnyVal { 
def toPar = new Par(r) 
} 
class Par[Repr](r: Repr)
def findDoe(names: Array[String]): Option[String] = { 
(new Par(names)).find(_.endsWith(“Doe”)) 
} 
implicit class ParOps[Repr](val r: Repr) extends AnyVal { 
def toPar = new Par(r) 
} 
class Par[Repr](r: Repr)
def findDoe(names: Array[String]): Option[String] = { 
(new Par(names)).find(_.endsWith(“Doe”)) 
} 
class Par[Repr](r: Repr) 
But, Par[Repr] does not 
have the find method!
def findDoe(names: Array[String]): Option[String] = { 
(new Par(names)).find(_.endsWith(“Doe”)) 
} 
class Par[Repr](r: Repr) 
True, but Par[Array[String]] 
does have a find method.
def findDoe(names: Array[String]): Option[String] = { 
(new Par(names)).find(_.endsWith(“Doe”)) 
} 
class Par[Repr](r: Repr) 
implicit class ParArrayOps[T](pa: Par[Array[T]]) { 
... 
def find(p: T => Boolean): Option[T] 
... 
}
More flexible!
More flexible! 
● does not have to implement methods that 
make no sense in parallel
More flexible! 
● does not have to implement methods that 
make no sense in parallel 
● slow conversions explicit
No standard library collections were 
hurt doing this.
More flexible! 
● does not have to implement methods that 
make no sense in parallel 
● slow conversions explicit 
● non-intrusive addition to standard library
More flexible! 
● does not have to implement methods that 
make no sense in parallel 
● slow conversions explicit 
● non-intrusive addition to standard library 
● easy to add new methods and collections
More flexible! 
● does not have to implement methods that 
make no sense in parallel 
● slow conversions explicit 
● non-intrusive addition to standard library 
● easy to add new methods and collections 
● import switches between implementations
def findDoe(names: Seq[String]): Option[String] = { 
names.toPar.find(_.endsWith(“Doe”)) 
}
def findDoe(names: Seq[String]): Option[String] = { 
names.toPar.find(_.endsWith(“Doe”)) 
}
def findDoe(names: Seq[String]): Option[String] = { 
names.toPar.find(_.endsWith(“Doe”)) 
} 
But how do I write generic code?
def findDoe[Repr[_]](names: Par[Repr[String]]) = { 
names.toPar.find(_.endsWith(“Doe”)) 
}
def findDoe[Repr[_]](names: Par[Repr[String]]) = { 
names.toPar.find(_.endsWith(“Doe”)) 
} 
Par[Repr[String]]does not 
have a find
def findDoe[Repr[_]: Ops](names: Par[Repr[String]]) = { 
names.toPar.find(_.endsWith(“Doe”)) 
}
def findDoe[Repr[_]: Ops](names: Par[Repr[String]]) = { 
names.toPar.find(_.endsWith(“Doe”)) 
} 
We don’t do this.
Make everything as simple as 
possible, but not simpler.
def findDoe(names: Reducable[String])= { 
names.find(_.endsWith(“Doe”)) 
}
def findDoe(names: Reducable[String])= { 
names.find(_.endsWith(“Doe”)) 
} 
findDoe(Array(1, 2, 3).toPar)
def findDoe(names: Reducable[String])= { 
names.find(_.endsWith(“Doe”)) 
} 
findDoe(toReducable(Array(1, 2, 3).toPar))
def findDoe(names: Reducable[String])= { 
names.find(_.endsWith(“Doe”)) 
} 
findDoe(toReducable(Array(1, 2, 3).toPar)) 
def arrayIsReducable[T]: IsReducable[T] = { … }
So let’s write a program!
import scala.collection.par._ 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
}
import scala.collection.par._ 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
val x = idx % wdt 
val y = idx / wdt 
}
import scala.collection.par._ 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
val x = idx % wdt 
val y = idx / wdt 
pixels(idx) = computeColor(x, y) 
}
import scala.collection.par._ 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
val x = idx % wdt 
val y = idx / wdt 
pixels(idx) = computeColor(x, y) 
} 
Scheduler not found!
import scala.collection.par._ 
import Scheduler.Implicits.global 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
val x = idx % wdt 
val y = idx / wdt 
pixels(idx) = computeColor(x, y) 
}
import scala.collection.par._ 
import Scheduler.Implicits.global 
val pixels = new Array[Int](wdt * hgt) 
for (idx <- (0 until (wdt * hgt)).toPar) { 
val x = idx % wdt 
val y = idx / wdt 
pixels(idx) = computeColor(x, y) 
}
New parallel collections 
33% faster! 
Now 
103 ms 
Previously 
148 ms
Workstealing tree scheduler 
rocks!
Workstealing tree scheduler 
rocks! 
But, are there other interesting 
workloads?
Fine-grained uniform 
workloads are on the opposite 
side of the spectrum.
def mean(xs: Array[Float]): Float = { 
val sum = xs.toPar.fold(0)(_ + _) 
sum / xs.length 
}
def mean(xs: Array[Float]): Float = { 
val sum = xs.toPar.fold(0)(_ + _) 
sum / xs.length 
} 
Now 
Previously 
15 ms 
565 ms
But how?
def fold[T](a: Iterable[T])(z:T)(op: (T, T) => T) = { 
var it = a.iterator 
var acc = z 
while (it.hasNext) { 
acc = op(acc, it.next) 
} 
acc 
}
def fold[T](a: Iterable[T])(z:T)(op: (T, T) => T) = { 
var it = a.iterator 
var acc = z 
while (it.hasNext) { 
acc = box(op(acc, it.next)) 
} 
acc 
}
def fold[T](a: Iterable[T])(z:T)(op: (T, T) => T) = { 
var it = a.iterator 
var acc = z 
while (it.hasNext) { 
acc = box(op(acc, it.next)) 
} 
acc 
} 
Generic methods cause boxing of primitives
def mean(xs: Array[Float]): Float = { 
val sum = xs.toPar.fold(0)(_ + _) 
sum / xs.length 
}
def mean(xs: Array[Float]): Float = { 
val sum = xs.toPar.fold(0)(_ + _) 
sum / xs.length 
} 
Generic methods hurt performance 
What can we do instead?
def mean(xs: Array[Float]): Float = { 
val sum = xs.toPar.fold(0)(_ + _) 
sum / xs.length 
} 
Generic methods hurt performance 
What can we do instead? 
Inline method body!
def mean(xs: Array[Float]): Float = { 
val sum = { 
var it = xs.iterator 
var acc = 0 
while (it.hasNext) { 
acc = acc + it.next 
} 
acc 
} 
sum / xs.length 
}
def mean(xs: Array[Float]): Float = { 
val sum = { 
var it = xs.iterator 
var acc = 0 
while (it.hasNext) { 
acc = acc + it.next 
} 
acc 
} 
sum / xs.length 
} 
Specific type 
No boxing! 
No memory allocation!
def mean(xs: Array[Float]): Float = { 
val sum = { 
var it = xs.iterator 
var acc = 0 
while (it.hasNext) { 
acc = acc + it.next 
} 
acc 
} 
sum / xs.length 
} 
Specific type 
No boxing! 
No memory allocation! 
565 ms → 281 ms 
2X speedup
def mean(xs: Array[Float]): Float = { 
val sum = { 
var it = xs.iterator 
var acc = 0 
while (it.hasNext) { 
acc = acc + it.next 
} 
acc 
} 
sum / xs.length 
}
def mean(xs: Array[Float]): Float = { 
val sum = { 
var it = xs.iterator 
var acc = 0 
while (it.hasNext) { 
acc = acc + it.next 
} 
acc 
} 
sum / xs.length 
} 
Iterators? For Array? 
We don’t need them!
def mean(xs: Array[Float]): Float = { 
val sum = { 
var i = 0 
val until = xs.size 
var acc = 0 
while (i < until) { 
acc = acc + a(i) 
i = i + 1 
} 
acc 
} 
sum / xs.length 
} 
Use index-based access!
def mean(xs: Array[Float]): Float = { 
val sum = { 
var i = 0 
val until = xs.size 
var acc = 0 
while (i < until) { 
acc = acc + a(i) 
i = i + 1 
} 
acc 
} 
sum / xs.length 
} 
Use index-based access! 
281 ms → 15 ms 
19x speedup
Are those optimizations parallel-collections specific?
Are those optimizations parallel-collections specific? 
No
Are those optimizations parallel-collections specific? 
No 
You can use them on sequential collections
def mean(xs: Array[Float]): Float = { 
val sum = xs.fold(0)(_ + _) 
sum / xs.length 
}
import scala.collections.optimizer._ 
def mean(xs: Array[Float]): Float = optimize{ 
val sum = xs.fold(0)(_ + _) 
sum / xs.length 
}
import scala.collections.optimizer._ 
def mean(xs: Array[Float]): Float = optimize{ 
val sum = xs.fold(0)(_ + _) 
sum / xs.length 
} 
You get 38 times speedup!
Future work
@specialized collections 
● Maps 
● Sets 
● Lists 
● Vectors 
Both faster & 
consuming less 
memory
@specialized collections 
● Maps 
● Sets 
● Lists 
● Vectors 
Both faster & 
consuming less 
memory 
Expect to get this for free inside 
optimize{} block
jdk8-style streams(parallel views) 
● Fast 
● Lightweight 
● Expressive API 
● Optimized 
Lazy data-parallel 
operations made 
easy
Future’s based asynchronous API 
val sum = future{ xs.sum } 
val normalized = sum.andThen(sum => sum/xs.size) 
Boilerplate code, ugly
Future’s based asynchronous API 
val sum = xs.toFuture.sum 
val scaled = xs.map(_ / sum) 
● Simple to use 
● Lightweight 
● Expressive API 
● Optimized 
Asynchronous data-parallel 
operations 
made easy
Current research: operation fusion 
val minMaleAge = people.filter(_.isMale) 
.map(_.age).min 
val minFemaleAge = people.filter(_.isFemale) 
.map(_.age).min
Current research: operation fusion 
val minMaleAge = people.filter(_.isMale) 
.map(_.age).min 
val minFemaleAge = people.filter(_.isFemale) 
.map(_.age).min 
● Requires up to 3 times more memory than original collection 
● Requires 6 traversals of collections
Current research: operation fusion 
val minMaleAge = people.filter(_.isMale) 
.map(_.age).min 
val minFemaleAge = people.filter(_.isFemale) 
.map(_.age).min 
● Requires up to 3 times more memory than original collection 
● Requires 6 traversals of collections 
We aim to reduce this to single traversal with no 
additional memory. 
Without you changing your code

Mais conteúdo relacionado

Mais procurados

JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
PROIDEA
 

Mais procurados (16)

A bit about Scala
A bit about ScalaA bit about Scala
A bit about Scala
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
JDD2015: Functional programing and Event Sourcing - a pair made in heaven - e...
 
Scala for Java Developers - Intro
Scala for Java Developers - IntroScala for Java Developers - Intro
Scala for Java Developers - Intro
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Switching from java to groovy
Switching from java to groovySwitching from java to groovy
Switching from java to groovy
 
20170509 rand db_lesugent
20170509 rand db_lesugent20170509 rand db_lesugent
20170509 rand db_lesugent
 
Kotlin standard
Kotlin standardKotlin standard
Kotlin standard
 
Scala collection
Scala collectionScala collection
Scala collection
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
P3 2017 python_regexes
P3 2017 python_regexesP3 2017 python_regexes
P3 2017 python_regexes
 
Coding in Style
Coding in StyleCoding in Style
Coding in Style
 
Scala - en bedre Java?
Scala - en bedre Java?Scala - en bedre Java?
Scala - en bedre Java?
 

Semelhante a ScalaBlitz

(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
Tomasz Wrobel
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
Mario Fusco
 

Semelhante a ScalaBlitz (20)

(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
 
Scala
ScalaScala
Scala
 
Meet scala
Meet scalaMeet scala
Meet scala
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Scala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereldScala: Functioneel programmeren in een object georiënteerde wereld
Scala: Functioneel programmeren in een object georiënteerde wereld
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
From Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksFrom Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risks
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Scala Refactoring for Fun and Profit
Scala Refactoring for Fun and ProfitScala Refactoring for Fun and Profit
Scala Refactoring for Fun and Profit
 
Functional programming with_scala
Functional programming with_scalaFunctional programming with_scala
Functional programming with_scala
 
Scala in Places API
Scala in Places APIScala in Places API
Scala in Places API
 
Monadologie
MonadologieMonadologie
Monadologie
 
Java Cheat Sheet
Java Cheat SheetJava Cheat Sheet
Java Cheat Sheet
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
 

Último

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
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Último (20)

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
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
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
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
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 🔝✔️✔️
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
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
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
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
 

ScalaBlitz