<commit_before>#!/usr/bin/env python
#
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
#
# transform_sql.py -- create a header file with the appropriate SQL variables
# from an SQL file
#

import os
import re
import sys

DEFINE_END = '  ""\n\n'

def usage_and_exit(msg):
  if msg:
    sys.stderr.write('%s\n\n' % msg)
  sys.stderr.write(
    'USAGE: %s SQLITE_FILE [OUTPUT_FILE]\n'
    '  stdout will be used if OUTPUT_FILE is not provided.\n'
    % os.path.basename(sys.argv[0]))
  sys.stderr.flush()
  sys.exit(1)

class Processor(object):
  re_comments = re.compile(r'/\*.*?\*/', re.MULTILINE|re.DOTALL)

  # a few SQL comments that act as directives for this transform system
  re_format = re.compile('-- *format: *([0-9]+)')
  re_statement = re.compile('-- *STMT_([A-Z_0-9]+)')
  re_include = re.compile('-- *include: *([-a-z]+)')
  re_define = re.compile('-- *define: *([A-Z_0-9]+)')

  def _sub_format(self, match):
    vsn = match.group(1)

    self.close_define()
    self.output.write('#define %s_%s \\\n' % (self.var_name, match.group(1)))
    self.var_printed = True

  def _sub_statement(self, match):
    name = match.group(1)

    self.close_define()
    self.output.write('#define STMT_%s %d\n' % (match.group(1),
                                                self.stmt_count))
    self.output.write('#define STMT_%d \\\n' % (self.stmt_count,))
    self.var_printed = True

    self.stmt_count += 1

  def _sub_include(self, match):
    filepath = os.path.join(self.dirpath, match.group(1) + '.sql')

    self.close_define()
    self.process_file(open(filepath).read())

  def _sub_define(self, match):
    define = match.group(1)

    self.output.write('  APR_STRINGIFY(%s) \\\n' % define)

  def __init__(self, dirpath, output, var_name):
    self.dirpath = dirpath
    self.output = output
    self.var_name = var_name

    self.stmt_count = 0
    self.var_printed = False

    self._directives = {
        self.re_format      : self._sub_format,
        self.re_statement   : self._sub_statement,
        self.re_include     : self._sub_include,
        self.re_define      : self._sub_define,
      }

  def process_file(self, input):
    input = self.re_comments.sub('', input)

    for line in input.split('\n'):
      line = line.replace('"', '\\"')
      line = re.sub(r'IS_STRICT_DESCENDANT_OF[(]([A-Za-z_.]+), ([?][0-9]+)[)]',
                    r"((\1 > \2 || '/') AND (\1 < \2 || '0')) ",
                    line)

      if line.strip():
        handled = False

        for regex, handler in self._directives.iteritems():
          match = regex.match(line)
          if match:
            handler(match)
            handled = True
            break

        # we've handed the line, so skip it
        if handled:
          continue

        if not self.var_printed:
          self.output.write('#define %s \\\n' % self.var_name)
          self.var_printed = True

        # got something besides whitespace. write it out. include some whitespace
        # to separate the SQL commands. and a backslash to continue the string
        # onto the next line.
        self.output.write('  "%s " \\\n' % line)

    # previous line had a continuation. end the madness.
    self.close_define()

  def close_define(self):
    if self.var_printed:
      self.output.write(DEFINE_END)
      self.var_printed = False

def main(input_filepath, output):
  filename = os.path.basename(input_filepath)
  input = open(input_filepath, 'r').read()

  var_name = re.sub('[-.]', '_', filename).upper()

  output.write(
    '/* This file is automatically generated from %s.\n'
    ' * Do not edit this file -- edit the source and rerun gen-make.py */\n'
    '\n'
    % (filename,))

  proc = Processor(os.path.dirname(input_filepath), output, var_name)
  proc.process_file(input)

  ### the STMT_%d naming precludes *multiple* transform_sql headers from
  ### being used within the same .c file. for now, that's more than fine.
  ### in the future, we can always add a var_name discriminator or use
  ### the statement name itself (which should hopefully be unique across
  ### all names in use; or can easily be made so)
  if proc.stmt_count > 0:
    output.write(
      '#define %s_DECLARE_STATEMENTS(varname) \\\n' % (var_name,)
      + '  static const char * const varname[] = { \\\n'
      + ', \\\n'.join('    STMT_%d' % (i,) for i in range(proc.stmt_count))
      + ', \\\n    NULL \\\n  }\n')

if __name__ == '__main__':
  if len(sys.argv) < 2 or len(sys.argv) > 3:
    usage_and_exit('Incorrect number of arguments')

  # Note: we could use stdin, but then we'd have no var_name
  input_filepath = sys.argv[1]

  if len(sys.argv) > 2:
    output_file = open(sys.argv[2], 'w')
  else:
    output_file = sys.stdout

  main(input_filepath, output_file)
<commit_msg>* build/transform_sql.py   (Processor.process_file): Tweak generated parentheses.<commit_after>#!/usr/bin/env python
#
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
#
# transform_sql.py -- create a header file with the appropriate SQL variables
# from an SQL file
#

import os
import re
import sys

DEFINE_END = '  ""\n\n'

def usage_and_exit(msg):
  if msg:
    sys.stderr.write('%s\n\n' % msg)
  sys.stderr.write(
    'USAGE: %s SQLITE_FILE [OUTPUT_FILE]\n'
    '  stdout will be used if OUTPUT_FILE is not provided.\n'
    % os.path.basename(sys.argv[0]))
  sys.stderr.flush()
  sys.exit(1)

class Processor(object):
  re_comments = re.compile(r'/\*.*?\*/', re.MULTILINE|re.DOTALL)

  # a few SQL comments that act as directives for this transform system
  re_format = re.compile('-- *format: *([0-9]+)')
  re_statement = re.compile('-- *STMT_([A-Z_0-9]+)')
  re_include = re.compile('-- *include: *([-a-z]+)')
  re_define = re.compile('-- *define: *([A-Z_0-9]+)')

  def _sub_format(self, match):
    vsn = match.group(1)

    self.close_define()
    self.output.write('#define %s_%s \\\n' % (self.var_name, match.group(1)))
    self.var_printed = True

  def _sub_statement(self, match):
    name = match.group(1)

    self.close_define()
    self.output.write('#define STMT_%s %d\n' % (match.group(1),
                                                self.stmt_count))
    self.output.write('#define STMT_%d \\\n' % (self.stmt_count,))
    self.var_printed = True

    self.stmt_count += 1

  def _sub_include(self, match):
    filepath = os.path.join(self.dirpath, match.group(1) + '.sql')

    self.close_define()
    self.process_file(open(filepath).read())

  def _sub_define(self, match):
    define = match.group(1)

    self.output.write('  APR_STRINGIFY(%s) \\\n' % define)

  def __init__(self, dirpath, output, var_name):
    self.dirpath = dirpath
    self.output = output
    self.var_name = var_name

    self.stmt_count = 0
    self.var_printed = False

    self._directives = {
        self.re_format      : self._sub_format,
        self.re_statement   : self._sub_statement,
        self.re_include     : self._sub_include,
        self.re_define      : self._sub_define,
      }

  def process_file(self, input):
    input = self.re_comments.sub('', input)

    for line in input.split('\n'):
      line = line.replace('"', '\\"')
      line = re.sub(r'IS_STRICT_DESCENDANT_OF[(]([A-Za-z_.]+), ([?][0-9]+)[)]',
                    r"((\1) > (\2) || '/' AND (\1) < (\2) || '0') ",
                    line)

      if line.strip():
        handled = False

        for regex, handler in self._directives.iteritems():
          match = regex.match(line)
          if match:
            handler(match)
            handled = True
            break

        # we've handed the line, so skip it
        if handled:
          continue

        if not self.var_printed:
          self.output.write('#define %s \\\n' % self.var_name)
          self.var_printed = True

        # got something besides whitespace. write it out. include some whitespace
        # to separate the SQL commands. and a backslash to continue the string
        # onto the next line.
        self.output.write('  "%s " \\\n' % line)

    # previous line had a continuation. end the madness.
    self.close_define()

  def close_define(self):
    if self.var_printed:
      self.output.write(DEFINE_END)
      self.var_printed = False

def main(input_filepath, output):
  filename = os.path.basename(input_filepath)
  input = open(input_filepath, 'r').read()

  var_name = re.sub('[-.]', '_', filename).upper()

  output.write(
    '/* This file is automatically generated from %s.\n'
    ' * Do not edit this file -- edit the source and rerun gen-make.py */\n'
    '\n'
    % (filename,))

  proc = Processor(os.path.dirname(input_filepath), output, var_name)
  proc.process_file(input)

  ### the STMT_%d naming precludes *multiple* transform_sql headers from
  ### being used within the same .c file. for now, that's more than fine.
  ### in the future, we can always add a var_name discriminator or use
  ### the statement name itself (which should hopefully be unique across
  ### all names in use; or can easily be made so)
  if proc.stmt_count > 0:
    output.write(
      '#define %s_DECLARE_STATEMENTS(varname) \\\n' % (var_name,)
      + '  static const char * const varname[] = { \\\n'
      + ', \\\n'.join('    STMT_%d' % (i,) for i in range(proc.stmt_count))
      + ', \\\n    NULL \\\n  }\n')

if __name__ == '__main__':
  if len(sys.argv) < 2 or len(sys.argv) > 3:
    usage_and_exit('Incorrect number of arguments')

  # Note: we could use stdin, but then we'd have no var_name
  input_filepath = sys.argv[1]

  if len(sys.argv) > 2:
    output_file = open(sys.argv[2], 'w')
  else:
    output_file = sys.stdout

  main(input_filepath, output_file)
<|endoftext|>


<commit_before>from django.core.urlresolvers import reverse_lazy
from django.views import generic

from . import forms
from . import models

