Browse Source

added context switcher

Taco 1 year ago
parent
commit
02645b3a8c
3 changed files with 1541 additions and 174 deletions
  1. 78 115
      diff.xml
  2. 832 57
      entitlements.html
  3. 631 2
      entitlements.org

+ 78 - 115
diff.xml

@@ -1,193 +1,156 @@
1 1
 <?xml version="1.0"?>
2 2
 <result>
3 3
   <request>
4
-    <application>decodeapp:zontrax</application>
5
-    <contextType>6</contextType>
4
+    <application>decodeapp:rank</application>
5
+    <contextType>2</contextType>
6 6
     <required>
7
-      <property>go:need</property>
8
-      <property>decode:birthdate</property>
9 7
       <property>go:neighborhood_role</property>
8
+      <property>decode:first_name</property>
9
+      <property>go:need</property>
10 10
     </required>
11 11
     <optional>
12
-      <property>decode:homepage</property>
13
-      <property>decode:profession</property>
12
+      <property>go:proof_of_membership</property>
13
+      <property>twitter:id</property>
14 14
     </optional>
15
-    <plSum>14</plSum>
15
+    <plSum>12</plSum>
16 16
     <plMean>2</plMean>
17 17
   </request>
18 18
   <diffs>
19 19
     <diff>
20
-      <contextName>Antwan</contextName>
21
-      <intersect>
22
-        <property>go:neighborhood_role</property>
23
-      </intersect>
20
+      <contextName>Russel</contextName>
21
+      <intersect/>
24 22
       <except>
23
+        <property>go:neighborhood_role</property>
24
+        <property>decode:first_name</property>
25 25
         <property>go:need</property>
26
-        <property>decode:birthdate</property>
27
-        <property>decode:homepage</property>
28
-        <property>decode:profession</property>
26
+        <property>go:proof_of_membership</property>
27
+        <property>twitter:id</property>
29 28
       </except>
30 29
     </diff>
31 30
     <diff>
32
-      <contextName>Altenwerth and Sons</contextName>
33
-      <intersect>
34
-        <property>go:need</property>
35
-      </intersect>
31
+      <contextName>Clarinet</contextName>
32
+      <intersect/>
36 33
       <except>
37
-        <property>decode:birthdate</property>
38 34
         <property>go:neighborhood_role</property>
39
-        <property>decode:homepage</property>
40
-        <property>decode:profession</property>
35
+        <property>decode:first_name</property>
36
+        <property>go:need</property>
37
+        <property>go:proof_of_membership</property>
38
+        <property>twitter:id</property>
41 39
       </except>
42 40
     </diff>
43 41
     <diff>
44
-      <contextName>Metallica</contextName>
45
-      <intersect/>
42
+      <contextName>North Colorado College</contextName>
43
+      <intersect>
44
+        <property>go:neighborhood_role</property>
45
+      </intersect>
46 46
       <except>
47
+        <property>decode:first_name</property>
47 48
         <property>go:need</property>
48
-        <property>decode:birthdate</property>
49
-        <property>go:neighborhood_role</property>
50
-        <property>decode:homepage</property>
51
-        <property>decode:profession</property>
49
+        <property>go:proof_of_membership</property>
50
+        <property>twitter:id</property>
52 51
       </except>
53 52
     </diff>
54 53
     <diff>
55
-      <contextName>Dentist</contextName>
56
-      <intersect>
57
-        <property>go:need</property>
58
-        <property>go:neighborhood_role</property>
59
-      </intersect>
54
+      <contextName>Alanna</contextName>
55
+      <intersect/>
60 56
       <except>
61
-        <property>decode:birthdate</property>
62
-        <property>decode:homepage</property>
63
-        <property>decode:profession</property>
57
+        <property>go:neighborhood_role</property>
58
+        <property>decode:first_name</property>
59
+        <property>go:need</property>
60
+        <property>go:proof_of_membership</property>
61
+        <property>twitter:id</property>
64 62
       </except>
65 63
     </diff>
66 64
   </diffs>
67 65
   <profile>
68 66
     <contextObj>
69
-      <contextName>Antwan</contextName>
67
+      <contextName>Russel</contextName>
70 68
       <contextType>0</contextType>
71
-      <plSum>12</plSum>
72
-      <plMean>2</plMean>
69
+      <plSum>5</plSum>
70
+      <plMean>5</plMean>
73 71
       <properties>
74 72
         <property>
