def draw_cornu_bezier(x0, y0, t0, t1, s0, c0, flip, cs, ss, cmd, scale, rot):

s = None<EOL>for j in range(<NUM_LIT:0>, <NUM_LIT:5>):<EOL><INDENT>t = j * <NUM_LIT><EOL>t2 = t+ <NUM_LIT><EOL>curvetime = t0 + t * (t1 - t0)<EOL>curvetime2 = t0 + t2 * (t1 - t0)<EOL>Dt = (curvetime2 - curvetime) * scale<EOL>if not s:<EOL><INDENT>s, c = eval_cornu(curvetime)<EOL>s *= flip<EOL>s -= s0<EOL>c -= c0<EOL>dx1 =  cos(pow(curvetime, <NUM_LIT:2>) + (flip * rot))  <EOL>dy1 =  flip * sin(pow(curvetime, <NUM_LIT:2>) + (flip *rot))<EOL>x = ((c * cs - s * ss) +x0)<EOL>y = ((s * cs + c * ss) + y0)<EOL><DEDENT>s2,c2 = eval_cornu(curvetime2) <EOL>s2 *= flip<EOL>s2 -= s0<EOL>c2 -= c0<EOL>dx2 = cos(pow(curvetime2, <NUM_LIT:2>) + (flip * rot)) <EOL>dy2 = flip * sin(pow(curvetime2, <NUM_LIT:2>) + (flip * rot))<EOL>x3 = ((c2 * cs - s2 * ss)+x0)<EOL>y3 = ((s2 * cs + c2 * ss)+y0)<EOL>x1 = (x + ((Dt/<NUM_LIT>) * dx1))<EOL>y1 = (y + ((Dt/<NUM_LIT>) * dy1))   <EOL>x2 = (x3 - ((Dt/<NUM_LIT>) * dx2))<EOL>y2 = (y3 - ((Dt/<NUM_LIT>) * dy2))<EOL>if cmd == '<STR_LIT>':<EOL><INDENT>print_pt(x, y, cmd)<EOL>cmd = '<STR_LIT>'<EOL><DEDENT>print_crv(x1, y1, x2, y2, x3, y3)<EOL>dx1, dy1 = dx2, dy2<EOL>x,y = x3, y3<EOL><DEDENT>return cmd<EOL>

Mark Meyer's code draws elegant CURVETO segments.


def draw_cornu_flat(x0, y0, t0, t1, s0, c0, flip, cs, ss, cmd):

for j in range(<NUM_LIT:0>, <NUM_LIT:100>):<EOL><INDENT>t = j * <NUM_LIT><EOL>s, c = eval_cornu(t0 + t * (t1 - t0))<EOL>s *= flip<EOL>s -= s0<EOL>c -= c0<EOL>x = c * cs - s * ss<EOL>y = s * cs + c * ss<EOL>print_pt(x0 + x, y0 + y, cmd)<EOL>cmd = '<STR_LIT>'<EOL><DEDENT>return cmd<EOL>

Raph Levien's code draws fast LINETO segments.


def overlap(self, x1, y1, x2, y2, r=<NUM_LIT:5>):

if abs(x2-x1) < r and abs(y2-y1) < r:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT>

Returns True when point 1 and point 2 overlap.

        There is an r treshold in which point 1 and point 2
        are considered to overlap.


a = degrees( atan((y1-y0) / (x1-x0+<NUM_LIT>)) ) + <NUM_LIT><EOL>if x1-x0 < <NUM_LIT:0>: a += <NUM_LIT><EOL>return a<EOL>

Calculates the angle between two points.


x, y = mouse()<EOL>if self.show_grid:<EOL><INDENT>x, y = self.grid.snap(x, y)<EOL><DEDENT>if _ctx._ns["<STR_LIT>"]and not self.freehand:<EOL><INDENT>self._dirty = True<EOL>if self.edit != Noneand not self.drag_pointand not self.drag_handle1and not self.drag_handle2:<EOL><INDENT>pt = self._points[self.edit]<EOL>dx = pt.x+self.btn_x<EOL>dy = pt.y+self.btn_y<EOL>if self.overlap(dx, dy, x, y, r=self.btn_r):<EOL><INDENT>self.delete = self.edit<EOL>return<EOL><DEDENT>dx += self.btn_r*<NUM_LIT:2> + <NUM_LIT:2><EOL>if self.edit == len(self._points) -<NUM_LIT:1> andself.overlap(dx, dy, x, y, r=self.btn_r):<EOL><INDENT>self.moveto = self.edit<EOL>return<EOL><DEDENT><DEDENT>if self.insert:<EOL><INDENT>self.inserting = True<EOL>return<EOL><DEDENT>if not self.drag_point andnot self.drag_handle1 andnot self.drag_handle2:<EOL><INDENT>self.editing = False<EOL>indices = range(len(self._points))<EOL>indices.reverse()<EOL>for i in indices:<EOL><INDENT>pt = self._points[i]<EOL>if pt != self.newand self.overlap(x, y, pt.x, pt.y)and self.new == None:<EOL><INDENT>if self.edit == i+<NUM_LIT:1>and self.overlap(self._points[i+<NUM_LIT:1>].ctrl1.x,<EOL>self._points[i+<NUM_LIT:1>].ctrl1.y, x, y):<EOL><INDENT>continue<EOL><DEDENT>else:<EOL><INDENT>self.edit = i<EOL>self.editing = True<EOL>break<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if not self.editing:<EOL><INDENT>if self.edit != None:<EOL><INDENT>pt = self._points[self.edit]<EOL>if self.overlap(pt.ctrl1.x, pt.ctrl1.y, x, y) orself.overlap(pt.ctrl2.x, pt.ctrl2.y, x, y):<EOL><INDENT>self.editing = True<EOL><DEDENT>else:<EOL><INDENT>self.edit = None<EOL><DEDENT><DEDENT><DEDENT>if self.edit == None:<EOL><INDENT>if self.new == None:<EOL><INDENT>self.new = PathElement()<EOL>if self.moveto == Trueor len(self._points) == <NUM_LIT:0>:<EOL><INDENT>cmd = MOVETO<EOL>self.moveto = None<EOL>self.last_moveto = self.new<EOL><DEDENT>else:<EOL><INDENT>cmd = CURVETO<EOL><DEDENT>self.new.cmd = cmd<EOL>self.new.x = x<EOL>self.new.y = y<EOL>self.new.ctrl1 = Point(x, y)<EOL>self.new.ctrl2 = Point(x, y)<EOL>self.new.freehand = False<EOL>if len(self._points) > <NUM_LIT:0>:<EOL><INDENT>prev = self._points[-<NUM_LIT:1>]<EOL>rx, ry = self.reflect(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)<EOL>self.new.ctrl1 = Point(rx, ry)<EOL><DEDENT>self._points.append(self.new)<EOL><DEDENT>else:<EOL><INDENT>rx, ry = self.reflect(self.new.x, self.new.y, x, y)<EOL>self.new.ctrl2 = Point(rx, ry)<EOL><DEDENT><DEDENT>elif self.new == None:<EOL><INDENT>pt = self._points[self.edit]<EOL>if self.overlap(pt.x, pt.y, x, y)and not self.drag_handle1and not self.drag_handle2and not self.new != None:<EOL><INDENT>self.drag_point = True<EOL>self.drag_handle1 = False<EOL>self.drag_handle2 = False<EOL><DEDENT>if self.overlap(pt.ctrl1.x, pt.ctrl1.y, x, y)and pt.cmd == CURVETOand not self.drag_pointand not self.drag_handle2:<EOL><INDENT>self.drag_point = False<EOL>self.drag_handle1 = True<EOL>self.drag_handle2 = False<EOL><DEDENT>if self.overlap(pt.ctrl2.x, pt.ctrl2.y, x, y)and pt.cmd == CURVETOand not self.drag_pointand not self.drag_handle1:<EOL><INDENT>self.drag_point = False<EOL>self.drag_handle1 = False<EOL>self.drag_handle2 = True<EOL><DEDENT>if self.drag_point == True:<EOL><INDENT>dx = x - pt.x<EOL>dy = y - pt.y<EOL>pt.x = x<EOL>pt.y = y<EOL>pt.ctrl2.x += dx<EOL>pt.ctrl2.y += dy<EOL>if self.edit < len(self._points)-<NUM_LIT:1>:<EOL><INDENT>rx, ry = self.reflect(pt.x, pt.y, x, y)<EOL>next = self._points[self.edit+<NUM_LIT:1>]<EOL>next.ctrl1.x += dx<EOL>next.ctrl1.y += dy<EOL><DEDENT><DEDENT>if self.drag_handle1 == True:<EOL><INDENT>pt.ctrl1 = Point(x, y)<EOL>if self.edit > <NUM_LIT:0>and self.last_key != "<STR_LIT:x>":<EOL><INDENT>prev = self._points[self.edit-<NUM_LIT:1>]<EOL>d = self.distance(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)<EOL>a = self.angle(prev.x, prev.y, pt.ctrl1.x, pt.ctrl1.y)<EOL>prev.ctrl2 = self.coordinates(prev.x, prev.y, d, a+<NUM_LIT>)                        <EOL><DEDENT><DEDENT>if self.drag_handle2 == True:   <EOL><INDENT>pt.ctrl2 = Point(x, y)<EOL>if self.edit < len(self._points)-<NUM_LIT:1>and self.last_key != "<STR_LIT:x>":<EOL><INDENT>next = self._points[self.edit+<NUM_LIT:1>]<EOL>d = self.distance(pt.x, pt.y, next.ctrl1.x, next.ctrl1.y)<EOL>a = self.angle(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)<EOL>next.ctrl1 = self.coordinates(pt.x, pt.y, d, a+<NUM_LIT>)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>elif not self.freehand:<EOL><INDENT>self.new = None<EOL>self.drag_point = False<EOL>self.drag_handle1 = False<EOL>self.drag_handle2 = False<EOL>if self.delete != None and len(self._points) > <NUM_LIT:0>:<EOL><INDENT>i = self.delete<EOL>cmd = self._points[i].cmd<EOL>del self._points[i]<EOL>if <NUM_LIT:0> < i < len(self._points):<EOL><INDENT>prev = self._points[i-<NUM_LIT:1>]<EOL>rx, ry = self.reflect(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)<EOL>self._points[i].ctrl1 = Point(rx, ry)<EOL><DEDENT>start_i = i<EOL>while i > <NUM_LIT:1>:<EOL><INDENT>i -= <NUM_LIT:1><EOL>pt = self._points[i]<EOL>if pt.freehand:<EOL><INDENT>del self._points[i]<EOL><DEDENT>elif i < start_i-<NUM_LIT:1> and pt.freehand == False:<EOL><INDENT>if pt.cmd == MOVETO:<EOL><INDENT>del self._points[i]<EOL><DEDENT>break<EOL><DEDENT><DEDENT>if len(self._points) > <NUM_LIT:0>and (cmd == MOVETO or i == <NUM_LIT:0>):<EOL><INDENT>self.last_moveto = self._points[<NUM_LIT:0>]<EOL>for pt in self._points:<EOL><INDENT>if pt.cmd == MOVETO:<EOL><INDENT>self.last_moveto = pt<EOL><DEDENT><DEDENT><DEDENT>self.delete = None<EOL>self.edit = None<EOL><DEDENT>elif isinstance(self.moveto, int):<EOL><INDENT>self.moveto = True<EOL>self.edit = None<EOL><DEDENT>elif self.edit == Noneand self.contains_point(x, y, d=<NUM_LIT:2>):<EOL><INDENT>self.insert = True<EOL><DEDENT>else:<EOL><INDENT>self.insert = False<EOL><DEDENT>if self.insertingand self.contains_point(x, y, d=<NUM_LIT:2>): <EOL><INDENT>self.insert_point(x, y)<EOL>self.insert = False<EOL><DEDENT>self.inserting = False<EOL>if self._dirty == True:<EOL><INDENT>self.export_svg()<EOL>self._dirty = False<EOL><DEDENT><DEDENT>if _ctx._ns["<STR_LIT>"]:<EOL><INDENT>self.last_key = _ctx._ns["<STR_LIT:key>"]<EOL>self.last_keycode = _ctx._ns["<STR_LIT>"]<EOL><DEDENT>if not _ctx._ns["<STR_LIT>"] and self.last_key != None:<EOL><INDENT>if self.last_keycode == KEY_TAB:<EOL><INDENT>self.show_grid = not self.show_grid<EOL><DEDENT>if self.last_key == "<STR_LIT:f>":<EOL><INDENT>self.edit = None<EOL>self.freehand = not self.freehand<EOL>if self.freehand:<EOL><INDENT>self.msg = "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>self.msg = "<STR_LIT>"<EOL><DEDENT><DEDENT>if self.last_keycode == KEY_ESC:<EOL><INDENT>self.edit = None<EOL><DEDENT>if self.last_keycode == _ctx.KEY_BACKSPACEand self.edit != None:<EOL><INDENT>self.delete = self.edit<EOL><DEDENT>self.last_key = None<EOL>self.last_code = None<EOL><DEDENT>if _ctx._ns["<STR_LIT>"]:<EOL><INDENT>dx = <NUM_LIT:0><EOL>dy = <NUM_LIT:0><EOL>keycode = _ctx._ns["<STR_LIT>"]<EOL>if keycode == _ctx.KEY_LEFT:<EOL><INDENT>dx = -<NUM_LIT:10><EOL><DEDENT>elif keycode == _ctx.KEY_RIGHT:<EOL><INDENT>dx = <NUM_LIT:10><EOL><DEDENT>if keycode == _ctx.KEY_UP:<EOL><INDENT>dy = -<NUM_LIT:10><EOL><DEDENT>elif keycode == _ctx.KEY_DOWN:<EOL><INDENT>dy = <NUM_LIT:10><EOL><DEDENT>if dx != <NUM_LIT:0> or dy != <NUM_LIT:0>:<EOL><INDENT>for pt in self._points:<EOL><INDENT>pt.x += dx<EOL>pt.y += dy<EOL>pt.ctrl1.x += dx<EOL>pt.ctrl1.y += dy<EOL>pt.ctrl2.x += dx<EOL>pt.ctrl2.y += dy<EOL><DEDENT><DEDENT><DEDENT>

Update runs each frame to check for mouse interaction.

        Alters the path by allowing the user to add new points,
        drag point handles and move their location.
        Updates are automatically stored as SVG
        in the given filename.