class GoodsBrowseView(generic.TemplateView):
    template_name = 'goods/goods-browse.html'

    def get_context_data(self, **kwargs):
        context = super(GoodsBrowseView, self).get_context_data(**kwargs)
        context['event_goods'] = Good.objects.filter(event__isnull=False)
        context['shop_goods'] = Good.objects.filter(shop__isnull=False)
        return context

class ShopListView(generic.ListView):
    queryset = Shop.objects.all()
    template_name = 'goods/shop-list.html'

class ShopDetailView(generic.DetailView):
    queryset = Shop.objects.all()
    template_name = 'goods/shop-detail.html'

class ShopCreateView(generic.CreateView):
    form_class = forms.ShopForm
    model = models.Shop
    success_url = reverse_lazy('shop-detail')

class ShopUpdateView(generic.CreateView):
    form_class = forms.ShopForm
    model = models.Shop
    success_url = reverse_lazy('shop-detail')

class GoodCreateView(generic.CreateView):
    form_class = forms.GoodForm
    model = models.Good
    success_url = reverse_lazy('goods-browse')

class GoodUpdateView(generic.UpdateView):
    form_class = forms.GoodForm
    model = models.Good
    success_url = reverse_lazy('goods-browse')

class SetCreateView(generic.CreateView):
    form_class = forms.SetForm
    model = models.Set
    success_url = reverse_lazy('goods-browse')

class SetUpdateView(generic.UpdateView):
    form_class = forms.SetForm
    model = models.Set
    success_url = reverse_lazy('goods-browse')

class SuperSetCreateView(generic.CreateView):
    form_class = forms.SuperSetForm
    model = models.SuperSet
    success_url = reverse_lazy('goods-browse')

class SuperSetUpdateView(generic.UpdateView):
    form_class = forms.SuperSetForm
    model = models.SuperSet
    success_url = reverse_lazy('goods-browse')

# See if we can change success_url from 'goods-browse' good permalink?
<commit_msg>Add LoginRequiredMixins to the good views.<commit_after>from braces.views import LoginRequiredMixin
from django.core.urlresolvers import reverse_lazy
from django.views import generic

from . import forms
from . import models

class GoodsBrowseView(generic.TemplateView):
    template_name = 'goods/goods-browse.html'

    def get_context_data(self, **kwargs):
        context = super(GoodsBrowseView, self).get_context_data(**kwargs)
        context['event_goods'] = Good.objects.filter(event__isnull=False)
        context['shop_goods'] = Good.objects.filter(shop__isnull=False)
        return context

class ShopListView(generic.ListView):
    queryset = Shop.objects.all()
    template_name = 'goods/shop-list.html'

class ShopDetailView(generic.DetailView):
    queryset = Shop.objects.all()
    template_name = 'goods/shop-detail.html'

class ShopCreateView(LoginRequiredMixin, generic.CreateView):
    form_class = forms.ShopForm
    model = models.Shop
    success_url = reverse_lazy('shop-detail')

class ShopUpdateView(LoginRequiredMixin, generic.CreateView):
    form_class = forms.ShopForm
    model = models.Shop
    success_url = reverse_lazy('shop-detail')

class GoodCreateView(LoginRequiredMixin, generic.CreateView):
    form_class = forms.GoodForm
    model = models.Good
    success_url = reverse_lazy('goods-browse')

class GoodUpdateView(LoginRequiredMixin, generic.UpdateView):
    form_class = forms.GoodForm
    model = models.Good
    success_url = reverse_lazy('goods-browse')

class SetCreateView(LoginRequiredMixin, generic.CreateView):
    form_class = forms.SetForm
    model = models.Set
    success_url = reverse_lazy('goods-browse')

class SetUpdateView(LoginRequiredMixin, generic.UpdateView):
    form_class = forms.SetForm
    model = models.Set
    success_url = reverse_lazy('goods-browse')

class SuperSetCreateView(LoginRequiredMixin, generic.CreateView):
    form_class = forms.SuperSetForm
    model = models.SuperSet
    success_url = reverse_lazy('goods-browse')

class SuperSetUpdateView(LoginRequiredMixin, generic.UpdateView):
    form_class = forms.SuperSetForm
    model = models.SuperSet
    success_url = reverse_lazy('goods-browse')

# See if we can change success_url from 'goods-browse' good permalink?
<|endoftext|>


<commit_before>'''
This implementation is based in John Tromp's Java implementation
of Connect 4.

https://github.com/qu1j0t3/fhourstones/blob/master/Connect4.java
'''

from __future__ import division, unicode_literals

import six
from . import Game
from ..util import print_aec, str_aec, ZobristHashing

ROWS = 6
COLS = 7
H1 = ROWS + 1
H2 = ROWS + 2
SIZE = ROWS * COLS
SIZE1 = H1 * COLS
ALL1 = (1 << SIZE1) - 1
COL1 = (1 << H1) - 1
BOTTOM = ALL1 // COL1
TOP = BOTTOM << ROWS

def board_str_to_board_mdarray(board):
    return [list(board[row*COLS:(row*COLS)+COLS]) for row in range(ROWS)]

class Connect4(Game):

    ROWS = 6
    COLS = 7

    name = 'Connect4'
    n_positions = ROWS * COLS
    n_pieces = 2
    zobrist_hash = ZobristHashing(n_positions, n_pieces)

    def __init__(self, board=None):
        if board:
            if isinstance(board, six.string_types):
                self.board = board_str_to_board_mdarray(board)
            elif isinstance(board, list):
                self.board = board
        else:
            self.reset()

    def __hash__(self):
        return Connect4.zobrist_hash(self.board)

    def __eq__(self, other):
        attrs = ['_cur_player', '_boards', '_moves', '_height']
        return all([getattr(self, name) == getattr(other, name) for name in attrs])

    def __repr__(self):
        return Connect4View(self).render()

    def __str__(self):
        return Connect4View(self).render()

    ########
    # Game #
    ########

    def copy(self):
        c4 = Connect4()
        c4._cur_player = self._cur_player
        c4._boards = self._boards[:]
        c4._moves = self._moves[:]
        c4._height = self._height[:]
        return c4

    def cur_player(self):
        return self._cur_player

    def legal_moves(self):
        '''
        Returns the legal moves for the player in turn.
        Each move is the letter of the column where the piece
        will be placed.
        Example: ['a', 'b', 'c', 'f']
        '''
        return [chr(ord('a') + move) for move in self._moves]

    def make_move(self, move):
        '''
        A move is the letter of the column where the piece will be placed.
        '''
        move = ord(move) - ord('a')
        if move not in self._moves:
            print(type(move))
            raise Exception('Invalid move: {}'.format(move))
        new_board = self._boards[self.cur_player()] | (1 << self._height[move])
        self._height[move] += 1
        self._boards[self.cur_player()] = new_board
        self._cur_player ^= 1
        self._moves = [] if self._is_win(new_board) else self._generate_moves()
        if self._is_win(new_board):
            self._moves = []
            # self._cur_player = None
        else:
            self._moves = self._generate_moves()
        return self

    def outcomes(self):
        if self._is_win(self._boards[0]):
            return ['W', 'L']
        elif self._is_win(self._boards[1]):
            return ['L', 'W']
        return ['D', 'D']

    def reset(self):
        self._cur_player = 0
        self._boards = [0, 0]
        self._height = [H1 * col for col in range(COLS)]
        self._moves = self._generate_moves()

    #############
    # Connect 4 #
    #############

    @property
    def board(self):
        b = []
        for row in range(ROWS - 1, -1, -1):
            for col in range(COLS):
                hello = (col * 7) + row
                if (1 << hello) & self._boards[0]:
                    b.append(0)
                elif (1 << hello) & self._boards[1]:
                    b.append(1)
                else:
                    b.append(' ')
        return b

    @board.setter
    def board(self, board):
        '''
        board: a string

        Example:

        game.board = (
            'O------'
            'X------'
            'O------'
            'X------'
            'O------'
            'X------'
        )
        '''
        self._boards = [0, 0]
        counters = [0, 0]
        self._height = [H1 * col for col in range(COLS)]
        max_cols =  [0] * COLS
        for row in range(ROWS):
            for col in range(COLS):
                if (board[row][col] == 'X'):
                    self._boards[0] |= 1 << ((col * COLS) + (ROWS - row - 1))
                    counters[0] += 1
                    max_cols[col] = max(max_cols[col], 6 - row)
                elif (board[row][col] == 'O'):
                    self._boards[1] |= 1 << ((col * COLS) + (ROWS - row - 1))
                    counters[1] += 1
                    max_cols[col] = max(max_cols[col], 6 - row)
        for col in range(COLS):
            self._height[col] = (col * 7) + max_cols[col]
        if self._is_win(self._boards[0]) or self._is_win(self._boards[1]):
            # self._cur_player = None
            self._moves = []
            return
        diff = counters[0] - counters[1]
        if diff == 0:
            self._cur_player = 0
        elif diff == 1:
            self._cur_player = 1
        else:
            raise Exception('Illegal board!')
        self._moves = self._generate_moves()

    def _generate_moves(self):
        return [col for col in range(COLS) if ((1 << self._height[col]) & TOP) == 0]

    def _is_win(self, board):
        '''Returns Ttrue if the given bitboard has a winning pattern.'''
        y = board & (board >> ROWS)
        if y & (y >> 2 * ROWS):
            return True
        y = board & (board >> H1)
        if y & (y >> 2 * H1):
            return True
        y = board & (board >> H2)
        if y & (y >> 2 * H2):
            return True
        y = board & (board >> 1)
        if y & (y >> 2):
            return True
        return False

    #############
    # Debugging #
    #############

    def print_bitboard(self, board):
        out = '  '
        for col in range(COLS):
            out += ' ' + chr(97 + col)
        out = str_aec(out, 'bold_green') + '\n'
        for row in range(ROWS, -1, -1):
            out += ' ' + str_aec(str(row + 1), 'bold_green')
            for col in range(COLS + 10):
                hello = (col * 7) + row
                if (1 << hello) & board:
                    out += str_aec(' X', 'bold_red')
                else:
                    out += ' .'
            out += '\n'
        out += '\n'
        out += '-' * 80
        out += '\n'
        print(out)

