Download presentation
Presentation is loading. Please wait.
1
1 Lecture 09 – Synthesis of Synchronization Eran Yahav
2
Previously Predicate abstraction Abstraction refinement at a high level 2
3
Today Synthesis of Synchronization 3
4
Verification Challenge 4 P S ?
5
With abstraction 5 P S ?
6
Now what? 6 P S P ’ S abstraction refinement
7
Change the abstraction to match the program A Standard Approach: Abstraction Refinement program specification Abstract counter example abstraction Abstraction Refinement Abstract counter example Verify Valid 7
8
Alternatively… 8 P’ S program modification P S
9
program specification Abstract counter example abstraction Abstraction Refinement Change the program to match the abstraction Verify Abstraction-Guided Synthesis [VYY-POPL’10] Program Restriction Implement P’ Abstract counter example 9
10
Alternatively… 10 P S’ change specification (but to what?) P S
11
Focus on Program Modification Given a program P, specification S, and an abstraction such that P S find a modified program P’ such that P’ S how do you find such a program? very hard in general there is some hope when considering equivalent programs or restricted programs changing a program to add new legal behaviors is hard program restriction natural in concurrent programs reducing permitted schedules 11
12
Example int x, y, sign; x = ?; if (x<0) { sign = -1; } else { sign = 1; } y = x/sign; 12 Example from “The Trace Partitioning Abstract Domain” Rival&Mauborgne x [- , ], sign x [- , -1], sign [-1, -1] x [0, ], sign [1, 1] x [- , ], sign [-1, 1] Specification S: no division by zero. Abstract domain : intervals 0 [-1,1] division by zero seems possible P S
13
Now what? Can use a more refined abstract domain Disjunctive completion abstract value = set (disjunction) of intervals 13 int x, y, sign; x = ?; if (x<0) { sign = -1; } else { sign = 1; } y = x/sign; x {[- , ]}, sign x {[- , -1]}, sign {[-1, -1]} x {[0, ]}, sign {[1, 1]} x {[- , -1],[0, ]}, sign {[-1, -1],[1,1]} Specification S: no division by zero. Abstract domain ’: set of intervals 0 [-1, -1] and 0 [1,1] division by zero impossible P ’ S
14
Are we done? Exponential cost ! Can we do better? Idea: track relationship between x and sign 14 x < 0 sign = -1 x >= 0 sign = 1 Problem: again, expensive Which relationships should I track? Domains such as polyhedra won’t help (convex)
15
Trace partitioning abstract domain refine abstraction by adding some control history won’t get into that further reading Rival and Mauborgne. The trace partitioning abstract domain. TOPLAS’07. Holley and Rosen. Qualified data flow problems. POPL'80 15
16
We can also change the program 16 int x, y, sign; x = ?; if (x<0) { sign = -1; } else { sign = 1; } y = x/sign; int x, y, sign; x = ?; if (x<0) { sign = -1; y = x/sign; } else { sign = 1; y = x/sign; } PP’
17
Modified Program 17 int x, y, sign; x = ?; if (x<0) { sign = -1; y = x/sign; } else { sign = 1; y = x/sign; } x [- , ], sign x [- , -1], sign [-1, -1] x [0, ], sign [1, 1] x [- , ], sign [-1, 1] Specification S: no division by zero. Abstract domain : intervals 0 [-1, -1] division by zero impossible 0 [1, 1] division by zero impossible
18
Another Example 18 while(e) { s; } … if (e) { s; while(e) { s; } … PP’
19
Process 1Process 2Process 3 Shared memory concurrent program No synchronization: often incorrect (but “efficient”) Coarse-grained synchronization: easy to reason about, often inefficient Fine-grained synchronization: hard to reason about, programmer often gets this wrong Challenge: Correct and Efficient Synchronization 19
20
Process 1Process 2Process 3 Shared memory concurrent program No synchronization: often incorrect (but “efficient”) Coarse-grained synchronization: easy to reason about, often inefficient Fine-grained synchronization: hard to reason about, programmer often gets this wrong Challenge: Correct and Efficient Synchronization 20
21
Process 1Process 2Process 3 Shared memory concurrent program No synchronization: often incorrect (but “efficient”) Coarse-grained synchronization: easy to reason about, often inefficient Fine-grained synchronization: hard to reason about, programmer often gets this wrong Challenge: Correct and Efficient Synchronization 21
22
Challenge Process 1Process 2Process 3 How to synchronize processes to achieve correctness and efficiency? 22
23
Atomic sections Conditional critical region (CCR) Memory barriers (fences) CAS Semaphores Monitors Locks .... Synchronization Primitives 23
24
{ ……………… …… …………………. ……………………. ………………………… } P1() Example: Correct and Efficient Synchronization with Atomic Sections { …………………………… ……………………. … } P2() atomic { ………………….. …… ……………………. ……………… …………………… } P3() atomic Safety Specification: S 24
25
{ ……………… …… …………………. ……………………. ………………………… } P1() { …………………………… ……………………. … } P2() { ………………….. …… ……………………. ……………… …………………… } P3() Safety Specification: S Assist the programmer by automatically inferring correct and efficient synchronization Example: Correct and Efficient Synchronization with Atomic Sections 25
26
Challenge Find minimal synchronization that makes the program satisfy the specification Avoid all bad interleavings while permitting as many good interleavings as possible Assumption: we can prove that serial executions satisfy the specification Interested in bad behaviors due to concurrency Handle infinite-state programs 26
27
Abstraction-Guided Synthesis of Synchronization Synthesis of synchronization via abstract interpretation Compute over-approximation of all possible program executions Add minimal synchronization to avoid (over-approximation of) bad interleavings Interplay between abstraction and synchronization Finer abstraction may enable finer synchronization Coarse synchronization may enable coarser abstraction 27
28
program specification Abstract counter example abstraction Abstraction Refinement Change the program to match the abstraction Verify Abstraction-Guided Synthesis Program Restriction Implement P’ Abstract counter example 28
29
AGS Algorithm – High Level = true while(true) { BadTraces = { | ( P ) and S } if (BadTraces is empty) return implement(P, ) select BadTraces if (?) { = avoid( ) if ( false) = else abort } else { ’ = refine( , ) if ( ’ ) = ’ else abort } Input: Program P, Specification S, Abstraction Output: Program P’ satisfying S under 29
30
Avoid and Implement Desired output – program satisfying the spec Implementability guides the choice of constraint language Examples Atomic sections [POPL’10] Conditional critical regions (CCRs) [TACAS’09] Memory fences (for weak memory models) [FMCAD’10 + abstractions in progress] … 30
31
Avoiding an interleaving with atomic sections Adding atomicity constraints Atomicity predicate [l1,l2] – no context switch allowed between execution of statements at l1 and l2 avoid( ) A disjunction of all possible atomicity predicates that would prevent Thread A A1 A2 Thread B B1 B2 = A 1 B 1 A 2 B 2 avoid( ) = [A 1,A 2 ] [B 1,B 2 ] 31
32
Avoid and abstraction = avoid( ) Enforcing avoids any abstract trace ’ such that ’ Potentially avoiding “good traces” Abstraction may affect our ability to avoid a smaller set of traces 32
33
Example T1 1: x += z 2: x += z T2 1: z++ 2: z++ T3 1: y1 = f(x) 2: y2 = x 3: assert(y1 != y2) f(x) { if (x == 1) return 3 else if (x == 2) return 6 else return 5 } 33
34
Example: Concrete Values 023 1 2 3 4 5 4 6 y2 y1 1 Concrete values T1 1: x += z 2: x += z T2 1: z++ 2: z++ T3 1: y1 = f(x) 2: y2 = x 3: assert(y1 != y2) f(x) { if (x == 1) return 3 else if (x == 2) return 6 else return 5 } x += z; x += z; z++;z++;y1=f(x);y2=x;assert y1=5,y2=0 z++; x+=z; y1=f(x); z++; x+=z; y2=x;assert y1=3,y2=3 … 34
35
Example: Parity Abstraction 023 1 2 3 4 5 4 6 y2 y1 1 Concrete values T1 1: x += z 2: x += z T2 1: z++ 2: z++ T3 1: y1 = f(x) 2: y2 = x 3: assert(y1 != y2) f(x) { if (x == 1) return 3 else if (x == 2) return 6 else return 5 } x += z; x += z; z++;z++;y1=f(x);y2=x;assert y1=Odd,y2=Even 023 1 2 3 4 5 4 6 y2 y1 1 Parity abstraction (even/odd) 35
36
Example: Avoiding Bad Interleavings avoid( 1 ) = [z++,z++] = [z++,z++] = true while(true) { BadTraces={ | ( P ) and S } if (BadTraces is empty) return implement(P, ) select BadTraces if (?) { = avoid( ) } else { = refine( , ) } 36
37
Example: Avoiding Bad Interleavings avoid( 2 ) =[x+=z,x+=z] = [z++,z++] = [z++,z++] [x+=z,x+=z] = true while(true) { BadTraces={ | ( P ) and S } if (BadTraces is empty) return implement(P, ) select BadTraces if (?) { = avoid( ) } else { = refine( , ) } 37
38
Example: Avoiding Bad Interleavings T1 1: x += z 2: x += z T2 1: z++ 2: z++ T3 1: y1 = f(x) 2: y2 = x 3: assert(y1 != y2) = [z++,z++] [x+=z,x+=z] 38 = true while(true) { BadTraces={ | ( P ) and S } if (BadTraces is empty) return implement(P, ) select BadTraces if (?) { = avoid( ) } else { = refine( , ) }
39
023 1 2 3 4 5 4 6 y2 y1 1 parity 0123 1 2 3 4 5 4 6 0123 1 2 3 4 5 4 6 parity x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 Example: Avoiding Bad Interleavings But we can also refine the abstraction… 39
40
023 1 2 3 4 5 4 6 y2 y1 1 0123 1 2 3 4 5 4 6 0123 1 2 3 4 5 4 6 parity interval octagon 0123 1 2 3 4 5 4 6 0123 1 2 3 4 5 4 6 0123 1 2 3 4 5 4 6 0123 1 2 3 4 5 4 6 (a)(b) (c) (d)(e) (f)(g) parity interval octagon x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 x+=z; x+=z z++; y1=f(x) y2=x assert y1!= y2 T1 T2 T3 40
41
Multiple Solutions Performance: smallest atomic sections Interval abstraction for our example produces the atomicity constraint: ([x+=z,x+=z] ∨ [z++,z++]) ∧ ([y1=f(x),y2=x] ∨ [x+=z,x+=z] ∨ [z++,z++]) Minimal satisfying assignments 1 = [z++,z++] 2 = [x+=z,x+=z] 41
42
Input: Program P, Specification S, Abstraction Output: Program P’ satisfying S under = true while(true) { BadTraces = { | ( P ) and S } if (BadTraces is empty) return implement(P, ) select BadTraces if (?) { = avoid( ) if ( false) = else abort } else { ’ = refine( , ) if ( ’ ) = ’ else abort } Choosing between abstraction refinement and program restriction - not always possible to refine/avoid - may try and backtrack AGS Algorithm – More Details Forward Abstract Interpretation, taking into account for pruning infeasible interleavings Backward exploration of invalid Interleavings using to prune infeasible interleavings. Order of selection matters Up to this point did not commit to a synchronization mechanism 42
43
T1 0: if (y==0) goto L 1: x++ 2: L: T2 0: y=2 1: x+=1 2: assert x !=y Choosing a trace to avoid pc1,pc2 x,y 0,0 0,1 0,2 2,0 0,0 1,1 0,2 2,1 0,2 2,2 1,2 2,1 1,2 2,2 y=2 if (y==0) x++ x+=1 if (y==0) y=2 x+=1 legend 0,0 E,E 0,1 E,E 2,0 E,E 1,1 E,E 2,1 T,E 2,2 T,E y=2 if (y==0) x++ x+=1 if (y==0) y=2 x+=1 43
44
Implementability No program transformations (e.g., loop unrolling) Memoryless strategy T1 1: while(*) { 2: x++ 3: x++ 4: } T2 1: assert (x != 1) Separation between schedule constraints and how they are realized Can realize in program: atomic sections, locks,… Can realize in scheduler: benevolent scheduler 44
45
Atomic sections results If we can show disjoint access we can avoid synchronization Requires abstractions rich enough to capture access pattern to shared data Parity Intervals ProgramRefine StepsAvoid Steps Double buffering12 Defragmentation18 3D array update223 Array Removal117 Array Init156 45
46
AGS with guarded commands Implementation mechanism: conditional critical region (CCR) Constraint language: Boolean combinations of equalities over variables (x == c) Abstraction: what variables a guard can observe guard stmt 46
47
Avoiding a transition using a guard Add guard to z = y+1 to prevent execution from state s 1 Guard for s 1 : (x 1 y 1 z 0) Can affect other transitions where z = y+1 is executed x=1, y=1, z=0 y=x+1 z=y+1 x=1, y=1, z=2 x=1, y=2, z=0 s1s1 s2s2 s3s3 47
48
Example: full observability (y = 2 z = 1) No Stuck States Specification: { x, y, z } Abstraction: T1 1: x = z + 1 T2 1: y = x + 1 T3 1: z = y + 1 48
49
Build Transition System 1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e,2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 1,1,1 0,0,0 X Y Z PC1 PC2 PC3 legend 49
50
Avoid transition 1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e,2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 50
51
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e,2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 e,1,e 1,0,1 e,e,e 1,2,1 y=x+1 x 1 y 0 z 0 Correct and Maximally Permissive Result is valid 51 x 1 y 0 z 0 z=y+1
52
Resulting program (y = 2 z = 1) No Stuck States Specification: { x, y, z } Abstraction: T1 1: x = z + 1 T2 1: y = x + 1 T3 1: z = y + 1 T1 1: x = z + 1 T2 1: y = x + 1 T3 1: (x 1 y 0 z 0) z = y + 1 52
53
(y = 2 z = 1) No Stuck States Specification: { x, z } Abstraction: Example: limited observability T1 1: x = z + 1 T2 1: y = x + 1 T3 1: z = y + 1 53
54
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e,2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 Build transition system 1,1,1 0,0,0 X Y Z PC1 PC2 PC3 legend 54
55
Avoid bad state 1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e, 2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 55
56
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e, 2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 Implementability Select all equivalent transitions 56
57
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 3,1,2 e,e,e, 2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 x=z+1 z=y+1 x=z+1 y=x+1 side-effects e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 y=x+1 z=y+1 x 1 z 0 z=y+1 x 1 z 0 Result has stuck states 57
58
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 3,1,2 e,e,e, 2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 x=z+1 z=y+1 x=z+1 y=x+1 e,e,1 1,2,0 e,1,e 1,0,1 e,e,1 1,1,0 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 y=x+1 z=y+1 x 1 z 0 z=y+1 x 1 z 0 Select transition to remove 58
59
1,1,1 0,0,0 e,1,1 1,0,0 1,e,1 0,1,0 1,1,e 0,0,1 e,e,3 1,2,0 e,2,e 1,0,1 e,e,3 1,1,0 1,e,e 0,1,2 e,1,e 2,0,1 1,e,e 0,1,1 e,e,e 1,2,3 e,e,e 1,2,1 e,e,e 1,1,2 e,e,e 3,1,2 e,e,e,2,3,1 e,e,e 2,1,1 x=z+1 y=x+1 z=y+1 y=x+1 z=y+1 x=z+1 z=y+1 x=z+1 y=x+1 x 1 z 0 x 0 z 0 x 1 z 0 x 0 z 0x 0 z 0 Result is valid Correct and Maximally Permissive 59
60
Resulting program ! (y = 2 && z = 1) No Stuck States Specification: { x, z } Abstraction: T1 1: x = z + 1 T2 1: y = x + 1 T3 1: z = y + 1 T1 1: (x 0 z 0) x = z + 1 T2 1: y = x + 1 T3 1: (x 1 z 0) z = y + 1 60
61
T1 x = z + 1 T2 y = x + 1 T3 z = y + 1 T1 x = z + 1 T2 y = x + 1 T3 (x 1 z 0) z = y + 1 T1 (x 0 z 0) x = z + 1 T2 y = x + 1 T3 (x 1 z 0) z = y + 1 T1 x = z + 1 T2 y = x + 1 T3 z = y + 1 T1 x = z + 1 T2 y = x + 1 T3 (x 1 y 0 z 0) z = y + 1 { x } { x,z } { x,y,z } T1 x = z + 1 T2 y = x + 1 T3 z = y + 1 T1 x = z + 1 T2 y = x + 1 T3 (x 1) z = y + 1 T1 (x 0) x = z + 1 T2 y = x + 1 T3 (x 1) z = y + 1 61
62
AGS with memory fences Avoidable transition more tricky to define Operational semantics of weak memory models Special abstraction required to deal with potentially unbounded store-buffers Even for finite-state programs Informally “finer abstraction = fewer fences” 62
63
Synthesis Results 63 Mostly mutual exclusion primitives Different variations of the abstraction ProgramFD k=0FD k=1PD k=0PD k=1PD k=2 Sense0 Pet0 Dek0 Lam0T/O Fast0T/O Fast1a Fast1b Fast1cT/O
64
Chase-Lev Work-Stealing Queue 1 int take() { 2 long b = bottom – 1; 3 item_t * q = wsq; 4 bottom = b 5 fence(“store-load”); 6 long t = top 7 if (b < t) { 8 bottom = t; 9 return EMPTY; 10 } 11 task = q->ap[b % q->size]; 12 if (b > t) 13 return task 14 if (!CAS(&top, t, t+1)) 15 return EMPTY; 16 bottom = t + 1; 17 return task; 18 } 1 void push(int task) { 2 long b = bottom; 3 long t = top; 4 item_t * q = wsq; 5 if (b – t >= q->size – 1) { 6 wsq = expand(); 7 q = wsq; 8 } 9 q->ap[b % q->size] = task; 10 fence(“store-store”); 11 bottom = b + 1; 12} 1 int steal() { 2 long t = top; 3 fence(“load-load”); 4 long b = bottom; 5 fence(“load-load”); 6 item_t * q = wsq; 7 if (t >= b) 8 return EMPTY; 9 task = q->ap[t % q->size]; 10 fence(“load-store”); 11 if (!CAS(&top, t, t+1)) 12 return ABORT; 13 return task; 14} Specification: no lost items, no phantom items, memory safety 1item_t* expand() { 2int newsize = wsq->size * 2; 3int* newitems = (int *) malloc(newsize*sizeof(int)); 4item_t *newq = (item_t *)malloc(sizeof(item_t)); 5for (long i = top; i < bottom; i++) { 6 newitems[i % newsize] = wsq->ap[i % wsq->size]; 7} 8newq->size = newsize; 9newq->ap = newitems; 10fence("store-store"); 11wsq = newq; 12return newq; }
65
Results
66
Performance
67
Some AGS instances AvoidImplementation Mechanism Abstraction Space (examples) Reference Context switchAtomic sectionsNumerical abstractions[POPL’10] TransitionConditional critical regions (CCRs) Observability[TACAS’09] ReorderingMemory fencesPartial-Coherence abstractions for Store buffers [FMCAD’10] [PLDI’11] … 67
68
program specification Abstract counter example abstraction Abstraction Refinement Change the specification to match the abstraction Verify General Setting Revisited Program Restriction Implement P’ Abstract counter example S’ Spec Weakening 68
69
Summary Modifying the program to fit an abstraction examples inspired by the trace partitioning domain (trace partitioning domain can capture these effects, and more, without changing the program) An algorithm for Abstraction-Guided Synthesis Synthesize efficient and correct synchronization Handles infinite-state systems based on abstract interpretation Refine the abstraction and/or restrict program behavior Interplay between abstraction and synchronization Separate characterization of solution from choosing optimal solutions (e.g., smallest atomic sections) 69
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.