<EOL>self.update()<EOL>x, y = mouse()<EOL>if self.show_grid:<EOL><INDENT>self.grid.draw()<EOL>x, y = self.grid.snap(x, y)<EOL><DEDENT>_ctx.strokewidth(self.strokewidth)<EOL>if self.freehand:<EOL><INDENT>self.draw_freehand()<EOL><DEDENT>r = <NUM_LIT:4><EOL>_ctx.nofill()<EOL>if len(self._points) > <NUM_LIT:0>:<EOL><INDENT>first = True            <EOL>for i in range(len(self._points)):<EOL><INDENT>pt = self._points[i]<EOL>if first:<EOL><INDENT>_ctx.beginpath(pt.x, pt.y)<EOL>first = False<EOL><DEDENT>else:<EOL><INDENT>if pt.cmd == CLOSE:<EOL><INDENT>_ctx.closepath()<EOL><DEDENT>elif pt.cmd == MOVETO:<EOL><INDENT>_ctx.moveto(pt.x, pt.y)<EOL><DEDENT>elif pt.cmd == LINETO:<EOL><INDENT>_ctx.lineto(pt.x, pt.y)<EOL><DEDENT>elif pt.cmd == CURVETO:<EOL><INDENT>_ctx.curveto(pt.ctrl1.x, pt.ctrl1.y, <EOL>pt.ctrl2.x, pt.ctrl2.y, <EOL>pt.x, pt.y)<EOL><DEDENT><DEDENT>if ((i == self.edit and self.new == None)or pt == self.new)and pt.cmd == CURVETOand not pt.freehand:<EOL><INDENT>_ctx.stroke(self.handle_color)<EOL>_ctx.nofill()<EOL>_ctx.oval(pt.x-r, pt.y-r, r*<NUM_LIT:2>, r*<NUM_LIT:2>)<EOL>_ctx.stroke(self.handle_color)<EOL>_ctx.line(pt.ctrl2.x, pt.ctrl2.y, pt.x, pt.y)<EOL>_ctx.fill(self.handle_color)<EOL><DEDENT>if pt == self.newand not pt.freehand:<EOL><INDENT>rx, ry = self.reflect(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)<EOL>_ctx.stroke(self.handle_color)<EOL>_ctx.line(rx, ry, pt.x, pt.y)<EOL>_ctx.nostroke()<EOL>_ctx.fill(self.handle_color)<EOL>_ctx.oval(rx-r/<NUM_LIT:2>, ry-r/<NUM_LIT:2>, r, r)<EOL><DEDENT>if i == self.editand self.new == Noneand pt.cmd == CURVETOand not pt.freehand:<EOL><INDENT>_ctx.oval(pt.ctrl2.x-r/<NUM_LIT:2>, pt.ctrl2.y-r/<NUM_LIT:2>, r, r)<EOL>if i > <NUM_LIT:0>:<EOL><INDENT>prev = self._points[i-<NUM_LIT:1>]<EOL>_ctx.line(pt.ctrl1.x, pt.ctrl1.y, prev.x, prev.y)<EOL>_ctx.oval(pt.ctrl1.x-r/<NUM_LIT:2>, pt.ctrl1.y-r/<NUM_LIT:2>, r, r)<EOL><DEDENT>if i > <NUM_LIT:0> and self._points[i-<NUM_LIT:1>].cmd != MOVETO:<EOL><INDENT>_ctx.line(prev.ctrl2.x, prev.ctrl2.y, prev.x, prev.y)<EOL><DEDENT>if i < len(self._points)-<NUM_LIT:1>:<EOL><INDENT>next = self._points[i+<NUM_LIT:1>]<EOL>if next.cmd == CURVETO:<EOL><INDENT>_ctx.line(next.ctrl1.x, next.ctrl1.y, pt.x, pt.y)<EOL><DEDENT><DEDENT><DEDENT>elif self.overlap(x, y, pt.x, pt.y)and not pt.freehand:<EOL><INDENT>self.insert = False <EOL>_ctx.nofill()<EOL>_ctx.stroke(self.handle_color)<EOL>_ctx.oval(pt.x-r, pt.y-r, r*<NUM_LIT:2>, r*<NUM_LIT:2>)<EOL><DEDENT>_ctx.fontsize(<NUM_LIT:9>)<EOL>_ctx.fill(self.handle_color)<EOL>txt = "<STR_LIT>"+str(int(pt.x))+"<STR_LIT:U+002CU+0020>"+str(int(pt.y))+"<STR_LIT:)>"<EOL>if (i == self.edit and self.new == None)or pt == self.newand not pt.freehand:<EOL><INDENT>_ctx.text(txt, pt.x+r, pt.y+<NUM_LIT:2>)                                       <EOL><DEDENT>elif self.overlap(x, y, pt.x, pt.y)and not pt.freehand:<EOL><INDENT>_ctx.text(txt, pt.x+r, pt.y+<NUM_LIT:2>)<EOL><DEDENT>if not pt.freehand:<EOL><INDENT>if pt.cmd != MOVETO:<EOL><INDENT>_ctx.fill(self.path_color)<EOL>_ctx.nostroke()<EOL><DEDENT>else:<EOL><INDENT>_ctx.stroke(self.path_color)<EOL>_ctx.nofill()<EOL><DEDENT>_ctx.oval(pt.x-r/<NUM_LIT:2>, pt.y-r/<NUM_LIT:2>, r, r)<EOL><DEDENT><DEDENT>_ctx.stroke(self.path_color)<EOL>_ctx.fill(self.path_fill)<EOL>_ctx.autoclosepath(False)    <EOL>p = _ctx.endpath()<EOL>self.path = p<EOL>if self.insert:<EOL><INDENT>_ctx.stroke(self.handle_color)<EOL>_ctx.nofill()<EOL>_ctx.oval(x-r*<NUM_LIT>, y-r*<NUM_LIT>, r*<NUM_LIT>, r*<NUM_LIT>)<EOL><DEDENT>if self.edit == Noneand self.new == Noneand self.moveto != Trueand not self.freehand:<EOL><INDENT>_ctx.nofill()<EOL>_ctx.stroke(self.new_color)<EOL>rx, ry = self.reflect(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)<EOL>_ctx.beginpath(pt.x, pt.y)<EOL>_ctx.curveto(rx, ry, x, y, x, y)<EOL>_ctx.endpath()<EOL>if self.last_moveto != None:<EOL><INDENT>start = self.last_moveto<EOL><DEDENT>else:<EOL><INDENT>start = self._points[<NUM_LIT:0>]<EOL><DEDENT>p = _ctx.line(x, y, start.x, start.y, draw=False)<EOL>try: p._nsBezierPath.setLineDash_count_phase_([<NUM_LIT:2>,<NUM_LIT:4>], <NUM_LIT:2>, <NUM_LIT:50>)<EOL>except:<EOL><INDENT>pass<EOL><DEDENT>_ctx.drawpath(p)<EOL><DEDENT>elif self.edit == Noneand self.new == Noneand self.moveto != None:<EOL><INDENT>_ctx.stroke(self.new_color)<EOL>_ctx.nofill()<EOL>_ctx.oval(x-r*<NUM_LIT>, y-r*<NUM_LIT>, r*<NUM_LIT>, r*<NUM_LIT>)<EOL><DEDENT>if self.edit != None:<EOL><INDENT>pt = self._points[self.edit]<EOL>x = pt.x + self.btn_x<EOL>y = pt.y + self.btn_y<EOL>r = self.btn_r<EOL>_ctx.nostroke()<EOL>_ctx.fill(<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT>)<EOL>_ctx.fill(self.handle_color)<EOL>_ctx.oval(x-r, y-r, r*<NUM_LIT:2>, r*<NUM_LIT:2>)<EOL>_ctx.fill(<NUM_LIT:1>)<EOL>_ctx.rotate(<NUM_LIT>)<EOL>_ctx.rect(x-r+<NUM_LIT:2>, y-<NUM_LIT>, r+<NUM_LIT:1>, <NUM_LIT>)<EOL>_ctx.rotate(-<NUM_LIT>)<EOL>_ctx.rect(x-r+<NUM_LIT:2>, y-<NUM_LIT>, r+<NUM_LIT:1>, <NUM_LIT>)<EOL>_ctx.reset()<EOL>if self.edit == len(self._points)-<NUM_LIT:1>:<EOL><INDENT>_ctx.fill(self.handle_color)<EOL>_ctx.oval(x+r*<NUM_LIT:2>+<NUM_LIT:2>-r, y-r, r*<NUM_LIT:2>, r*<NUM_LIT:2>)<EOL>_ctx.fill(<NUM_LIT:1>)<EOL>_ctx.rect(x+r*<NUM_LIT:2>+<NUM_LIT:2>-<NUM_LIT>, y-r+<NUM_LIT:3>, <NUM_LIT>, r-<NUM_LIT:1>)<EOL>_ctx.rect(x+r*<NUM_LIT:2>+<NUM_LIT:2>+<NUM_LIT>, y-r+<NUM_LIT:3>, <NUM_LIT>, r-<NUM_LIT:1>)<EOL><DEDENT><DEDENT><DEDENT>if self.msg != "<STR_LIT>":<EOL><INDENT>self.msg_alpha -= <NUM_LIT:0.1><EOL>_ctx.nostroke()<EOL>_ctx.fill(<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT:0>, self.msg_alpha)<EOL>_ctx.fontsize(<NUM_LIT>)<EOL>_ctx.lineheight(<NUM_LIT:1>)<EOL>w = _ctx.textwidth(self.msg)<EOL>_ctx.rect(_ctx.WIDTH/<NUM_LIT:2>-w/<NUM_LIT:2>-<NUM_LIT:9>, _ctx.HEIGHT/<NUM_LIT:2>-<NUM_LIT>, w+<NUM_LIT>, <NUM_LIT>, roundness=<NUM_LIT>)<EOL>_ctx.fill(<NUM_LIT:1>,<NUM_LIT:1>,<NUM_LIT:1>, <NUM_LIT>)<EOL>_ctx.align(CENTER) <EOL>_ctx.text(self.msg, <NUM_LIT:0>, _ctx.HEIGHT/<NUM_LIT:2>, width=_ctx.WIDTH)<EOL><DEDENT>if self.msg_alpha <= <NUM_LIT:0.0>:<EOL><INDENT>self.msg = "<STR_LIT>"<EOL>self.msg_alpha = <NUM_LIT:1.0><EOL><DEDENT>

Draws the editable path and interface elements.


def contains_point(self, x, y, d=<NUM_LIT:2>):

if self.path != None and len(self.path) > <NUM_LIT:1>and self.path.contains(x, y):<EOL><INDENT>if not self.path.contains(x+d, y)or not self.path.contains(x, y+d)or not self.path.contains(x-d, y)or not self.path.contains(x, y-d)or not self.path.contains(x+d, y+d)or not self.path.contains(x-d, y-d)or not self.path.contains(x+d, y-d)or not self.path.contains(x-d, y+d):<EOL><INDENT>return True<EOL><DEDENT><DEDENT>return False<EOL>

Returns true when x, y is on the path stroke outline.


return sqrt(pow(x1-x0, <NUM_LIT:2>) + pow(y1-y0, <NUM_LIT:2>))<EOL>

Calculates the distance between two points.


rx = x0 - (x-x0)<EOL>ry = y0 - (y-y0)<EOL>return rx, ry<EOL>

Reflects the point x, y through origin x0, y0.


if _ctx._ns["<STR_LIT>"]:<EOL><INDENT>x, y = mouse()<EOL>if self.show_grid:<EOL><INDENT>x, y = self.grid.snap(x, y)<EOL><DEDENT>if self.freehand_move == True:<EOL><INDENT>cmd = MOVETO<EOL>self.freehand_move = False<EOL><DEDENT>else:<EOL><INDENT>cmd = LINETO<EOL><DEDENT>pt = PathElement()<EOL>if cmd != MOVETO:<EOL><INDENT>pt.freehand = True <EOL><DEDENT>else:<EOL><INDENT>pt.freehand = False<EOL><DEDENT>pt.cmd = cmd<EOL>pt.x = x<EOL>pt.y = y<EOL>pt.ctrl1 = Point(x,y)<EOL>pt.ctrl2 = Point(x,y)<EOL>self._points.append(pt)<EOL>r = <NUM_LIT:4><EOL>_ctx.nofill()<EOL>_ctx.stroke(self.handle_color)<EOL>_ctx.oval(pt.x-r, pt.y-r, r*<NUM_LIT:2>, r*<NUM_LIT:2>)<EOL>_ctx.fontsize(<NUM_LIT:9>)<EOL>_ctx.fill(self.handle_color)<EOL>_ctx.text("<STR_LIT>"+str(int(pt.x))+"<STR_LIT:U+002CU+0020>"+str(int(pt.y))+"<STR_LIT:)>", pt.x+r, pt.y)<EOL>self._dirty = True<EOL><DEDENT>else:<EOL><INDENT>self.freehand_move = True<EOL>if self._dirty:<EOL><INDENT>self._points[-<NUM_LIT:1>].freehand = False<EOL>self.export_svg()<EOL>self._dirty = False<EOL><DEDENT><DEDENT>


import colorsys<EOL>p1 = list(img1.getdata())<EOL>p2 = list(img2.getdata())<EOL>for i in range(len(p1)):<EOL><INDENT>r1, g1, b1, a1 = p1[i]<EOL>r1 = r1 / <NUM_LIT><EOL>g1 = g1 / <NUM_LIT><EOL>b1 = b1 / <NUM_LIT><EOL>h1, s1, v1 = colorsys.rgb_to_hsv(r1, g1, b1)<EOL>r2, g2, b2, a2 = p2[i]<EOL>r2 = r2 / <NUM_LIT><EOL>g2 = g2 / <NUM_LIT><EOL>b2 = b2 / <NUM_LIT><EOL>h2, s2, v2 = colorsys.rgb_to_hsv(r2, g2, b2)<EOL>r3, g3, b3 = colorsys.hsv_to_rgb(h2, s2, v1)<EOL>r3 = int(r3*<NUM_LIT:255>)<EOL>g3 = int(g3*<NUM_LIT:255>)<EOL>b3 = int(b3*<NUM_LIT:255>)<EOL>p1[i] = (r3, g3, b3, a1)<EOL><DEDENT>img = Image.new("<STR_LIT>", img1.size, <NUM_LIT:255>)<EOL>img.putdata(p1)<EOL>return img<EOL>

Applies the color blend mode.

        Colorize image img1 with image img2.
        The color filter replaces the hue and saturation of pixels in img1
        with the hue and saturation of pixels in img2.
        Returns a composite image with the alpha channel retained.


self. interpolation = interpolation<EOL>

Settings that influence image manipulation.

        Currently, only defines the image interpolation,
        which can be set to NEAREST, BICUBIC or BILINEAR.


self.x = x<EOL>self.y = y<EOL>

Positions the layer at the given coordinates.

        The x and y parameters define where to position
        the top left corner of the layer,
        measured from the top left of the canvas.


layers.sort()<EOL>if layers[<NUM_LIT:0>] == <NUM_LIT:0>: del layers[<NUM_LIT:0>]<EOL>self.flatten(layers)<EOL>

Flattens the given layers on the canvas.

        Merges the given layers with the indices in the list
        on the bottom layer in the list.
        The other layers are discarded.


p1 = list(img1.getdata())<EOL>p2 = list(img2.getdata())<EOL>for i in range(len(p1)):<EOL><INDENT>p3 = ()<EOL>for j in range(len(p1[i])):<EOL><INDENT>a = p1[i][j] / <NUM_LIT><EOL>b = p2[i][j] / <NUM_LIT><EOL>if j == <NUM_LIT:3>:<EOL><INDENT>d = min(a,b)<EOL><DEDENT>elif a > <NUM_LIT:0.5>: <EOL><INDENT>d = <NUM_LIT:2>*(a+b-a*b)-<NUM_LIT:1><EOL><DEDENT>else: <EOL><INDENT>d = <NUM_LIT:2>*a*b            <EOL><DEDENT>p3 += (int(d*<NUM_LIT:255>),)<EOL><DEDENT>p1[i] = p3<EOL><DEDENT>img = Image.new("<STR_LIT>", img1.size, <NUM_LIT:255>)<EOL>img.putdata(p1)<EOL>return img<EOL>

Applies the overlay blend mode.

        Overlays image img2 on image img1.
        The overlay pixel combines multiply and screen:
        it multiplies dark pixels values and screen light values.
        Returns a composite image with the alpha channel retained.


self.flatten()<EOL>self.layers[<NUM_LIT:1>].img.save(filename)<EOL>return filename<EOL>

Exports the flattened canvas.

        Flattens the canvas.
        PNG retains the alpha channel information.
        Other possibilities are JPEG and GIF.


i = self.canvas.layer(self.img.copy(), self.x, self.y, self.name)<EOL>clone = self.canvas.layers[i]<EOL>clone.alpha = self.alpha<EOL>clone.blend = self.blend<EOL>

Creates a copy of the current layer.

        This copy becomes the top layer on the canvas.


def distort(self, x1=<NUM_LIT:0>,y1=<NUM_LIT:0>, x2=<NUM_LIT:0>,y2=<NUM_LIT:0>, x3=<NUM_LIT:0>,y3=<NUM_LIT:0>, x4=<NUM_LIT:0>,y4=<NUM_LIT:0>):