75
-          <type>linkedin:id</type>
76
-          <value>hattie_runolfon@mosciski.org</value>
77
-          <pl>2</pl>
78
-        </property>
79
-        <property>
80
-          <type>go:newsletter_approval</type>
81
-          <value>true</value>
82
-          <pl>3</pl>
83
-        </property>
84
-        <property>
85
-          <type>decode:postcode</type>
86
-          <value>72708</value>
73
+          <type>decode:street</type>
74
+          <value>317 Dietrich Crescent</value>
87 75
           <pl>5</pl>
88 76
         </property>
89
-        <property>
90
-          <type>go:neighborhood_role</type>
91
-          <value>scholier</value>
92
-          <pl>1</pl>
93
-        </property>
94
-        <property>
95
-          <type>twitter:id</type>
96
-          <value>rosa_roberts</value>
97
-          <pl>1</pl>
98
-        </property>
99
-      </properties>
100
-    </contextObj>
101
-    <contextObj>
102
-      <contextName>Altenwerth and Sons</contextName>
103
-      <contextType>3</contextType>
104
-      <plSum>0</plSum>
105
-      <plMean>0</plMean>
106
-      <properties>
107
-        <property>
108
-          <type>go:need</type>
109
-          <value>I extended my compression algorithm to support... get this... 12-bit color. Okay, so our users will be able to experience a 10 percent increase in image quality with absolutely no increase in server load whatsoever. Just-Just-Just... Just watch this. Before. After. Before. After.</value>
110
-          <pl>0</pl>
111
-        </property>
112 77
       </properties>
113 78
     </contextObj>
114 79
     <contextObj>
115
-      <contextName>Metallica</contextName>
80
+      <contextName>Clarinet</contextName>
116 81
       <contextType>4</contextType>
117
-      <plSum>21</plSum>
118
-      <plMean>3</plMean>
82
+      <plSum>16</plSum>
83
+      <plMean>4</plMean>
119 84
       <properties>
120 85
         <property>
121
-          <type>facebook:id</type>
122
-          <value>tyson.kaulke@mcclureschaefer.biz</value>
123
-          <pl>4</pl>
124
-        </property>
125
-        <property>
126
-          <type>decode:first_name</type>
127
-          <value>Tianna</value>
86
+          <type>go:newsletter_approval</type>
87
+          <value>true</value>
128 88
           <pl>3</pl>
129 89
         </property>
130 90
         <property>
131
-          <type>go:my_dreams</type>
132
-          <value>It's a figure of speech, Morty! They're bureaucrats! I don't respect them. Just keep shooting, Morty! You have no idea what prison is like here!</value>
133
-          <pl>3</pl>
91
+          <type>decode:postcode</type>
92
+          <value>59936</value>
93
+          <pl>5</pl>
134 94
         </property>
135 95
         <property>
136
-          <type>go:project_association</type>
137
-          <value>Cold Duck</value>
138
-          <pl>2</pl>
96
+          <type>decode:last_name</type>
97
+          <value>Veum</value>
98
+          <pl>3</pl>
139 99
         </property>
140 100
         <property>
141
-          <type>decode:avg_yearly_gas_use_m3</type>
142
-          <value>1159</value>
101
+          <type>decode:avg_yearly_electricy_use_kwh</type>
102
+          <value>2702</value>
143 103
           <pl>5</pl>
144 104
         </property>
145
-        <property>
146
-          <type>decode:persons_in_household</type>
147
-          <value>4</value>
148
-          <pl>4</pl>
149
-        </property>
150 105
       </properties>
151 106
     </contextObj>
152 107
     <contextObj>
153
-      <contextName>Dentist</contextName>
154
-      <contextType>1</contextType>
155
-      <plSum>18</plSum>
108
+      <contextName>North Colorado College</contextName>
109
+      <contextType>2</contextType>
110
+      <plSum>16</plSum>
156 111
       <plMean>2</plMean>
157 112
       <properties>
158 113
         <property>
159
-          <type>decode:first_name</type>
160
-          <value>Hertha</value>
114
+          <type>decode:email</type>
115
+          <value>billie@murphy.biz</value>
161 116
           <pl>2</pl>
162 117
         </property>
163 118
         <property>
164
-          <type>decode:persons_in_household</type>
165
-          <value>4</value>
166
-          <pl>4</pl>
119
+          <type>decode:last_name</type>
120
+          <value>Skiles</value>
121
+          <pl>2</pl>
167 122
         </property>
168 123
         <property>
