SlideShare a Scribd company logo
1 of 69
Reactive Model-View-ViewModel
모바일 응용프로그램 아키텍쳐
이규원
https://www.facebook.com/gyuwon.yi
@styletigger
MVVM
Model-View-ViewModel
MVVM(Model-View-ViewModel)
• In 2005, John Gossman(Microsoft)
• Separation of Presentation and Presentation Logic
• Two-way Binding
• Properties and Commands
• Testability
• WPF, Silverlight, Xamarin Forms, AngularJS, EmberJS, KnockoutJS, RoboBinding
• Introduction to Model/View/ViewModel pattern for building WPF apps
• WPF Apps With The Model-View-ViewModel Design Pattern
ViewModel
Presentation Logic
View
User Interface
Model
Business Logic and
Data
2-way Binding
MVVM 응용프로그램
ViewModel
Presentation Logic
View
User Interface
API
Service
2-way Binding
Model
Server Client
서비스 클라이언트 응용프로그램
상태 동기화
State Synchronization
Showcase …
Showcase 15
no envy
Showcase …
…
… …
Showcase 15
no envy
Profile
Showcase 15
no envy
Showcase …
…
New Feed Explore Notifications
단일 컨텐트에 대한 다중 뷰
Showcase …
Showcase 15
1 envy
Showcase …
…
… …
Showcase 15
1 envy
New Feed Explore Notifications
Profile
Showcase 15
1 envy
Showcase …
…
뷰 상태 동기화
동기화 흐름
Flow of Synchronization
Showcase …
Showcase 15
1 envy
Showcase …
…
… …
Showcase 15
1 envy
New Feed Explore Notifications
Profile
Showcase 15
1 envy
Showcase …
…
뷰모델 사이의 데이터 흐름
VM
VM VM
VM VM
VM
뷰모델 사이의 데이터 흐름
ViewModelRepository
One-way
Push
Publish
One-way
단방향 데이터 흐름
Scale
Complexity
상태 동기화 복잡도
불변 모델 개체
Immutable Model Objects
ShowcaseViewModel
IsEnvied: bool
EnvyCount: int
뷰모델 속성을 통한 데이터 노출
<Button BackgroundColor="{Binding IsEnvied, Converter={...}}" />
<Label Text="{Binding EnvyCount, StringFormat='...'}" />
뷰모델 속성 바인딩
IsEnvied EnvyCount PropertyChanged Validity
False 0 Valid
True 0 "IsEnvied" Invalid
True 1 "EnvyCount" Valid
뷰모델 속성 상태 변경
뷰에 바인딩된 속성에 대한 PropertyChanged 이벤트는
레이아웃 계산과 그리기 작업을 촉발한다
모델 속성을 통한 데이터 노출
ShowcaseViewModel ShowcaseModel
IsEnvied: bool
EnvyCount: int
Model
<Button BackgroundColor="{Binding Model.IsEnvied, Converter={...}}" />
<Label Text="{Binding Model.EnvyCount, StringFormat='...'}" />
모델 속성 바인딩
Model PropertyChanged Validity
{ IsEnvied: False, EnvyCount: 0 } Valid
{ IsEnvied: True, EnvyCount: 1 } "Model" Valid
모델 상태 변경
단, 모델 개체는 불변성을 가져야한다
Immutable Objects
• Cannot be modified after initialization
• Thread-safe
• Readability
• Runtime efficiency
• Functional programming
모델 속성을 통한 데이터 노출
ShowcaseViewModel ShowcaseModel
<< immutable >>
IsEnvied: bool
EnvyCount: int
Model
불변 모델 반응형 스트림
Reactive Streams of Immutable Model Objects
데이터 흐름
• 컨텐트 상태는 불변성을 가지는 모델 개체로 캡슐화
• 뷰모델은 모델 개체를 속성으로 뷰에 노출
• 컨텐트 상태가 변경되면 새로운 모델 인스턴스 발행
‘불변성을 가진 모델 개체의 반응형 스트림’
…
Model
Revision n + 2
Model
Revision n + 1
Model
Revision n
…
스트림 저장소
Rx(Reactive Extensions)
• Observables + LINQ + Schedulers
• Asynchronous and event-based programming
• C#, JavaScript, C, C++, Ruby, Python, Java
• Microsoft Open Tech(*RxJava by Netflix)
• https://rx.codeplex.com/
반응형 스트림
public interface IObservable<out T>
{
IDisposable Subscribe(IObserver<T> observer);
}
public interface IObserver<in T>
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}
모델
public abstract class Model<TModel, TId>
where TModel : Model<TModel, TId>
where TId : IEquatable<TId>
{
private readonly TId _id;
public TId Id { get { return _id; } }
protected Model(TId id)
{
_id = id;
}
}
모델
public sealed class ShowcaseModel : Model<ShowcaseModel, long>
{
private readonly bool _isEnvied;
private readonly int _envyCount;
public ShowcaseModel(long id, bool isEnvied, int envyCount) : base(id)
{
_isEnvied = isEnvied;
_envyCount = envyCount;
}
public bool IsEnvied { get { return _isEnvied; } }
public int EnvyCount { get { return _envyCount; } }
}
스트림 저장소
public static class StreamStore<TModel, TId>
where TModel : Model<TModel, TId>
where TId: IEquatable<TId>
{
public static IObservable<TModel> GetStream(TId id);
public static void Push(TModel model);
}
모델-뷰모델
public abstract class ModelViewModel<TModel, TId> : ViewModel
{
private TModel _model = null;
public TModel Model
{
get { return _model;}
set { SetProperty(ref _model, value); }
}
protected virtual void OnNext(TModel next)
{
Model = next;
}
}
스트림 구독
Stream Subscription
약한 스트림 구독
ModelViewModel
Observer WeakSubscription
Stream
Reference
Weak Reference
약한 스트림 구독
public abstract class ModelViewModel<TModel, TId> : ViewModel
{
private readonly TId _id;
private readonly IObserver<TModel> _observer;
private readonly IDisposable _subscription;
protected ModelViewModel(TId id)
{
_id = id;
var stream = StreamStore<TModel, TId>.GetStream(id);
_observer = Observer.Create<TModel>(onNext: OnNext);
_subscription = new WeakSubscription<TModel>(stream, _observer);
}
~ModelViewModel() { _subscription.Dispose(); }
}
스위치 연산자
Switch Operator
비동기 데이터 조회
• 응용프로그램 반응성 향상
• Futures Pattern
중복된 비동기 데이터 조회
• 불필요한 무효화(invalidation)
• 시작과 종료 순서의 불일치
Switch()
“Transforms an observable
sequence of observable sequences
into an observable sequence
producing values only from the
most recent observable sequence.”
- from MSDN
스위치
스위치
public abstract class ModelViewModel<TModel, TId> : ViewModel
{
private readonly Subject<IObservable<TModel>> _spout = new Subject<IObservable<TModel>>();
protected ModelViewModel(TId id)
{
_spout.Switch()
.Subscribe(next => StreamStore<TModel, TId>.Push(next));
}
protected virtual void Push(IObservable<TModel> next)
{
_spout.OnNext(next);
}
}
Task to Observable
public abstract class ModelViewModel<TModel, TId> : ViewModel
{
protected void Push(Task<TModel> next)
{
Push(next.ToObservable());
}
protected void Push(Func<Task<TModel>> next)
{
Push(next.Invoke().ToObservable());
}
}
Model to Observable
public abstract class ModelViewModel<TModel, TId> : ViewModel
{
protected void Push(TModel next)
{
Push(Task.FromResult(next).ToObservable());
}
}
병합 연산자
Coalescing Operator
UserModel
Id : "user1"
UserName
ProfilePhotoUri
UserModel
Id: "user1"
UserName
ProfilePhotoUri
FolloweeCount
FollowerCount
Followees: 10
Followers: 24
목록 조회와 상세 정보 조회
데이터 유실
UserModel
Id : "user1"
UserName
ProfilePhotoUri
UserModel
Id: "user1"
UserName
ProfilePhotoUri
FolloweeCount
FollowerCount
Followees: 10
Followers: 24
UserModel
Id: "user1"
UserName
ProfilePhotoUri
FolloweeCount
FollowerCount
Followees: 10
Followers: 24
Push User Detail Page Push User List Page Pop
Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount
Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount
Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount
Coalesce
=
병합 연산
병합 연산
public static class ModelExtensions
{
public static UserModel Coalesce(this UserModel user, UserModel other)
{
if (user == null) throw new ArgumentNullException("user");
if (other == null) return user;
if (other.Id != user.Id) throw new ArgumentException();
if (user.Equals(other)) return user;
return new UserModel(user.Id,
user.UserName,
user.ProfilePhotoUri,
user.FolloweeCount ?? other.FolloweeCount,
user.FollowerCount ?? other.FollowerCount);
}
}
병합 연산
public class UserViewModel : ModelViewModel<UserModel, string>
{
protected override void OnNext(UserModel next)
{
var current = Model;
base.OnNext(next.Coalesce(current));
}
}
같음 확인
Equality Comparisons
뷰모델 속성 설정
public class ViewModel : INotifyPropertyChanged
{
protected bool SetProperty<T>(ref T field,
T value,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
NotifyPropertyChanged(propertyName);
return true;
}
}
Changed!Changed…?
Showcase
Id: 15
IsEnvied: true
EnvyCount: 10
Showcase
Id: 15
IsEnvied: true
EnvyCount: 10
Showcase
Id: 15
IsEnvied: false
EnvyCount: 9
Changed…?
개체 참조 비교
같음 확인 논리
public sealed class ShowcaseModel : Model<ShowcaseModel, long>, IEquatable<ShowcaseModel>
{
public bool Equals(ShowcaseModel other)
{
if (other == null)
return false;
if (object.ReferenceEquals(this, other))
return true;
return Id == other.Id &&
_isEnvied == other._isEnvied &&
_envyCount == other._envyCount;
}
}
Changed!Changed…?
Showcase
Id: 15
IsEnvied: true
EnvyCount: 10
Showcase
Id: 15
IsEnvied: true
EnvyCount: 10
Showcase
Id: 15
IsEnvied: false
EnvyCount: 9
Not
Changed
모델 데이터 비교
정리
Reactive MVVM Architecture
• 단방향 데이터 흐름
• 불변 모델
• 반응형 스트림
• 약한 스트림 구독
• 스위치 연산
• 병합 연산
• 같음 확인
Reactive MVVM Architecture
ViewModel Model
<< 1-way binding >>
Model
<< push >>
Coalescing
Equality
Comparison
Stream Store
Switch
Weak
Subscription
View
Commands,
Entry Fields
and UI States
Model
<< publish >>
Reactive MVVM 아키텍쳐를
적용한 안드로이드 앱을
함께 개발하실 멋쟁이
프로그래머느님을
애타게 찾고 있습니다.
public async Task<IEnvicase> CreateAndroidAsync()
{
var team = await JoinUsAsync(new You());
return team.CreateAndroidApp();
}
https://www.facebook.com/gyuwon.yi
@styletigger
gyuwon@tidcorp.com
감사합니다