w, h = self.img.size<EOL>quad = (-x1,-y1, -x4,h-y4, w-x3,w-y3, w-x2,-y2)<EOL>self.img = self.img.transform(self.img.size, Image.QUAD, quad, INTERPOLATION)<EOL>

Distorts the layer.

        Distorts the layer by translating
        the four corners of its bounding box to the given coordinates:
        upper left (x1,y1), upper right(x2,y2),
        lower right (x3,y3) and lower left (x4,y4).


alpha = self.img.split()[<NUM_LIT:3>]<EOL>self.img = self.img.convert("<STR_LIT>")<EOL>self.img = ImageOps.invert(self.img)<EOL>self.img = self.img.convert("<STR_LIT>")<EOL>self.img.putalpha(alpha)<EOL>


self.img = self.img.filter(ImageFilter.BLUR)<EOL>


i = self.index()<EOL>if i != None: del self.canvas.layers[i]<EOL>


alpha = self.img.split()[<NUM_LIT:3>]<EOL>self.img = self.img.convert("<STR_LIT:L>")<EOL>self.img = self.img.convert("<STR_LIT>")<EOL>self.img.putalpha(alpha)<EOL>

Desaturates the layer, making it grayscale.

        Instantly removes all color information from the layer,
        while maintaing its alpha channel.


def gradient(self, style=LINEAR, w=<NUM_LIT:1.0>, h=<NUM_LIT:1.0>, name="<STR_LIT>"):

from types import FloatType<EOL>w0 = self.w <EOL>h0 = self.h<EOL>if type(w) == FloatType: w *= w0<EOL>if type(h) == FloatType: h *= h0<EOL>img = Image.new("<STR_LIT:L>", (int(w),int(h)), <NUM_LIT:255>)<EOL>draw = ImageDraw.Draw(img)<EOL>if style == LINEAR:<EOL><INDENT>for i in range(int(w)):<EOL><INDENT>k = <NUM_LIT> * i/w<EOL>draw.rectangle((i, <NUM_LIT:0>, i, h), fill=int(k))<EOL><DEDENT><DEDENT>if style == RADIAL:<EOL><INDENT>r = min(w,h)/<NUM_LIT:2><EOL>for i in range(int(r)):<EOL><INDENT>k = <NUM_LIT:255> - <NUM_LIT> * i/r<EOL>draw.ellipse((w/<NUM_LIT:2>-r+i, h/<NUM_LIT:2>-r+i, w/<NUM_LIT:2>+r-i, h/<NUM_LIT:2>+r-i), fill=int(k))<EOL><DEDENT><DEDENT>if style == DIAMOND:<EOL><INDENT>r = max(w,h)<EOL>for i in range(int(r)):<EOL><INDENT>x = int(i*w/r*<NUM_LIT:0.5>)<EOL>y = int(i*h/r*<NUM_LIT:0.5>)<EOL>k = <NUM_LIT> * i/r<EOL>draw.rectangle((x, y, w-x, h-y), outline=int(k))<EOL><DEDENT><DEDENT>img = img.convert("<STR_LIT>")<EOL>self.layer(img, <NUM_LIT:0>, <NUM_LIT:0>, name="<STR_LIT>")<EOL>

Creates a gradient layer.

        Creates a gradient layer, that is usually used
        together with the mask() function.

        All the image functions work on gradients,
        so they can easily be flipped, rotated, scaled, inverted,
        made brighter or darker, ...

        Styles for gradients are LINEAR, RADIAL and DIAMOND.


self.interpolation = BILINEAR<EOL>self.layers = Layers()<EOL>self.w = w<EOL>self.h = h<EOL>img = Image.new("<STR_LIT>", (w,h), (<NUM_LIT:255>,<NUM_LIT:255>,<NUM_LIT:255>,<NUM_LIT:0>))<EOL>self.layer(img, name="<STR_LIT>")<EOL>

Creates a new canvas.

        Creates the working area on which to blend layers.
        The canvas background is transparent,
        but a background color could be set using the fill() function.


i = self.index()<EOL>if i != None:<EOL><INDENT>del self.canvas.layers[i]<EOL>i = min(len(self.canvas.layers), i+<NUM_LIT:1>)<EOL>self.canvas.layers.insert(i, self)<EOL><DEDENT>

Moves the layer up in the stacking order.


if axis == HORIZONTAL:<EOL><INDENT>self.img = self.img.transpose(Image.FLIP_LEFT_RIGHT)<EOL><DEDENT>if axis == VERTICAL:<EOL><INDENT>self.img = self.img.transpose(Image.FLIP_TOP_BOTTOM)<EOL><DEDENT>

Flips the layer, either HORIZONTAL or VERTICAL.


import colorsys<EOL>p1 = list(img1.getdata())<EOL>p2 = list(img2.getdata())<EOL>for i in range(len(p1)):<EOL><INDENT>r1, g1, b1, a1 = p1[i]<EOL>r1 = r1 / <NUM_LIT><EOL>g1 = g1 / <NUM_LIT><EOL>b1 = b1 / <NUM_LIT><EOL>h1, s1, v1 = colorsys.rgb_to_hsv(r1, g1, b1)<EOL>r2, g2, b2, a2 = p2[i]<EOL>r2 = r2 / <NUM_LIT><EOL>g2 = g2 / <NUM_LIT><EOL>b2 = b2 / <NUM_LIT><EOL>h2, s2, v2 = colorsys.rgb_to_hsv(r2, g2, b2)<EOL>r3, g3, b3 = colorsys.hsv_to_rgb(h2, s1, v1)<EOL>r3 = int(r3*<NUM_LIT:255>)<EOL>g3 = int(g3*<NUM_LIT:255>)<EOL>b3 = int(b3*<NUM_LIT:255>)<EOL>p1[i] = (r3, g3, b3, a1)<EOL><DEDENT>img = Image.new("<STR_LIT>", img1.size, <NUM_LIT:255>)<EOL>img.putdata(p1)<EOL>return img<EOL>

Applies the hue blend mode.

        Hues image img1 with image img2.
        The hue filter replaces the hues of pixels in img1
        with the hues of pixels in img2.
        Returns a composite image with the alpha channel retained.


for i in range(len(self.canvas.layers)):<EOL><INDENT>if self.canvas.layers[i] == self: break<EOL><DEDENT>if self.canvas.layers[i] == self: <EOL><INDENT>return i<EOL><DEDENT>else:<EOL><INDENT>return None<EOL><DEDENT>

Returns this layer's index in the canvas.layers[].

        Searches the position of this layer in the canvas'
        layers list, return None when not found.


self._name = name.rstrip("<STR_LIT>")<EOL>from os import unlink<EOL>if overwrite: <EOL><INDENT>try: unlink(self._name + "<STR_LIT>")<EOL>except: pass       <EOL><DEDENT>self._con = sqlite.connect(self._name + "<STR_LIT>")<EOL>self._cur = self._con.cursor()<EOL>

Creates an SQLite database file.

        Creates an SQLite database with the given name.
        The .box file extension is added automatically.
        Overwrites any existing database by default.


self._commit = each<EOL>self._con.commit()<EOL>

Sets the commit frequency.

        Modifications to the database,
        e.g. row insertions are commited in batch,
        specified by the given number.
        A number that is reasonably high allows for faster transactions.
        Commits anything still pending.


sql = "<STR_LIT>"+self._key+"<STR_LIT>"+self._name<EOL>self._db._cur.execute(sql)<EOL>i = <NUM_LIT:0><EOL>for r in self._db._cur: i += <NUM_LIT:1><EOL>return i<EOL>

The row count of the table. This should be optimized.


def create_index(self, table, field, unique=False, ascending=True):

if unique: u = "<STR_LIT>"<EOL>else: u = "<STR_LIT>"<EOL>if ascending: a = "<STR_LIT>"<EOL>else: a = "<STR_LIT>"<EOL>sql  = "<STR_LIT>"+u+"<STR_LIT>"+table+"<STR_LIT:_>"+field+"<STR_LIT:U+0020>"<EOL>sql += "<STR_LIT>"+table+"<STR_LIT:(>"+field+"<STR_LIT:U+0020>"+a+"<STR_LIT:)>"<EOL>self._cur.execute(sql)<EOL>self._con.commit()<EOL>

Creates a table index.

        Creates an index on the given table,
        on the given field with unique values enforced or not,
        in ascending or descending order.


self._name = name.rstrip("<STR_LIT>")<EOL>self._con = sqlite.connect(self._name + "<STR_LIT>")<EOL>self._cur = self._con.cursor()<EOL>self._tables = []<EOL>self._cur.execute("<STR_LIT>")<EOL>for r in self._cur: self._tables.append(r[<NUM_LIT:0>])<EOL>self._indices = []<EOL>self._cur.execute("<STR_LIT>")<EOL>for r in self._cur: self._indices.append(r[<NUM_LIT:0>])<EOL>for t in self._tables:<EOL><INDENT>self._cur.execute("<STR_LIT>"+t+"<STR_LIT:)>")<EOL>fields = []<EOL>key = "<STR_LIT>"<EOL>for r in self._cur:<EOL><INDENT>fields.append(r[<NUM_LIT:1>])<EOL>if r[<NUM_LIT:2>] == "<STR_LIT>": key = r[<NUM_LIT:1>]<EOL><DEDENT>setattr(self, t, Table(self, t, key, fields))<EOL><DEDENT>

Generic database.

        Opens the SQLite database with the given name.
        The .db extension is automatically appended to the name.
        For each table in the database an attribute is created,
        and assigned a Table object.

        You can do: database.table or database[table].


return self.find("<STR_LIT:*>")<EOL>


self._con.commit()<EOL>self._cur.close()<EOL>self._con.close()<EOL>

Commits any pending transactions and closes the database.


def segments(self, generation, time=None):

if not time:<EOL><INDENT>time = maxint<EOL><DEDENT>_ctx.push()<EOL>self._reset()<EOL>self._grow(generation, self.root, self.angle, self.d, time, draw=False)<EOL>_ctx.pop()<EOL>return self._segments<EOL>

Returns the number of segments drawn for a number of generations.

        The number of segments that are drawn to the screen
        depends of the number of generations and the amount of time.
        Each F command has a cost that depletes time.
        Segments will stop being drawn if generation reaches 0,
        when there is no time left
        or when the segment length falls below LSystem.threshold.


self._segments = <NUM_LIT:0><EOL>self._duration = <NUM_LIT:0><EOL>

Resets the number of drawn segments and the duration.

        To calculate the number of segments or the total time needed,
        we need to recurse through LSystem._grow().
        Before that, the draw(), segments() and duration() command
        will reset both tally variables.


def draw(self, x, y, generation, time=None, ease=None):

angle = self.angle<EOL>if time is not None and ease:<EOL><INDENT>angle = min(self.angle, self.angle * time / ease)<EOL><DEDENT>self._timed = True<EOL>if not time:<EOL><INDENT>self._timed = False<EOL>time = maxint<EOL><DEDENT>mode = _ctx.transform()<EOL>_ctx.transform(CORNER)<EOL>_ctx.push()<EOL>_ctx.translate(x, y)<EOL>self._reset()<EOL>self._grow(generation, self.root, angle, self.d, time, draw=True)<EOL>_ctx.pop()<EOL>_ctx.transform(mode)<EOL>

Draws a number of generations at the given position.

        The time parameter can be used to progress the system in an animatiom.
        As time nears LSystem.duration(generation), more segments will be drawn.

        The ease parameter can be used to gradually increase the branching angle
        as more segments are drawn.


def _grow(self, generation, rule, angle, length, time=maxint, draw=True):

if generation == <NUM_LIT:0>:<EOL><INDENT>self._duration = <NUM_LIT:1> + maxint-time<EOL><DEDENT>if length <= self.threshold:<EOL><INDENT>self._duration = <NUM_LIT:1> + maxint-time<EOL>return<EOL><DEDENT>if rule in self.commands:<EOL><INDENT>self.commands[rule](self, generation, rule, angle, length, time)<EOL><DEDENT>if draw:<EOL><INDENT>if rule == "<STR_LIT:f>":<EOL><INDENT>_ctx.translate(<NUM_LIT:0>, -min(length, length*time))<EOL><DEDENT>elif rule == "<STR_LIT:->":<EOL><INDENT>_ctx.rotate(max(-angle, -angle*time))<EOL><DEDENT>elif rule == "<STR_LIT:+>":<EOL><INDENT>_ctx.rotate(min(+angle, +angle*time))<EOL><DEDENT>elif rule == "<STR_LIT:|>":<EOL><INDENT>_ctx.rotate(<NUM_LIT>)<EOL><DEDENT>elif rule == "<STR_LIT:[>":<EOL><INDENT>_ctx.push()<EOL><DEDENT>elif rule == "<STR_LIT:]>":<EOL><INDENT>_ctx.pop()<EOL><DEDENT><DEDENT>if rule in self.rulesand generation > <NUM_LIT:0>and time > <NUM_LIT:0>:<EOL><INDENT>for cmd in self.rules[rule]:<EOL><INDENT>if cmd == "<STR_LIT:F>":<EOL><INDENT>time -= self.cost<EOL><DEDENT>elif cmd == "<STR_LIT:!>":<EOL><INDENT>angle = -angle<EOL><DEDENT>elif cmd == "<STR_LIT:(>":<EOL><INDENT>angle *= <NUM_LIT><EOL><DEDENT>elif cmd == "<STR_LIT:)>":<EOL><INDENT>angle *= <NUM_LIT><EOL><DEDENT>elif cmd == "<STR_LIT:<>":<EOL><INDENT>length *= <NUM_LIT><EOL><DEDENT>elif cmd == "<STR_LIT:>>":<EOL><INDENT>length *= <NUM_LIT><EOL><DEDENT>self._grow(<EOL>generation-<NUM_LIT:1>,<EOL>cmd,<EOL>angle,<EOL>length*self.decrease,<EOL>time,<EOL>draw<EOL>)<EOL><DEDENT><DEDENT>elif rule == "<STR_LIT:F>"or (rule in self.rules and self.rules[rule] == "<STR_LIT>"):<EOL><INDENT>self._segments += <NUM_LIT:1><EOL>if draw and time > <NUM_LIT:0>:<EOL><INDENT>length = min(length, length*time)<EOL>if self._timed:<EOL><INDENT>self.segment(length, generation, time, id=self._segments)<EOL><DEDENT>else:<EOL><INDENT>self.segment(length, generation, None, id=self._segments)<EOL><DEDENT>_ctx.translate(<NUM_LIT:0>, -length)<EOL><DEDENT><DEDENT>

Recurse through the system.

        When a segment is drawn, the LSsytem.segment() method will be called.
        You can customize this method to create your own visualizations.
        It takes an optional time parameter.

        If you divide this parameter by LSsytem.duration() you get
        a number between 0.0 and 1.0 you can use as an alpha value for example.

        The method also has an id parameter which is a unique number
        between 0 and LSystem.segments.


raise NotImplementedError<EOL>

The method which gets executed when a new state of the object was
received.


self.socket.close()<EOL>


return self.profiles.get(profile, None)<EOL>

Returns a specific profile from the profile list and otherwise None


self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<EOL>self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <NUM_LIT:1>)<EOL>self.socket.setblocking(<NUM_LIT:0>)<EOL>self.socket.bind((self.host, self.port))<EOL>

Opens the socket and binds to the given host and port. Uses
SO_REUSEADDR to be as robust as possible.


message = incoming[<NUM_LIT:0>]<EOL>if message:<EOL><INDENT>address, command = message[<NUM_LIT:0>], message[<NUM_LIT:2>]<EOL>profile = self.get_profile(address)<EOL>if profile is not None:<EOL><INDENT>try:<EOL><INDENT>getattr(profile, command)(self, message)<EOL><DEDENT>except AttributeError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT><DEDENT>

Gets called by the CallbackManager if a new message was received


def dispatch(self, message, source = None):