class Connect4View(object):

    def __init__(self, game):
        self.game = game

    def _info(self):
        if self.game.is_over():
            return self._game_over() + '\n'
        return self._next_player() + self._moves() + '\n'

    def _game_over(self):
        return str_aec('Game Over!', 'bold_green') + '\n'

    def _next_player(self):
        return str_aec('Next player: ', 'bold_green') + str(self.game.cur_player()) + '\n'

    def _moves(self):
        s = '[{}]'.format(', '.join([str(s) for s in self.game.legal_moves()]))
        out = ''
        out += str_aec('Moves: ', 'bold_green') + s + '\n'
        return out

    def _board(self):
        out = '  '
        for col in range(COLS):
            out += ' ' + chr(97 + col)
        out = str_aec(out, 'bold_green') + '\n'
        for row in range(ROWS - 1, -1, -1):
            out += ' ' + str_aec(str(row + 1), 'bold_green')
            for col in range(COLS):
                hello = (col * 7) + row
                if (1 << hello) & self.game._boards[0]:
                    out += str_aec(' X', 'bold_red')
                elif (1 << hello) & self.game._boards[1]:
                    out += str_aec(' O', 'bold_blue')
                else:
                    out += ' .'
            out += '\n'
        out += '\n'
        out += '-' * 80
        out += '\n'
        return out

    def _outcomes(self):
        return '\n' + str(self.game.outcomes()) if self.game.is_over() else ''

    def render(self):
        return '{info}{board}{outcomes}'.format(
            info=self._info(),
            board=self._board(),
            outcomes=self._outcomes()
        )
<commit_msg>update<commit_after>'''
This implementation is based in John Tromp's Java implementation
of Connect 4.

https://github.com/qu1j0t3/fhourstones/blob/master/Connect4.java
'''

from __future__ import division, unicode_literals

import six
from . import Game
from ..util import print_aec, str_aec, ZobristHashing

ROWS = 6
COLS = 7
H1 = ROWS + 1
H2 = ROWS + 2
SIZE = ROWS * COLS
SIZE1 = H1 * COLS
ALL1 = (1 << SIZE1) - 1
COL1 = (1 << H1) - 1
BOTTOM = ALL1 // COL1
TOP = BOTTOM << ROWS

def board_str_to_board_mdarray(board):
    return [list(board[row*COLS:(row*COLS)+COLS]) for row in range(ROWS)]

class Connect4(Game):

    ROWS = 6
    COLS = 7

    name = 'Connect4'
    n_positions = ROWS * COLS
    n_pieces = 2
    zobrist_hash = ZobristHashing(n_positions, n_pieces)

    def __init__(self, board=None):
        if board:
            if isinstance(board, six.string_types):
                self.board = board_str_to_board_mdarray(board)
            elif isinstance(board, list):
                self.board = board
        else:
            self.reset()

    def __hash__(self):
        return Connect4.zobrist_hash(self.board)

    def __eq__(self, other):
        attrs = ['_cur_player', '_boards', '_moves', '_height']
        return all([getattr(self, name) == getattr(other, name) for name in attrs])

    def __repr__(self):
        return Connect4View(self).render()

    def __str__(self):
        return Connect4View(self).render()

    ########
    # Game #
    ########

    def copy(self):
        c4 = Connect4()
        c4._cur_player = self._cur_player
        c4._boards = self._boards[:]
        c4._moves = self._moves[:]
        c4._height = self._height[:]
        return c4

    def cur_player(self):
        return self._cur_player

    def legal_moves(self):
        '''
        Returns the legal moves for the player in turn.
        Each move is the letter of the column where the piece
        will be placed.
        Example: ['a', 'b', 'c', 'f']
        '''
        return [chr(ord('a') + move) for move in self._moves]

    def make_move(self, move):
        '''
        A move is the letter of the column where the piece will be placed.
        '''
        move = ord(move) - ord('a')
        if move not in self._moves:
            print(type(move))
            raise Exception('Invalid move: {}'.format(move))
        new_board = self._boards[self.cur_player()] | (1 << self._height[move])
        self._height[move] += 1
        self._boards[self.cur_player()] = new_board
        self._cur_player ^= 1
        self._moves = [] if self._is_win(new_board) else self._generate_moves()
        if self._is_win(new_board):
            self._moves = []
            # self._cur_player = None
        else:
            self._moves = self._generate_moves()
        return self

    def outcomes(self):
        if self._is_win(self._boards[0]):
            return ['W', 'L']
        elif self._is_win(self._boards[1]):
            return ['L', 'W']
        return ['D', 'D']

    def reset(self):
        self._cur_player = 0
        self._boards = [0, 0]
        self._height = [H1 * col for col in range(COLS)]
        self._moves = self._generate_moves()

    #############
    # Connect 4 #
    #############

    @property
    def board(self):
        b = []
        for row in range(ROWS - 1, -1, -1):
            for col in range(COLS):
                hello = (col * 7) + row
                if (1 << hello) & self._boards[0]:
                    b.append(0)
                elif (1 << hello) & self._boards[1]:
                    b.append(1)
                else:
                    b.append(' ')
        return b

    @board.setter
    def board(self, board):
        '''
        board: a string

        Example:

        game.board = (
            'O------'
            'X------'
            'O------'
            'X------'
            'O------'
            'X------'
        )
        '''
        self._boards = [0, 0]
        counters = [0, 0]
        self._height = [H1 * col for col in range(COLS)]
        max_cols =  [0] * COLS
        for row in range(ROWS):
            for col in range(COLS):
                if (board[row][col] == 'X'):
                    self._boards[0] |= 1 << ((col * COLS) + (ROWS - row - 1))
                    counters[0] += 1
                    max_cols[col] = max(max_cols[col], 6 - row)
                elif (board[row][col] == 'O'):
                    self._boards[1] |= 1 << ((col * COLS) + (ROWS - row - 1))
                    counters[1] += 1
                    max_cols[col] = max(max_cols[col], 6 - row)
        for col in range(COLS):
            self._height[col] = (col * 7) + max_cols[col]
        if self._is_win(self._boards[0]) or self._is_win(self._boards[1]):
            # self._cur_player = None
            self._moves = []
            return
        diff = counters[0] - counters[1]
        if diff == 0:
            self._cur_player = 0
        elif diff == 1:
            self._cur_player = 1
        else:
            raise Exception('Illegal board!')
        self._moves = self._generate_moves()

    def _generate_moves(self):
        return [col for col in range(COLS) if ((1 << self._height[col]) & TOP) == 0]

    def _is_win(self, board):
        '''Returns Ttrue if the given bitboard has a winning pattern.'''
        y = board & (board >> ROWS)
        if y & (y >> 2 * ROWS):
            return True
        y = board & (board >> H1)
        if y & (y >> 2 * H1):
            return True
        y = board & (board >> H2)
        if y & (y >> 2 * H2):
            return True
        y = board & (board >> 1)
        if y & (y >> 2):
            return True
        return False

    #############
    # Debugging #
    #############

    def print_bitboard(self, board):
        out = '  '
        for col in range(COLS):
            out += ' ' + chr(97 + col)
        out = str_aec(out, 'bold_green') + '\n'
        for row in range(ROWS, -1, -1):
            out += ' ' + str_aec(str(row + 1), 'bold_green')
            for col in range(COLS + 10):
                hello = (col * 7) + row
                if (1 << hello) & board:
                    out += str_aec(' X', 'bold_red')
                else:
                    out += ' .'
            out += '\n'
        out += '\n'
        out += '-' * 80
        out += '\n'
        print(out)

class Connect4View(object):

    def __init__(self, game):
        self.game = game

    def _info(self):
        if self.game.is_over():
            return self._game_over() + '\n'
        return self._next_player() + self._moves() + '\n'

    def _game_over(self):
        return str_aec('Game Over!', 'bold_green') + '\n'

    def _next_player(self):
        return str_aec('Next player: ', 'bold_green') + str(self.game.cur_player()) + '\n'

    def _moves(self):
        s = '[{}]'.format(', '.join([str(s) for s in self.game.legal_moves()]))
        out = ''
        out += str_aec('Moves: ', 'bold_green') + s + '\n'
        return out

    def _board(self):
        out = '  '
        for col in range(COLS):
            out += ' ' + chr(97 + col)
        out = str_aec(out, 'bold_green') + '\n'
        for row in range(ROWS - 1, -1, -1):
            out += ' ' + str_aec(str(row + 1), 'bold_green')
            for col in range(COLS):
                hello = (col * 7) + row
                if (1 << hello) & self.game._boards[0]:
                    out += str_aec(' X', 'bold_red')
                elif (1 << hello) & self.game._boards[1]:
                    out += str_aec(' O', 'bold_blue')
                else:
                    out += ' .'
            out += '\n'
        return out

    def _outcomes(self):
        return '\n' + str(self.game.outcomes()) if self.game.is_over() else ''

    def render(self):
        return '{info}{board}{outcomes}'.format(
            info=self._info(),
            board=self._board(),
            outcomes=self._outcomes()
        )
<|endoftext|>


<commit_before>from django.db import models
from django.db.models.manager import BaseManager
from .helper import bulk_update

class BulkUpdateQuerySet(models.QuerySet):
    def bulk_update(self, objs, update_fields=None, exclude_fields=None):
        self._for_write = True
        bulk_update(objs, update_fields=update_fields,
                    exclude_fields=exclude_fields, using=self.db)

class BulkUpdateManager(BaseManager.from_queryset(BulkUpdateQuerySet)):
    pass