More Related Content

What's hot

Use Eclipse technologies to build a modern embedded IDE
Use Eclipse technologies to build a modern embedded IDEUse Eclipse technologies to build a modern embedded IDE
Use Eclipse technologies to build a modern embedded IDE
Benjamin Cabé
 

What's hot (20)

Devoxx 2012 (v2)
Devoxx 2012 (v2)Devoxx 2012 (v2)
Devoxx 2012 (v2)
 
Effective JavaFX architecture with FxObjects
Effective JavaFX architecture with FxObjectsEffective JavaFX architecture with FxObjects
Effective JavaFX architecture with FxObjects
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern
 
Building scalable applications with angular js
Building scalable applications with angular jsBuilding scalable applications with angular js
Building scalable applications with angular js
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CN
 
ExtJs Basic Part-1
ExtJs Basic Part-1ExtJs Basic Part-1
ExtJs Basic Part-1
 
Cocoa Design Patterns
Cocoa Design PatternsCocoa Design Patterns
Cocoa Design Patterns
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module Patterns
 
The Case for React.js and ClojureScript
The Case for React.js and ClojureScriptThe Case for React.js and ClojureScript
The Case for React.js and ClojureScript
 
Reverse Engineering 안드로이드 학습
Reverse Engineering 안드로이드 학습Reverse Engineering 안드로이드 학습
Reverse Engineering 안드로이드 학습
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Android development with Scala and SBT
Android development with Scala and SBTAndroid development with Scala and SBT
Android development with Scala and SBT
 