msgtype = "<STR_LIT>"<EOL>try:<EOL><INDENT>if type(message[<NUM_LIT:0>]) == str:<EOL><INDENT>address = message[<NUM_LIT:0>]<EOL>self.callbacks[address](message)<EOL><DEDENT>elif type(message[<NUM_LIT:0>]) == list:<EOL><INDENT>for msg in message:<EOL><INDENT>self.dispatch(msg)<EOL><DEDENT><DEDENT><DEDENT>except KeyError as key:<EOL><INDENT>print('<STR_LIT>' % (address, key, message))<EOL>pprint.pprint(message)<EOL><DEDENT>except IndexError as e:<EOL><INDENT>print('<STR_LIT>' % (e, message))<EOL>pass<EOL><DEDENT>except None as e:<EOL><INDENT>print("<STR_LIT>", address, "<STR_LIT>", e)<EOL><DEDENT>return<EOL>

Sends decoded OSC data to an appropriate calback


if callback == None:<EOL><INDENT>del self.callbacks[name]<EOL><DEDENT>else:<EOL><INDENT>self.callbacks[name] = callback<EOL><DEDENT>

Adds a callback to our set of callbacks,
        or removes the callback with name if callback
        is None.


for i in range(len(bytes)):<EOL><INDENT>sys.stdout.write("<STR_LIT>" % (ord(bytes[i])))<EOL>if (i+<NUM_LIT:1>) % <NUM_LIT:8> == <NUM_LIT:0>:<EOL><INDENT>print(repr(bytes[i-<NUM_LIT:7>:i+<NUM_LIT:1>]))<EOL><DEDENT><DEDENT>if(len(bytes) % <NUM_LIT:8> != <NUM_LIT:0>):<EOL><INDENT>print(string.rjust("<STR_LIT>", <NUM_LIT:11>), repr(bytes[i-len(bytes)%<NUM_LIT:8>:i+<NUM_LIT:1>]))<EOL><DEDENT>

Useful utility; prints the string in hexadecimal


self.message = self.message + data<EOL>

Appends raw data to the message.  Use append().


table = {"<STR_LIT:i>":readInt, "<STR_LIT:f>":readFloat, "<STR_LIT:s>":readString, "<STR_LIT:b>":readBlob}<EOL>decoded = []<EOL>address,  rest = readString(data)<EOL>typetags = "<STR_LIT>"<EOL>if address == "<STR_LIT>":<EOL><INDENT>time, rest = readLong(rest)<EOL>decoded.append(address)<EOL>decoded.append(time)<EOL>while len(rest)><NUM_LIT:0>:<EOL><INDENT>length, rest = readInt(rest)<EOL>decoded.append(decodeOSC(rest[:length]))<EOL>rest = rest[length:]<EOL><DEDENT><DEDENT>elif len(rest) > <NUM_LIT:0>:<EOL><INDENT>typetags, rest = readString(rest)<EOL>decoded.append(address)<EOL>decoded.append(typetags)<EOL>if typetags[<NUM_LIT:0>] == "<STR_LIT:U+002C>":<EOL><INDENT>for tag in typetags[<NUM_LIT:1>:]:<EOL><INDENT>value, rest = table[tag](rest)<EOL>decoded.append(value)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT><DEDENT>return decoded<EOL>

Converts a typetagged OSC message to a Python list.


raise NotImplementedError<EOL>

The 'alive' message contains the session ids of all alive fiducials
known to reacTIVision.


def blend(self, clr, factor=<NUM_LIT:0.5>):

r = self.r * (<NUM_LIT:1> - factor) + clr.r * factor<EOL>g = self.g * (<NUM_LIT:1> - factor) + clr.g * factor<EOL>b = self.b * (<NUM_LIT:1> - factor) + clr.b * factor<EOL>a = self.a * (<NUM_LIT:1> - factor) + clr.a * factor<EOL>return Color(r, g, b, a, mode="<STR_LIT>")<EOL>


if s == <NUM_LIT:0>: return v, v, v<EOL>h = h / (<NUM_LIT> / <NUM_LIT>)<EOL>i = floor(h)<EOL>f = h - i<EOL>p = v * (<NUM_LIT:1> - s)<EOL>q = v * (<NUM_LIT:1> - s * f)<EOL>t = v * (<NUM_LIT:1> - s * (<NUM_LIT:1> - f))<EOL>if i == <NUM_LIT:0>:<EOL><INDENT>r = v;<EOL>g = t;<EOL>b = p<EOL><DEDENT>elif i == <NUM_LIT:1>:<EOL><INDENT>r = q;<EOL>g = v;<EOL>b = p<EOL><DEDENT>elif i == <NUM_LIT:2>:<EOL><INDENT>r = p;<EOL>g = v;<EOL>b = t<EOL><DEDENT>elif i == <NUM_LIT:3>:<EOL><INDENT>r = p;<EOL>g = q;<EOL>b = v<EOL><DEDENT>elif i == <NUM_LIT:4>:<EOL><INDENT>r = t;<EOL>g = p;<EOL>b = v<EOL><DEDENT>else:<EOL><INDENT>r = v;<EOL>g = p;<EOL>b = q<EOL><DEDENT>return r, g, b<EOL>

Hue, saturation, brightness to red, green, blue.
    http://www.koders.com/python/fidB2FE963F658FE74D9BF74EB93EFD44DCAE45E10E.aspx
    Results will differ from the way NSColor converts color spaces.


def swatch(self, x, y, w=<NUM_LIT>, h=<NUM_LIT>, padding=<NUM_LIT:4>, roundness=<NUM_LIT:0>, n=<NUM_LIT:12>, d=<NUM_LIT>, grouped=None):

if grouped is None:  <EOL><INDENT>grouped = self.group_swatches<EOL><DEDENT>if not grouped:<EOL><INDENT>s = sum([wgt for clr, rng, wgt in self.ranges])<EOL>for clr, rng, wgt in self.ranges:<EOL><INDENT>cols = max(<NUM_LIT:1>, int(wgt / s * n))<EOL>for i in _range(cols):<EOL><INDENT>rng.colors(clr, n=n, d=d).swatch(x, y, w, h, padding=padding, roundness=roundness)<EOL>x += w + padding<EOL><DEDENT><DEDENT>return x, y + n * (h + padding)<EOL><DEDENT>grouped = self._weight_by_hue()<EOL>for total_weight, normalized_weight, hue, ranges in grouped:<EOL><INDENT>dy = y<EOL>rc = <NUM_LIT:0><EOL>for clr, rng, weight in ranges:<EOL><INDENT>dx = x<EOL>cols = int(normalized_weight * n)<EOL>cols = max(<NUM_LIT:1>, min(cols, n - len(grouped)))<EOL>if clr.name == "<STR_LIT>": rng = rng.black<EOL>if clr.name == "<STR_LIT>": rng = rng.white<EOL>for i in _range(cols):<EOL><INDENT>rows = int(weight / total_weight * n)<EOL>rows = max(<NUM_LIT:1>, rows)<EOL>if (clr, rng, weight) == ranges[-<NUM_LIT:1>] and rc + rows < n: rows += <NUM_LIT:1><EOL>rng.colors(clr, n=rows, d=d).swatch(dx, dy, w, h, padding=padding, roundness=roundness)<EOL>dx += w + padding<EOL><DEDENT>dy += (w + padding) * rows  <EOL>rc = rows<EOL><DEDENT>x += (w + padding) * cols + padding<EOL><DEDENT>return x, dy<EOL>

Draws a weighted swatch with approximately n columns and rows.

When the grouped parameter is True, colors are grouped in blocks of the same hue
(also see the _weight_by_hue() method).


_list.__init__(self)<EOL>self.name = "<STR_LIT>"<EOL>self.tags = []<EOL>for arg in args:<EOL><INDENT>if arg.__class__ == Color:<EOL><INDENT>self.append(arg)<EOL><DEDENT>if arg.__class__ == BaseColor:<EOL><INDENT>self.append(color(arg.r, arg.g, arg.b, mode="<STR_LIT>"))<EOL><DEDENT>try:<EOL><INDENT>self.name = arg.label<EOL>for r, g, b in arg:<EOL><INDENT>self.append(color(r, g, b, mode="<STR_LIT>"))<EOL><DEDENT><DEDENT>except:<EOL><INDENT>pass<EOL><DEDENT>if isinstance(arg, _list)or isinstance(arg, tuple):<EOL><INDENT>for clr in arg:<EOL><INDENT>if clr.__class__ == Color:<EOL><INDENT>self.append(clr)<EOL><DEDENT>if clr.__class__ == BaseColor:<EOL><INDENT>self.append(color(clr))<EOL><DEDENT><DEDENT><DEDENT>if isinstance(arg, (str, unicode)):<EOL><INDENT>if os.path.exists(arg):<EOL><INDENT>n = <NUM_LIT:10><EOL>if "<STR_LIT:n>" in kwargs.keys(): n = kwargs["<STR_LIT:n>"]<EOL>self.image_to_rgb(arg, n)<EOL><DEDENT>else:<EOL><INDENT>clr = Color(arg)<EOL>if not clr.is_transparent:<EOL><INDENT>self.append(clr)<EOL>self.name = arg<EOL><DEDENT>else:<EOL><INDENT>self.extend(self.context_to_rgb(arg))<EOL>self.tags = arg<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if "<STR_LIT:name>" in kwargs.keys():<EOL><INDENT>self.name = kwargs["<STR_LIT:name>"]<EOL><DEDENT>if "<STR_LIT>" in kwargs.keys():<EOL><INDENT>self.tags = kwargs["<STR_LIT>"]<EOL><DEDENT>

Construct a list of colors.

Colors can be supplied as individual arguments,
or in a list or tuple:
ColorList(clr1, clr2)
ColorList([clr1, clr2])
ColorList((clr1, clr2))

You can also supply an object from inside a
web.kuler.search() or web.colr.search() list.

Or a string with a named color, a descriptive feel,
or the pathname of an image.

ColorList furthermore takes two named parameters,
a name and a list of tags.


grouped = self._weight_by_hue()<EOL>xml = "<STR_LIT>" + self.name + "<STR_LIT>" + "<STR_LIT:U+002CU+0020>".join(self.tags) + "<STR_LIT>"<EOL>for total_weight, normalized_weight, hue, ranges in grouped:<EOL><INDENT>if hue == self.blue: hue = "<STR_LIT>"<EOL>clr = color(hue)<EOL>xml += "<STR_LIT>" + clr.name + "<STR_LIT>" + str(normalized_weight) + "<STR_LIT>"<EOL>xml += "<STR_LIT>" + str(clr.r) + "<STR_LIT>" + str(clr.g) + "<STR_LIT>"<EOL>xml += "<STR_LIT>" + str(clr.b) + "<STR_LIT>" + str(clr.a) + "<STR_LIT>"<EOL>for clr, rng, wgt in ranges:<EOL><INDENT>xml += "<STR_LIT>" + str(rng) + "<STR_LIT>" + str(wgt / total_weight) + "<STR_LIT>"<EOL><DEDENT>xml = xml.rstrip("<STR_LIT:U+0020>") + "<STR_LIT>"<EOL><DEDENT>xml += "<STR_LIT>"<EOL>return xml<EOL>

Returns the color information as XML.

The XML has the following structure:
<colors query="">
    <color name="" weight="" />
        <rgb r="" g="" b="" />
        <shade name="" weight="" />
    </color>
</colors>

Notice that ranges are stored by name and retrieved in the _load()
method with the shade() command - and are thus expected to be
shades (e.g. intense, warm, ...) unless the shade() command would
return any custom ranges as well. This can be done by appending custom
ranges to the shades list.


matches = []<EOL>for clr in context:<EOL><INDENT>tags = context[clr]<EOL>for tag in tags:<EOL><INDENT>if tag.startswith(str)or str.startswith(tag):<EOL><INDENT>matches.append(clr)<EOL>break<EOL><DEDENT><DEDENT><DEDENT>matches = [color(name) for name in matches]<EOL>return matches<EOL>

Returns the colors that have the given word in their context.

        For example, the word "anger" appears
        in black, orange and red contexts,
        so the list will contain those three colors.


r, g, b, a = <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0><EOL>for clr in self:<EOL><INDENT>r += clr.r<EOL>g += clr.g<EOL>b += clr.b<EOL>a += clr.alpha<EOL><DEDENT>r /= len(self)<EOL>g /= len(self)<EOL>b /= len(self)<EOL>a /= len(self)<EOL>return color(r, g, b, a, mode="<STR_LIT>")<EOL>

Returns one average color for the colors in the list.


def outline(path, colors, precision=<NUM_LIT>, continuous=True):

<EOL>def _point_count(path, precision):<EOL><INDENT>return max(int(path.length * precision * <NUM_LIT:0.5>), <NUM_LIT:10>)<EOL><DEDENT>n = sum([_point_count(contour, precision) for contour in path.contours])<EOL>contour_i = <NUM_LIT:0><EOL>contour_n = len(path.contours) - <NUM_LIT:1><EOL>if contour_n == <NUM_LIT:0>: continuous = False<EOL>i = <NUM_LIT:0><EOL>for contour in path.contours:<EOL><INDENT>if not continuous: i = <NUM_LIT:0><EOL>j = _point_count(contour, precision)<EOL>first = True<EOL>for pt in contour.points(j):<EOL><INDENT>if first:<EOL><INDENT>first = False<EOL><DEDENT>else:<EOL><INDENT>if not continuous:<EOL><INDENT>clr = float(i) / j * len(colors)<EOL><DEDENT>else:<EOL><INDENT>clr = float(i) / n * len(colors) - <NUM_LIT:1> * contour_i / contour_n<EOL><DEDENT>_ctx.stroke(colors[int(clr)])<EOL>_ctx.line(x0, y0, pt.x, pt.y)<EOL><DEDENT>x0 = pt.x<EOL>y0 = pt.y<EOL>i += <NUM_LIT:1><EOL><DEDENT>pt = contour.point(<NUM_LIT>)  <EOL>_ctx.line(x0, y0, pt.x, pt.y)<EOL>contour_i += <NUM_LIT:1><EOL><DEDENT>

Outlines each contour in a path with the colors in the list.

Each contour starts with the first color in the list,
and ends with the last color in the list.

Because each line segment is drawn separately,
works only with corner-mode transforms.


return ColorList(<EOL>[color(clr.r, clr.g, clr.b, clr.a, mode="<STR_LIT>") for clr in self],<EOL>name=self.name,<EOL>tags=self.tags<EOL>)<EOL>


def recombine(self, other, d=<NUM_LIT>):

a, b = self, other<EOL>d1 = max(<NUM_LIT:0>, min(d, <NUM_LIT:1>))<EOL>d2 = d1<EOL>c = ColorTheme(<EOL>name=a.name[:int(len(a.name) * d1)] +<EOL>b.name[int(len(b.name) * d2):],<EOL>ranges=a.ranges[:int(len(a.ranges) * d1)] +<EOL>b.ranges[int(len(b.ranges) * d2):],<EOL>top=a.top,<EOL>cache=os.path.join(DEFAULT_CACHE, "<STR_LIT>"),<EOL>blue=a.blue,<EOL>length=a.length * d1 + b.length * d2<EOL>)<EOL>c.tags = a.tags[:int(len(a.tags) * d1)]<EOL>c.tags += b.tags[int(len(b.tags) * d2):]<EOL>return c<EOL>

Genetic recombination of two themes using cut and splice technique.


clr = color(clr)<EOL>colors = colorlist(clr)<EOL>colors.append(clr.complement)<EOL>return colors<EOL>

Returns the color and its complement in a list.


