[Question]
  [
Little Chandler is sad. Draw him a cloud to cheer him up.  
*Note: Drawing a cloud won't actually cheer him up.*
A circle can be defined as a 3-tuple `(x,y,r)` where `x` is the x position of the circle on a Cartesian plane, `y` is the y position of the circle on a Cartesian plane, and `r` is the radius of the circle. `x` and `y` may be negative. `r` is always positive. The input is a list of circles in the form of space separated 3-tuples. For instance:
```
3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8
```
The `3,1,1` means "A circle with centre point at `3,1` with 1 radius. `3,2,1.5` means "A circle with centre point at `3,2` with 1.5 radius.
If we draw all of these circles of the input on a graph, it looks like this (I've included grid lines and labels for clarity only; they are not required):
![Graph](https://i.stack.imgur.com/jyZzd.png)
Notice how all the circles are *cohesive*. That is, they're all overlapped together such that it forms one large group without any small groups of circles separated from the rest. The input is *guaranteed* to be cohesive. 
Suppose now we draw a line that travels around the "border" formed by these circles, without any of the other lines. It would be like drawing the border of the silhouette formed by all the circles. The resulting cloud would look something like this:
![cloud](https://i.stack.imgur.com/zDuUa.png "Yes, I know it looks nothing like a cloud. Just... use your imagination.")
So this cloud has been formed by drawing only the arcs of the circles in the input that form a border, resulting in a single shape. In other words, the cloud is formed by only drawing the arcs that are not within another circle. Your program will take in input in the form explained above, and output an image that displays the resulting cloud. The overall shape of the cloud must be correct, but the scale, colour, line thickness, and how it looks at vertexes is up to you. Note that the cloud must be visible, so you can't pull something like "This program draws a white cloud on a white background", "This program draws a cloud at a infinitesimally small scale", "This program draws a cloud with 0 line thickness", etc. Also note that the colour of the border must be different from the colour of the fill or background.
Another example. Input: 
```
1,4,2 5,2,1 3,1,1 3.5,2,1.2 3,3,0.7 1,2,0.7
```
Output:
![cloud2](https://i.stack.imgur.com/mLzXk.png)
If there is a "hole" in the cloud, you should draw the hole as well. Input:
```
0,5,4 3,4,4 4,3,4 5,0,4 4,-3,4 3,-4,4 0,-5,4 -3,-4,4 -4,-3,4 -5,0,4 -4,3,4 -3,4,4 
```
Output:
![cloud3](https://i.stack.imgur.com/F5K2j.png)
Here is an important rule: your program must draw *only* the lines that form the border. This means that you CANNOT simply draw the circles fully, and then draw the circles slightly smaller with a white fill -- because that method still draws lines that don't form a border, it just covers them up afterwards. The purpose of the rule was to prevent the "draw the circles, then draw the circles again with a white fill" implementations, or anything similar to that. The answer is expected to actually calculate where to draw things before drawing it.
This is code golf, so the shortest character count wins. 
  
[Answer]
# T-SQL ~~235~~ ~~234~~ ~~229~~ ~~212~~ ~~171~~ 73 bytes
This makes use of spatial functionality in SQL Server 2012+. When it is run in SSMS (SQL Server Management Studio) is produces a spatial results pane.
~~The input is from variable @i. I could reduce it further if the input could be taken from a table.~~
Since table input is now allowed.
```
SELECT Geometry::UnionAggregate(Geometry::Point(X,Y,0).STBuffer(R))FROM A
```
I've left the previous solution below.
```
DECLARE @ VARCHAR(999)='WITH a AS(SELECT *FROM(VALUES('+REPLACE(@i,' ','),(')+'))A(X,Y,R))SELECT Geometry::UnionAggregate(Geometry::Point(X,Y,0).STBuffer(R))FROM a'EXEC(@)
```
**Edit**: Remove stray space, surplus **into** and subquery
171: Replaced table creation with CTE and @s with @.
![enter image description here](https://i.stack.imgur.com/0wRot.png)
Break down of the Dynamic SQL
```
DECLARE @i VARCHAR(100) = '1,4,2 5,2,1 3,1,1 3.5,2,1.2 3,3,0.7 1,2,0.7' -- Input
DECLARE @ VARCHAR(999) = '
WITH a AS(                                       --CTE to produce rows of x,y,r 
    SELECT *FROM(VALUES('+
        REPLACE(@i,' ','),(')                    --Format @i to a value set
        +'))A(X,Y,R)
)
SELECT Geometry::UnionAggregate(                 --Aggregate Buffered Points
    Geometry::Point(X,Y,0).STBuffer(R)           --Create point and buffer
    )               
FROM a                                           --from the table variable
'
EXEC(@)                                          --Execute Dynamic sql
```
[Answer]
# Mathematica ~~177 126 121~~ 119
## Solving by Disk Regions: the mathematician's approach
The logic is to 
* Create Region 1 (R1), the circles (without their interiors);
* Create Region 2 (R2), the disks (without the circle borders).
* Create Region 3 (R3 = R1-R2).
 - 
![region inference](https://i.stack.imgur.com/ZPHQQ.png)
This is precisely the approach taken below. It produced the 3 figures above.
```
input = "3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8";
circles = ((x - #)^2 + (y - #2)^2 == #3^2) & @@@ 
     ToExpression[#~StringSplit~","] &@(StringSplit@input);
R1 = ImplicitRegion[Or @@ circles, {x, y}];
r1 = RegionPlot[R1, PlotLabel -> "R1: circles containing borders", 
   AspectRatio -> 1, PlotRange -> {{-1, 5}, {-1, 5}}];
innerDisks = ((x - #)^2 + (y - #2)^2 < #3^2) & @@@ 
     ToExpression[#~StringSplit~","] &@(StringSplit@input);
R2 = ImplicitRegion[Or @@ innerDisks, {x, y}];
r2 = RegionPlot[R2, PlotLabel -> "R2: disks within circle borders", 
   AspectRatio -> 1, PlotRange -> {{-1, 5}, {-1, 5}}];
R3 = RegionDifference[R1, R2]
r3 = RegionPlot[R3, PlotLabel -> "R3 = R1-R2", AspectRatio -> 1, 
   PlotRange -> {{-1, 5}, {-1, 5}}];
GraphicsGrid[{{r1, r2, r3}}, ImageSize -> 600]
```
Implicit region #1 is the union of the circles.
Implicit region #2 is the union of the disks lying within the circles.
Their difference is the border.
> 
> RegionDifference[  
> 
>  ImplicitRegion[(-3 + x)^2 + (-1 + y)^2 == 
>  1 || (-3 + x)^2 + (-2 + y)^2 == 2.25 || (-1 + x)^2 + (-2 + y)^2 ==
>  0.49 || (-0.9 + x)^2 + (-1.2 + y)^2 == 
>  1.44 || (-1 + x)^2 + y^2 == 0.64, {x, y}],  
> 
>  ImplicitRegion[(-3 + x)^2 + (-1 + y)^2 < 
>  1 || (-3 + x)^2 + (-2 + y)^2 < 2.25 || (-1 + x)^2 + (-2 + y)^2 < 
>  0.49 || (-0.9 + x)^2 + (-1.2 + y)^2 < 1.44 || (-1 + x)^2 + y^2 < 
>  0.64, {x, y}]]
> 
> 
> 
---
## Solving by Disk Regions: the engineer's approach (119 chars)
The following takes the union of the disk regions,
discretizes that region, and finds it's boundary. The points in the diagram demarcate the intervals of the Delaunay mesh. We display the discretized region below to highlight the object that furnishes the boundary of interest (the outline of the cloud). 
```
s = StringSplit;RegionBoundary@DiscretizeRegion[RegionUnion[Disk[{#, #2}, #3] &@@@
ToExpression[#~s~","] &@(s@InputString[])]]
```
**"3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8"**
The region boundary is discretized.
![reg1](https://i.stack.imgur.com/dd5Ab.png)
---
## Solving by Detecting Edges: The Photographer's Approach - 121 chars
![edge detection](https://i.stack.imgur.com/pEgcG.png)
It draws the disks in black, rasterizes the image, detects the edges, and inverts black and white.
```
s=StringSplit;ColorNegate@EdgeDetect@Rasterize@Graphics[Disk[{#,#2},#3]&@@@
((ToExpression/@s[#,","])&/@s[InputString[]])]
```
[Answer]
## Mathematica, ~~175~~ ~~158~~ 149 bytes
```
s=StringSplit;l=ToExpression[#~s~","]&@s@InputString[];RegionPlot[Or@@(Norm@{x-#,y-#2}<#3&@@@l),{x,m=Min@(k={{##}-#3,{##}+#3}&@@@l),M=Max@k},{y,m,M}]
```
I remember from discussion in the sandbox that this approach was supposed to be valid, but I'm not entirely sure how it sits with the new wording of the rules, so @Lilac, let me know if you think this violates the rules.
Basically, I'm creating a logical condition which is true for all points inside the cloud and false for all points outside it. I'm feeding that to `RegionPlot` which then renders the region of all points where the expression is `True` as well as an outline around it.
![enter image description here](https://i.stack.imgur.com/NLLEw.png)
Ungolfed:
```
s = StringSplit;
l = ToExpression[#~s~","] &@s@InputString[];
RegionPlot[
 Or @@ (Norm@{x - #, y - #2} < #3 & @@@ l), 
 {x, m = Min@(k = {{##} - #3, {##} + #3} & @@@ l), M = Max@k},
 {y, m, M}
]
```
[Answer]
## Python 3.3 (183 177 164 160 bytes)
```
B=list(map(eval,input().split()))
print("".join(" ## "[sum(any(r*r>(x-d%80/4+10)**2+(y+d//80/4-10)**2for
x,y,r in B)for d in[i,i+1,i+80])]for i in range(6400)))
```
It requires an 80 character wide console, which I know is the default in Windows. It works best if your console has a square font. Here are some excerpts from some of the test inputs.
**Original:**
```
           ########
          ##       #
         ##         #
     #####          #
    ##   #          #
   ##               #
  ##                #
 ##                 #
 #                  #
 #                 ##
  #               ##
  #       ##      #
   #      # #    ##
   #      #  #####
   #      #
    #    ##
     #  ##
      ###
```
**Another:**
```
    ########
  ###       ##
 ##           #
 #            #
##             #
#              #
#              #
#              #
#              #
#               ##
#                 #
 #                 ##
 #                   ######
  #                        #
   ##      ###             #
     #    ## #             #
     #    #  #             #
      #  ## ##             #
       ###  #             ##
            #       #######
            #      ##
            #      #
             #    ##
              #####
```
**Hole:**
```
                              ############
                            ###           ##
                          ###               ##
                         ##                   #
                  ########                     #######
                ###                                   ##
              ###                                       ##
             ##                                           #
            ##                                             #
           ##                                               #
          ##                                                 #
         ##                                                   #
        ##                                                     #
       ##                                                       #
      ##                                                         #
      #                                                          #
     ##                                                           #
     #                                                            #
    ##                                                             #
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
   ##                                                               #
  ##                                                                 #
  #                                                                  #
 ##                                                                   #
 #                                                                    #
##                                                                     #
#                                 ####                                 #
#                                ##   #                                #
#                               ##     #                               #
#                              ##       #                              #
#                              #        #                              #
#                              #        #                              #
#                               #      ##                              #
#                                #    ##                               #
#                                 #  ##                                #
#                                  ###                                 #
 #                                                                    ##
 #                                                                    #
  #                                                                  ##
  #                                                                  #
   #                                                                ##
    #                                                              ##
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
    #                                                              #
     #                                                            ##
     #                                                            #
      #                                                          ##
      #                                                          #
       #                                                        ##
        #                                                      ##
         #                                                    ##
          #                                                  ##
           #                                                ##
            #                                              ##
             #                                            ##
              #                                          ##
               ##                                      ###
                 ##                                  ###
                   #######                    ########
                          #                  ##
                           ##              ###
                             ##          ###
                               ###########
```
[Answer]
# Python - ~~253~~ ~~249~~ ~~215~~ 199
This is an advertisement for the awesome [shapely](https://pypi.python.org/pypi/Shapely) library, whose geometry operations made writing the solution straightforward by drawing the outline(s) of the union of overlapping circles (=buffered points):
```
from pylab import*
from shapely.geometry import*
c=Point()
for s in raw_input().split():
 x,y,r=eval(s)
 c=c.union(Point(x,y).buffer(r))
plot(*c.exterior.xy)
for i in c.interiors:
 plot(*i.xy)
show()
```
Output:
![three clouds](https://i.stack.imgur.com/rxcqN.png)
Edit(s):
* 249: Replaced `sys.argv[1:]` by `raw_input().split()`, saving a `import sys`
* 215: Removed `k={'color':'k'}` luxury, replaced `savefig` by `show`
* 199: Replaced `map(float,s.split(','))` by `eval(s)`
[Answer]
## Python – 535
```
import math as m
import matplotlib.pyplot as l
c = "3,1,1 3,2,1.5 1,2,0.7 0.9,1.2,1.2 1,0,0.8"
a = [[float(y) for y in x.split(",")] for x in c.split(" ")]
for a2 in a:
    for x in xrange(0,200):
        q=x*m.pi/100.0
        p=(a2[0]+m.sin(q)*a2[2], a2[1]+m.cos(q)*a2[2])
        cc = []
        for z in a:            
            if z != a2:               
                if ((z[0] - p[0]) ** 2 + (z[1] - p[1]) ** 2 ) < (z[2] ** 2) :
                    cc.append(z)
        if not cc: 
            l.scatter(p[0],p[1])
l.show()
```
[Answer]
## Python – ~~296~~ ~~249~~ ~~231~~ ~~223~~ 212
```
from pylab import*
a=map(eval,raw_input().split())
for x,y,r in a:
 for i in range(200):
  q=i*pi/100;p=x+r*sin(q);t=y+r*cos(q);[z for z in a if z!=(x,y,r)and(z[0]-p)**2+(z[1]-t)**2<z[2]**2]or scatter(p,t)
show()
```
Credit goes to [@richard-green](https://codegolf.stackexchange.com/users/31714/richard-green) (permission was given) for the original solution, I've just whittled it down a bit.
[Answer]
# JavaScript (E6) + HTML 322
[JSFiddle](http://jsfiddle.net/e6kLsurq/3/)
Each circle is subdivided in about 100 small arcs, and each arc is drawn if its middle point is not inside any of the other circles.
```
<canvas id='c'/>
<script>
t=c.getContext("2d"),z=99,c.width=c.height=400,
l=prompt().split(' ').map(c=>c.split(',').map(v=>40*v)),
l.map(c=>{
  for(i=z;--i+z;)
    s=4/z,r=c[2],x=c[0]+r*Math.cos(a=i*s),y=c[1]+r*Math.sin(a),
    t.beginPath(),
    l.some(q=>c!=q&(d=x-q[0],e=y-q[1],d*d+e*e<q[2]*q[2]))||t.arc(z+c[0],z+c[1],r,a-s,a+s),
    t.stroke()
})
</script>
```
[Answer]
# Python 274 bytes
This takes input from stdin and checks every point on the display, drawing the pixels one by one as it goes. Not exactly efficient but it follows all the rules.
```
c=[eval(s)for s in raw_input().split()]
import pygame
S=pygame.display.set_mode((500,500))
S.fill([255]*3)
for p in((x,y)for x in range(500)for y in range(500)if 0<min((((x-250)/25.-a)**2+((y-250)/25.-b)**2)**.5-r for(a,b,r)in c)<.1):S.set_at(p,[0]*3)
pygame.display.update()
```
Note that the pygame display will terminate as soon as the drawing is complete, I wasn't sure if I should include it as part of my answer but to view it you can either throw a `raw_input` in at the end or add a little loop if you want to stop the OS from complaining about it not responding and such:
```
alive = True
while alive:
    pygame.display.update()
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            alive = False
```
Example images:
`1,4,2 5,2,1 3,1,1 3.5,2,1.2 3,3,0.7, 1,2,0.7`
![enter image description here](https://i.stack.imgur.com/OD9PM.png)
`0,5,4 3,4,4 4,3,4 5,0,4 4,-3,4 3,-4,4 0,-5,4 -3,-4,4 -4,-3,4 -5,0,4 -4,3,4 -3,4,4`
![enter image description here](https://i.stack.imgur.com/TsEQE.png)
[Answer]
## Perl - 430
```
@e=map{[map{int($_*32)}split',']}(split' ',<>);for$g(@e){for(0..3){($a[$_]>($q=$$g[$_&1]+(($_>>1)*2-1)*$$g[2]))^($_>>1)&&($a[$_]=$q)}}for(2,3){$a[$_]-=$a[$_-2]-1}for(@e){($x,$y,$r)=@$_;$x-=$a[0];$y-=$a[1];for$k($x-$r..$x+$r){for$l($y-$r..$y+$r){$i=(int(sqrt(($x-$k)**2+($y-$l)**2)+0.5)<=>$r)-1;$f[$l][$k]=($j=$f[$l][$k])<-1||$i<-1?-2:$i||$j;}}}print"P1
$a[2] $a[3]
".join("
",map{join' ',map{$_+1?0:1}@$_,('0')x($a[2]-@$_)}@f)."
"
```
Writes a pbm file to stdout.
Test image (converted to png):
![Second test image (converted to png)](https://i.stack.imgur.com/u0RKo.png)
]