169
-          <type>decode:gender</type>
170
-          <value>Divorced</value>
124
+          <type>skype:id</type>
125
+          <value>fredy</value>
171 126
           <pl>3</pl>
172 127
         </property>
173 128
         <property>
174
-          <type>decode:profile_picture</type>
175
-          <value>http://lorempixel.com/300/300</value>
129
+          <type>go:my_dreams</type>
130
+          <value>No no, If I wanted to be sober, I wouldn&#x2019;t have gotten drunk.</value>
176 131
           <pl>3</pl>
177 132
         </property>
178 133
         <property>
179
-          <type>go:need</type>
180
-          <value>Of course they know that you're not pitching Shazam. That already exists. This would be a Shazam... for food.</value>
181
-          <pl>1</pl>
134
+          <type>decode:marital_status</type>
135
+          <value>Divorced</value>
136
+          <pl>4</pl>
182 137
         </property>
183 138
         <property>
184 139
           <type>go:neighborhood_role</type>
185
-          <value>geinteresseerd</value>
186
-          <pl>1</pl>
140
+          <value>toekomstige</value>
141
+          <pl>2</pl>
187 142
         </property>
143
+      </properties>
144
+    </contextObj>
145
+    <contextObj>
146
+      <contextName>Alanna</contextName>
147
+      <contextType>0</contextType>
148
+      <plSum>4</plSum>
149
+      <plMean>4</plMean>
150
+      <properties>
188 151
         <property>
189
-          <type>decode:street</type>
190
-          <value>4524 Senger Rue</value>
152
+          <type>decode:avg_yearly_electricy_use_kwh</type>
153
+          <value>2199</value>
191 154
           <pl>4</pl>
192 155
         </property>
193 156
       </properties>

File diff suppressed because it is too large
+ 832 - 57
entitlements.html


+ 631 - 2
entitlements.org

@@ -2269,5 +2269,634 @@ void mouseReleased()
2269 2269
 </script> <canvas id="ob-95c93303456868d70e9bd12946e4defd3dfd1425"></canvas>
2270 2270
 #+END_EXPORT
2271 2271
 