<EOL>if isinstance(colorrange, Color):<EOL><INDENT>colorrange = ColorList(colorrange)<EOL><DEDENT>if isinstance(colorrange, ColorList)and not isinstance(colorrange, ColorRange):<EOL><INDENT>colorrange = ColorRange([(clr.h, clr.h) for clr in colorrange], [], [])<EOL><DEDENT>hsba = [[], [], [], []]<EOL>for r in [self, colorrange]:<EOL><INDENT>for i in _range(<NUM_LIT:4>):<EOL><INDENT>v = [r.h, r.s, r.b, r.a][i]<EOL>if isinstance(v, _list):<EOL><INDENT>hsba[i].extend(v)<EOL><DEDENT>elif isinstance(v, tuple):<EOL><INDENT>hsba[i].append(v)<EOL><DEDENT>else:<EOL><INDENT>hsba[i].append((v, v))<EOL><DEDENT><DEDENT><DEDENT>r = ColorRange(*hsba)<EOL>return r<EOL>

Combines two ColorRange objects into one.

For example, if you merge a dark green range and a light red range,
you get a range returning dark and light variations of green and red.


clr = color(clr)<EOL>colors = colorlist(clr)<EOL>colors.append(clr.rotate_ryb(angle).lighten(<NUM_LIT:0.1>))<EOL>colors.append(clr.rotate_ryb(-angle).lighten(<NUM_LIT:0.1>))<EOL>return colors<EOL>

Returns a triad of colors.

The triad is made up of this color and two other colors
that together make up an equilateral triangle on
the artistic color wheel.


def image_to_rgb(self, path, n=<NUM_LIT:10>):

from PIL import Image<EOL>img = Image.open(path)<EOL>p = img.getdata()<EOL>f = lambda p: choice(p)<EOL>for i in _range(n):<EOL><INDENT>rgba = f(p)<EOL>rgba = _list(rgba)<EOL>if len(rgba) == <NUM_LIT:3>:<EOL><INDENT>rgba.append(<NUM_LIT:255>)<EOL><DEDENT>r, g, b, a = [v / <NUM_LIT> for v in rgba]<EOL>clr = color(r, g, b, a, mode="<STR_LIT>")<EOL>self.append(clr)<EOL><DEDENT>

Returns a list of colors based on pixel values in the image.

The Core Image library must be present to determine pixel colors.
F. Albers: http://nodebox.net/code/index.php/shared_2007-06-11-11-37-05


for clr2 in self:<EOL><INDENT>if clr.r == clr2.r andclr.g == clr2.g andclr.b == clr2.b:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>return False<EOL>

Returns True if clr's RGB values match a color in the list.


hex = hex.lstrip("<STR_LIT:#>")<EOL>if len(hex) < <NUM_LIT:6>:<EOL><INDENT>hex += hex[-<NUM_LIT:1>] * (<NUM_LIT:6> - len(hex))<EOL><DEDENT>r, g, b = hex[<NUM_LIT:0>:<NUM_LIT:2>], hex[<NUM_LIT:2>:<NUM_LIT:4>], hex[<NUM_LIT:4>:]<EOL>r, g, b = [int(n, <NUM_LIT:16>) / <NUM_LIT> for n in (r, g, b)]<EOL>return r, g, b<EOL>

Returns RGB values for a hex color string.


ColorList.__init__(self)<EOL>self.name = name<EOL>self.h = h<EOL>self.s = s<EOL>self.b = b<EOL>self.a = a<EOL>self.grayscale = grayscale<EOL>if not grayscale:<EOL><INDENT>self.black = ColorRange((<NUM_LIT:0>, <NUM_LIT:1>), <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>, True, name)<EOL>self.white = ColorRange((<NUM_LIT:0>, <NUM_LIT:1>), <NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:1>, True, name)<EOL><DEDENT>self.length = length<EOL>

A stateless list of colors whose HSB values are confined to a range.

Hue, saturation and brightness are confined to a (min, max) tuple,
or a list of (min, max) tuples for discontinuous ranges, or to a single value.
This way you can describe concepts such as "light", "dark", etc.

With stateless we mean that you are never sure which colors are
in the ColorRange, different colors that fall within the ranges
are returned each time when calling color() or colors().

ColorRange has all the ColorList transformations (such as darken()),
these return ColorList objects. It's like a snapshot of the original
stateless ColorRange.


if not isinstance(clr, Color):<EOL><INDENT>return False<EOL><DEDENT>if not isinstance(clr, _list):<EOL><INDENT>clr = [clr]<EOL><DEDENT>for clr in clr:<EOL><INDENT>if clr.is_grey and not self.grayscale:<EOL><INDENT>return (self.black.contains(clr) orself.white.contains(clr))<EOL><DEDENT>for r, v in [(self.h, clr.h), (self.s, clr.s), (self.b, clr.brightness), (self.a, clr.a)]:<EOL><INDENT>if isinstance(r, _list):<EOL><INDENT>pass<EOL><DEDENT>elif isinstance(r, tuple):<EOL><INDENT>r = [r]<EOL><DEDENT>else:<EOL><INDENT>r = [(r, r)]<EOL><DEDENT>for min, max in r:<EOL><INDENT>if not (min <= v <= max):<EOL><INDENT>return False<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return True<EOL>

Returns True if the given color is part of this color range.

Check whether each h, s, b, a component of the color
falls within the defined range for that component.

If the given color is grayscale,
checks against the definitions for black and white.


def morguefile(query, n=<NUM_LIT:10>, top=<NUM_LIT:10>):

from web import morguefile<EOL>images = morguefile.search(query)[:top]<EOL>path = choice(images).download(thumbnail=True, wait=<NUM_LIT:10>)<EOL>return ColorList(path, n, name=query)<EOL>

Returns a list of colors drawn from a morgueFile image.

With the Web library installed,
downloads a thumbnail from morgueFile and retrieves pixel colors.


r = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, c + k)<EOL>g = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, m + k)<EOL>b = <NUM_LIT:1.0> - min(<NUM_LIT:1.0>, y + k)<EOL>return r, g, b<EOL>

Cyan, magenta, yellow, black to red, green, blue.
    ReportLab, http://www.koders.com/python/fid5C006F554616848C01AC7CB96C21426B69D2E5A9.aspx
    Results will differ from the way NSColor converts color spaces.


def _load(self, top=<NUM_LIT:5>, blue="<STR_LIT>", archive=None, member=None):

if archive is None:<EOL><INDENT>path = os.path.join(self.cache, self.name + "<STR_LIT>")<EOL>xml = open(path).read()<EOL><DEDENT>else:<EOL><INDENT>assert member is not None<EOL>xml = archive.read(member)<EOL><DEDENT>dom = parseString(xml).documentElement<EOL>attr = lambda e, a: e.attributes[a].value<EOL>for e in dom.getElementsByTagName("<STR_LIT>")[:top]:<EOL><INDENT>w = float(attr(e, "<STR_LIT>"))<EOL>try:<EOL><INDENT>rgb = e.getElementsByTagName("<STR_LIT>")[<NUM_LIT:0>]<EOL>clr = color(<EOL>float(attr(rgb, "<STR_LIT:r>")),<EOL>float(attr(rgb, "<STR_LIT:g>")),<EOL>float(attr(rgb, "<STR_LIT:b>")),<EOL>float(attr(rgb, "<STR_LIT:a>")),<EOL>mode="<STR_LIT>"<EOL>)<EOL>try:<EOL><INDENT>clr.name = attr(e, "<STR_LIT:name>")<EOL>if clr.name == "<STR_LIT>": clr = color(blue)<EOL><DEDENT>except:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>except:<EOL><INDENT>name = attr(e, "<STR_LIT:name>")<EOL>if name == "<STR_LIT>": name = blue<EOL>clr = color(name)<EOL><DEDENT>for s in e.getElementsByTagName("<STR_LIT>"):<EOL><INDENT>self.ranges.append((<EOL>clr,<EOL>shade(attr(s, "<STR_LIT:name>")),<EOL>w * float(attr(s, "<STR_LIT>"))<EOL>))<EOL><DEDENT><DEDENT>

Loads a theme from aggregated web data.

The data must be old-style Prism XML: <color>s consisting of <shade>s.
Colors named "blue" will be overridden with the blue parameter.

archive can be a file like object (e.g. a ZipFile)
and will be used along with 'member' if specified.


right = split_complementary(clr)[<NUM_LIT:2>]<EOL>colors = complementary(clr)<EOL>colors[<NUM_LIT:3>].h = right.h<EOL>colors[<NUM_LIT:4>].h = right.h<EOL>colors[<NUM_LIT:5>].h = right.h<EOL>colors = colorlist(<EOL>colors[<NUM_LIT:0>], colors[<NUM_LIT:2>], colors[<NUM_LIT:1>], colors[<NUM_LIT:5>], colors[<NUM_LIT:4>], colors[<NUM_LIT:3>]<EOL>)<EOL>return colors<EOL>

Returns the right half of the split complement.


def colors(self, n=<NUM_LIT:10>, d=<NUM_LIT>):

s = sum([w for clr, rng, w in self.ranges])<EOL>colors = colorlist()<EOL>for i in _range(n):<EOL><INDENT>r = random()<EOL>for clr, rng, weight in self.ranges:<EOL><INDENT>if weight / s >= r: break<EOL>r -= weight / s<EOL><DEDENT>colors.append(rng(clr, d))<EOL><DEDENT>return colors<EOL>

Returns a number of random colors from the theme.


min, n = (<NUM_LIT:1.0>, <NUM_LIT:1.0>, <NUM_LIT:1.0>), <NUM_LIT><EOL>for clr in self:<EOL><INDENT>if clr.r + clr.g + clr.b < n:<EOL><INDENT>min, n = clr, clr.r + clr.g + clr.b<EOL><DEDENT><DEDENT>return min<EOL>

Returns the darkest color from the list.

Knowing the contrast between a light and a dark swatch
can help us decide how to display readable typography.


def swatch(self, x, y, w=<NUM_LIT>, h=<NUM_LIT>, padding=<NUM_LIT:0>, roundness=<NUM_LIT:0>):

for clr in self:<EOL><INDENT>clr.swatch(x, y, w, h, roundness)<EOL>y += h + padding<EOL><DEDENT>

Rectangle swatches for all the colors in the list.


coord = lambda a, d: (cos(radians(a)) * d, sin(radians(a)) * d)<EOL>x0, y0 = coord(self.h * <NUM_LIT>, self.s)<EOL>x1, y1 = coord(clr.h * <NUM_LIT>, clr.s)<EOL>z0 = self.brightness<EOL>z1 = clr.brightness<EOL>d = sqrt((x1 - x0) ** <NUM_LIT:2> + (y1 - y0) ** <NUM_LIT:2> + (z1 - z0) ** <NUM_LIT:2>)<EOL>return d<EOL>

Returns the Euclidean distance between two colors (0.0-1.0).