<commit_msg>[#47] add batch size<commit_after>from django.db import models
from django.db.models.manager import BaseManager
from .helper import bulk_update

class BulkUpdateQuerySet(models.QuerySet):
    def bulk_update(self, objs, update_fields=None, exclude_fields=None, batch_size=None):
        self._for_write = True
        return bulk_update(
            objs, update_fields=update_fields,
            exclude_fields=exclude_fields, using=self.db,
            batch_size=batch_size)

class BulkUpdateManager(BaseManager.from_queryset(BulkUpdateQuerySet)):
    pass
<|endoftext|>


<commit_before>from datetime import datetime
import json

import requests
from flask import (
    abort,
    render_template,
    request,
    redirect,
    url_for,
    flash,
    session,
    current_app
)
from flask.ext.login import (
    login_required,
    current_user
)
from forms import (
    ChangeForm,
    ConfirmForm,
    SelectTaskForm,
    ConveyancerAddClientForm
)
from application.services import (
    post_to_cases,
    is_matched,
    is_owner,
    get_lrid_and_roles,
    get_client_lrid,
    is_within_view_limit,
    is_allowed_to_see_title
)
from application.auth.models import User
from application import (
    app
)
from utils import (
    get_or_log_error,
    AddressBuilder
)

from pytz import timezone

@app.template_filter()
def format_date_YMD(value):
    new_date = datetime.strptime(value, '%Y-%m-%d')
    return new_date.strftime('%d %B %Y')

@app.template_filter()
def format_date_DMY(value):
    new_date = datetime.strptime(value, '%d-%m-%Y')
    return new_date.strftime('%d %B %Y')

def _tz(dt):
    utc = timezone('UTC').localize(dt)
    bst = timezone('Europe/London').localize(dt)
    return bst + (utc - bst)

@app.template_filter()
def format_date_time_DMYHM(value):
    new_datetime = datetime.strptime(value, '%d-%m-%Y %H:%M:%S')
    return _tz(new_datetime).strftime('%d-%m-%Y %H:%M')

@app.template_filter()
def currency(value):
    """Format a comma separated  currency to 2 decimal places."""
    return "{:,.2f}".format(float(value))

def unix_timestamp_to_DMYHMS(value):
    return datetime.fromtimestamp(int(value)).strftime('%d %B %Y %H:%M:%S')

@app.route('/')
@login_required
def index():
    lrid, roles = get_lrid_and_roles(session)
    return render_template('index.html', roles=roles, lrid=lrid)

@app.route('/property/<title_number>')
@login_required
def property_by_title(title_number):
    if is_within_view_limit(current_user):
        title_url = "%s/%s/%s" % (
           app.config['AUTHENTICATED_SEARCH_API'],
           'auth/titles',
           title_number)
        app.logger.debug("Requesting title url : %s" % title_url)
        response = get_or_log_error(title_url)
        title = response.json()

        app.logger.debug("Found the following title: %s" % title)
        owner = is_owner(current_user, title_number)
        raw_address = title["property_description"]["fields"]["address"][0]
        address = AddressBuilder(**raw_address).build()
        return render_template(
           'view_property.html',
           title=title,
           is_owner=owner,
           address=address,
           apiKey=app.config['OS_API_KEY'])
    else:
        return redirect(url_for('auth.login'))

# Sticking to convention, "/property/<title_number>" will show the
# resource, and "/property/<title_number>/edit" will show a form
# to edit said resource. Here we go a step further, and limit
# the form to a section on the resource, e.g. "proprietor".
@app.route('/property/<title_number>/edit/title.proprietor.<int:proprietor_index>', methods=['GET', 'POST'])
@login_required
def property_by_title_edit_proprietor(title_number, proprietor_index):
    if is_owner(current_user, title_number):
        form = ChangeForm(request.form, marriage_country='GB')
        if request.method == 'GET':
            title = _get_title(title_number)
            app.logger.debug("Found the following title: %s" % title)
            form.title_number.data = title['title_number']

            proprietor = title['proprietorship']['fields']['proprietors'][proprietor_index - 1]
            form.proprietor_full_name.data = proprietor['name']['full_name']

        if form.validate_on_submit():
            if 'confirm' in form and form.confirm.data:

                post_to_cases('change-name-marriage', form.data)
                # TODO handle non-200 responses, and ack accordingly.
                return render_template('acknowledgement.html', form=form)
            else:
                from datatypes.validators.iso_country_code_validator import countries

                country = countries.get(alpha2=form.data['marriage_country']).name
                return render_template('confirm.html', form=ConfirmForm(obj=form.data), country=country)
        return render_template('edit_property.html', form=form)
    else:
        abort(401)

def _get_title(title_number):
    title_url = "%s/%s/%s" % (
        app.config['AUTHENTICATED_SEARCH_API'],
        'auth/titles',
        title_number)
    app.logger.debug("Requesting title url : %s" % title_url)
    response = get_or_log_error(title_url)
    return response.json()

# @app.route('/login', methods=['GET', 'POST'])
# def login():
#     form = LoginForm()
#     if form.validate_on_submit():
#         user = User.query.get(form.email.data)
#         if user and is_allowed_to_see_title(user, form.password.data):
#             login_user(user)
#             return redirect(form.next.data or url_for('.index'))
#         else:
#             app.logger.info("Login failed for user email %s" % form.email.data)
#             flash("Sorry, those details haven’t been recognised. Please try again.")
#     return render_template("auth/login_user.html", form=form)

# @app.route("/logout")
# @login_required
# def logout():
#     session.pop("lrid", None)
#     session.pop("roles", None)
#     logout_user()
#     return redirect(url_for('.login'))

@app.route('/relationship/client')
def relationship_client():
    return render_template('client-enter-token.html')

@app.route('/relationship/client/accept', methods=['POST'])
def client_get_relationship_details():
    url = current_app.config['INTRODUCTION_URL'] + '/details/' + request.form['token']
    app.logger.debug("INTRO URL: %s" % url)
    response = get_or_log_error(url)
    app.logger.debug("INTRO response json: %s " % response.json())
    return render_template('client-confirm.html', details=response.json(), token=request.form['token'])

@app.route('/relationship/client/confirm', methods=['POST'])
def client_confirm_relationship():
    request_json = json.dumps({'token': request.form['token'], "client_lrid": session['lrid']})
    url = current_app.config['INTRODUCTION_URL'] + '/confirm'

    response = requests.post(url, data=request_json, headers={'Content-Type': 'application/json'})

    return render_template('client-confirmed.html', conveyancer_name=response.json()['conveyancer_name'])

@app.route('/relationship/conveyancer')
def conveyancer_start():
    return render_template('conveyancer-start.html')

@app.route('/relationship/conveyancer/search')
@login_required
def client_relationship_flow_step_1_show_search():
    return render_template('conveyancer-search.html')

@app.route('/relationship/conveyancer/property', methods=['POST'])
@login_required
def client_relationship_flow_step_2_render_results_in_template():
    query = request.form['search-text']
    search_url = "%s/auth/titles/%s" % ( app.config['AUTHENTICATED_SEARCH_API'], query)
    app.logger.debug("URL requested %s" % search_url)
    response = get_or_log_error(search_url)
    title = response.json()
    app.logger.debug("RESULT = %s" % title)

    raw_address = title["property_description"]["fields"]["address"][0]
    address = AddressBuilder(**raw_address).build()

    return render_template('conveyancer-select-property.html',
                           title=title,
                           address=address,
                           apiKey=app.config['OS_API_KEY'])

@app.route('/relationship/conveyancer/task', methods=['POST'])
@login_required
def client_relationship_flow_step_3_store_selected_title_and_show_task_choices():
    session['title_no'] = request.form['title_no']
    session['property_full_address'] = request.form['property_full_address']
    return render_template('conveyancer-select-task.html', form=(SelectTaskForm(request.form)))

@app.route('/relationship/conveyancer/client', methods=['POST'])
@login_required
def client_relationship_flow_step_5a_store_number_of_clients_and_show_the_add_client_form():
    session['buying_or_selling'] = request.form['buying_or_selling_property']
    client_form = ConveyancerAddClientForm()
    return render_template('conveyancer-add-client.html', action_path='/relationship/conveyancer/confirm',
                           form=client_form)

@app.route('/relationship/conveyancer/confirm', methods=['POST'])
@login_required
def client_relationship_flow_step_6():
    form = ConveyancerAddClientForm(request.form)
    if form.validate_on_submit():

        session['client_full_name'] = form.full_name.data
        session['client_date_of_birth'] = str(form.date_of_birth.data)
        session['client_address'] = form.address.data
        session['client_telephone'] = form.telephone.data
        session['client_email'] = form.email.data

        client_lrid = get_client_lrid(_create_user(form))

        if client_lrid:
            session['client_lrid'] = client_lrid
        else:
            flash("The client is not in our system")
            return render_template('conveyancer-add-client.html', form=form,
                                   action_path='/relationship/conveyancer/confirm', add_client_heading='Add client')

        return render_template('conveyancer-confirm.html', dict=conveyancer_dict(), address=property_full_address(),
                               client_name=session['client_full_name'], client_address=session['client_address'])
    else:
        return render_template('conveyancer-add-client.html', form=form,
                               action_path='/relationship/conveyancer/confirm', add_client_heading='Add client')

def conveyancer_dict():
    client = [{
                  "lrid": session['client_lrid']
              }]

    data = {
        "conveyancer_lrid": session['lrid'],
        "title_number": session['title_no'],
        "clients": client,
        "task": session['buying_or_selling']
    }

    return data

def property_full_address():
    address = {
        "property_full_address": session['property_full_address'],
    }
    return address

def _create_user(form):
    client_data = {'name': form.full_name.data,
                   'date_of_birth': form.date_of_birth.data,
                   'current_address': form.address.data,
                   'gender': form.gender.data}
    return User(**client_data)

@app.route('/relationship/conveyancer/token')
@login_required
def conveyancer_token():
    headers = {'content-type': 'application/json'}

    data = json.dumps(conveyancer_dict())
    relationship_url = app.config['INTRODUCTION_URL'] + '/relationship'

    app.logger.debug("Sending data %s to introduction at %s" % (data, relationship_url))
    response = requests.post(relationship_url, data=data, headers=headers)
    token = response.json()['token']
    clear_captured_client_relationship_session_variables()
    return render_template('conveyancer-token.html', token=token)

def clear_captured_client_relationship_session_variables():
    session.pop('client_full_name', None)
    session.pop('client_address', None)
    session.pop('client_date_of_birth', None)
    session.pop('client_telephone', None)
    session.pop('client_lrid', None)
    session.pop('title_no', None)
    session.pop('buying_or_selling', None)
    session.pop('property_full_address', None)

@app.route('/property/<title_number>/changes')
@login_required
def changes(title_number):
    if is_owner(current_user, title_number):
        cases_url = app.config['CASES_URL'] + '/cases/property/' + title_number
        app.logger.debug("Requesting cases from %s" % cases_url)
        cases_response = requests.get(cases_url)
        cases = cases_response.json()
        pending = []
        historical_changes_list = {}

        historian_list_url = app.config['HISTORIAN_URL'] + '/' + title_number + '?version=list'
        historian_version_url = app.config['HISTORIAN_URL'] + '/' + title_number + '?version='
        app.logger.debug('requesting history from ' + historian_list_url)
        historian_list_response = requests.get(historian_list_url)
        if historian_list_response:
            #version information put in a list to pass to the template.
            for version in historian_list_response.json()['versions']:
                historian_version_response = requests.get(historian_version_url + version['version_id'])
                converted_unix_timestamp = unix_timestamp_to_DMYHMS(str(historian_version_response.json()['contents']['created_ts']))
                historical_changes_list[version['version_id']] = converted_unix_timestamp
                #historical_changes_list[version['version_id']] = historian_version_response.json()['contents']['created_ts']

        for case in cases:
            if case['status'] != 'completed':
                pending.append(case)

        order_by_latest_version_first = list(reversed(sorted(historical_changes_list.keys())))

        return render_template('changes.html', title_number=title_number, pending=pending,
                               historical_changes=historical_changes_list,
                               order_by_latest_version_first=order_by_latest_version_first)
    else:
        abort(401)

@app.route('/property/<title_number>/changes/<version>')
@login_required
def change_version(title_number, version):

    historian_version_url = app.config['HISTORIAN_URL'] + '/' + title_number + '?version='
    app.logger.debug('requesting historical version from ' + historian_version_url)
    historian_version_response = requests.get(historian_version_url + version).json()['contents']
    converted_unix_timestamp = unix_timestamp_to_DMYHMS(str(historian_version_response['created_ts']))
    owner = is_owner(current_user, title_number)

    return render_template(
        'view_historical_version.html',
        title=historian_version_response,
        is_owner=owner,
        apiKey=app.config['OS_API_KEY'],
        change_date=converted_unix_timestamp)

<commit_msg>Small fixes to get the history pages working<commit_after>from datetime import datetime
import json

import requests
from flask import (
    abort,
    render_template,
    request,
    redirect,
    url_for,
    flash,
    session,
    current_app
)
from flask.ext.login import (
    login_required,
    current_user
)
from forms import (
    ChangeForm,
    ConfirmForm,
    SelectTaskForm,
    ConveyancerAddClientForm
)
from application.services import (
    post_to_cases,
    is_matched,
    is_owner,
    get_lrid_and_roles,
    get_client_lrid,
    is_within_view_limit,
    is_allowed_to_see_title
)
from application.auth.models import User
from application import (
    app
)
from utils import (
    get_or_log_error,
    AddressBuilder
)

from pytz import timezone

@app.template_filter()
def format_date_YMD(value):
    new_date = datetime.strptime(value, '%Y-%m-%d')
    return new_date.strftime('%d %B %Y')

@app.template_filter()
def format_date_DMY(value):
    new_date = datetime.strptime(value, '%d-%m-%Y')
    return new_date.strftime('%d %B %Y')

def _tz(dt):
    utc = timezone('UTC').localize(dt)
    bst = timezone('Europe/London').localize(dt)
    return bst + (utc - bst)

@app.template_filter()
def format_date_time_DMYHM(value):
    new_datetime = datetime.strptime(value, '%d-%m-%Y %H:%M:%S')
    return _tz(new_datetime).strftime('%d-%m-%Y %H:%M')

@app.template_filter()
def currency(value):
    """Format a comma separated  currency to 2 decimal places."""
    return "{:,.2f}".format(float(value))

def unix_timestamp_to_DMYHMS(value):
    return datetime.fromtimestamp(int(value)).strftime('%d %B %Y %H:%M:%S')

@app.route('/')
@login_required
def index():
    lrid, roles = get_lrid_and_roles(session)
    return render_template('index.html', roles=roles, lrid=lrid)

@app.route('/property/<title_number>')
@login_required
def property_by_title(title_number):
    if is_within_view_limit(current_user):
        title_url = "%s/%s/%s" % (
           app.config['AUTHENTICATED_SEARCH_API'],
           'auth/titles',
           title_number)
        app.logger.debug("Requesting title url : %s" % title_url)
        response = get_or_log_error(title_url)
        title = response.json()

        app.logger.debug("Found the following title: %s" % title)
        owner = is_owner(current_user, title_number)
        raw_address = title["property_description"]["fields"]["address"][0]
        address = AddressBuilder(**raw_address).build()
        return render_template(
           'view_property.html',
           title=title,
           is_owner=owner,
           address=address,
           apiKey=app.config['OS_API_KEY'])
    else:
        return redirect(url_for('auth.login'))

# Sticking to convention, "/property/<title_number>" will show the
# resource, and "/property/<title_number>/edit" will show a form
# to edit said resource. Here we go a step further, and limit
# the form to a section on the resource, e.g. "proprietor".
@app.route('/property/<title_number>/edit/title.proprietor.<int:proprietor_index>', methods=['GET', 'POST'])
@login_required
def property_by_title_edit_proprietor(title_number, proprietor_index):
    if is_owner(current_user, title_number):
        form = ChangeForm(request.form, marriage_country='GB')
        if request.method == 'GET':
            title = _get_title(title_number)
            app.logger.debug("Found the following title: %s" % title)
            form.title_number.data = title['title_number']

            proprietor = title['proprietorship']['fields']['proprietors'][proprietor_index - 1]
            form.proprietor_full_name.data = proprietor['name']['full_name']

        if form.validate_on_submit():
            if 'confirm' in form and form.confirm.data:

                post_to_cases('change-name-marriage', form.data)
                # TODO handle non-200 responses, and ack accordingly.
                return render_template('acknowledgement.html', form=form)
            else:
                from datatypes.validators.iso_country_code_validator import countries

                country = countries.get(alpha2=form.data['marriage_country']).name
                return render_template('confirm.html', form=ConfirmForm(obj=form.data), country=country)
        return render_template('edit_property.html', form=form)
    else:
        abort(401)

def _get_title(title_number):
    title_url = "%s/%s/%s" % (
        app.config['AUTHENTICATED_SEARCH_API'],
        'auth/titles',
        title_number)
    app.logger.debug("Requesting title url : %s" % title_url)
    response = get_or_log_error(title_url)
    return response.json()

# @app.route('/login', methods=['GET', 'POST'])
# def login():
#     form = LoginForm()
#     if form.validate_on_submit():
#         user = User.query.get(form.email.data)
#         if user and is_allowed_to_see_title(user, form.password.data):
#             login_user(user)
#             return redirect(form.next.data or url_for('.index'))
#         else:
#             app.logger.info("Login failed for user email %s" % form.email.data)
#             flash("Sorry, those details haven’t been recognised. Please try again.")
#     return render_template("auth/login_user.html", form=form)

# @app.route("/logout")
# @login_required
# def logout():
#     session.pop("lrid", None)
#     session.pop("roles", None)
#     logout_user()
#     return redirect(url_for('.login'))

@app.route('/relationship/client')
def relationship_client():
    return render_template('client-enter-token.html')

@app.route('/relationship/client/accept', methods=['POST'])
def client_get_relationship_details():
    url = current_app.config['INTRODUCTION_URL'] + '/details/' + request.form['token']
    app.logger.debug("INTRO URL: %s" % url)
    response = get_or_log_error(url)
    app.logger.debug("INTRO response json: %s " % response.json())
    return render_template('client-confirm.html', details=response.json(), token=request.form['token'])

@app.route('/relationship/client/confirm', methods=['POST'])
def client_confirm_relationship():
    request_json = json.dumps({'token': request.form['token'], "client_lrid": session['lrid']})
    url = current_app.config['INTRODUCTION_URL'] + '/confirm'

    response = requests.post(url, data=request_json, headers={'Content-Type': 'application/json'})

    return render_template('client-confirmed.html', conveyancer_name=response.json()['conveyancer_name'])

@app.route('/relationship/conveyancer')
def conveyancer_start():
    return render_template('conveyancer-start.html')

@app.route('/relationship/conveyancer/search')
@login_required
def client_relationship_flow_step_1_show_search():
    return render_template('conveyancer-search.html')

@app.route('/relationship/conveyancer/property', methods=['POST'])
@login_required
def client_relationship_flow_step_2_render_results_in_template():
    query = request.form['search-text']
    search_url = "%s/auth/titles/%s" % ( app.config['AUTHENTICATED_SEARCH_API'], query)
    app.logger.debug("URL requested %s" % search_url)
    response = get_or_log_error(search_url)
    title = response.json()
    app.logger.debug("RESULT = %s" % title)

    raw_address = title["property_description"]["fields"]["address"][0]
    address = AddressBuilder(**raw_address).build()

    return render_template('conveyancer-select-property.html',
                           title=title,
                           address=address,
                           apiKey=app.config['OS_API_KEY'])

@app.route('/relationship/conveyancer/task', methods=['POST'])
@login_required
def client_relationship_flow_step_3_store_selected_title_and_show_task_choices():
    session['title_no'] = request.form['title_no']
    session['property_full_address'] = request.form['property_full_address']
    return render_template('conveyancer-select-task.html', form=(SelectTaskForm(request.form)))

@app.route('/relationship/conveyancer/client', methods=['POST'])
@login_required
def client_relationship_flow_step_5a_store_number_of_clients_and_show_the_add_client_form():
    session['buying_or_selling'] = request.form['buying_or_selling_property']
    client_form = ConveyancerAddClientForm()
    return render_template('conveyancer-add-client.html', action_path='/relationship/conveyancer/confirm',
                           form=client_form)

@app.route('/relationship/conveyancer/confirm', methods=['POST'])
@login_required
def client_relationship_flow_step_6():
    form = ConveyancerAddClientForm(request.form)
    if form.validate_on_submit():

        session['client_full_name'] = form.full_name.data
        session['client_date_of_birth'] = str(form.date_of_birth.data)
        session['client_address'] = form.address.data
        session['client_telephone'] = form.telephone.data
        session['client_email'] = form.email.data

        client_lrid = get_client_lrid(_create_user(form))

        if client_lrid:
            session['client_lrid'] = client_lrid
        else:
            flash("The client is not in our system")
            return render_template('conveyancer-add-client.html', form=form,
                                   action_path='/relationship/conveyancer/confirm', add_client_heading='Add client')

        return render_template('conveyancer-confirm.html', dict=conveyancer_dict(), address=property_full_address(),
                               client_name=session['client_full_name'], client_address=session['client_address'])
    else:
        return render_template('conveyancer-add-client.html', form=form,
                               action_path='/relationship/conveyancer/confirm', add_client_heading='Add client')

def conveyancer_dict():
    client = [{
                  "lrid": session['client_lrid']
              }]

    data = {
        "conveyancer_lrid": session['lrid'],
        "title_number": session['title_no'],
        "clients": client,
        "task": session['buying_or_selling']
    }

    return data

def property_full_address():
    address = {
        "property_full_address": session['property_full_address'],
    }
    return address

def _create_user(form):
    client_data = {'name': form.full_name.data,
                   'date_of_birth': form.date_of_birth.data,
                   'current_address': form.address.data,
                   'gender': form.gender.data}
    return User(**client_data)

@app.route('/relationship/conveyancer/token')
@login_required
def conveyancer_token():
    headers = {'content-type': 'application/json'}

    data = json.dumps(conveyancer_dict())
    relationship_url = app.config['INTRODUCTION_URL'] + '/relationship'

    app.logger.debug("Sending data %s to introduction at %s" % (data, relationship_url))
    response = requests.post(relationship_url, data=data, headers=headers)
    token = response.json()['token']
    clear_captured_client_relationship_session_variables()
    return render_template('conveyancer-token.html', token=token)

def clear_captured_client_relationship_session_variables():
    session.pop('client_full_name', None)
    session.pop('client_address', None)
    session.pop('client_date_of_birth', None)
    session.pop('client_telephone', None)
    session.pop('client_lrid', None)
    session.pop('title_no', None)
    session.pop('buying_or_selling', None)
    session.pop('property_full_address', None)

@app.route('/property/<title_number>/changes')
@login_required
def changes(title_number):
    if is_owner(current_user, title_number):
        cases_url = app.config['CASES_URL'] + '/cases/property/' + title_number
        app.logger.debug("Requesting cases from %s" % cases_url)
        cases_response = requests.get(cases_url)
        cases = cases_response.json()
        pending = []
        historical_changes_list = {}

        historian_list_url = app.config['HISTORIAN_URL'] + '/titles/' + title_number + '?version=list'
        historian_version_url = app.config['HISTORIAN_URL'] + '/titles/' + title_number + '?version='
        app.logger.debug('requesting history from ' + historian_list_url)
        historian_list_response = requests.get(historian_list_url)
        if historian_list_response:
            #version information put in a list to pass to the template.
            for version in historian_list_response.json()['versions']:
                historian_version_response = requests.get(historian_version_url + version['version_id'])
                historical_changes_list[version['version_id']] = historian_version_response.json()['contents']['edition_date']

        for case in cases:
            if case['status'] != 'completed':
                pending.append(case)

        order_by_latest_version_first = list(reversed(sorted(historical_changes_list.keys())))

        return render_template('changes.html', title_number=title_number, pending=pending,
                               historical_changes=historical_changes_list,
                               order_by_latest_version_first=order_by_latest_version_first)
    else:
        abort(401)

@app.route('/property/<title_number>/changes/<version>')
@login_required
def change_version(title_number, version):

    historian_version_url = app.config['HISTORIAN_URL'] + '/titles/' + title_number + '?version='
    app.logger.debug('requesting historical version from ' + historian_version_url)
    historian_version_response = requests.get(historian_version_url + version).json()['contents']
    converted_unix_timestamp = historian_version_response['edition_date']
    owner = is_owner(current_user, title_number)

    return render_template(
        'view_historical_version.html',
        title=historian_version_response,
        is_owner=owner,
        apiKey=app.config['OS_API_KEY'],
        change_date=converted_unix_timestamp)

<|endoftext|>


<commit_before>"""Copyright 2009 Chris Davis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License."""

import os
import sys
import pwd

from os.path import join, dirname, normpath, exists, isdir
from optparse import OptionParser
from ConfigParser import ConfigParser

import whisper
from carbon import log

from twisted.python import usage

defaults = dict(
  LOCAL_DATA_DIR="/opt/graphite/storage/whisper/",
  WHITELISTS_DIR="/opt/graphite/storage/",
  USER="",
  MAX_CACHE_SIZE='inf',
  MAX_UPDATES_PER_SECOND=1000,
  MAX_CREATES_PER_MINUTE='inf',
  LINE_RECEIVER_INTERFACE='0.0.0.0',
  LINE_RECEIVER_PORT=2003,
  PICKLE_RECEIVER_INTERFACE='0.0.0.0',
  PICKLE_RECEIVER_PORT=2004,
  CACHE_QUERY_INTERFACE='0.0.0.0',
  CACHE_QUERY_PORT=7002,
  LOG_UPDATES=True,
  WHISPER_AUTOFLUSH=False,
  MAX_DATAPOINTS_PER_MESSAGE=500,
  ENABLE_AMQP=False,
  AMQP_VERBOSE=False,
  BIND_PATTERNS=['#'],
  ENABLE_MANHOLE=False,
  MANHOLE_INTERFACE='127.0.0.1',
  MANHOLE_PORT=7222,
  MANHOLE_USER="",
  MANHOLE_PUBLIC_KEY="",
  RELAY_METHOD='rules',
  CH_HOST_LIST=[],
)

def _umask(value):
    return int(value, 8)

class OrderedConfigParser(ConfigParser):
  """Hacky workaround to ensure sections are always returned in the order
   they are defined in. Note that this does *not* make any guarantees about
   the order of options within a section or the order in which sections get
   written back to disk on write()."""
  _ordered_sections = []

  def read(self, path):
    result = ConfigParser.read(self, path)

    sections = []
    for line in open(path):
      line = line.strip()

      if line.startswith('[') and line.endswith(']'):
        sections.append( line[1:-1] )

    self._ordered_sections = sections

    return result

  def sections(self):
    return list( self._ordered_sections ) # return a copy for safety

class Settings(dict):
  __getattr__ = dict.__getitem__

  def __init__(self):
    dict.__init__(self)
    self.update(defaults)

  def readFrom(self, path, section):
    parser = ConfigParser()
    if not parser.read(path):
      raise Exception("Failed to read config file %s" % path)

    if not parser.has_section(section):
      return

    for key,value in parser.items(section):
      key = key.upper()

      # Detect type from defaults dict
      if key in defaults:
        valueType = type( defaults[key] )
      else:
        valueType = str

      if valueType is list:
        value = [ v.strip() for v in value.split(',') ]

      elif valueType is bool:
        value = parser.getboolean(section, key)

      else:
        # Attempt to figure out numeric types automatically
        try:
          value = int(value)
        except:
          try:
            value = float(value)
          except:
            pass

      self[key] = value

settings = Settings()
settings.update(defaults)

class CarbonCacheOptions(usage.Options):

    optFlags = [
        ["debug", "", "Run in debug mode."],
        ]

    optParameters = [
        ["config", "c", None, "Use the given config file."],
        ["instance", "", None, "Manage a specific carbon instance."],
        ["logdir", "", None, "Write logs to the given directory."],
        ]

    def postOptions(self):
        global settings

        program = self.parent.subCommand

        # Use provided pidfile (if any) as default for configuration. If it's
        # set to 'twistd.pid', that means no value was provided and the default
        # was used.
        pidfile = self.parent["pidfile"]
        if pidfile.endswith("twistd.pid"):
            pidfile = None
        self["pidfile"] = pidfile

        # Enforce a default umask of '022' if none was set.
        if not self.parent.has_key("umask") or self.parent["umask"] is None:
            self.parent["umask"] = 022

        # Read extra settings from the configuration file.
        program_settings = read_config(program, self)
        settings.update(program_settings)
        settings["program"] = program

        # Set process uid/gid by changing the parent config, if a user was
        # provided in the configuration file.
        if settings.USER:
            self.parent["uid"], self.parent["gid"] = (
                pwd.getpwnam(settings.USER)[2:4])

        # Set the pidfile in parent config to the value that was computed by
        # C{read_config}.
        self.parent["pidfile"] = settings["pidfile"]

        storage_schemas = join(settings["CONF_DIR"], "storage-schemas.conf")
        if not exists(storage_schemas):
            print "Error: missing required config %s" % storage_schemas
            sys.exit(1)

        if settings.WHISPER_AUTOFLUSH:
            log.msg("enabling whisper autoflush")
            whisper.AUTOFLUSH = True

        # If we are not running in debug mode or non-daemon mode, then log to a
        # directory, otherwise log output will go to stdout.
        if not (self["debug"] or self.parent["nodaemon"]):
            logdir = settings.LOG_DIR
            if not isdir(logdir):
                os.makedirs(logdir)
            log.logToDir(logdir)

        if not "action" in self:
            self["action"] = "start"
        self.handleAction()

    def parseArgs(self, action):
        """If an action was provided, store it for further processing."""
        self["action"] = action

    def handleAction(self):
        """Handle extra argument for backwards-compatibility.

        * C{start} will simply do minimal pid checking and otherwise let twistd
              take over.
        * C{stop} will kill an existing running process if it matches the
              C{pidfile} contents.
        * C{status} will simply report if the process is up or not.
        """
        action = self["action"]
        pidfile = self.parent["pidfile"]
        program = settings["program"]
        instance = self["instance"]

        if action == "stop":
            if not exists(pidfile):
                print "Pidfile %s does not exist" % pidfile
                raise SystemExit(0)
            pf = open(pidfile, 'r')
            try:
                pid = int(pf.read().strip())
            except:
                print "Could not read pidfile %s" % pidfile
                raise SystemExit(1)
            print "Sending kill signal to pid %d" % pid
            os.kill(pid, 15)

            print "Deleting %s (contained pid %d)" % (pidfile, pid)
            os.unlink(pidfile)
            raise SystemExit(0)

        elif action == "status":
            if not exists(pidfile):
                print "%s (instance %s) is not running" % (program, instance)
                raise SystemExit(0)
            pf = open(pidfile, "r")
            try:
                pid = int(pf.read().strip())
            except:
                print "Failed to read pid from %s" % pidfile
                raise SystemExit(1)

            if exists("/proc/%d" % pid):
                print ("%s (instance %s) is running with pid %d" %
                       (program, instance, pid))
                raise SystemExit(0)
            else:
                print "%s (instance %s) is not running" % (program, instance)
                raise SystemExit(0)
        elif action == "start":
            if exists(pidfile):
                print ("Pidfile %s already exists, is %s already running?" %
                       (pidfile, program))
                raise SystemExit(1)

class CarbonAggregatorOptions(CarbonCacheOptions):

    optParameters = [
        ["rules", "", None, "Use the given aggregation rules file."],
        ["rewrite-rules", "", None, "Use the given rewrite rules file."],
        ] + CarbonCacheOptions.optParameters

    def postOptions(self):
        CarbonCacheOptions.postOptions(self)
        if self["rules"] is None:
            self["rules"] = join(settings["CONF_DIR"], "aggregation-rules.conf")
        settings["aggregation-rules"] = self["rules"]

        if self["rewrite-rules"] is None:
            self["rewrite-rules"] = join(settings["CONF_DIR"],
                                         "rewrite-rules.conf")
        settings["rewrite-rules"] = self["rewrite-rules"]

class CarbonRelayOptions(CarbonCacheOptions):

    optParameters = [
        ["rules", "", None, "Use the given relay rules file."],
        ] + CarbonCacheOptions.optParameters

    def postOptions(self):
        CarbonCacheOptions.postOptions(self)
        if self["rules"] is None:
            self["rules"] = join(settings["CONF_DIR"], "relay-rules.conf")
        settings["relay-rules"] = self["rules"]

        if settings["RELAY_METHOD"] not in ("rules", "consistent-hashing"):
            print ("In carbon.conf, RELAY_METHOD must be either 'rules' or "
                   "'consistent-hashing'. Invalid value: '%s'" %
                   settings.RELAY_METHOD)
            sys.exit(1)

def get_default_parser(usage="%prog [options] <start|stop|status>"):
    """Create a parser for command line options."""
    parser = OptionParser(usage=usage)
    parser.add_option(
        "--debug", action="store_true",
        help="Run in the foreground, log to stdout")
    parser.add_option(
        "--profile",
        help="Record performance profile data to the given file")
    parser.add_option(
        "--pidfile", default=None,
        help="Write pid to the given file")
    parser.add_option(
        "--config",
        default=None,
        help="Use the given config file")
    parser.add_option(
        "--logdir",
        default=None,
        help="Write logs in the given directory")
    parser.add_option(
        "--instance",
        default=None,
        help="Manage a specific carbon instance")

    return parser

def get_parser(name):
    parser = get_default_parser()
    if name == "carbon-aggregator":
        parser.add_option(
            "--rules",
            default=None,
            help="Use the given aggregation rules file.")
        parser.add_option(
            "--rewrite-rules",
            default=None,
            help="Use the given rewrite rules file.")
    elif name == "carbon-relay":
        parser.add_option(
            "--rules",
            default=None,
            help="Use the given relay rules file.")
    return parser

def parse_options(parser, args):
    """
    Parse command line options and print usage message if no arguments were
    provided for the command.
    """
    (options, args) = parser.parse_args(args)

    if not args:
        parser.print_usage()
        raise SystemExit(1)

    if args[0] not in ("start", "stop", "status"):
        parser.print_usage()
        raise SystemExit(1)

    return options, args

def read_config(program, options, **kwargs):
    """
    Read settings for 'program' from configuration file specified by
    'options["config"]', with missing values provided by 'defaults'.
    """
    settings = Settings()
    settings.update(defaults)

    # Initialize default values if not set yet.
    for name, value in kwargs.items():
        settings.setdefault(name, value)

    graphite_root = os.environ['GRAPHITE_ROOT']

    # Default config directory to root-relative, unless overriden by the
    # 'GRAPHITE_CONF_DIR' environment variable.
    settings.setdefault("CONF_DIR",
                        os.environ.get("GRAPHITE_CONF_DIR",
                                       join(graphite_root, "conf")))
    if options["config"] is None:
        options["config"] = join(settings["CONF_DIR"], "carbon.conf")
    else:
        # Set 'CONF_DIR' to the parent directory of the 'carbon.conf' config
        # file.
        settings["CONF_DIR"] = dirname(normpath(options["config"]))

    # Storage directory can be overriden by the 'GRAPHITE_STORAGE_DIR'
    # environment variable. It defaults to a path relative to GRAPHITE_ROOT
    # for backwards compatibility though.
    settings.setdefault("STORAGE_DIR",
                        os.environ.get("GRAPHITE_STORAGE_DIR",
                                       join(graphite_root, "storage")))
    settings.setdefault(
        "LOG_DIR", join(settings["STORAGE_DIR"], "log", program))

    # Read configuration options from program-specific section.
    section = program[len("carbon-"):]
    settings.readFrom(options["config"], section)

    # If a specific instance of the program is specified, augment the settings
    # with the instance-specific settings and provide sane defaults for
    # optional settings.
    if options["instance"]:
        settings.readFrom(options["config"],
                          "%s:%s" % (section, options["instance"]))
        settings["pidfile"] = (
            options["pidfile"] or
            join(settings["STORAGE_DIR"], "%s-%s.pid" %
                 (program, options["instance"])))
        settings["LOG_DIR"] = (options["logdir"] or
                              "%s-%s" % (settings["LOG_DIR"].rstrip('/'),
                                          options["instance"]))
    else:
        settings["pidfile"] = (
            options["pidfile"] or
            join(settings["STORAGE_DIR"], '%s.pid' % program))
        settings["LOG_DIR"] = (options["logdir"] or settings["LOG_DIR"])

    return settings
<commit_msg>fixed missing output from cli commands<commit_after>"""Copyright 2009 Chris Davis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License."""

import os
import sys
import pwd

from os.path import join, dirname, normpath, exists, isdir
from optparse import OptionParser
from ConfigParser import ConfigParser

import whisper
from carbon import log

from twisted.python import usage

defaults = dict(
  LOCAL_DATA_DIR="/opt/graphite/storage/whisper/",
  WHITELISTS_DIR="/opt/graphite/storage/",
  USER="",
  MAX_CACHE_SIZE='inf',
  MAX_UPDATES_PER_SECOND=1000,
  MAX_CREATES_PER_MINUTE='inf',
  LINE_RECEIVER_INTERFACE='0.0.0.0',
  LINE_RECEIVER_PORT=2003,
  PICKLE_RECEIVER_INTERFACE='0.0.0.0',
  PICKLE_RECEIVER_PORT=2004,
  CACHE_QUERY_INTERFACE='0.0.0.0',
  CACHE_QUERY_PORT=7002,
  LOG_UPDATES=True,
  WHISPER_AUTOFLUSH=False,
  MAX_DATAPOINTS_PER_MESSAGE=500,
  ENABLE_AMQP=False,
  AMQP_VERBOSE=False,
  BIND_PATTERNS=['#'],
  ENABLE_MANHOLE=False,
  MANHOLE_INTERFACE='127.0.0.1',
  MANHOLE_PORT=7222,
  MANHOLE_USER="",
  MANHOLE_PUBLIC_KEY="",
  RELAY_METHOD='rules',
  CH_HOST_LIST=[],
)

def _umask(value):
    return int(value, 8)

class OrderedConfigParser(ConfigParser):
  """Hacky workaround to ensure sections are always returned in the order
   they are defined in. Note that this does *not* make any guarantees about
   the order of options within a section or the order in which sections get
   written back to disk on write()."""
  _ordered_sections = []

  def read(self, path):
    result = ConfigParser.read(self, path)

    sections = []
    for line in open(path):
      line = line.strip()

      if line.startswith('[') and line.endswith(']'):
        sections.append( line[1:-1] )

    self._ordered_sections = sections

    return result

  def sections(self):
    return list( self._ordered_sections ) # return a copy for safety

class Settings(dict):
  __getattr__ = dict.__getitem__

  def __init__(self):
    dict.__init__(self)
    self.update(defaults)

  def readFrom(self, path, section):
    parser = ConfigParser()
    if not parser.read(path):
      raise Exception("Failed to read config file %s" % path)

    if not parser.has_section(section):
      return

    for key,value in parser.items(section):
      key = key.upper()

      # Detect type from defaults dict
      if key in defaults:
        valueType = type( defaults[key] )
      else:
        valueType = str

      if valueType is list:
        value = [ v.strip() for v in value.split(',') ]

      elif valueType is bool:
        value = parser.getboolean(section, key)

      else:
        # Attempt to figure out numeric types automatically
        try:
          value = int(value)
        except:
          try:
            value = float(value)
          except:
            pass

      self[key] = value

settings = Settings()
settings.update(defaults)

class CarbonCacheOptions(usage.Options):

    optFlags = [
        ["debug", "", "Run in debug mode."],
        ]

    optParameters = [
        ["config", "c", None, "Use the given config file."],
        ["instance", "", None, "Manage a specific carbon instance."],
        ["logdir", "", None, "Write logs to the given directory."],
        ]

    def postOptions(self):
        global settings

        program = self.parent.subCommand

        # Use provided pidfile (if any) as default for configuration. If it's
        # set to 'twistd.pid', that means no value was provided and the default
        # was used.
        pidfile = self.parent["pidfile"]
        if pidfile.endswith("twistd.pid"):
            pidfile = None
        self["pidfile"] = pidfile

        # Enforce a default umask of '022' if none was set.
        if not self.parent.has_key("umask") or self.parent["umask"] is None:
            self.parent["umask"] = 022

        # Read extra settings from the configuration file.
        program_settings = read_config(program, self)
        settings.update(program_settings)
        settings["program"] = program

        # Set process uid/gid by changing the parent config, if a user was
        # provided in the configuration file.
        if settings.USER:
            self.parent["uid"], self.parent["gid"] = (
                pwd.getpwnam(settings.USER)[2:4])

        # Set the pidfile in parent config to the value that was computed by
        # C{read_config}.
        self.parent["pidfile"] = settings["pidfile"]

        storage_schemas = join(settings["CONF_DIR"], "storage-schemas.conf")
        if not exists(storage_schemas):
            print "Error: missing required config %s" % storage_schemas
            sys.exit(1)

        if settings.WHISPER_AUTOFLUSH:
            log.msg("enabling whisper autoflush")
            whisper.AUTOFLUSH = True

        if not "action" in self:
            self["action"] = "start"
        self.handleAction()

        # If we are not running in debug mode or non-daemon mode, then log to a
        # directory, otherwise log output will go to stdout.
        if not (self["debug"] or self.parent["nodaemon"]):
            logdir = settings.LOG_DIR
            if not isdir(logdir):
                os.makedirs(logdir)
            log.logToDir(logdir)

    def parseArgs(self, action):
        """If an action was provided, store it for further processing."""
        self["action"] = action

    def handleAction(self):
        """Handle extra argument for backwards-compatibility.

        * C{start} will simply do minimal pid checking and otherwise let twistd
              take over.
        * C{stop} will kill an existing running process if it matches the
              C{pidfile} contents.
        * C{status} will simply report if the process is up or not.
        """
        action = self["action"]
        pidfile = self.parent["pidfile"]
        program = settings["program"]
        instance = self["instance"]

        if action == "stop":
            if not exists(pidfile):
                print "Pidfile %s does not exist" % pidfile
                raise SystemExit(0)
            pf = open(pidfile, 'r')
            try:
                pid = int(pf.read().strip())
            except:
                print "Could not read pidfile %s" % pidfile
                raise SystemExit(1)
            print "Sending kill signal to pid %d" % pid
            os.kill(pid, 15)

            print "Deleting %s (contained pid %d)" % (pidfile, pid)
            os.unlink(pidfile)
            raise SystemExit(0)

        elif action == "status":
            if not exists(pidfile):
                print "%s (instance %s) is not running" % (program, instance)
                raise SystemExit(0)
            pf = open(pidfile, "r")
            try:
                pid = int(pf.read().strip())
            except:
                print "Failed to read pid from %s" % pidfile
                raise SystemExit(1)

            if exists("/proc/%d" % pid):
                print ("%s (instance %s) is running with pid %d" %
                       (program, instance, pid))
                raise SystemExit(0)
            else:
                print "%s (instance %s) is not running" % (program, instance)
                raise SystemExit(0)
        elif action == "start":
            if exists(pidfile):
                print ("Pidfile %s already exists, is %s already running?" %
                       (pidfile, program))
                raise SystemExit(1)
            print "Starting %s (instance %s)" % (program, instance)

class CarbonAggregatorOptions(CarbonCacheOptions):

    optParameters = [
        ["rules", "", None, "Use the given aggregation rules file."],
        ["rewrite-rules", "", None, "Use the given rewrite rules file."],
        ] + CarbonCacheOptions.optParameters

    def postOptions(self):
        CarbonCacheOptions.postOptions(self)
        if self["rules"] is None:
            self["rules"] = join(settings["CONF_DIR"], "aggregation-rules.conf")
        settings["aggregation-rules"] = self["rules"]

        if self["rewrite-rules"] is None:
            self["rewrite-rules"] = join(settings["CONF_DIR"],
                                         "rewrite-rules.conf")
        settings["rewrite-rules"] = self["rewrite-rules"]

class CarbonRelayOptions(CarbonCacheOptions):

    optParameters = [
        ["rules", "", None, "Use the given relay rules file."],
        ] + CarbonCacheOptions.optParameters

    def postOptions(self):
        CarbonCacheOptions.postOptions(self)
        if self["rules"] is None:
            self["rules"] = join(settings["CONF_DIR"], "relay-rules.conf")
        settings["relay-rules"] = self["rules"]

        if settings["RELAY_METHOD"] not in ("rules", "consistent-hashing"):
            print ("In carbon.conf, RELAY_METHOD must be either 'rules' or "
                   "'consistent-hashing'. Invalid value: '%s'" %
                   settings.RELAY_METHOD)
            sys.exit(1)

def get_default_parser(usage="%prog [options] <start|stop|status>"):
    """Create a parser for command line options."""
    parser = OptionParser(usage=usage)
    parser.add_option(
        "--debug", action="store_true",
        help="Run in the foreground, log to stdout")
    parser.add_option(
        "--profile",
        help="Record performance profile data to the given file")
    parser.add_option(
        "--pidfile", default=None,
        help="Write pid to the given file")
    parser.add_option(
        "--config",
        default=None,
        help="Use the given config file")
    parser.add_option(
        "--logdir",
        default=None,
        help="Write logs in the given directory")
    parser.add_option(
        "--instance",
        default=None,
        help="Manage a specific carbon instance")

    return parser

def get_parser(name):
    parser = get_default_parser()
    if name == "carbon-aggregator":
        parser.add_option(
            "--rules",
            default=None,
            help="Use the given aggregation rules file.")
        parser.add_option(
            "--rewrite-rules",
            default=None,
            help="Use the given rewrite rules file.")
    elif name == "carbon-relay":
        parser.add_option(
            "--rules",
            default=None,
            help="Use the given relay rules file.")
    return parser

def parse_options(parser, args):
    """
    Parse command line options and print usage message if no arguments were
    provided for the command.
    """
    (options, args) = parser.parse_args(args)

    if not args:
        parser.print_usage()
        raise SystemExit(1)

    if args[0] not in ("start", "stop", "status"):
        parser.print_usage()
        raise SystemExit(1)

    return options, args

def read_config(program, options, **kwargs):
    """
    Read settings for 'program' from configuration file specified by
    'options["config"]', with missing values provided by 'defaults'.
    """
    settings = Settings()
    settings.update(defaults)

    # Initialize default values if not set yet.
    for name, value in kwargs.items():
        settings.setdefault(name, value)

    graphite_root = os.environ['GRAPHITE_ROOT']

    # Default config directory to root-relative, unless overriden by the
    # 'GRAPHITE_CONF_DIR' environment variable.
    settings.setdefault("CONF_DIR",
                        os.environ.get("GRAPHITE_CONF_DIR",
                                       join(graphite_root, "conf")))
    if options["config"] is None:
        options["config"] = join(settings["CONF_DIR"], "carbon.conf")
    else:
        # Set 'CONF_DIR' to the parent directory of the 'carbon.conf' config
        # file.
        settings["CONF_DIR"] = dirname(normpath(options["config"]))

    # Storage directory can be overriden by the 'GRAPHITE_STORAGE_DIR'
    # environment variable. It defaults to a path relative to GRAPHITE_ROOT
    # for backwards compatibility though.
    settings.setdefault("STORAGE_DIR",
                        os.environ.get("GRAPHITE_STORAGE_DIR",
                                       join(graphite_root, "storage")))
    settings.setdefault(
        "LOG_DIR", join(settings["STORAGE_DIR"], "log", program))

    # Read configuration options from program-specific section.
    section = program[len("carbon-"):]
    settings.readFrom(options["config"], section)

    # If a specific instance of the program is specified, augment the settings
    # with the instance-specific settings and provide sane defaults for
    # optional settings.
    if options["instance"]:
        settings.readFrom(options["config"],
                          "%s:%s" % (section, options["instance"]))
        settings["pidfile"] = (
            options["pidfile"] or
            join(settings["STORAGE_DIR"], "%s-%s.pid" %
                 (program, options["instance"])))
        settings["LOG_DIR"] = (options["logdir"] or
                              "%s-%s" % (settings["LOG_DIR"].rstrip('/'),
                                          options["instance"]))
    else:
        settings["pidfile"] = (
            options["pidfile"] or
            join(settings["STORAGE_DIR"], '%s.pid' % program))
        settings["LOG_DIR"] = (options["logdir"] or settings["LOG_DIR"])

    return settings
<|endoftext|>