2272
-*** TODO: How does the end user actually accept the request? Is it by dragging the request onto the context?
2273
-*** TODO: How does the end user decline the request?
2272
+We have come up with an interaction for entitlements that is based around a 'context switcher'.
2273
+The color of the section in the center always represents the current context.
2274
+The outer ring is divided into separate 'sectors' for each context that you have defined.
2275
+ 
2276
+Each context has a different color, based on the context type and the data that it holds. 
2277
+For example if you are at work you would (or the application will automatically) 
2278
+set the current context to blue by clicking on the blue sector. 
2279
+
2280
+When a request comes in through decode, it will be positioned in orbit around the context switcher,
2281
+close by the sector of the calculated best fitted context. Based on the category and the data diff.
2282
+
2283
+The user can drag the request around the outer ring to compare the impact it would have,
2284
+ accepting the request for each sector in the context switcher.
2285
+
2286
+After a suitable context is found, the user can let go of the request, and a dialog appears in the center,
2287
+asking the user to either accept or decline the request.
2288
+ 
2289
+#+name: context_switcher_src
2290
+#+BEGIN_SRC java :exports none
2291
+//magic numbers
2292
+float contextSize = 500;//random(50,100); //random between 50 and 100
2293
+float requestSize = 50;
2294
+float eqd_angle = TWO_PI / contexts.length;
2295
+float PROPORTION_CENTER = 0.6;
2296
+float DISTANCE_FACTOR = 1.4;
2297
+
2298
+//globals
2299
+float centerX, centerY;
2300
+float xOffset, yOffset;
2301
+float requestX, requestY;//request coordinates, they can move
2302
+boolean hitRequest = false;
2303
+boolean dragging = false;
2304
+int hitContext = -1;
2305
+int currentContext = 1;//first context is the default context
2306
+PFont font;
2307
+PFont titleFont;
2308
+
2309
+void setup()
2310
+{
2311
+  size(800,800);
2312
+  rectMode(RADIUS);
2313
+  smooth();
2314
+
2315
+  titleFont = createFont("HelveticaNeue", 20);
2316
+  font = createFont("HelveticaNeue", 14);
2317
+
2318
+  centerX = width/2;
2319
+  centerY = height/2;
2320
+
2321
+  //TODO: calculate most relevant sector for the request
2322
+  PVector position = positionForSectorIndex(1);
2323
+  requestX = position.x;
2324
+  requestY = position.y;
2325
+}
2326
+
2327
+//the position should be outside the center of the middle of the sector
2328
+PVector positionForSectorIndex(int index)
2329
+{
2330
+  float angle = (PI/2) + (index * eqd_angle) + (eqd_angle/2);
2331
+  float x = centerX + (contextSize/2 * DISTANCE_FACTOR) * cos(angle); //calculate xPos
2332
+  float y = centerY + (contextSize/2 * DISTANCE_FACTOR) * sin(angle); //calculate yPos
2333
+
2334
+  return new PVector(x,y);
2335
+}
2336
+
2337
+//draw each frame
2338
+void draw()
2339
+{
2340
+  background(255);
2341
+  drawTitle();
2342
+  drawBorder();
2343
+  drawSectors();
2344
+  drawCurrentContext();
2345
+  drawRequest();
2346
+}
2347
+
2348
+//draw the request and label
2349
+void drawRequest()
2350
+{
2351
+  color strokeColor = hitRequest? 255 : 153;
2352
+  stroke(strokeColor);
2353
+
2354
+  color reqColor = getColor(request.plMean, request.contextType);
2355
+  fill(reqColor,127);
2356
+  ellipse(requestX,requestY, requestSize,requestSize);
2357
+ 
2358
+  colorMode(HSB);
2359
+  fill(darken(reqColor));
2360
+  textAlign(CENTER,CENTER);
2361
+  text(request.application, requestX, requestY + 50/1.5);
2362
+  text("" + request.plSum, requestX, requestY);
2363
+  colorMode(RGB);
2364
+}
2365
+
2366
+//draw current context as center circle over the pie
2367
+void drawCurrentContext()
2368
+{
2369
+  Context current = contexts[currentContext];
2370
+  
2371
+  //set up colors for current context
2372
+  color contextColor = getColor(current.plMean, current.contextType);
2373
+  colorMode(HSB);
2374
+  color darkContextColor = darken(contextColor);
2375
+  colorMode(RGB);
2376
+
2377
+  fill(contextColor);
2378
+  noStroke();
2379
+  ellipse(centerX, centerY, contextSize * PROPORTION_CENTER, contextSize * PROPORTION_CENTER);
2380
+
2381
+  //if we have hit a context draw detailed information in the center
2382
+  if(hitContext > -1)
2383
+  {
2384
+    fill(255);
2385
+    noStroke();
2386
+    ellipse(centerX, centerY, contextSize * PROPORTION_CENTER * 0.95, contextSize * PROPORTION_CENTER * 0.95);
2387
+    
2388
+    if(dragging == false)
2389
+    {
2390
+      drawButtons(darkContextColor);
2391
+    }
2392
+    else
2393
+    {
2394
+      drawDiff(current, contextColor);
2395
+    }
2396
+  }
2397
+  else //just draw the current context title
2398
+  {
2399
+    textFont(font);
2400
+    fill(255);
2401
+    noStroke();
2402
+    ellipse(centerX, centerY, contextSize * 0.2, contextSize * 0.2);
2403
+    fill(darkContextColor);
2404
+    textAlign(CENTER,CENTER);
2405
+    text("my \n" + current.title + "\n data", centerX, centerY);
2406
+  }
2407
+}
2408
+
2409
+//darken the given color, expects hsb color mode 
2410
+int darken(int c)
2411
+{
2412
+  float h = hue(c);
2413
+  float s = saturation(c);
2414
+  float v = brightness(c);
2415
+
2416
+  return color(h,s,v * 0.6);
2417
+}
2418
+
2419
+//draw the accept / decline buttons
2420
+void drawButtons(color darkContextColor)
2421
+{
2422
+   //draw accept and decline button
2423
+  fill(darkContextColor);
2424
+  textFont(font);
2425
+  textAlign(CENTER,CENTER);
2426
+  text("ACCEPT    |   DECLINE", centerX, centerY);
2427
+}
2428
+
2429
+//show diff information
2430
+void drawDiff(Context c, color contextColor)
2431
+{
2432
+  ellipse(centerX, centerY, contextSize * PROPORTION_CENTER * 0.95, contextSize * PROPORTION_CENTER * 0.95);
2433
+  colorMode(HSB);
2434
+  fill(darken(contextColor));
2435
+  colorMode(RGB);
2436
+    
2437
+  Diff d = diffs[hitContext];
2438
+  String available = getIntersection(c,d);
2439
+  String missing = getMissing(d);
2440
+  String diffMessage = "DATA TO ENTITLE: \n" + available + "\nSTILL MISSING: \n" + missing;
2441
+  textAlign(CENTER,CENTER);
2442
+  text(diffMessage, centerX, centerY);
2443
+}
2444
+
2445
+//draw Sectors for each context as pie pieces
2446
+void drawSectors()
2447
+{
2448
+  int count = 0;
2449
+  float begin = (PI/2);
2450
+  float end = begin + eqd_angle;
2451
+  for(String context : contexts)
2452
+  { 
2453
+    //color strokeColor = (hitContext == count) ? 255 : 153;
2454
+    noStroke();
2455
+
2456
+    color contextColor = getColor(context.plMean, context.contextType);
2457
+    fill(contextColor);
2458
+
2459
+    arc(centerX, centerY, contextSize, contextSize, begin, end);
2460
+    begin = end;
2461
+    end = begin + eqd_angle;
2462
+    count++;
2463
+  }
2464
+}
2465
+
2466
+//draw outer rim
2467
+void drawBorder()
2468
+{
2469
+  stroke(0);
2470
+  fill(255);
2471
+  ellipse(centerX, centerY, contextSize + 10, contextSize + 10);
2472
+}
2473
+
2474
+//draw title
2475
+void drawTitle()
2476
+{
2477
+  textFont(titleFont);
2478
+  fill(150);
2479
+  textAlign(CENTER);
2480
+  text("Do you want to get *****d by Facebook?\nPlease drag the request on to your preferred context." , centerX, 80);
2481
+}
2482
+
2483
+/* interaction functions */
2484
+void mousePressed()
2485
+{
2486
+  //test if request hit
2487
+  boolean hitRequest = (mouseX > requestX - requestSize/2 && mouseX < requestX + requestSize/2 &&
2488
+     mouseY > requestY - requestSize/2 && mouseY < requestY + requestSize/2);
2489
+  
2490
+  //update global
2491
+  dragging = hitRequest;
2492
+  
2493
+  //test if context hit
2494
+  float deltaX = mouseX - centerX;
2495
+  float deltaY = mouseY - centerY;
2496
+  int index = hitContextIndex(deltaX,deltaY);
2497
+  
2498
+  if(index > -1)
2499
+  {
2500
+    currentContext = index;
2501
+  }
2502
+}
2503
+
2504
+void mouseDragged()
2505
+{
2506
+  float deltaX = mouseX - centerX;
2507
+  float deltaY = mouseY - centerY;
2508
+  
2509
+  float distance = sqrt(deltaX*deltaX + deltaY*deltaY);
2510
+  float fraction = distance / (contextSize / 2);
2511
+  float minDistanceFactor = (PROPORTION_CENTER + (1-PROPORTION_CENTER)/2);
2512
+  
2513
+  //outside the circle is allowed anywhere
2514
+  if(fraction > minDistanceFactor  && dragging)
2515
+  {
2516
+      requestX = mouseX - xOffset;
2517
+      requestY = mouseY - yOffset;
2518
+      hitContext = hitContextIndex(deltaX,deltaY);
2519
+      if(hitContext > -1){currentContext = hitContext;}
2520
+  }
2521
+  else if(dragging) //else calculate closest point that is allowed
2522
+  {
2523
+      float mouseAngle = (PI/2) - atan2(deltaX, deltaY);
2524
+      float x = centerX + (contextSize/2 * minDistanceFactor) * cos(mouseAngle); //calculate xPos
2525
+      float y = centerY + (contextSize/2 * minDistanceFactor) * sin(mouseAngle); //calculate yPos
2526
+      requestX = x;
2527
+      requestY = y;
2528
+      hitContext = hitContextIndex(x - centerX, y - centerY);
2529
+      currentContext = hitContext;
2530
+  }
2531
+}
2532
+
2533
+void mouseReleased()
2534
+{
2535
+  dragging = false;
2536
+  //hitContext = -1;
2537
+  //PVector position = positionForSectorIndex(1);
2538
+  //requestX = position.x;
2539
+  //requestY = position.y;
2540
+} 
2541
+
2542
+//calculate which pie part was clicked, 
2543
+//by means of the angle between the mouse point an the center of the circle
2544
+//returns -1 if no pie part was clicked 
2545
+//(because the distance is not between 0.8 and 1 times the distanceSize)
2546
+int hitContextIndex(float deltaX, float deltaY)
2547
+{ 
2548
+  float distance = sqrt(deltaX*deltaX + deltaY*deltaY);
2549
+  float fraction = distance / (contextSize / 2);
2550
+  if(fraction < PROPORTION_CENTER || fraction > 1)
2551
+  {
2552
+    return -1;
2553
+  }
2554
+  
2555
+  //overstaande, aanliggende => tan dus atan2
2556
+  float mouseAngle = atan2(deltaX, deltaY);
2557
+  float degrees = mouseAngle * 180 / PI;
2558
+  if(degrees < 0){degrees = 360 + degrees;} //so everyting is on one continuum
2559
+  float part = eqd_angle * 180 /PI;
2560
+  int index = (contexts.length - ((int) (degrees / part))) - 1;//because we start at the bottom.
2561
+  return index;
2562
+}
2563
+
2564
+/* data functions */
2565
+
2566
+//create a string that lists the values of the intersection in d, with the values in c
2567
+String getIntersection(Context c, Diff d)
2568
+{
2569
+    String result = "";
2570
+    for(String key : d.intersect)
2571
+    {
2572
+        String value = getPropertyValue(c, key);
2573
+        if(value != null) result += key + " (" + value + ")\n";
2574
+    }
2575
+    return result;
2576
+}
2577
+
2578
+//create a string that lists the missing keys in the intersection d
2579
+String getMissing(Diff d)
2580
+{
2581
+    String result = "";
2582
+    for(String key : d.except)
2583
+    {
2584
+        result += key + "\n";
2585
+    }
2586
+    return result;
2587
+}
2588
+
2589
+//get the value of a property value in c designated by key
2590
+String getPropertyValue(Context c, String key)
2591
+{
2592
+    for(Property p : c.properties)
2593
+    {
2594
+        if(p.type == key)
2595
+        {
2596
+            return p.value;
2597
+        }
2598
+    }
2599
+    return null;
2600
+}
2601
+
2602
+#+END_SRC
2603
+
2604
+*** TODO font sizes
2605
+*** TODO cut off long values with ...
2606
+*** TODO correctly place request
2607
+*** TODO change number of generated contexts to multiple sectors and place same category next to eachother.
2608
+
2609
+#+name: context_switcher
2610
+#+BEGIN_SRC processing :noweb yes
2611
+<<pcolors>>
2612
+<<glue>>
2613
+<<context_switcher_src>>
2614
+#+END_SRC
2615
+
2616
+#+RESULTS: context_switcher
2617
+#+BEGIN_EXPORT html
2618
+<script src="processing.js"></script>
2619
+ <script type="text/processing" data-processing-target="ob-b08b9ab6dca87cd6f3682e15abf24f929a90a794">
2620
+String[] levels = {"commons", "public", "affiliate", "intimate", "private", "secret"};
2621
+String[] contextTypes = {"personal", "health", "education", "work", "hobby", "financial", "other"};
2622
+
2623
+static class PrivacyLevel {
2624
+  public static int SECRET = 5;
2625
+  public static int PRIVATE = 4;
2626
+  public static int INTIMATE = 3;
2627
+  public static int AFFILIATE = 2;
2628
+  public static int PUBLIC = 1;
2629
+  public static int COMMONS = 0;
2630
+}
2631
+
2632
+static class ContextType {
2633
+  public static int PERSONAL = 0; 
2634
+  public static int HEALTH = 1;
2635
+  public static int EDUCATION = 2;
2636
+  public static int WORK = 3;
2637
+  public static int HOBBY = 4;
2638
+  public static int FINANCIAL = 5;
2639
+  public static int OTHER = 6;
2640
+}
2641
+
2642
+int[][] colors = generateColors();
2643
+
2644
+//generate colors to maximize contrast
2645
+int[][] generateColors()
2646
+{
2647
+  int[][] pcolors = new int[contextTypes.length][levels.length];
2648
+  
2649
+//we start with d0 as a seed color
2650
+  color seed = #FFE9BE;//seed color
2651
+  
2652
+  colorMode(HSB);
2653
+  
2654
+  float h_seed = hue(seed);
2655
+  float s_seed = saturation(seed);
2656
+  float v_seed = brightness(seed);
2657
+
2658
+  float levelshift = 255/levels.length;
2659
+  float contextshift = 255/contextTypes.length + 1;
2660
+  
2661
+  //cycle hue for each level
2662
+  for (int i = 0; i < contextTypes.length; i++){
2663
+    float h = h_seed + i * contextshift;
2664
+    if(h > 255){h = h - 255;}
2665
+    
2666
+    //cycle brightness for each context
2667
+    for(int j = 0; j < levels.length; j++)
2668
+    {
2669
+      float v = v_seed - (j * levelshift);
2670
+      float s = s_seed + (j * levelshift); 
2671
+      
2672
+      color c = color(h,s,v);
2673
+      pcolors[i][j] = c;
2674
+    }
2675
+  }
2676
+  colorMode(RGB);
2677
+
2678
+  return pcolors;
2679
+}
2680
+
2681
+public int getColor(int privacy_level, int context_type)
2682
+{
2683
+    return colors[context_type][privacy_level];
2684
+}
2685
+class Request
2686
+{
2687
+  public String application;
2688
+  public int contextType;
2689
+  public String[] required_properties;
2690
+  public String[] optional_properties;
2691
+  public int plSum;
2692
+  public int plMean;
2693
+
2694
+  public Request(String app, int contextType, String[] req, String[] opt, int sum, int mean)
2695
+  {
2696
+    this.application = app;
2697
+    this.contextType = contextType;
2698
+    this.required_properties = req;
2699
+    this.optional_properties = opt;
2700
+    this.plSum = sum;
2701
+    this.plMean = mean;
2702
+  }
2703
+}
2704
+
2705
+class Diff
2706
+{
2707
+  public String context;
2708
+  public String[] intersect;
2709
+  public String[] except;
2710
+
2711
+  public Diff(String ctx, String[] intersect, String[] except)
2712
+  {
2713
+    this.context = ctx;
2714
+    this.intersect = intersect;
2715
+    this.except = except;
2716
+  } 
2717
+}
2718
+
2719
+class Property
2720
+{
2721
+  public String type;
2722
+  public String value;
2723
+  public int pl;//privacy level
2724
+
2725
+  public Property(String type, String value, int pl)
2726
+  {
2727
+    this.type = type;
2728
+    this.value = value;
2729
+    this.pl = pl;
2730
+  }
2731
+}
2732
+
2733
+class Context
2734
+{
2735
+  public String title;
2736
+  public int plSum;
2737
+  public int plMean;
2738
+  public int contextType;
2739
+  public Property[] properties;
2740
+
2741
+  public Context(String title, int plSum, int plMean, int contextType, Property[] properties)
2742
+  {
2743
+    this.title = title;
2744
+    this.plSum = plSum;
2745
+    this.plMean = plMean;
2746
+    this.properties = properties;
2747
+    this.contextType = contextType;
2748
+  }
2749
+}
2750
+
2751
+XMLElement doc = new XMLElement(this, 'diff.xml');
2752
+
2753
+//create typed versions because this is java :-(
2754
+Request parseRequest(XMLElement xml)
2755
+{
2756
+  XMLElement req = xml.getChild(0);
2757
+  String name = req.getChild(0).getContent();
2758
+  int contextType = req.getChild(1).getContent();
2759
+  String[] required = new String[req.getChild(2).getChildCount()];
2760
+  String[] optional = new String[req.getChild(3).getChildCount()];
2761
+  int plSum = parseInt(req.getChild(4).getContent());
2762
+  int plMean = parseInt(req.getChild(5).getContent());
2763
+
2764
+  for (int i = 0; i < required.length; i++) {
2765
+    required[i] = req.getChild(2).getChild(i).getContent();
2766
+  }
2767
+
2768
+  for (int i = 0; i < optional.length; i++) {
2769
+    optional[i] = req.getChild(3).getChild(i).getContent();
2770
+  }
2771
+
2772
+  Request r = new Request(name,contextType,required,optional, plSum, plMean);
2773
+  return r;
2774
+}
2775
+
2776
+Context[] parseProfile(XMLElement xml)
2777
+{
2778
+  XMLElement profile = xml.getChild(2);
2779
+  Context[] contexts = new Context[profile.getChildCount()];
2780
+
2781
+  for(int i = 0; i < contexts.length; i++)
2782
+  {
2783
+    String contextName = profile.getChild(i).getChild(0).getContent();
2784
+    int contextType = parseInt(profile.getChild(i).getChild(1).getContent());
2785
+    int plSum = parseInt(profile.getChild(i).getChild(2).getContent());
2786
+    int plMean = parseInt(profile.getChild(i).getChild(3).getContent());
2787
+    XMLElement propertiesEl = profile.getChild(i).getChild(4);
2788
+    Property[] properties = new Property[propertiesEl.getChildCount()];
2789
+    for(int j = 0; j < properties.length; j++)
2790
+    {
2791
+      Property prop = parseProperty(propertiesEl.getChild(j));
2792
+      properties[j] = prop;
2793
+    }
2794
+
2795
+    Context context = new Context(contextName, plSum, plMean, contextType, properties);
2796
+    contexts[i] = context;
2797
+  }
2798
+  return contexts;
2799
+}
2800
+
2801
+Property parseProperty(XMLElement propertyEl)
2802
+{
2803
+  String propertyType = propertyEl.getChild(0).getContent();
2804
+  String value = propertyEl.getChild(1).getContent();
2805
+  int pl = parseInt(propertyEl.getChild(2).getContent());
2806
+  return new Property(propertyType, value, pl);
2807
+}
2808
+
2809
+//create typed versions because this is java :-(
2810
+Diff[] parseDiffs(xml)
2811
+{
2812
+  XMLElement diffsEl = xml.getChild(1);
2813
+  Diff[] diffs = new Diff[diffsEl.getChildCount()];
2814
+  for(int i = 0; i < diffs.length; i++)
2815
+  {
2816
+    String contextName = diffsEl.getChild(i).getChild(0).getContent();
2817
+    String[] intersects = new String[diffsEl.getChild(i).getChild(1).getChildCount()];
2818
+    String[] except = new String[diffsEl.getChild(i).getChild(2).getChildCount()];
2819
+    
2820
+    for(int j = 0; j < intersects.length; j++)
2821
+    {
2822
+      intersects[j] = diffsEl.getChild(i).getChild(1).getChild(j).getContent();
2823
+    }
2824
+
2825
+    for(int j = 0; j < except.length; j++)
2826
+    {
2827
+      except[j] = diffsEl.getChild(i).getChild(2).getChild(j).getContent();
2828
+    }
2829
+
2830
+    Diff diff = new Diff(contextName,intersects,except);
2831
+    diffs[i] = diff;
2832
+  }
2833
+  return diffs;
2834
+}
2835
+
2836
+Request request = parseRequest(doc);
2837
+Diff[] diffs = parseDiffs(doc);
2838
+Context[] contexts = parseProfile(doc);
2839
+
2840
+//magic numbers
2841
+float contextSize = 500;//random(50,100); //random between 50 and 100
2842
+float requestSize = 50;
2843
+float eqd_angle = TWO_PI / contexts.length;
2844
+float PROPORTION_CENTER = 0.6;
2845
+float DISTANCE_FACTOR = 1.4;
2846
+
2847
+//globals
2848
+float centerX, centerY;
2849
+float xOffset, yOffset;
2850
+float requestX, requestY;//request coordinates, they can move
2851
+boolean hitRequest = false;
2852
+boolean dragging = false;
2853
+int hitContext = -1;
2854
+int currentContext = 1;//first context is the default context
2855
+PFont font;
2856
+PFont titleFont;
2857
+
2858
+void setup()
2859
+{
2860
+  size(800,800);
2861
+  rectMode(RADIUS);
2862
+  smooth();
2863
+  
2864
+  titleFont = createFont("HelveticaNeue", 20);
2865
+  font = createFont("HelveticaNeue", 14);
2866
+  
2867
+  centerX = width/2;
2868
+  centerY = height/2;
2869
+  
2870
+  //TODO: calculate most relevant sector for the request
2871
+  PVector position = positionForSectorIndex(1);
2872
+  requestX = position.x;
2873
+  requestY = position.y;
2874
+}
2875
+
2876
+//the position should be outside the center of the middle of the sector
2877
+PVector positionForSectorIndex(int index)
2878
+{
2879
+  float angle = (PI/2) + (index * eqd_angle) + (eqd_angle/2);
2880
+  float x = centerX + (contextSize/2 * DISTANCE_FACTOR) * cos(angle); //calculate xPos
2881
+  float y = centerY + (contextSize/2 * DISTANCE_FACTOR) * sin(angle); //calculate yPos
2882
+  
2883
+  return new PVector(x,y);
2884
+}
2885
+
2886
+void draw()
2887
+{
2888
+  background(255);
2889
+  drawTitle();
2890
+}
2891
+
2892
+void drawTitle()
2893
+{
2894
+  //title
2895
+  textFont(titleFont);
2896
+  fill(150);
2897
+  textAlign(CENTER);
2898
+  text("Do you want to get *****d by Facebook?\nPlease drag the request on to your preferred context." , centerX, 80);
2899
+}
2900
+</script> <canvas id="ob-b08b9ab6dca87cd6f3682e15abf24f929a90a794"></canvas>
2901
+#+END_EXPORT
2902
+