Consider colors arranged on the color wheel:
- hue is the angle of a color along the center
- saturation is the distance of a color from the center
- brightness is the elevation of a color from the center
  (i.e. we're on color a sphere)


if q is None:<EOL><INDENT>return self<EOL><DEDENT>candidate = None<EOL>if _favorites.data.has_key(q):<EOL><INDENT>candidate = q<EOL><DEDENT>for name, (tags, colors) in _favorites.data.iteritems():<EOL><INDENT>if q in tags:<EOL><INDENT>candidate = name<EOL><DEDENT><DEDENT>if candidate:<EOL><INDENT>tags, colors = _favorites.data[candidate]<EOL>colors = ColorList([color(r, g, b, a) for r, g, b, a in colors], name=candidate)<EOL>colors.tags = tags.split("<STR_LIT:U+0020>")<EOL>return colors<EOL><DEDENT>return None<EOL>

Returns the favorite colors list which name/tags matches q.


def _wrap(x, min, threshold, plus):<EOL><INDENT>if x - min < threshold:<EOL><INDENT>return x + plus<EOL><DEDENT>else:<EOL><INDENT>return x - min<EOL><DEDENT><DEDENT>colors = colorlist(clr)<EOL>c = clr.copy()<EOL>c.brightness = _wrap(clr.brightness, <NUM_LIT:0.5>, <NUM_LIT>, <NUM_LIT>)<EOL>c.saturation = _wrap(clr.saturation, <NUM_LIT>, <NUM_LIT:0.1>, <NUM_LIT>)<EOL>colors.append(c)<EOL>c = clr.copy()<EOL>c.brightness = _wrap(clr.brightness, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>)<EOL>colors.append(c)<EOL>c = clr.copy()<EOL>c.brightness = max(<NUM_LIT>, clr.brightness + (<NUM_LIT:1> - clr.brightness) * <NUM_LIT>)<EOL>c.saturation = _wrap(clr.saturation, <NUM_LIT>, <NUM_LIT:0.1>, <NUM_LIT>)<EOL>colors.append(c)<EOL>c = clr.copy()<EOL>c.brightness = _wrap(clr.brightness, <NUM_LIT:0.5>, <NUM_LIT>, <NUM_LIT>)<EOL>colors.append(c)<EOL>return colors<EOL>

Returns colors in the same hue with varying brightness/saturation.


if len(colors) == <NUM_LIT:1>:<EOL><INDENT>if isinstance(colors[<NUM_LIT:0>], _list)or isinstance(colors[<NUM_LIT:0>], tuple):<EOL><INDENT>self._colors = _list(colors[<NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>self._colors = [colors[<NUM_LIT:0>]]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self._colors = _list(colors)<EOL><DEDENT>self._colors = [color(clr) for clr in self._colors]<EOL>self._steps = <NUM_LIT:100><EOL>if kwargs.has_key("<STR_LIT>"):<EOL><INDENT>self._steps = kwargs["<STR_LIT>"]<EOL><DEDENT>if kwargs.has_key("<STR_LIT>"):<EOL><INDENT>self._steps = kwargs["<STR_LIT>"]<EOL><DEDENT>self._spread = <NUM_LIT:0.5><EOL>if kwargs.has_key("<STR_LIT>"):<EOL><INDENT>self._spread = kwargs["<STR_LIT>"]<EOL><DEDENT>self._cache()<EOL>

Creates a list of gradient colors based on a few given base colors.

The colors can be supplied as a list or tuple of colors,
or simply an enumeration of color parameters.

The steps named parameter defining how many colors are in the list.
The spread named parameter controls the midpoint of the gradient


def cluster_sort(self, cmp1="<STR_LIT>", cmp2="<STR_LIT>", reversed=False, n=<NUM_LIT:12>):

sorted = self.sort(cmp1)<EOL>clusters = ColorList()<EOL>d = <NUM_LIT:1.0><EOL>i = <NUM_LIT:0><EOL>for j in _range(len(sorted)):<EOL><INDENT>if getattr(sorted[j], cmp1) < d:<EOL><INDENT>clusters.extend(sorted[i:j].sort(cmp2))<EOL>d -= <NUM_LIT:1.0> / n<EOL>i = j<EOL><DEDENT><DEDENT>clusters.extend(sorted[i:].sort(cmp2))<EOL>if reversed: _list.reverse(clusters)<EOL>return clusters<EOL>

Sorts the list by cmp1, then cuts it into n pieces which are sorted by cmp2.

If you want to cluster by hue, use n=12 (since there are 12 primary/secondary hues).
The resulting list will not contain n even slices:
n is used rather to slice up the cmp1 property of the colors,
e.g. cmp1=brightness and n=3 will cluster colors by brightness >= 0.66, 0.33, 0.0


left = split_complementary(clr)[<NUM_LIT:1>]<EOL>colors = complementary(clr)<EOL>colors[<NUM_LIT:3>].h = left.h<EOL>colors[<NUM_LIT:4>].h = left.h<EOL>colors[<NUM_LIT:5>].h = left.h<EOL>colors = colorlist(<EOL>colors[<NUM_LIT:0>], colors[<NUM_LIT:2>], colors[<NUM_LIT:1>], colors[<NUM_LIT:3>], colors[<NUM_LIT:4>], colors[<NUM_LIT:5>]<EOL>)<EOL>return colors<EOL>

Returns the left half of the split complement.

A list is returned with the same darker and softer colors
as in the complementary list, but using the hue of the
left split complement instead of the complement itself.


grouped = {}<EOL>weights = []<EOL>for clr, rng, weight in self.ranges:<EOL><INDENT>h = clr.nearest_hue(primary=False)<EOL>if grouped.has_key(h):<EOL><INDENT>ranges, total_weight = grouped[h]<EOL>ranges.append((clr, rng, weight))<EOL>total_weight += weight<EOL>grouped[h] = (ranges, total_weight)<EOL><DEDENT>else:<EOL><INDENT>grouped[h] = ([(clr, rng, weight)], weight)<EOL><DEDENT><DEDENT>s = <NUM_LIT:1.0> * sum([w for r, w in grouped.values()])<EOL>grouped = [(grouped[h][<NUM_LIT:1>], grouped[h][<NUM_LIT:1>] / s, h, grouped[h][<NUM_LIT:0>]) for h in grouped]<EOL>grouped.sort()<EOL>grouped.reverse()<EOL>return grouped<EOL>

Returns a list of (hue, ranges, total weight, normalized total weight)-tuples.

ColorTheme is made up out of (color, range, weight) tuples.
For consistency with XML-output in the old Prism format
(i.e. <color>s made up of <shade>s) we need a group
weight per different hue.

The same is true for the swatch() draw method.
Hues are grouped as a single unit (e.g. dark red, intense red, weak red)
after which the dimensions (rows/columns) is determined.


def __init__(self, dx=<NUM_LIT:10>, dy=<NUM_LIT:10>, alpha=<NUM_LIT>, blur=<NUM_LIT>, clr=None):

Grob.__init__(self, _ctx)<EOL>if clr is None:<EOL><INDENT>clr = color(<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>, alpha, mode="<STR_LIT>")<EOL><DEDENT>self.dx = dx<EOL>self.dy = dy<EOL>self.blur = blur<EOL>self.clr = clr.copy()<EOL>self.clr.alpha = alpha<EOL>global _shadow<EOL>_shadow = self<EOL>

Sets the dropshadow for all onscreen elements.

Both the fill and stroke of a path get a dropshadow.

TODO - Implement shadow, could work as a postprocessing effect


clr = Color(clr)<EOL>if clr.is_transparent: return "<STR_LIT>"<EOL>if clr.is_black: return "<STR_LIT>"<EOL>if clr.is_white: return "<STR_LIT>"<EOL>if clr.is_black: return "<STR_LIT>"<EOL>for name in named_colors:<EOL><INDENT>try:<EOL><INDENT>r, g, b = named_colors[name]<EOL><DEDENT>except:<EOL><INDENT>continue<EOL><DEDENT>if r == clr.r and g == clr.g and b == clr.b:<EOL><INDENT>return name<EOL><DEDENT><DEDENT>for shade in shades:<EOL><INDENT>if clr in shade:<EOL><INDENT>return shade.name + "<STR_LIT:U+0020>" + clr.nearest_hue()<EOL>break<EOL><DEDENT><DEDENT>return clr.nearest_hue()<EOL>

Guesses the shade and hue name of a color.

If the given color is named in the named_colors list, return that name.
Otherwise guess its nearest hue and shade range.


tags1 = None<EOL>for clr in self:<EOL><INDENT>overlap = []<EOL>if clr.is_black:<EOL><INDENT>name = "<STR_LIT>"<EOL><DEDENT>elif clr.is_white:<EOL><INDENT>name = "<STR_LIT>"<EOL><DEDENT>elif clr.is_grey:<EOL><INDENT>name = "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>name = clr.nearest_hue(primary=True)<EOL><DEDENT>if name == "<STR_LIT>" and clr.brightness < <NUM_LIT>:<EOL><INDENT>name = "<STR_LIT>"<EOL><DEDENT>tags2 = context[name]<EOL>if tags1 is None:<EOL><INDENT>tags1 = tags2<EOL><DEDENT>else:<EOL><INDENT>for tag in tags2:<EOL><INDENT>if tag in tags1:<EOL><INDENT>if tag not in overlap:<EOL><INDENT>overlap.append(tag)<EOL><DEDENT><DEDENT><DEDENT>tags1 = overlap<EOL><DEDENT><DEDENT>overlap.sort()<EOL>return overlap<EOL>

Returns the intersection of each color's context.

Get the nearest named hue of each color,
and finds overlapping tags in each hue's colors.
For example, a list containing yellow, deeppink and olive
yields: femininity, friendship, happiness, joy.


def swatch(self, x, y, w=<NUM_LIT>, h=<NUM_LIT>, roundness=<NUM_LIT:0>):

_ctx.fill(self)<EOL>_ctx.rect(x, y, w, h, roundness)<EOL>


def parse(svg, cached=False, _copy=True):

if not cached:<EOL><INDENT>dom = parser.parseString(svg)<EOL>paths = parse_node(dom, [])<EOL><DEDENT>else:<EOL><INDENT>id = _cache.id(svg)<EOL>if not _cache.has_key(id):<EOL><INDENT>dom = parser.parseString(svg)<EOL>_cache.save(id, parse_node(dom, []))<EOL><DEDENT>paths = _cache.load(id, _copy)<EOL><DEDENT>return paths<EOL>

Returns cached copies unless otherwise specified.


def get_attribute(element, attribute, default=<NUM_LIT:0>):

a = element.getAttribute(attribute)<EOL>if a == "<STR_LIT>": <EOL><INDENT>return default<EOL><DEDENT>return a<EOL>

Returns XML element's attribute, or default if none.


def transform_from_local(xp, yp, cphi, sphi, mx, my):

x = xp * cphi - yp * sphi + mx<EOL>y = xp * sphi + yp * cphi + my<EOL>return (x,y)<EOL>

Transform from the local frame to absolute space.


def bezier_arc(x1, y1, x2, y2, start_angle=<NUM_LIT:0>, extent=<NUM_LIT>):

x1,y1, x2,y2 = min(x1,x2), max(y1,y2), max(x1,x2), min(y1,y2)<EOL>if abs(extent) <= <NUM_LIT>:<EOL><INDENT>frag_angle = float(extent)<EOL>nfrag = <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>nfrag = int(ceil(abs(extent)/<NUM_LIT>))<EOL>if nfrag == <NUM_LIT:0>:<EOL><INDENT>warnings.warn('<STR_LIT>' % extent)<EOL>return []<EOL><DEDENT>frag_angle = float(extent) / nfrag<EOL><DEDENT>x_cen = (x1+x2)/<NUM_LIT><EOL>y_cen = (y1+y2)/<NUM_LIT><EOL>rx = (x2-x1)/<NUM_LIT><EOL>ry = (y2-y1)/<NUM_LIT><EOL>half_angle = radians(frag_angle) / <NUM_LIT:2><EOL>kappa = abs(<NUM_LIT> / <NUM_LIT> * (<NUM_LIT:1.> - cos(half_angle)) / sin(half_angle))<EOL>if frag_angle < <NUM_LIT:0>:<EOL><INDENT>sign = -<NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>sign = <NUM_LIT:1><EOL><DEDENT>point_list = []<EOL>for i in range(nfrag):<EOL><INDENT>theta0 = radians(start_angle + i*frag_angle)<EOL>theta1 = radians(start_angle + (i+<NUM_LIT:1>)*frag_angle)<EOL>c0 = cos(theta0)<EOL>c1 = cos(theta1)<EOL>s0 = sin(theta0)<EOL>s1 = sin(theta1)<EOL>if frag_angle > <NUM_LIT:0>:<EOL><INDENT>signed_kappa = -kappa<EOL><DEDENT>else:<EOL><INDENT>signed_kappa = kappa<EOL><DEDENT>point_list.append((x_cen + rx * c0,<EOL>y_cen - ry * s0,<EOL>x_cen + rx * (c0 + signed_kappa * s0),<EOL>y_cen - ry * (s0 - signed_kappa * c0),<EOL>x_cen + rx * (c1 - signed_kappa * s1),<EOL>y_cen - ry * (s1 + signed_kappa * c1),<EOL>x_cen + rx * c1,<EOL>y_cen - ry * s1))<EOL><DEDENT>return point_list<EOL>

Compute a cubic Bezier approximation of an elliptical arc.

    (x1, y1) and (x2, y2) are the corners of the enclosing rectangle.
    The coordinate system has coordinates that increase to the right and down.
    Angles, measured in degress, start with 0 to the right (the positive X axis)
    and increase counter-clockwise.
    The arc extends from start_angle to start_angle+extent.
    I.e. start_angle=0 and extent=180 yields an openside-down semi-circle.

    The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4)
    such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and
    (x3, y3) as their respective Bezier control points.


def elliptical_arc_to(x1, y1, rx, ry, phi, large_arc_flag, sweep_flag, x2, y2):

<EOL>rx = abs(rx)<EOL>ry = abs(ry)<EOL>phi = phi % <NUM_LIT><EOL>if x1==x2 and y1==y2:<EOL><INDENT>return []<EOL><DEDENT>if rx == <NUM_LIT:0> or ry == <NUM_LIT:0>:<EOL><INDENT>return [(x2,y2)]<EOL><DEDENT>rphi = radians(phi)<EOL>cphi = cos(rphi)<EOL>sphi = sin(rphi)<EOL>dx = <NUM_LIT:0.5>*(x1 - x2)<EOL>dy = <NUM_LIT:0.5>*(y1 - y2)<EOL>x1p =  cphi * dx + sphi * dy<EOL>y1p = -sphi * dx + cphi * dy<EOL>lam = (x1p/rx)**<NUM_LIT:2> + (y1p/ry)**<NUM_LIT:2><EOL>if lam > <NUM_LIT:1.0>:<EOL><INDENT>scale = sqrt(lam)<EOL>rx *= scale<EOL>ry *= scale<EOL><DEDENT>num = max((rx*ry)**<NUM_LIT:2> - (rx*y1p)**<NUM_LIT:2> - (ry*x1p)**<NUM_LIT:2>, <NUM_LIT:0.0>)<EOL>den = ((rx*y1p)**<NUM_LIT:2> + (ry*x1p)**<NUM_LIT:2>)<EOL>a = sqrt(num / den)<EOL>cxp = a * rx*y1p/ry<EOL>cyp = -a * ry*x1p/rx<EOL>if large_arc_flag == sweep_flag:<EOL><INDENT>cxp = -cxp<EOL>cyp = -cyp<EOL><DEDENT>mx = <NUM_LIT:0.5>*(x1+x2)<EOL>my = <NUM_LIT:0.5>*(y1+y2)<EOL>dx = (x1p-cxp) / rx<EOL>dy = (y1p-cyp) / ry<EOL>dx2 = (-x1p-cxp) / rx<EOL>dy2 = (-y1p-cyp) / ry<EOL>theta1 = angle(<NUM_LIT:1>,<NUM_LIT:0>,dx,dy)<EOL>dtheta = angle(dx,dy,dx2,dy2)<EOL>if not sweep_flag and dtheta > <NUM_LIT:0>:<EOL><INDENT>dtheta -= <NUM_LIT><EOL><DEDENT>elif sweep_flag and dtheta < <NUM_LIT:0>:<EOL><INDENT>dtheta += <NUM_LIT><EOL><DEDENT>p = []<EOL>control_points = bezier_arc(cxp-rx,cyp-ry,cxp+rx,cyp+ry, theta1, dtheta)<EOL>for x1p,y1p, x2p,y2p, x3p,y3p, x4p,y4p in control_points:<EOL><INDENT>p.append((<EOL>transform_from_local(x2p,y2p,cphi,sphi,mx,my) +<EOL>transform_from_local(x3p,y3p,cphi,sphi,mx,my) +<EOL>transform_from_local(x4p,y4p,cphi,sphi,mx,my)<EOL>))<EOL><DEDENT>return p<EOL>

An elliptical arc approximated with Bezier curves or a line segment.
Algorithm taken from the SVG 1.1 Implementation Notes:
http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes


vx = vy = vz = <NUM_LIT:0><EOL>for b in self.boids:<EOL><INDENT>if b != self:<EOL><INDENT>vx, vy, vz = vx+b.vx, vy+b.vy, vz+b.vz<EOL><DEDENT><DEDENT>n = len(self.boids)-<NUM_LIT:1><EOL>vx, vy, vz = vx/n, vy/n, vz/n<EOL>return (vx-self.vx)/d, (vy-self.vy)/d, (vz-self.vz)/d<EOL>


vx = vy = vz = <NUM_LIT:0><EOL>for b in self.boids:<EOL><INDENT>if b != self:<EOL><INDENT>if abs(self.x-b.x) < r: vx += (self.x-b.x)<EOL>if abs(self.y-b.y) < r: vy += (self.y-b.y)<EOL>if abs(self.z-b.z) < r: vz += (self.z-b.z)<EOL><DEDENT><DEDENT>return vx, vy, vz<EOL>

Boids keep a small distance from other boids.

        Ensures that boids don't collide into each other,
        in a smoothly accelerated motion.


dx = self.w * <NUM_LIT:0.1><EOL>dy = self.h * <NUM_LIT:0.1> <EOL>for b in self:<EOL><INDENT>if b.x < self.x-dx: b.vx += _ctx.random(dx)<EOL>if b.y < self.y-dy: b.vy += _ctx.random(dy)<EOL>if b.x > self.x+self.w+dx: b.vx -= _ctx.random(dx)<EOL>if b.y > self.y+self.h+dy: b.vy -= _ctx.random(dy)<EOL>if b.z < <NUM_LIT:0>: b.vz += <NUM_LIT:10><EOL>if b.z > <NUM_LIT:100>: b.vz -= <NUM_LIT:10><EOL>if b.y > self._perch_y and _ctx.random() < self._perch:<EOL><INDENT>b.y = self._perch_y<EOL>b.vy = -abs(b.vy) * <NUM_LIT><EOL>b.is_perching = True<EOL>try:<EOL><INDENT>b._perch_t = self._perch_t()<EOL><DEDENT>except:<EOL><INDENT>b._perch_t = self._perch_t<EOL><DEDENT><DEDENT><DEDENT>

Cages the flock inside the x, y, w, h area.

        The actual cage is a bit larger,
        so boids don't seem to bounce of invisible walls
        (they are rather "encouraged" to stay in the area).

        If a boid touches the ground level,
        it may decide to perch there for a while.


return self.find("<STR_LIT:title>").string<EOL>


domain = URLParser(self.url).domain<EOL>links = []<EOL>for a in self("<STR_LIT:a>"):<EOL><INDENT>for attribute, value in a.attrs:<EOL><INDENT>if attribute == "<STR_LIT>":<EOL><INDENT>if not externalor (value.startswith("<STR_LIT>") and value.find("<STR_LIT>"+domain) < <NUM_LIT:0>):<EOL><INDENT>links.append(value)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return links<EOL>

Retrieves links in the page.

        Returns a list of URL's.
        By default, only external URL's are returned.
        External URL's starts with http:// and point to another
        domain than the domain the page is on.


h = md5(id).hexdigest()<EOL>return os.path.join(self.path, h+self.type)<EOL>

Creates a unique filename in the cache for the id.


path = self.hash(id)<EOL>if os.path.exists(path):<EOL><INDENT>modified = datetime.datetime.fromtimestamp(os.stat(path)[<NUM_LIT:8>])<EOL>age = datetime.datetime.today() - modified<EOL>return age.days<EOL><DEDENT>else:<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>

Returns the age of the cache entry, in days.


def search_images(q, start=<NUM_LIT:0>, size="<STR_LIT>", wait=<NUM_LIT:10>, asynchronous=False, cached=False):

service = GOOGLE_IMAGES<EOL>return GoogleSearch(q, start, service, size, wait, asynchronous, cached)<EOL>

Returns a Google images query formatted as a GoogleSearch list object.


return s.encode("<STR_LIT:utf-8>")<EOL>


def search(q, start=<NUM_LIT:0>, wait=<NUM_LIT:10>, asynchronous=False, cached=False):

service = GOOGLE_SEARCH<EOL>return GoogleSearch(q, start, service, "<STR_LIT>", wait, asynchronous, cached)<EOL>

Returns a Google web query formatted as a GoogleSearch list object.


def search_news(q, start=<NUM_LIT:0>, wait=<NUM_LIT:10>, asynchronous=False, cached=False):

service = GOOGLE_NEWS<EOL>return GoogleSearch(q, start, service, "<STR_LIT>", wait, asynchronous, cached)<EOL>

Returns a Google news query formatted as a GoogleSearch list object.


if self.total > other.total:<EOL><INDENT>return <NUM_LIT:1><EOL><DEDENT>elif self.total < other.total: <EOL><INDENT>return -<NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>

Compares with another GoogleSearch based on the number of results.


def sort(words, context="<STR_LIT>", strict=True, relative=True, service=GOOGLE_SEARCH,<EOL>wait=<NUM_LIT:10>, asynchronous=False, cached=False):

results = []<EOL>for word in words:<EOL><INDENT>q = word + "<STR_LIT:U+0020>" + context<EOL>q.strip()<EOL>if strict: q = "<STR_LIT>"+q+"<STR_LIT>"<EOL>r = GoogleSearch(q, <NUM_LIT:1>, service, "<STR_LIT>", wait, asynchronous, cached)<EOL>results.append(r)<EOL><DEDENT>results.sort(GoogleResults.__cmp__)<EOL>results.reverse()<EOL>if relative and len(results) > <NUM_LIT:0>:<EOL><INDENT>sum = <NUM_LIT><EOL>for r in results: sum += r.total<EOL>for r in results: r.total /= float(sum)<EOL><DEDENT>results = [(r.query, r.total) for r in results]<EOL>return results<EOL>

Performs a Google sort on the given list.

    Sorts the items in the list according to
    the result count Google yields on an item.

    Setting a context sorts the items according
    to their relation to this context;
    for example sorting [red, green, blue] by "love"
    yields red as the highest results,
    likely because red is the color commonly associated with love.


def search(q, start=<NUM_LIT:1>, count=<NUM_LIT:10>, context=None, wait=<NUM_LIT:10>, asynchronous=False, cached=False):

service = YAHOO_SEARCH<EOL>return YahooSearch(q, start, count, service, context, wait, asynchronous, cached)<EOL>

Returns a Yahoo web query formatted as a YahooSearch list object.


def __init__(self, q, start=<NUM_LIT:1>, count=<NUM_LIT:10>, service=YAHOO_SEARCH, context=None, <EOL>wait=<NUM_LIT:10>, asynchronous=False, cached=True):

self.query = q<EOL>self.service = service<EOL>if cached:<EOL><INDENT>cache = "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>cache = None<EOL><DEDENT>url = "<STR_LIT>"<EOL>if service == YAHOO_SEARCH and context == None : url += "<STR_LIT>"<EOL>if service == YAHOO_SEARCH and context != None : url += "<STR_LIT>"<EOL>if service == YAHOO_IMAGES   :  url += "<STR_LIT>"<EOL>if service == YAHOO_NEWS     :  url += "<STR_LIT>"<EOL>if service == YAHOO_SPELLING :  url += "<STR_LIT>"<EOL>arg = urllib.urlencode((("<STR_LIT>", YAHOO_ID), <EOL>("<STR_LIT>", q),<EOL>("<STR_LIT:start>", start),<EOL>("<STR_LIT>", count),<EOL>("<STR_LIT>", unicode(context))))<EOL>url += arg<EOL>URLAccumulator.__init__(self, url, wait, asynchronous, cache, "<STR_LIT>")<EOL>

Searches Yahoo for the given query.

        By default, return cached results whenever possible.
        Otherwise, go online and update the local cache.
        The number of results is limited to count and starts at the given index.

        The returned results depend on the service used:
        web pages, images, news, spelling suggestion or contextual links.


def replace(match):<EOL><INDENT>return ESCAPE_DCT[match.group(<NUM_LIT:0>)]<EOL><DEDENT>return '<STR_LIT:">' + ESCAPE.sub(replace, s) + '<STR_LIT:">'<EOL>

Return a JSON representation of a Python string


<EOL>if isinstance(o, basestring):<EOL><INDENT>if isinstance(o, str):<EOL><INDENT>_encoding = self.encoding<EOL>if (_encoding is not None <EOL>and not (_encoding == '<STR_LIT:utf-8>')):<EOL><INDENT>o = o.decode(_encoding)<EOL><DEDENT><DEDENT>if self.ensure_ascii:<EOL><INDENT>return encode_basestring_ascii(o)<EOL><DEDENT>else:<EOL><INDENT>return encode_basestring(o)<EOL><DEDENT><DEDENT>chunks = list(self.iterencode(o))<EOL>return '<STR_LIT>'.join(chunks)<EOL>

Return a JSON string representation of a Python data structure.

>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
'{"foo": ["bar", "baz"]}'


raise TypeError("<STR_LIT>" % (o,))<EOL>

Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).

For example, to support arbitrary iterators, you could
implement default like this::

    def default(self, o):
        try:
            iterable = iter(o)
        except TypeError:
            pass
        else:
            return list(iterable)
        return JSONEncoder.default(self, o)


def __init__(self, skipkeys=False, ensure_ascii=True,<EOL>check_circular=True, allow_nan=True, sort_keys=False,<EOL>indent=None, separators=None, encoding='<STR_LIT:utf-8>', default=None):

self.skipkeys = skipkeys<EOL>self.ensure_ascii = ensure_ascii<EOL>self.check_circular = check_circular<EOL>self.allow_nan = allow_nan<EOL>self.sort_keys = sort_keys<EOL>self.indent = indent<EOL>self.current_indent_level = <NUM_LIT:0><EOL>if separators is not None:<EOL><INDENT>self.item_separator, self.key_separator = separators<EOL><DEDENT>if default is not None:<EOL><INDENT>self.default = default<EOL><DEDENT>self.encoding = encoding<EOL>

Constructor for JSONEncoder, with sensible defaults.

If skipkeys is False, then it is a TypeError to attempt
encoding of keys that are not str, int, long, float or None.  If
skipkeys is True, such items are simply skipped.

If ensure_ascii is True, the output is guaranteed to be str
objects with all incoming unicode characters escaped.  If
ensure_ascii is false, the output will be unicode object.

If check_circular is True, then lists, dicts, and custom encoded
objects will be checked for circular references during encoding to
prevent an infinite recursion (which would cause an OverflowError).
Otherwise, no such check takes place.

If allow_nan is True, then NaN, Infinity, and -Infinity will be
encoded as such.  This behavior is not JSON specification compliant,
but is consistent with most JavaScript based encoders and decoders.
Otherwise, it will be a ValueError to encode such floats.

If sort_keys is True, then the output of dictionaries will be
sorted by key; this is useful for regression tests to ensure
that JSON serializations can be compared on a day-to-day basis.

If indent is a non-negative integer, then JSON array
elements and object members will be pretty-printed with that
indent level.  An indent level of 0 will only insert newlines.
None is the most compact representation.

If specified, separators should be a (item_separator, key_separator)
tuple.  The default is (', ', ': ').  To get the most compact JSON
representation you should specify (',', ':') to eliminate whitespace.

If specified, default is a function that gets called for objects
that can't otherwise be serialized.  It should return a JSON encodable
version of the object or raise a ``TypeError``.

If encoding is not None, then all input strings will be
transformed into unicode using that encoding prior to JSON-encoding.
The default is UTF-8.


def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,<EOL>allow_nan=True, cls=None, indent=None, separators=None,<EOL>encoding='<STR_LIT:utf-8>', default=None, **kw):