How AngularJS Embraced Traditional Design Patterns
How AngularJS Embraced Traditional Design PatternsHow AngularJS Embraced Traditional Design Patterns
How AngularJS Embraced Traditional Design Patterns
 
Use Eclipse technologies to build a modern embedded IDE
Use Eclipse technologies to build a modern embedded IDEUse Eclipse technologies to build a modern embedded IDE
Use Eclipse technologies to build a modern embedded IDE
 
Speed up your GWT coding with gQuery
Speed up your GWT coding with gQuerySpeed up your GWT coding with gQuery
Speed up your GWT coding with gQuery
 
JavaScript 101
JavaScript 101JavaScript 101
JavaScript 101
 
Best Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIBest Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part III
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS Meetup
 
Javascript Common Design Patterns
Javascript Common Design PatternsJavascript Common Design Patterns
Javascript Common Design Patterns
 

Similar to Reactive Model-View-ViewModel Architecture

Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 

Similar to Reactive Model-View-ViewModel Architecture (20)

Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...
Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...
Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019
 
MV* presentation frameworks in Javascript: en garde, pret, allez!
MV* presentation frameworks in Javascript: en garde, pret, allez!MV* presentation frameworks in Javascript: en garde, pret, allez!
MV* presentation frameworks in Javascript: en garde, pret, allez!
 