<EOL>if (skipkeys is False and ensure_ascii is True and<EOL>check_circular is True and allow_nan is True and<EOL>cls is None and indent is None and separators is None and<EOL>encoding == '<STR_LIT:utf-8>' and default is None and not kw):<EOL><INDENT>return _default_encoder.encode(obj)<EOL><DEDENT>if cls is None:<EOL><INDENT>cls = JSONEncoder<EOL><DEDENT>return cls(<EOL>skipkeys=skipkeys, ensure_ascii=ensure_ascii,<EOL>check_circular=check_circular, allow_nan=allow_nan, indent=indent,<EOL>separators=separators, encoding=encoding, default=default,<EOL>**kw).encode(obj)<EOL>

Serialize ``obj`` to a JSON formatted ``str``.

If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.

If ``ensure_ascii`` is ``False``, then the return value will be a
``unicode`` instance subject to normal Python ``str`` to ``unicode``
coercion rules instead of being escaped to an ASCII ``str``.

If ``check_circular`` is ``False``, then the circular reference check
for container types will be skipped and a circular reference will
result in an ``OverflowError`` (or worse).

If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
strict compliance of the JSON specification, instead of using the
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).

If ``indent`` is a non-negative integer, then JSON array elements and
object members will be pretty-printed with that indent level. An indent
level of 0 will only insert newlines. ``None`` is the most compact
representation.

If ``separators`` is an ``(item_separator, dict_separator)`` tuple
then it will be used instead of the default ``(', ', ': ')`` separators.
``(',', ':')`` is the most compact JSON representation.

``encoding`` is the character encoding for str instances, default is UTF-8.

``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.

To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg.


import warnings<EOL>warnings.warn("<STR_LIT>",<EOL>DeprecationWarning)<EOL>return dumps(obj)<EOL>

jsonlib, JsonUtils, python-json, json-py API compatibility hook.
Use dumps(s) instead.


import warnings<EOL>warnings.warn("<STR_LIT>",<EOL>DeprecationWarning)<EOL>return loads(s)<EOL>

demjson, python-cjson API compatibility hook. Use loads(s) instead.


def __init__(self, encoding=None, object_hook=None, parse_float=None,<EOL>parse_int=None, parse_constant=None, strict=True):

self.encoding = encoding<EOL>self.object_hook = object_hook<EOL>self.parse_float = parse_float<EOL>self.parse_int = parse_int<EOL>self.parse_constant = parse_constant<EOL>self.strict = strict<EOL>

``encoding`` determines the encoding used to interpret any ``str``
objects decoded by this instance (utf-8 by default).  It has no
effect when decoding ``unicode`` objects.

Note that currently only encodings that are a superset of ASCII work,
strings of other encodings should be passed in as ``unicode``.

``object_hook``, if specified, will be called with the result
of every JSON object decoded and its return value will be used in
place of the given ``dict``.  This can be used to provide custom
deserializations (e.g. to support JSON-RPC class hinting).

``parse_float``, if specified, will be called with the string
of every JSON float to be decoded. By default this is equivalent to
float(num_str). This can be used to use another datatype or parser
for JSON floats (e.g. decimal.Decimal).

``parse_int``, if specified, will be called with the string
of every JSON int to be decoded. By default this is equivalent to
int(num_str). This can be used to use another datatype or parser
for JSON integers (e.g. float).

``parse_constant``, if specified, will be called with one of the
following strings: -Infinity, Infinity, NaN, null, true, false.
This can be used to raise an exception if invalid JSON numbers
are encountered.


def iterscan(self, string, idx=<NUM_LIT:0>, context=None):

match = self.scanner.scanner(string, idx).match<EOL>actions = self.actions<EOL>lastend = idx<EOL>end = len(string)<EOL>while True:<EOL><INDENT>m = match()<EOL>if m is None:<EOL><INDENT>break<EOL><DEDENT>matchbegin, matchend = m.span()<EOL>if lastend == matchend:<EOL><INDENT>break<EOL><DEDENT>action = actions[m.lastindex]<EOL>if action is not None:<EOL><INDENT>rval, next_pos = action(m, context)<EOL>if next_pos is not None and next_pos != matchend:<EOL><INDENT>matchend = next_pos<EOL>match = self.scanner.scanner(string, matchend).match<EOL><DEDENT>yield rval, matchend<EOL><DEDENT>lastend = matchend<EOL><DEDENT>


global languages<EOL>translations = {}<EOL>m = re.findall(self.re["<STR_LIT>"], markup)<EOL>for language, translation in m:<EOL><INDENT>if language in languages:<EOL><INDENT>translations[language] = translation<EOL><DEDENT><DEDENT>return translations<EOL>

Returns a dictionary of translations for the page title.

        A Wikipedia language link looks like: [[af:Rekenaar]].
        The parser will also fetch links like "user:" and "media:"
        but these are stripped against the dictionary of
        Wikipedia languages.

        You can get a translated page by searching Wikipedia
        with the appropriate language code and supplying
        the translated title as query.


def draw_table(table, x, y, w, padding=<NUM_LIT:5>):

try: from web import _ctx<EOL>except: pass<EOL>f = _ctx.fill()<EOL>_ctx.stroke(f)<EOL>h = _ctx.textheight("<STR_LIT:U+0020>") + padding*<NUM_LIT:2><EOL>row_y = y<EOL>if table.title != "<STR_LIT>":<EOL><INDENT>_ctx.fill(f)<EOL>_ctx.rect(x, row_y, w, h)<EOL>_ctx.fill(<NUM_LIT:1>)<EOL>_ctx.text(table.title, x+padding, row_y+_ctx.fontsize()+ padding)<EOL>row_y += h<EOL><DEDENT>rowspans = [<NUM_LIT:1> for i in range(<NUM_LIT:10>)]<EOL>previous_cell_w = <NUM_LIT:0><EOL>for row in table:<EOL><INDENT>cell_x = x<EOL>cell_w  = <NUM_LIT:1.0> * w<EOL>cell_w -= previous_cell_w * len([n for n in rowspans if n > <NUM_LIT:1>])<EOL>cell_w /= len(row)<EOL>cell_h = <NUM_LIT:0><EOL>for cell in row:<EOL><INDENT>this_h = _ctx.textheight(cell, width=cell_w-padding*<NUM_LIT:2>) + padding*<NUM_LIT:2><EOL>cell_h = max(cell_h, this_h)<EOL><DEDENT>i = <NUM_LIT:0><EOL>for cell in row:<EOL><INDENT>if rowspans[i] > <NUM_LIT:1>:<EOL><INDENT>rowspans[i] -= <NUM_LIT:1><EOL>cell_x += previous_cell_w<EOL>i += <NUM_LIT:1><EOL><DEDENT>m = re.search("<STR_LIT>", cell.properties)<EOL>if m:<EOL><INDENT>rowspan = int(m.group(<NUM_LIT:1>))<EOL>rowspans[i] = rowspan<EOL><DEDENT>else:<EOL><INDENT>rowspan = <NUM_LIT:1><EOL><DEDENT>_ctx.fill(f)<EOL>_ctx.text(cell, cell_x+padding, row_y+_ctx.fontsize()+padding, cell_w-padding*<NUM_LIT:2>)<EOL>_ctx.line(cell_x, row_y, cell_x+cell_w, row_y)<EOL>if cell_x > x:<EOL><INDENT>_ctx.nofill()<EOL>_ctx.line(cell_x, row_y, cell_x, row_y+cell_h)<EOL><DEDENT>cell_x += cell_w<EOL>i += <NUM_LIT:1><EOL><DEDENT>row_y += cell_h<EOL>previous_cell_w = cell_w<EOL><DEDENT>_ctx.nofill()<EOL>_ctx.rect(x, y, w, row_y-y)<EOL>

This is a very poor algorithm to draw Wikipedia tables in NodeBox.


<EOL>refs = ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]<EOL>exclude = ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]<EOL>exclude.extend(refs)<EOL>paragraphs = []<EOL>paragraph = WikipediaParagraph(self.title)<EOL>paragraph_data = "<STR_LIT>"<EOL>for chunk in markup.split("<STR_LIT:\n>"):<EOL><INDENT>if not chunk.startswith("<STR_LIT:U+0020>"):<EOL><INDENT>chunk = chunk.strip()<EOL><DEDENT>if chunk.startswith("<STR_LIT:=>"):<EOL><INDENT>if paragraph.title.lower() in refsor (paragraph.parent and paragraph.parent.title.lower() in refs):<EOL><INDENT>self.parse_paragraph_references(paragraph_data)<EOL><DEDENT>paragraph.extend(self.parse_paragraph(paragraph_data))<EOL>paragraphs.append(paragraph)<EOL>title = chunk.strip().strip("<STR_LIT:=>")<EOL>title = self.plain(title)<EOL>paragraph = WikipediaParagraph(title)<EOL>paragraph.depth = self.parse_paragraph_heading_depth(chunk)<EOL>if paragraph.title.lower() not in exclude:<EOL><INDENT>paragraph = self.connect_paragraph(paragraph, paragraphs)<EOL><DEDENT>paragraph_data = "<STR_LIT>"<EOL><DEDENT>elif re.search(re.compile("<STR_LIT>", re.I), chunk):<EOL><INDENT>paragraph.main = [link.strip("<STR_LIT>") for link in chunk.split("<STR_LIT:|>")[<NUM_LIT:1>:]]<EOL>paragraph.main = [re.sub(re.compile("<STR_LIT>", re.I), "<STR_LIT>", link) <EOL>for link in paragraph.main]<EOL><DEDENT>elif re.search(re.compile("<STR_LIT>", re.I), chunk):<EOL><INDENT>paragraph.related = [link.strip("<STR_LIT>") for link in chunk.split("<STR_LIT:|>")[<NUM_LIT:1>:]]<EOL><DEDENT>else:<EOL><INDENT>paragraph_data += chunk +"<STR_LIT:\n>"<EOL><DEDENT><DEDENT>if paragraph.title.lower() in refsor (paragraph.parent and paragraph.parent.title.lower() in refs):<EOL><INDENT>self.parse_paragraph_references(paragraph_data)<EOL><DEDENT>paragraph.extend(self.parse_paragraph(paragraph_data))<EOL>paragraphs.append(paragraph)<EOL>paragraphs_exclude = []<EOL>for paragraph in paragraphs:<EOL><INDENT>if paragraph.title.lower() not in excludeand not (paragraph.parent and paragraph.parent.title.lower() in exclude):<EOL><INDENT>paragraphs_exclude.append(paragraph)<EOL><DEDENT><DEDENT>if len(paragraphs_exclude) == <NUM_LIT:1> andlen(paragraphs_exclude[<NUM_LIT:0>]) == <NUM_LIT:0>:<EOL><INDENT>return []<EOL><DEDENT>return paragraphs_exclude<EOL>

Returns a list of paragraphs in the markup.

        A paragraph has a title and multiple lines of plain text.
        A paragraph might have parent and child paragraphs,
        denoting subtitles or bigger chapters.

        A paragraph might have links to additional articles.

        Formats numbered lists by replacing # by 1.
        Formats bulleted sublists like ** or *** with indentation.


important = []<EOL>table_titles = [table.title for table in self.tables]<EOL>m = re.findall(self.re["<STR_LIT>"], markup)<EOL>for bold in m:<EOL><INDENT>bold = self.plain(bold)<EOL>if not bold in table_titles:<EOL><INDENT>important.append(bold.lower())<EOL><DEDENT><DEDENT>return important<EOL>

Returns a list of words that appear in bold in the article.

        Things like table titles are not added to the list,
        these are probably bold because it makes the layout nice,
        not necessarily because they are important.


def __init__(self, title, markup, light=False, full_strip=True):

self.title = title<EOL>self.markup = markup<EOL>self.full_strip = full_strip<EOL>self.disambiguation = []<EOL>self.categories = []<EOL>self.links = []<EOL>self.paragraphs = []<EOL>self.images = []<EOL>self.tables = []<EOL>self.references = []<EOL>self.translations = {}<EOL>self.important = []<EOL>self.re = {<EOL>"<STR_LIT>" : r"<STR_LIT>",<EOL>"<STR_LIT>"       : r"<STR_LIT>",<EOL>"<STR_LIT>"           : r"<STR_LIT>",<EOL>"<STR_LIT:image>"          : re.compile(r"<STR_LIT>", re.I),<EOL>"<STR_LIT>"        : re.compile("<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT>"          : re.compile(r"<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT>"     : re.compile(r"<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT>"      : re.compile(r"<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT>"       : re.compile(r"<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT:url>"            : r"<STR_LIT>",            <EOL>"<STR_LIT>"   : re.compile(r"<STR_LIT>", re.DOTALL),<EOL>"<STR_LIT>"    : r"<STR_LIT>",<EOL>"<STR_LIT>"           : r"<STR_LIT>",<EOL>"<STR_LIT>"        : re.compile(r"<STR_LIT>", re.DOTALL),       <EOL>}<EOL>self.ref = "<STR_LIT>"<EOL>self.parse(light)<EOL>

Wikipedia page parser.

        The expected markup is the stuff in Wikipedia's edit textarea.
        With light=True, it will onlt parse links to other articles (which is faster).
        With full_strip=False, it will preserve some HTML markup (links, bold, italic).


for chunk in str.split("<STR_LIT:\n>"):<EOL><INDENT>if  not chunk.startswith("<STR_LIT:U+0020>"):<EOL><INDENT>return False<EOL><DEDENT><DEDENT>return True<EOL>

Determines if an item in a paragraph is preformatted.

    If all of the lines in the markup start with a " "
    this indicates preformatted text.
    Preformatted is usually used for programming code.


for chunk in str.split("<STR_LIT:\n>"):<EOL><INDENT>chunk = chunk.replace("<STR_LIT:\t>", "<STR_LIT>")<EOL>if  not chunk.lstrip().startswith("<STR_LIT:*>")and not re.search(r"<STR_LIT>", chunk.lstrip()):<EOL><INDENT>return False<EOL><DEDENT><DEDENT>return True<EOL>

Determines if an item in a paragraph is a list.

    If all of the lines in the markup start with a "*" or "1."
    this indicates a list as parsed by parse_paragraphs().
    It can be drawn with draw_list().


<EOL>if self.full_strip:<EOL><INDENT>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)<EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)<EOL><DEDENT>markup = re.sub(self.re["<STR_LIT>"], "<STR_LIT>", markup)<EOL>markup = re.sub(self.re["<STR_LIT>"], "<STR_LIT>", markup)<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>if self.full_strip:<EOL><INDENT>markup = re.sub(r"<STR_LIT>", "<STR_LIT>", markup)<EOL><DEDENT>else:<EOL><INDENT>markup = re.sub(r"<STR_LIT>", '<STR_LIT>', markup)<EOL>markup = re.sub(r"<STR_LIT>", '<STR_LIT>', markup)    <EOL><DEDENT>markup = re.sub(self.re["<STR_LIT>"], "<STR_LIT>", markup)<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)<EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)<EOL>markup = markup.replace("<STR_LIT:[>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT:]>", "<STR_LIT>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT:[>")<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT:]>")<EOL>markup = re.sub(self.re["<STR_LIT>"], "<STR_LIT>", markup)                  <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)                      <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)           <EOL>markup = re.sub(self.ref+"<STR_LIT>", "<STR_LIT>", markup)        <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)                 <EOL>markup = re.sub(self.re["<STR_LIT>"], "<STR_LIT>", markup)                    <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)            <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)                   <EOL>markup = re.sub("<STR_LIT>", "<STR_LIT>", markup)         <EOL>markup = re.sub(re.compile("<STR_LIT>", re.DOTALL), "<STR_LIT>", markup)  <EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = re.sub("<STR_LIT>", "<STR_LIT:U+0020>", markup)<EOL>markup = markup.split("<STR_LIT:\n>")<EOL>for i in range(len(markup)):<EOL><INDENT>if not markup[i].startswith("<STR_LIT:U+0020>"):<EOL><INDENT>markup[i] = re.sub(r"<STR_LIT>", "<STR_LIT:U+0020>", markup[i])<EOL><DEDENT><DEDENT>markup = "<STR_LIT:\n>".join(markup)<EOL>markup = markup.replace("<STR_LIT>", "<STR_LIT:.>")<EOL>if self.full_strip:<EOL><INDENT>markup = strip_tags(markup, exclude=["<STR_LIT>"], linebreaks=True)<EOL><DEDENT>markup = markup.strip()<EOL>return markup<EOL>

Strips Wikipedia markup from given text.

        This creates a "plain" version of the markup,
        stripping images and references and the like.
        Does some commonsense maintenance as well,
        like collapsing multiple spaces.
        If you specified full_strip=False for WikipediaPage instance,
        some markup is preserved as HTML (links, bold, italic).


tables = []<EOL>m = re.findall(self.re["<STR_LIT>"], markup)<EOL>for chunk in m:<EOL><INDENT>table = WikipediaTable()<EOL>table.properties = chunk.split("<STR_LIT:\n>")[<NUM_LIT:0>].strip("<STR_LIT>").strip()<EOL>self.connect_table(table, chunk, markup)<EOL>row = None<EOL>for chunk in chunk.split("<STR_LIT:\n>"):<EOL><INDENT>chunk = chunk.strip()<EOL>if chunk.startswith("<STR_LIT>"):<EOL><INDENT>title = self.plain(chunk.strip("<STR_LIT>"))<EOL>table.title = title<EOL><DEDENT>elif chunk.startswith("<STR_LIT>"):<EOL><INDENT>if row: <EOL><INDENT>row.properties = chunk.strip("<STR_LIT>").strip()<EOL>table.append(row)<EOL><DEDENT>row = None<EOL><DEDENT>elif chunk.startswith("<STR_LIT>"):<EOL><INDENT>pass<EOL><DEDENT>elif chunk.startswith("<STR_LIT:|>")or chunk.startswith("<STR_LIT:!>"):<EOL><INDENT>row = self.parse_table_row(chunk, row)<EOL><DEDENT><DEDENT>if row: table.append(row)<EOL>if len(table) > <NUM_LIT:0>:<EOL><INDENT>tables.append(table)<EOL><DEDENT><DEDENT>return tables<EOL>

Returns a list of tables in the markup.

        A Wikipedia table looks like:
        {| border="1"
        |-
        |Cell 1 (no modifier - not aligned)
        |-
        |align="right" |Cell 2 (right aligned)
        |-
        |}


m = re.search(self.re["<STR_LIT>"], markup)<EOL>if m:<EOL><INDENT>return self.parse_links(m.group(<NUM_LIT:1>))<EOL><DEDENT>else:<EOL><INDENT>return []<EOL><DEDENT>

Gets the Wikipedia disambiguation page for this article.

        A Wikipedia disambiguation link refers to other pages
        with the same title but of smaller significance,
        e.g. {{dablink|For the IEEE magazine see [[Computer (magazine)]].}}


return markup.count("<STR_LIT:=>")/<NUM_LIT:2> - <NUM_LIT:1><EOL>

Returns the depth of a heading.

        The depth determines parent and child relations,
        which headings (and hence which paragraphs) are a child to a heading higher up.
        Returns 0 for <h1> =, 1 for <h2> ==, etc.

        Called from parse_paragraphs() method.


categories = []<EOL>m = re.findall(self.re["<STR_LIT>"], markup)<EOL>for category in m:<EOL><INDENT>category = category.split("<STR_LIT:|>")<EOL>page = category[<NUM_LIT:0>].strip()<EOL>display = u"<STR_LIT>"<EOL>if len(category) > <NUM_LIT:1>: <EOL><INDENT>display = category[<NUM_LIT:1>].strip()<EOL><DEDENT>if not page in categories:<EOL><INDENT>categories.append(page)<EOL><DEDENT><DEDENT>return categories<EOL>

Returns a list of categories the page belongs to.

        # A Wikipedia category link looks like:
        # [[Category:Computing]]
        # This indicates the page is included in the given category.
        # If "Category" is preceded by ":" this indicates a link to a category.


def connect_table(self, table, chunk, markup):

k = markup.find(chunk)<EOL>i = markup.rfind("<STR_LIT>", <NUM_LIT:0>, k)<EOL>j = markup.find("<STR_LIT:\n>", i+<NUM_LIT:1>)<EOL>paragraph_title = markup[i:j].strip().strip("<STR_LIT>")<EOL>for paragraph in self.paragraphs:<EOL><INDENT>if paragraph.title == paragraph_title:<EOL><INDENT>paragraph.tables.append(table)<EOL>table.paragraph = paragraph<EOL><DEDENT><DEDENT>

Creates a link from the table to paragraph and vice versa.

        Finds the first heading above the table in the markup.
        This is the title of the paragraph the table belongs to.


for table in re.findall(self.re["<STR_LIT>"], markup):<EOL><INDENT>wiki = table<EOL>wiki = re.sub(r"<STR_LIT>", "<STR_LIT>", wiki)<EOL>wiki = re.sub(r"<STR_LIT>", "<STR_LIT>", wiki)<EOL>wiki = re.sub(r"<STR_LIT>", "<STR_LIT>", wiki)<EOL>wiki = wiki.replace("<STR_LIT>", "<STR_LIT:\n>")<EOL>wiki = wiki.replace("<STR_LIT>", "<STR_LIT:\n>")<EOL>wiki = wiki.replace("<STR_LIT>", "<STR_LIT>")<EOL>markup = markup.replace(table, wiki)<EOL><DEDENT>return markup<EOL>

Subtitutes <table> content to Wikipedia markup.


def findAllNext(self, name=None, attrs={}, text=None, limit=None,<EOL>**kwargs):

return self._findAll(name, attrs, text, limit, self.nextGenerator,<EOL>**kwargs)<EOL>

Returns all items that match the given criteria and appear
        after this Tag in the document.


def findPrevious(self, name=None, attrs={}, text=None, **kwargs):

return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)<EOL>

Returns the first item that matches the given criteria and
        appears before this Tag in the document.


def findPreviousSiblings(self, name=None, attrs={}, text=None,<EOL>limit=None, **kwargs):

return self._findAll(name, attrs, text, limit,<EOL>self.previousSiblingGenerator, **kwargs)<EOL>

Returns the siblings of this Tag that match the given
        criteria and appear before this Tag in the document.


httpEquiv = None<EOL>contentType = None<EOL>contentTypeIndex = None<EOL>tagNeedsEncodingSubstitution = False<EOL>for i in range(<NUM_LIT:0>, len(attrs)):<EOL><INDENT>key, value = attrs[i]<EOL>key = key.lower()<EOL>if key == '<STR_LIT>':<EOL><INDENT>httpEquiv = value<EOL><DEDENT>elif key == '<STR_LIT:content>':<EOL><INDENT>contentType = value<EOL>contentTypeIndex = i<EOL><DEDENT><DEDENT>if httpEquiv and contentType: <EOL><INDENT>match = self.CHARSET_RE.search(contentType)<EOL>if match:<EOL><INDENT>if (self.declaredHTMLEncoding is not None or<EOL>self.originalEncoding == self.fromEncoding):<EOL><INDENT>def rewrite(match):<EOL><INDENT>return match.group(<NUM_LIT:1>) + "<STR_LIT>"<EOL><DEDENT>newAttr = self.CHARSET_RE.sub(rewrite, contentType)<EOL>attrs[contentTypeIndex] = (attrs[contentTypeIndex][<NUM_LIT:0>],<EOL>newAttr)<EOL>tagNeedsEncodingSubstitution = True<EOL><DEDENT>else:<EOL><INDENT>newCharset = match.group(<NUM_LIT:3>)<EOL>if newCharset and newCharset != self.originalEncoding:<EOL><INDENT>self.declaredHTMLEncoding = newCharset<EOL>self._feed(self.declaredHTMLEncoding)<EOL>raise StopParsing<EOL><DEDENT>pass<EOL><DEDENT><DEDENT><DEDENT>tag = self.unknown_starttag("<STR_LIT>", attrs)<EOL>if tag and tagNeedsEncodingSubstitution:<EOL><INDENT>tag.containsSubstitutions = True<EOL><DEDENT>

Beautiful Soup can detect a charset included in a META tag,
        try to convert the document to that charset, and re-parse the
        document from the beginning.