My perspective on MVP and architecture discussions
My perspective on MVP and architecture discussionsMy perspective on MVP and architecture discussions
My perspective on MVP and architecture discussions
 
Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.
 
Android development
Android developmentAndroid development
Android development
 
Moderne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJavaModerne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJava
 
Jeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend TitaniumJeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend Titanium
 
MVVM Design Pattern NDC2009
MVVM Design Pattern NDC2009MVVM Design Pattern NDC2009
MVVM Design Pattern NDC2009
 
Angular.js is super cool
Angular.js is super coolAngular.js is super cool
Angular.js is super cool
 
MVVM Lights
MVVM LightsMVVM Lights
MVVM Lights
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
 
Fundaments of Knockout js
Fundaments of Knockout jsFundaments of Knockout js
Fundaments of Knockout js
 
Developing maintainable Cordova applications
Developing maintainable Cordova applicationsDeveloping maintainable Cordova applications
Developing maintainable Cordova applications
 
Adopting Swift Generics
Adopting Swift GenericsAdopting Swift Generics
Adopting Swift Generics
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
Migrating an Application from Angular 1 to Angular 2
Migrating an Application from Angular 1 to Angular 2 Migrating an Application from Angular 1 to Angular 2
Migrating an Application from Angular 1 to Angular 2
 
Spring Web MVC
Spring Web MVCSpring Web MVC
Spring Web MVC
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture Components
 

More from Gyuwon Yi

More from Gyuwon Yi (11)

Event sourcing spring camp 2017.public
Event sourcing spring camp 2017.publicEvent sourcing spring camp 2017.public
Event sourcing spring camp 2017.public
 
Why you always fail with tdd
Why you always fail with tddWhy you always fail with tdd
Why you always fail with tdd
 
CQRS - Show me the code
CQRS - Show me the codeCQRS - Show me the code
CQRS - Show me the code
 
CQRS
CQRSCQRS
CQRS
 
프로그래밍, 설계 그리고 패턴
프로그래밍, 설계 그리고 패턴프로그래밍, 설계 그리고 패턴
프로그래밍, 설계 그리고 패턴
 
VSTS와 Azure를 이용한 팀 프로세스 관리
VSTS와 Azure를 이용한 팀 프로세스 관리VSTS와 Azure를 이용한 팀 프로세스 관리
VSTS와 Azure를 이용한 팀 프로세스 관리
 
Azure를 이용한 Join 없는 글로벌 분산 시스템 설계하기
Azure를 이용한 Join 없는 글로벌 분산 시스템 설계하기Azure를 이용한 Join 없는 글로벌 분산 시스템 설계하기
Azure를 이용한 Join 없는 글로벌 분산 시스템 설계하기
 
Unit testing
Unit testingUnit testing
Unit testing
 
Xamarin Forms, MVVM and Testing
Xamarin Forms, MVVM and TestingXamarin Forms, MVVM and Testing
Xamarin Forms, MVVM and Testing
 
Introduction to IoC Container
Introduction to IoC ContainerIntroduction to IoC Container
Introduction to IoC Container
 
Introduction to TPL
Introduction to TPLIntroduction to TPL
Introduction to TPL
 

Recently uploaded

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
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
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Recently uploaded (20)

LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
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 🔝✔️✔️
 
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
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
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
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
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
 
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
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
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
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 

Reactive Model-View-ViewModel Architecture