import math
import logging
from functools import partial
from collections import OrderedDict
from copy import deepcopy

import torch
import torch.nn as nn
import torch.nn.functional as F

from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD, IMAGENET_INCEPTION_MEAN, IMAGENET_INCEPTION_STD
from timm.models.helpers import build_model_with_cfg, named_apply, adapt_input_conv
from timm.models.layers import PatchEmbed, Mlp, DropPath, trunc_normal_, lecun_normal_
from timm.models.registry import register_model
from torch.nn.init import _calculate_fan_in_and_fan_out
import math
import warnings
from timm.models.layers.helpers import to_2tuple

_logger = logging.getLogger(__name__)

def _cfg(url='', **kwargs):
    return {
        'url': url,
        'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,
        'crop_pct': .9, 'interpolation': 'bicubic', 'fixed_input_size': True,
        'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD,
        'first_conv': 'patch_embed.proj', 'classifier': 'head',
        **kwargs
    }

# default_cfgs = {
#     'xciformer_224': _cfg(),
#     'xciformer_384': _cfg(input_size=(3, 384, 384), crop_pct=1.0),
# }

default_cfgs = {
    'xciformer_small': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_small.pth'),
    'xciformer_base': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_base.pth'),
    'xciformer_large': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_large.pth'),
    'xciformer_small_384': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_small_384.pth',
                            input_size=(3, 384, 384), crop_pct=1.0),
    'xciformer_base_384': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_base_384.pth',
                            input_size=(3, 384, 384), crop_pct=1.0),
    'xciformer_large_384': _cfg(url='https://huggingface.co/sail/dl2/resolve/main/xciformer/xciformer_large_384.pth',
                            input_size=(3, 384, 384), crop_pct=1.0),
}

def _no_grad_trunc_normal_(tensor, mean, std, a, b):
    # Cut & paste from PyTorch official master until it's in a few official releases - RW
    # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
    def norm_cdf(x):
        # Computes standard normal cumulative distribution function
        return (1. + math.erf(x / math.sqrt(2.))) / 2.

    if (mean < a - 2 * std) or (mean > b + 2 * std):
        warnings.warn("mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
            "The distribution of values may be incorrect.",
            stacklevel=2)

    with torch.no_grad():
        # Values are generated by using a truncated uniform distribution and
        # then using the inverse CDF for the normal distribution.
        # Get upper and lower cdf values
        l = norm_cdf((a - mean) / std)
        u = norm_cdf((b - mean) / std)

        # Uniformly fill tensor with values from [l, u], then translate to
        # [2l-1, 2u-1].
        tensor.uniform_(2 * l - 1, 2 * u - 1)

        # Use inverse cdf transform for normal distribution to get truncated
        # standard normal
        tensor.erfinv_()

        # Transform to proper mean, std
        tensor.mul_(std * math.sqrt(2.))
        tensor.add_(mean)

        # Clamp to ensure it's in the proper range
        tensor.clamp_(min=a, max=b)
        return tensor

def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
    # type: (torch.Tensor, float, float, float, float) -> torch.Tensor
    r"""Fills the input Tensor with values drawn from a truncated
    normal distribution. The values are effectively drawn from the
    normal distribution :math:`\mathcal{N}(\text{mean}, \text{std}^2)`
    with values outside :math:`[a, b]` redrawn until they are within
    the bounds. The method used for generating the random values works
    best when :math:`a \leq \text{mean} \leq b`.
    Args:
        tensor: an n-dimensional `torch.Tensor`
        mean: the mean of the normal distribution
        std: the standard deviation of the normal distribution
        a: the minimum cutoff value
        b: the maximum cutoff value
    Examples:
        >>> w = torch.empty(3, 5)
        >>> nn.init.trunc_normal_(w)
    """
    return _no_grad_trunc_normal_(tensor, mean, std, a, b)

def variance_scaling_(tensor, scale=1.0, mode='fan_in', distribution='normal'):
    fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor)
    if mode == 'fan_in':
        denom = fan_in
    elif mode == 'fan_out':
        denom = fan_out
    elif mode == 'fan_avg':
        denom = (fan_in + fan_out) / 2

    variance = scale / denom

    if distribution == "truncated_normal":
        # constant is stddev of standard normal truncated to (-2, 2)
        trunc_normal_(tensor, std=math.sqrt(variance) / .87962566103423978)
    elif distribution == "normal":
        tensor.normal_(std=math.sqrt(variance))
    elif distribution == "uniform":
        bound = math.sqrt(3 * variance)
        tensor.uniform_(-bound, bound)
    else:
        raise ValueError(f"invalid distribution {distribution}")

def lecun_normal_(tensor):
    variance_scaling_(tensor, mode='fan_in', distribution='truncated_normal')

from .patches import *
from .mixers import *
from .blocks import *

class CrossCovarianceInceptionTransformer(nn.Module):
    def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000, embed_dims=None, depths=None,
                num_heads=None, mlp_ratio=4., qkv_bias=True,
                drop_rate=0., attn_drop_rate=0., drop_path_rate=0., norm_layer=None,
                act_layer=None, weight_init='',
                attention_heads=None,
                use_layer_scale=False, layer_scale_init_value=1e-5,
                checkpoint_path=None,
                **kwargs
                ):

        super().__init__()
        st2_idx = sum(depths[:1])
        st3_idx = sum(depths[:2])
        st4_idx = sum(depths[:3])
        depth = sum(depths)

        self.num_classes = num_classes

        norm_layer = norm_layer or partial(nn.LayerNorm, eps=1e-6)
        act_layer = act_layer or nn.GELU

        dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)]  # stochastic depth decay rule

        self.patch_embed = XCiTFirstPatchEmbed(in_chans=in_chans, embed_dim=embed_dims[0])
        self.num_patches1 = num_patches = img_size // 4
        self.pos_embed1 = nn.Parameter(torch.zeros(1, num_patches, num_patches, embed_dims[0]))
        self.blocks1 = nn.ModuleList([
            XCiFormerBlock(
                dim=embed_dims[0], num_heads=num_heads[0], mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, drop=drop_rate,
                attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer, act_layer=act_layer, attention_head=attention_heads[i], pool_size=2,)
                # use_layer_scale=use_layer_scale, layer_scale_init_value=layer_scale_init_value,
                # )
            for i in range(0, st2_idx)])

        self.patch_embed2 = XCiTPatchEmbed(kernel_size=3, stride=2, padding=1, in_chans=embed_dims[0], embed_dim=embed_dims[1])
        self.num_patches2 = num_patches = num_patches // 2
        self.pos_embed2 = nn.Parameter(torch.zeros(1, num_patches, num_patches, embed_dims[1]))
        self.blocks2 = nn.ModuleList([
            XCiFormerBlock(
                dim=embed_dims[1], num_heads=num_heads[1], mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, drop=drop_rate,
                attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer, act_layer=act_layer, attention_head=attention_heads[i], pool_size=2,)
                # use_layer_scale=use_layer_scale, layer_scale_init_value=layer_scale_init_value, channel_layer_scale=channel_layer_scale,
                # )
            for i in range(st2_idx,st3_idx)])

        self.patch_embed3 = XCiTPatchEmbed(kernel_size=3, stride=2, padding=1, in_chans=embed_dims[1], embed_dim=embed_dims[2])
        self.num_patches3 = num_patches = num_patches // 2
        self.pos_embed3 = nn.Parameter(torch.zeros(1, num_patches, num_patches, embed_dims[2]))
        self.blocks3= nn.ModuleList([
            XCiFormerBlock(
                dim=embed_dims[2], num_heads=num_heads[2], mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, drop=drop_rate,
                attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer, act_layer=act_layer, attention_head=attention_heads[i], pool_size=1,
                use_layer_scale=use_layer_scale, layer_scale_init_value=layer_scale_init_value,
                )
            for i in range(st3_idx, st4_idx)])

        self.patch_embed4 = XCiTPatchEmbed(kernel_size=3, stride=2, padding=1, in_chans=embed_dims[2], embed_dim=embed_dims[3])
        self.num_patches4 = num_patches = num_patches // 2
        self.pos_embed4 = nn.Parameter(torch.zeros(1, num_patches, num_patches, embed_dims[3]))
        self.blocks4 = nn.ModuleList([
            XCiFormerBlock(
                dim=embed_dims[3], num_heads=num_heads[3], mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, drop=drop_rate,
                attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer, act_layer=act_layer, attention_head=attention_heads[i], pool_size=1,
                use_layer_scale=use_layer_scale, layer_scale_init_value=layer_scale_init_value,
                )
            for i in range(st4_idx,depth)])

        self.norm = norm_layer(embed_dims[-1])
        # Classifier head(s)
        self.head = nn.Linear(embed_dims[-1], num_classes) if num_classes > 0 else nn.Identity()
        # set post block, for example, class attention layers

        self.init_weights(weight_init)

    def init_weights(self, mode=''):
        trunc_normal_(self.pos_embed1, std=.02)
        trunc_normal_(self.pos_embed2, std=.02)
        trunc_normal_(self.pos_embed3, std=.02)
        trunc_normal_(self.pos_embed4, std=.02)

        self.apply(_init_vit_weights)

    def _init_weights(self, m):
        # this fn left here for compat with downstream users
        _init_vit_weights(m)

    @torch.jit.ignore
    def no_weight_decay(self):
        return {'pos_embed', 'cls_token', 'dist_token'}

    def get_classifier(self):
        if self.dist_token is None:
            return self.head
        else:
            return self.head, self.head_dist

    def reset_classifier(self, num_classes, global_pool=''):
        self.num_classes = num_classes
        self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity()
        if self.num_tokens == 2:
            self.head_dist = nn.Linear(self.embed_dim, self.num_classes) if num_classes > 0 else nn.Identity()

    def _get_pos_embed(self, pos_embed, num_patches_def, H, W):
        if H * W == num_patches_def * num_patches_def:
            return pos_embed
        else:
            return F.interpolate(
                pos_embed.permute(0, 3, 1, 2),
                size=(H, W), mode="bilinear").permute(0, 2, 3, 1)

    def forward_features(self, x):
        x = self.patch_embed(x)
        B, H, W, C = x.shape
        x = x + self._get_pos_embed(self.pos_embed1, self.num_patches1, H, W)
        # x = self.blocks1(x)
        for blk1 in self.blocks1:
            x = blk1(x)

        x = x.permute(0, 3, 1, 2)
        x = self.patch_embed2(x)
        B, H, W, C = x.shape
        x = x + self._get_pos_embed(self.pos_embed2, self.num_patches2, H, W)
        # x = self.blocks2(x)
        for blk2 in self.blocks2:
            x = blk2(x)

        x = x.permute(0, 3, 1, 2)
        x = self.patch_embed3(x)
        B, H, W, C = x.shape
        x = x + self._get_pos_embed(self.pos_embed3, self.num_patches3, H, W)
        # x = self.blocks3(x)
        for blk3 in self.blocks3:
            x = blk3(x)

        x = x.permute(0, 3, 1, 2)
        x = self.patch_embed4(x)
        B, H, W, C = x.shape
        x = x + self._get_pos_embed(self.pos_embed4, self.num_patches4, H, W)
        # x = self.blocks4(x)
        for blk4 in self.blocks4:
            x = blk4(x)
        x = x.flatten(1,2)

        x = self.norm(x)
        return x.mean(1)

    def forward(self, x):
        x = self.forward_features(x)
        x = self.head(x)
        return x

def _init_vit_weights(module: nn.Module, name: str = '', head_bias: float = 0.):
    """ ViT weight initialization
    * When called without n, head_bias, jax_impl args it will behave exactly the same
      as my original init for compatibility with prev hparam / downstream use cases (ie DeiT).
    """
    if isinstance(module, nn.Linear):
        if name.startswith('head'):
            nn.init.zeros_(module.weight)
            nn.init.constant_(module.bias, head_bias)
        elif name.startswith('pre_logits'):
            lecun_normal_(module.weight)
            nn.init.zeros_(module.bias)
        else:
            trunc_normal_(module.weight, std=.02)
            if module.bias is not None:
                nn.init.zeros_(module.bias)
    elif isinstance(module, (nn.LayerNorm, nn.GroupNorm, nn.BatchNorm2d)):
        nn.init.zeros_(module.bias)
        nn.init.ones_(module.weight)
    elif isinstance(module, nn.Conv2d):
        trunc_normal_(module.weight, std=.02)
        if module.bias is not None:
            nn.init.constant_(module.bias, 0)

@register_model
def xciformer_small(pretrained=False, **kwargs):
    """
    19.866M  4.849G 83.382
    """
    depths = [3, 3, 9, 3]
    embed_dims = [96, 192, 320, 384]
    num_heads = [3, 6, 10, 12]
    attention_heads = [1]*3 + [3]*3 + [7] * 4 + [9] * 5 + [11] * 3

    model = CrossCovarianceInceptionTransformer(img_size=224,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_small']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model

@register_model
def xciformer_small_384(pretrained=False, **kwargs):
    depths = [3, 3, 9, 3]
    embed_dims = [96, 192, 320, 384]
    num_heads = [3, 6, 10, 12]
    attention_heads = [1]*3 + [3]*3 + [7] * 4 + [9] * 5 + [11] * 3

    model = CrossCovarianceInceptionTransformer(img_size=384,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_small_384']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model

@register_model
def xciformer_base(pretrained=False, **kwargs):
    """
    47.866M  9.379G  84.598
    """
    depths = [4, 6, 14, 6]
    embed_dims = [96, 192, 384, 512]
    num_heads = [3, 6, 12, 16]
    attention_heads = [1]*4 + [3]*6 + [8] * 7 + [10] * 7 + [15] * 6

    model = CrossCovarianceInceptionTransformer(img_size=224,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_base']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model

@register_model
def xciformer_base_384(pretrained=False, **kwargs):
    depths = [4, 6, 14, 6]
    embed_dims = [96, 192, 384, 512]
    num_heads = [3, 6, 12, 16]
    attention_heads = [1]*4 + [3]*6 + [8] * 7 + [10] * 7 + [15] * 6

    model = CrossCovarianceInceptionTransformer(img_size=384,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_base_384']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model

@register_model
def xciformer_large(pretrained=False, **kwargs):
    """
    86.637M  14.048G 84.752
    """
    depths = [4, 6, 18, 8]
    embed_dims = [96, 192, 448, 640]
    num_heads = [3, 6, 14, 20]
    attention_heads = [1]*4 + [3]*6 + [10] * 9 + [12] * 9 + [19] * 8

    model = CrossCovarianceInceptionTransformer(img_size=224,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_large']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model

@register_model
def xciformer_large_384(pretrained=False, **kwargs):
    depths = [4, 6, 18, 8]
    embed_dims = [96, 192, 448, 640]
    num_heads = [3, 6, 14, 20]
    attention_heads = [1]*4 + [3]*6 + [10] * 9 + [12] * 9 + [19] * 8

    model = CrossCovarianceInceptionTransformer(img_size=384,
        depths=depths,
        embed_dims=embed_dims,
        num_heads=num_heads,
        attention_heads=attention_heads,
        use_layer_scale=True, layer_scale_init_value=1e-6,
        **kwargs)
    model.default_cfg = default_cfgs['xciformer_large_384']
    if pretrained:
        url = model.default_cfg['url']
        checkpoint = torch.hub.load_state_dict_from_url(url=url, map_location="cpu", check_hash=True)
        model.load_state_dict(checkpoint)
    return model


import json
import re

from sos.report.plugins import Plugin, IndependentPlugin, PluginOpt

class Process(Plugin, IndependentPlugin):

    short_desc = 'process information'

    plugin_name = 'process'
    profiles = ('system',)

    option_list = [
        PluginOpt('lsof', default=True, desc='collect info on all open files'),
        PluginOpt('lsof-threads', default=False,
                  desc='collect threads\' open file info if supported'),
        PluginOpt('smaps', default=False, desc='collect /proc/*/smaps files'),
        PluginOpt('samples', default=20, val_type=int,
                  desc='number of iotop samples to collect'),
        PluginOpt('numprocs', default=2048, val_type=int,
                  desc='number of process to collect /proc data of')
    ]

    def setup(self):
        ps_axo = "ps axo"
        # process group and thread options
        ps_group_opts = "pid,ppid,user,group,lwp,nlwp,start_time,comm,cgroup"
        ps_sched_opts = "flags,state,uid,pid,ppid,pgid,sid,cls,pri,addr,sz,"
        ps_sched_opts += "wchan:20,lstart,tty,time,cmd"

        self.add_copy_spec([
            "/proc/sched_debug",
            "/proc/stat"
        ])

        procs = [p for p in self.listdir("/proc") if re.match("[0-9]", p)]
        if self.get_option("numprocs"):
            procs = procs[:self.get_option("numprocs")]

        for proc in procs:
            self.add_copy_spec([
                "/proc/%s/status" % proc,
                "/proc/%s/cpuset" % proc,
                "/proc/%s/oom_*" % proc,
                "/proc/%s/stack" % proc,
                "/proc/%s/limits" % proc
            ])

        if self.get_option("smaps"):
            self.add_copy_spec("/proc/[0-9]*/smaps")

        self.add_cmd_output("ps auxwwwm", root_symlink="ps",
                            tags=['ps_aux', 'ps_auxww', 'ps_auxwww',
                                  'ps_auxwwwm', 'ps_auxcww'],
                            priority=1)

        self.add_cmd_output("pstree -lp", root_symlink="pstree")
        if self.get_option("lsof"):
            self.add_cmd_output("lsof +M -n -l -c ''", root_symlink="lsof",
                                timeout=15, priority=50, tags="lsof")

        if self.get_option("lsof-threads"):
            self.add_cmd_output("lsof +M -n -l", timeout=15, priority=50)

        self.add_cmd_output([
            "ps alxwww",
            "ps -elfL"
        ], cmd_as_tag=True)

        self.add_cmd_output([
            "%s %s" % (ps_axo, ps_group_opts),
            "%s %s" % (ps_axo, ps_sched_opts)
        ])

        if self.get_option("samples"):
            self.add_cmd_output("iotop -b -o -d 0.5 -t -n %s"
                                % self.get_option("samples"), priority=100)

        self.add_cmd_output([
            "pidstat -p ALL -rudvwsRU --human -h",
            "pidstat -tl"
        ])

    def collect(self):
        with self.collection_file('pids_to_packages.json') as pfile:
            if not self.policy.package_manager.query_path_command:
                pfile.write('Package manager not configured for path queries')
                return
            _ps = self.exec_cmd('ps --no-headers aex')
            pidpkg = {}
            paths = {}
            if not _ps['status'] == 0:
                pfile.write(f"Unable to get process list: {_ps['output']}")
                return
            for proc in _ps['output'].splitlines():
                proc = proc.strip().split()
                pid = proc[0]
                path = proc[4]
                if not self.path_exists(path):
                    continue
                if path not in paths:
                    paths[path] = self.policy.package_manager.pkg_by_path(path)
                pidpkg[pid] = {'path': path, 'package': paths[path]}

            pfile.write(json.dumps(pidpkg, indent=4))

# vim: set et ts=4 sw=4 :


from django.urls import path
from . import views

app_name = 'zomato_app'

urlpatterns = [
    path('dishes/', views.dish_list, name='dish_list'),
    path('add_dish/', views.add_dish, name='add_dish'),
    path('order_list/', views.order_list, name='order_list'),
    path('place_order/', views.place_order, name='place_order'),
]


import csv
import datetime
import itertools
import json
import os
import optparse
import urllib.request

TESTING = True
DEFAULT_DATE = (datetime.date.today() - datetime.timedelta(days=2)).isoformat()

def get_stations(filename='stations.txt'):
    with open(filename, 'r') as f:
        stations = json.load(f)
    return stations

def fetch_rainfall_from_file(file):
    with open(file, 'rb') as f:
        return csv.DictReader((l.decode('utf-8') for l in f.readlines()), )

def fetch_rainfall_data(date):
    url = f"http://environment.data.gov.uk/flood-monitoring/archive/readings-{date}.csv"
    resp = urllib.request.urlopen(url)
    return csv.DictReader((l.decode('utf-8') for l in resp.readlines()), )

def filter_data(raw_data, stations):
    data = {s['location']: [] for s in stations}
    for row in raw_data:
        for station in stations:
            loc = station['location']
            sid = station['station_id']
            if sid in row['measure']:
                timestamp = datetime.datetime.strptime(row['dateTime'], '%Y-%m-%dT%H:%M:%SZ')
                data[loc].append({'timestamp': timestamp, 'value': float(row['value'])})
    return data

def process_hourly(data):
    # group by hour
    hourly = {}
    sortkey = lambda x: x['timestamp'].hour
    for location, points in data.items():
        if len(points) == 0:
            print(f"ERROR: No data reported for location {location}")
            continue
        baseday = datetime.datetime.combine(points[0]['timestamp'].date(), datetime.datetime.min.time())
        points = sorted(points, key=sortkey)
        grouped = itertools.groupby(points, sortkey)
        hours = ((key, sum(point['value'] for point in group)) for key, group in grouped)
        hours = [(baseday + datetime.timedelta(hours=hour), value) for hour, value in hours]
        hourly[location] = hours
    return hourly

def save_hourly_csv(hourly):
    for location in hourly:
        date = hourly[location][0][0].date()
        hourly_file = f'data/{location}/{date:%Y-%m}.csv'
        if os.path.exists(hourly_file):
            with open(hourly_file, 'r') as f:
                r = csv.reader(f)
                existing_data = dict(list(r)[1:])  # skip the header
        else:
            existing_data = {}

        points = hourly[location]
        for time, value in points:
            existing_data[time.isoformat()] = value

        with open(hourly_file, 'w') as f:
            writer = csv.writer(f, lineterminator='\n')
            writer.writerow(['time', 'rainfall_mm'])
            for d in sorted(existing_data):
                val = existing_data[d]
                try:
                    val = float(val)
                    writer.writerow((d, '{:.1f}'.format(val)))
                except Exception as e:
                    print(f'Could not parse value {val}, skipping')

def save_daily_csv(daily):
    # group by day
    for location in daily:
        daily_file = f'data/{location}/daily.csv'
        if os.path.exists(daily_file):
            with open(daily_file, 'r') as f:
                r = csv.reader(f)
                existing_data = dict(list(r)[1:])
        else:
            existing_data = {}
        d, v = daily[location]
        existing_data[d] = v

        with open(daily_file, 'w') as f:
            writer = csv.writer(f, lineterminator='\n')
            writer.writerow(['time', 'rainfall_mm'])
            for d in sorted(existing_data):
                val = existing_data[d]
                try:
                    val = float(val)
                    writer.writerow((d, '{:.1f}'.format(val)))
                except Exception as e:
                    print(f'Could not parse value {val}, skipping')

def save_daily_json(data):
    # save daily json points
    for location, points in data.items():
        if len(points) == 0:
            print(f"ERROR: No data reported for location {location}")
            continue
        date = points[0]['timestamp'].date()
        datadir = f'data/{location}/{date.year}'
        if not os.path.isdir(datadir):
            os.makedirs(datadir)
        out = {
            'location': location,
            'date': date.isoformat(),
            'data': [{'timestamp': p['timestamp'].isoformat(), 'value': p['value']} for p in sorted(points, key=lambda x: x['timestamp'])]
        }
        with open(f'{datadir}/{date}.json', 'w') as f:
            json.dump(out, f, indent=2)

if __name__ == '__main__':
    parser = optparse.OptionParser()

    parser.add_option('-s', '--stations', default='./stations.txt')
    parser.add_option('-d', '--date', default=DEFAULT_DATE)
    parser.add_option('-f', '--file')

    options, args = parser.parse_args()

    stations = get_stations(options.stations)

    date = options.date
    year, month, day = date.split('-')
    today = datetime.datetime(int(year), int(month), int(day))

    if options.file:
        dd = fetch_rainfall_from_file(options.file)
    else:
        dd = fetch_rainfall_data(date)

    data = filter_data(dd, stations)

    hourly = process_hourly(data)
    daily = {location: (today.strftime('%Y-%m-%d'), sum(v[1] for v in values)) for location, values in hourly.items()}
    save_daily_csv(daily)
    save_hourly_csv(hourly)
    save_daily_json(data)


import sqlite3

csvfile = 'awesome-01.csv'

with open (csvfile) as f:
    lines = f.readlines()

breaks = []
for i in range(len(lines)):
    tokens = [t.strip() for t in lines[i].split(",")]
    print(len(tokens[0]))
    if len(tokens) == 1:
        breaks.append(i)

ap_header = lines[breaks[0]+1]
ap_data = lines[breaks[0]+2:breaks[1]-1]

client_header = lines[breaks[1]+1]

client_data   = lines[breaks[1]+2:breaks[2]-1]


m = int(input())
n = int(input())
num = int(input())

brushH = set()
brushV = set()

for _ in range(num):
    l = input().split()
    # print(l)
    digit = int(l[1]) - 1
    if l[0] == 'C':
        if digit in brushV:
            brushV.remove(digit)
        else:
            brushV.add(digit)
    elif l[0] == 'R':
        if digit in brushH:
            brushH.remove(digit)
        else:
            brushH.add(digit)

canvas = [[0 for i in range(n)] for i in range(m)]

for i in brushH:
    canvas[i] = [1 for i in range(n)]

for i in range(m):
    for j in brushV:
        canvas[i][j] += 1

cnt = 0
for i in canvas:
    for j in i:
        if j % 2 != 0:
            cnt += 1

print(cnt)


class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        left = ['{', '(', '[']
        right = ['}', ')', ']']
        for c in s:
            if c in left:
                stack.append(c)

            if c in right:
                if stack and left.index(stack[-1]) == right.index(c):
                    stack.pop()
                else:
                    return False

        return True if not len(stack) else False


from django.shortcuts import render
from .models import *
from light_monitoring.graphGenerator import *
from .API import emissionsCalc, energyPrices
from .forms import SettingsForm
from django.views.generic import TemplateView
from django.http import HttpResponseRedirect
from django.urls import reverse

def filament(request):
    now = datetime.now()

    dayTot = secondsUnitConv(getTot(day=now.date())[0])
    weekTot = secondsUnitConv(getTot(week=now.isocalendar()[1], year=now.year)[0])
    monthTot = secondsUnitConv(getTot(month=now.month, year=now.year)[0])
    yearTot = secondsUnitConv(getTot(year=now.year)[0])

    dayAvg = secondsUnitConv(calcDayAverage(now))
    weekAvg = secondsUnitConv(calcWeekAverage(now.isocalendar()[1], now.year))
    monthAvg = secondsUnitConv(calcMonthAverage(now.month, now.year))
    yearAvg = secondsUnitConv(calcYearAverage(now.year))

    DNO = SettingsData.objects.last().region if SettingsData.objects.last().region else "12"
    energyCosts = energyPrices.getEnergyCosts(DNO)
    power  = SettingsData.objects.last().bulbPower
    numBulbs = SettingsData.objects.last().numBulbs
    rate = emissionsCalc.getEmissionsRate()

    now = datetime.now()
    date = now.replace(hour=0, minute=0, second=0) - timedelta(days=1)
    week = (now - timedelta(weeks=1)).isocalendar()[1]
    year = now.year
    month = (now - timedelta(days=now.day)).month
    genDayGraph(date, r'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/dayAvgGraph')
    genWeekGraph(week, year, r'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/weekAvgGraph')
    genMonthGraph(month, year, r'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/monthAvgGraph')
    genYearGraph(year-1, r'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/yearAvgGraph')

    context = {
        "dailyAvg": dayAvg,
        "dayTot": dayTot,
        "weeklyAvg": weekAvg,
        "weekTot": weekTot,
        "monthlyAvg": monthAvg,
        "month": monthTot,
        "yearlyAvg": yearAvg,
        "yearTot": yearTot,
        "dailyCosts": f"{energyPrices.calcPrices(power, getTot(day=now.date())[0] / 3600, numBulbs, energyCosts):.2f}",
        "weeklyCosts": f"{energyPrices.calcPrices(power, getTot(week=now.isocalendar()[1], year=now.year)[0] / 3600, numBulbs, energyCosts):.2f}",
        "dailyEmissions": f"{emissionsCalc.getEmissions(power, numBulbs, getTot(day=now.date())[0] / 3600, rate):.2f}",
        "weeklyEmissions": f"{emissionsCalc.getEmissions(power, numBulbs, getTot(week=now.isocalendar()[1], year=now.year)[0] / 3600, rate):.2f}",

    }
    return render(request, 'light_monitoring/filament.html', context)

def data(request):
    context = {
        "dataEntries": Data_Entry.objects.all().order_by("endTime")
    }
    return render(request, 'light_monitoring/data.html', context)

class SettingsView(TemplateView):
    template_name = "light_monitoring/settings.html"

    def get(self, request):
        form = SettingsForm()
        region = SettingsData.objects.first().region
        context = {
            "form": form,
            "region": region,
        }
        return render(request, self.template_name, context)

    def post(self, request):
        form = SettingsForm(request.POST)

        if form.is_valid():
            form.save()
            region = form.cleaned_data["region"]
            numBulbs = form.cleaned_data["numBulbs"]
            bulbPower = form.cleaned_data["bulbPower"]
            bulbType = form.cleaned_data["bulbType"]
        else:
            form = SettingsForm()

        context = {
            "form": form,
            "region": region,
            "numBulbs": numBulbs,
            "bulbPower": bulbPower,
            "bulbType": bulbType,
        }
        return render(request, self.template_name, context)

def yearData(request, year):
    imgpath = fr'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/queries/{year}'
    qs = Data_Entry.objects.filter(endTime__year=year)
    context = {
        'dataEntries': qs,
        "year":year
    }
    genYearGraph(year, imgpath)
    return render(request, 'light_monitoring/yearData.html', context)

def monthData(request, year, month):
    qs = Data_Entry.objects.filter(endTime__year=year, endTime__month=month)
    imgpath = fr'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/queries/{year}_{month}'
    context = {
        'dataEntries': qs,
        "year": year,
        "month": month,
    }
    genMonthGraph(month, year, imgpath)
    return render(request, 'light_monitoring/monthData.html', context)

def dateData(request, year, month, day):
    qs = Data_Entry.objects.filter(endTime__year=year, endTime__month=month, endTime__day=day)
    imgpath = fr'/home/team-thorium/Documents/filament/Filament/light_monitoring/static/graphs/queries/{year}_{month}_{day}'
    context = {
        'dataEntries': qs,
        "year": year,
        "month": month,
        "day": day,
    }
    genDayGraph(datetime(year, month, day), imgpath)
    return render(request, 'light_monitoring/dateData.html', context)

def dataRedirect(request):
    date = request.GET.get('date')
    if date:
        c = date.count("/")
        if c == 0:
            return HttpResponseRedirect(reverse('yearData', args=[date]))
        elif c == 1:
            year, month = date.split('/')
            return HttpResponseRedirect(reverse('monthData', args=[year, month]))
        else:
            year, month, day = date.split("/")
            return HttpResponseRedirect(reverse('dateData', args=[year, month, day]))
    else:
        # Handle invalid form data
        pass

def advice(request):
    return render(request, "light_monitoring/advice.html")


class Exploder:
    """
    Words extractor
    """

    def __init__(self, stop_words, delimeters="`~@\"#№$;:%^&?*()-_=+<>,.\\|/[]{} \r\n\t"):
        """
        Initialize exploder
        :param stop_words: stopwords
        :type stop_words: list[str]
        :param delimeters: delimeter chars
        :type delimeters: str
        """
        self.stop_words = stop_words
        self.delimeters = delimeters

    def explode(self, text):
        """
        Explode text
        :param text: text
        :type text: str
        :return: words
        :rtype: list[str]
        """
        items = [""]
        for char in text.lower():
            if char in self.delimeters:
                items.append("")
            else:
                items[-1] += char
        items = [item for item in items if item != ""]
        return [item for item in items if item not in self.stop_words]


import re
from typing import Literal

import sqlalchemy as sa

from accounting import db
from accounting.models import Account, JournalEntryLineItem
from accounting.utils.options import options, Recurring

class DescriptionAccount:
    """An account for a description tag."""

    def __init__(self, account: Account, freq: int):
        """Constructs an account for a description tag.

        :param account: The account.
        :param freq: The frequency of the tag with the account.
        """
        self.__account: Account = account
        """The account."""
        self.id: int = account.id
        """The account ID."""
        self.code: str = account.code
        """The account code."""
        self.is_need_offset: bool = account.is_need_offset
        """Whether the journal entry line items of this account need offset."""
        self.freq: int = freq
        """The frequency of the tag with the account."""

    def __str__(self) -> str:
        """Returns the string representation of the account.

        :return: The string representation of the account.
        """
        return str(self.__account)

    @property
    def title(self) -> str:
        """Returns the account title.

        :return: The account title.
        """
        return self.__account.title

    def add_freq(self, freq: int) -> None:
        """Adds the frequency of an account.

        :param freq: The frequency of the tag name with the account.
        :return: None.
        """
        self.freq = self.freq + freq

class DescriptionTag:
    """A description tag."""

    def __init__(self, name: str):
        """Constructs a description tag.

        :param name: The tag name.
        """
        self.name: str = name
        """The tag name."""
        self.__account_dict: dict[int, DescriptionAccount] = {}
        """The accounts that come with the tag, in the order of their
        frequency."""
        self.freq: int = 0
        """The frequency of the tag."""

    def __str__(self) -> str:
        """Returns the string representation of the tag.

        :return: The string representation of the tag.
        """
        return self.name

    def add_account(self, account: Account, freq: int):
        """Adds an account.

        :param account: The associated account.
        :param freq: The frequency of the tag name with the account.
        :return: None.
        """
        self.__account_dict[account.id] = DescriptionAccount(account, freq)
        self.freq = self.freq + freq

    @property
    def accounts(self) -> list[DescriptionAccount]:
        """Returns the accounts by the order of their frequencies.

        :return: The accounts by the order of their frequencies.
        """
        return sorted(self.__account_dict.values(), key=lambda x: -x.freq)

    @property
    def account_codes(self) -> list[str]:
        """Returns the account codes by the order of their frequencies.

        :return: The account codes by the order of their frequencies.
        """
        return [x.code for x in self.accounts]

class DescriptionType:
    """A description type"""

    def __init__(self, type_id: Literal["general", "travel", "bus"]):
        """Constructs a description type.

        :param type_id: The type ID, either "general", "travel", or "bus".
        """
        self.id: Literal["general", "travel", "bus"] = type_id
        """The type ID."""
        self.__tag_dict: dict[str, DescriptionTag] = {}
        """A dictionary from the tag name to their corresponding tag."""

    def add_tag(self, name: str, account: Account, freq: int) -> None:
        """Adds a tag.

        :param name: The tag name.
        :param account: The associated account.
        :param freq: The frequency of the tag name with the account.
        :return: None.
        """
        if name not in self.__tag_dict:
            self.__tag_dict[name] = DescriptionTag(name)
        self.__tag_dict[name].add_account(account, freq)

    @property
    def tags(self) -> list[DescriptionTag]:
        """Returns the tags by the order of their frequencies.

        :return: The tags by the order of their frequencies.
        """
        return sorted(self.__tag_dict.values(), key=lambda x: -x.freq)

class DescriptionRecurring:
    """A recurring transaction."""

    def __init__(self, name: str, account: Account, description_template: str):
        """Constructs a recurring transaction.

        :param name: The name.
        :param description_template: The description template.
        :param account: The account.
        """
        self.name: str = name
        """The name."""
        self.account: DescriptionAccount = DescriptionAccount(account, 0)
        """The account."""
        self.description_template: str = description_template
        """The description template."""

    @property
    def account_codes(self) -> list[str]:
        """Returns the account codes by the order of their frequencies.

        :return: The account codes by the order of their frequencies.
        """
        return [self.account.code]

class DescriptionDebitCredit:
    """The description on debit or credit."""

    def __init__(self, debit_credit: Literal["debit", "credit"]):
        """Constructs the description on debit or credit.

        :param debit_credit: Either "debit" or "credit".
        """
        self.debit_credit: Literal["debit", "credit"] = debit_credit
        """Either debit or credit."""
        self.general: DescriptionType = DescriptionType("general")
        """The general tags."""
        self.travel: DescriptionType = DescriptionType("travel")
        """The travel tags."""
        self.bus: DescriptionType = DescriptionType("bus")
        """The bus tags."""
        self.__type_dict: dict[Literal["general", "travel", "bus"],
                               DescriptionType] \
            = {x.id: x for x in {self.general, self.travel, self.bus}}
        """A dictionary from the type ID to the corresponding tags."""
        self.recurring: list[DescriptionRecurring] = []
        """The recurring transactions."""

    def add_tag(self, tag_type: Literal["general", "travel", "bus"],
                name: str, account: Account, freq: int) -> None:
        """Adds a tag.

        :param tag_type: The tag type, either "general", "travel", or "bus".
        :param name: The name.
        :param account: The associated account.
        :param freq: The frequency of the tag name with the account.
        :return: None.
        """
        self.__type_dict[tag_type].add_tag(name, account, freq)

    @property
    def accounts(self) -> list[DescriptionAccount]:
        """Returns the suggested accounts of all tags in the description editor
        in debit or credit, in their frequency order.

        :return: The suggested accounts of all tags, in their frequency order.
        """
        accounts: dict[int, DescriptionAccount] = {}
        freq: dict[int, int] = {}
        for tag_type in self.__type_dict.values():
            for tag in tag_type.tags:
                for account in tag.accounts:
                    accounts[account.id] = account
                    if account.id not in freq:
                        freq[account.id] = 0
                    freq[account.id] \
                        = freq[account.id] + account.freq
        for recurring in self.recurring:
            accounts[recurring.account.id] = recurring.account
            if recurring.account.id not in freq:
                freq[recurring.account.id] = 0
        return [accounts[y] for y in sorted(freq.keys(),
                                            key=lambda x: -freq[x])]

class DescriptionEditor:
    """The description editor."""

    def __init__(self):
        """Constructs the description editor."""
        self.debit: DescriptionDebitCredit = DescriptionDebitCredit("debit")
        """The debit tags."""
        self.credit: DescriptionDebitCredit = DescriptionDebitCredit("credit")
        """The credit tags."""
        self.__init_tags()
        self.__init_recurring()

    def __init_tags(self):
        """Initializes the tags.

        :return: None.
        """
        debit_credit: sa.Label = sa.case(
            (JournalEntryLineItem.is_debit, "debit"),
            else_="credit").label("debit_credit")
        tag_type: sa.Label = sa.case(
            (JournalEntryLineItem.description.like("_%—_%—_%→_%"), "bus"),
            (sa.or_(JournalEntryLineItem.description.like("_%—_%→_%"),
                    JournalEntryLineItem.description.like("_%—_%↔_%")),
             "travel"),
            else_="general").label("tag_type")
        tag: sa.Label = get_prefix(JournalEntryLineItem.description, "—")\
            .label("tag")
        select: sa.Select = sa.Select(debit_credit, tag_type, tag,
                                      JournalEntryLineItem.account_id,
                                      sa.func.count().label("freq"))\
            .filter(JournalEntryLineItem.description.is_not(None),
                    JournalEntryLineItem.description.like("_%—_%"),
                    JournalEntryLineItem.original_line_item_id.is_(None))\
            .group_by(debit_credit, tag_type, tag,
                      JournalEntryLineItem.account_id)
        result: list[sa.Row] = db.session.execute(select).all()
        accounts: dict[int, Account] \
            = {x.id: x for x in Account.query
               .filter(Account.id.in_({x.account_id for x in result})).all()}
        debit_credit_dict: dict[Literal["debit", "credit"],
                                DescriptionDebitCredit] \
            = {x.debit_credit: x for x in {self.debit, self.credit}}
        for row in result:
            debit_credit_dict[row.debit_credit].add_tag(
                row.tag_type, row.tag, accounts[row.account_id], row.freq)

    def __init_recurring(self) -> None:
        """Initializes the recurring transactions.

        :return: None.
        """
        recurring: Recurring = options.recurring
        accounts: dict[str, Account] \
            = self.__get_accounts(recurring.codes)
        self.debit.recurring \
            = [DescriptionRecurring(x.name, accounts[x.account_code],
                                    x.description_template)
               for x in recurring.expenses]
        self.credit.recurring \
            = [DescriptionRecurring(x.name, accounts[x.account_code],
                                    x.description_template)
               for x in recurring.incomes]

    @staticmethod
    def __get_accounts(codes: set[str]) -> dict[str, Account]:
        """Finds and returns the accounts by codes.

        :param codes: The account codes.
        :return: The account.
        """
        if len(codes) == 0:
            return {}

        def get_condition(code0: str) -> sa.BinaryExpression:
            m: re.Match = re.match(r"^(\d{4})-(\d{3})$", code0)
            assert m is not None,\
                f"Malformed account code \"{code0}\" for regular transactions."
            return sa.and_(Account.base_code == m.group(1),
                           Account.no == int(m.group(2)))

        conditions: list[sa.BinaryExpression] \
            = [get_condition(x) for x in codes]
        accounts: dict[str, Account] \
            = {x.code: x for x in
               Account.query.filter(sa.or_(*conditions)).all()}
        for code in codes:
            assert code in accounts,\
                f"Unknown account \"{code}\" for regular transactions."
        return accounts

def get_prefix(string: str | sa.Column, separator: str | sa.Column) \
        -> sa.Function:
    """Returns the SQL function to find the prefix of a string.

    :param string: The string.
    :param separator: The separator.
    :return: The position of the substring, starting from 1.
    """
    return sa.func.substr(string, 0, get_position(string, separator))

def get_position(string: str | sa.Column, substring: str | sa.Column) \
        -> sa.Function:
    """Returns the SQL function to find the position of a substring.

    :param string: The string.
    :param substring: The substring.
    :return: The position of the substring, starting from 1.
    """
    if db.engine.name == "postgresql":
        return sa.func.strpos(string, substring)
    return sa.func.instr(string, substring)


from tokenizer import Tokenizer
from abstract_syntax_tree import ASTNode, ConcatNode, AlternationNode, DuplicationNode, CharNode, AnchorNode

class ParseError(Exception):
	pass

class Parser:

	'''
	Parses a regular expression into an abstract syntax tree.
	'''

	'''
	The order of precedence for of operators is as follows:

	Collation-related bracket symbols [==] [::] [..]
	Escaped characters \
	Character set (bracket expression) []
	Grouping ()
	Single-character-ERE duplication * + ? {m,n}
	Concatenation
	Anchoring ^$
	Alternation |
	'''

	def __init__(self, regex):
		self.tokenizer = Tokenizer(regex)

	def parse(self):
		ast = self.parse_regex()
		if not self.tokenizer.atEnd():
			raise ParseError()
		return ast

	def parse_regex(self):
		''' regex:  alternationExprn '''
		return self.parse_alternationExprn()

	def parse_concatExprn(self):
		''' concatExprn: duplicationExprn + '''
		children = []
		try:
			while not self.tokenizer.atEnd():
				dupExprn = self.parse_duplicationExprn()
				children.append(dupExprn)
		except ParseError:
			pass
		if len(children) == 1:
			return children[0]
		return ConcatNode(children)

	def parse_anchorExprn(self):
		''' anchorExprn: '^'? concatExprn? '$'? '''

		anchorStart, anchorEnd = False, False

		if not self.tokenizer.atEnd() and self.tokenizer.cur().isSpecial() and self.tokenizer.cur().value == '^':
			anchorStart = True
			self.tokenizer.advance()

		try:
			concatNode = self.parse_concatExprn()
		except ParseError:
			concatNode = None

		if not self.tokenizer.atEnd() and self.tokenizer.cur().isSpecial() and self.tokenizer.cur().value == '$':
			anchorEnd = True
			self.tokenizer.advance()

		if not anchorStart and not anchorEnd and concatNode is None:
			raise ParseError()

		if not anchorStart and not anchorEnd:
			return concatNode

		return AnchorNode(anchorStart, anchorEnd, concatNode)

	def parse_alternationExprn(self):
		''' alternationExprn: anchorExprn ('|' anchorExprn)* '''
		left = self.parse_anchorExprn()

		while not self.tokenizer.atEnd() and self.tokenizer.cur().isSpecial() and self.tokenizer.cur().value == '|':
			self.tokenizer.advance()
			right = self.parse_anchorExprn()
			left = AlternationNode(left, right)

		return left

	def parse_duplicationExprn(self):
		''' duplicationExprn: groupExprn ('*'|'+'|'?')? '''
		grpExprn = self.parse_groupExprn()

		if not self.tokenizer.atEnd() and self.tokenizer.cur().isSpecial() and self.tokenizer.cur().value in ('*', '+', '?'):
			op = self.tokenizer.advance()
			return DuplicationNode(op, grpExprn)
		return grpExprn

	def parse_groupExprn(self):
		''' groupExprn: CHAR | '(' regex ')' '''
		if self.tokenizer.cur().isChar():
			return CharNode(self.tokenizer.advance())
		if self.tokenizer.cur().value == '(':
			self.tokenizer.advance()
			subRegex = self.parse_regex()
			if self.tokenizer.cur().value != ')':
				raise ParseError()
			self.tokenizer.advance()
			return  subRegex
		raise ParseError()


## -*- coding: utf8 -*-
#!/usr/bin/python
# 日志类.
import logging
logging.basicConfig(level = logging.INFO)

import midmif_supporter
import gis_supporter
import grid_supporter

import const_param as cp
import map_matching_supporter as mm

import highway_map as hhm

import math

# 操作的主文件.
# # test main (20171205）

# 读取输入的高速公路路网.
high_way = hhm.map_obj(0, 9, 4)
high_way.create_map_obj(cp.input_mid_path, cp.input_mif_path)    # 计算出link的一些几何属性.
high_way.create_topo()
print('read highway input map ok.')

# 读取17q2的全路网.
dtiplus_map = hhm.map_obj(0, 5, 6)

dtiplus_map.link_dict = {}
dtiplus_map.fnode_topo_dict = {}
dtiplus_map.tnode_topo_dict = {}
dtiplus_map.pre_mif_lines = []

dtiplus_map.create_map_obj(cp.dtiplus_17q2_mid_path, cp.dtiplus_17q2_mif_path)
dtiplus_map.create_topo()
print('read cennavi 17q2 map ok.')

output_mid = open(cp.output_mid_path, 'w')
output_mif = open(cp.output_mif_path, 'w')

# 对高速路网进行格网索引.
grid_supporter.set_grids_bound(cp.min_long, cp.min_lat, cp.max_long, cp.max_lat)
grid_supporter.set_grid_len(cp.grid_len)
grid_supporter.set_link_id_type(1)

dict_links_by_grid = grid_supporter.return_grid_map2(high_way.link_dict)

# 打印mif文件头.
hhm.print_pre_mif_lines(output_mif)

# 1: 读取输入路网mid line，获取label所用的有用信息.
for link_id in sorted(high_way.link_dict.keys()):
    link_obj = high_way.link_dict[link_id]
    hhm.extract_label_info(link_obj)        # 目的：解决编号、第一条路的上下行、名称、类型的问题.

# 2: 对处在同一个trip中的路段按照拓扑进行排序.
hhm.sort_link_by_topo(high_way.link_dict) # 目的：解决了序号、全体道路上下行
# 全体道路上下行标记以后，将highway_code 加上 上下行的标记.
hhm.add_high_code_updir(high_way.link_dict)

# 收费站延伸出来的link，并进行属性标记.
dict_final_added_links = hhm.extract_toll_station_infos(dtiplus_map, high_way.link_dict, cp.toll_station_match_path)
print('******* toll station finished.******* ')

# 加载原始地图(四维17q2)中获取的信息.
hhm.extract_label_by_map(high_way.link_dict, cp.dtiplus_17q2_mid_path)
hhm.extract_label_by_map(dict_final_added_links, cp.dtiplus_17q2_mid_path)

# 加载里程桩信息.
hhm.add_mile_stake_info(dict_links_by_grid, high_way.link_dict, cp.stake_list_path)
print('******* mile stake finished.******* ')

# 加载桥梁/隧道信息.
hhm.add_bridge_info(dict_links_by_grid, high_way.link_dict, cp.poi_list_path, '9', 2)   # 桥梁
hhm.add_bridge_info(dict_links_by_grid, high_way.link_dict, cp.poi_list_path, '15', 1)  # 隧道.

print('******* bridge and tunnle finished.******* ')

# 因为服务区的影响范围是多边形，用格网表达，以利于后续的处理.
hhm.print_service_cover_grids(dict_links_by_grid, high_way.link_dict, cp.poi_list_path, '2', cp.service_cover_grids_path)
print('******* service zoo finished.******* ')

# 加载城市编码信息.
hhm.decode_city_code(high_way.link_dict, cp.city_encode_path)

# 寻找出入区域范围的路段.
hhm.find_in_out_links(high_way.link_dict)

# 打印结果.
for link_id in sorted(high_way.link_dict.keys()):
    link_obj = high_way.link_dict[link_id]
    link_obj.link_label.print_mid_line(output_mid)
    link_obj.print_mif_lines(output_mif)

# 打印新增道路的路段.
for link_id in sorted(dict_final_added_links.keys()):
    link_obj = dict_final_added_links[link_id]
    link_obj.link_label.print_mid_line(output_mid)
    link_obj.print_mif_lines(output_mif)

print("# 操作结束##")


##
##

import attr
import os

CLOUD_KEY = "gcp"

def get_auth_directory():
    return os.path.join(os.environ['HOME'], '.config', 'gcloud')

def get_default_credentials():
    if 'GOOGLE_APPLICATION_CREDENTIALS' in os.environ:
        return os.environ.get('GOOGLE_APPLICATION_CREDENTIALS')
    else:
        return os.path.join(get_auth_directory(), 'application_default_credentials.json')

@attr.s
class GCPDiskTypes(object):
    disk_type_list = [
        {
            "type": 'pd-standard'
        },
        {
            "type": 'pd-balanced'
        },
        {
            "type": 'pd-ssd'
        }
    ]

@attr.s
class GCPImageProjects(object):
    projects = [
        {
            "project": 'centos-cloud',
            "description": "CentOS Linux",
            "os_id": "centos",
            "user": "centos",
            "pattern": "centos-stream-(.+?)-v*"
        },
        {
            "project": 'debian-cloud',
            "description": "Debian Linux",
            "os_id": "debian",
            "user": "admin",
            "pattern": "debian-(.+?)-*-v*"
        },
        {
            "project": 'fedora-cloud',
            "description": "Fedora Linux",
            "os_id": "fedora",
            "user": "fedora",
            "pattern": "fedora-cloud-base-gcp-(.+?)-1-2-x86-64"
        },
        {
            "project": 'opensuse-cloud',
            "description": "OpenSUSE Linux",
            "os_id": "opensuse-leap",
            "user": "admin",
            "pattern": "opensuse-leap-(.+?)-*-v*"
        },
        {
            "project": 'rhel-cloud',
            "description": "Red Hat Enterprise Linux",
            "os_id": "rhel",
            "user": "admin",
            "pattern": "rhel-(.+?)-v*"
        },
        {
            "project": 'rocky-linux-cloud',
            "description": "Rocky Linux",
            "os_id": "rocky",
            "user": "rocky",
            "pattern": "rocky-linux-(.+?)-v*"
        },
        {
            "project": 'suse-cloud',
            "description": "SUSE Linux Enterprise Server",
            "os_id": "sles",
            "user": "admin",
            "pattern": "sles-(.+?)-*-v*"
        },
        {
            "project": 'ubuntu-os-cloud',
            "description": "Ubuntu Linux",
            "os_id": "ubuntu",
            "user": "ubuntu",
            "pattern": r"ubuntu-(.+?)-*-v*"
        },
        {
            "project": 'ubuntu-os-pro-cloud',
            "description": "Ubuntu Pro Linux",
            "os_id": "ubuntu",
            "user": "ubuntu",
            "pattern": r"ubuntu-pro-(.+?)-*-v*"
        }
    ]

@attr.s
class ComputeTypes(object):
    general_purpose = ['n2', 't2a', 'n2d']
    compute_optimized = ['c2', 'c2d']
    memory_optimized = ['m2', 'm3']

    def as_list(self) -> list:
        flat_list = []
        for element in [self.general_purpose, self.compute_optimized, self.memory_optimized]:
            flat_list.extend(element)
        return flat_list


from rest_framework import generics, mixins, status, viewsets
from rest_framework.exceptions import NotFound
from rest_framework.permissions import (
    AllowAny, IsAuthenticated, IsAuthenticatedOrReadOnly, IsAdminUser
)
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import Algorithm
from .renderers import AlgorithmJSONRenderer
from .serializers import AlgorithmSerializer

#Admin
class AlgorithmViewSetAdmin(viewsets.ModelViewSet):
    queryset = Algorithm.objects.all()
    serializer_class = AlgorithmSerializer
    lookup_field = 'slug'
    permission_classes = (IsAuthenticated,)
    permission_classes = (IsAdminUser,)

class AlgorithmViewSet(mixins.CreateModelMixin,
                     mixins.ListModelMixin,
                     mixins.RetrieveModelMixin,
                     viewsets.GenericViewSet):

    lookup_field = 'slug'
    queryset = Algorithm.objects.select_related('author', 'author__user')
    permission_classes = (IsAuthenticatedOrReadOnly,)
    renderer_classes = (AlgorithmJSONRenderer,)
    serializer_class = AlgorithmSerializer

    def get_queryset(self):
        queryset = self.queryset

        author = self.request.query_params.get('author', None)
        if author is not None:
            queryset = queryset.filter(author__user__username=author)

        favorited_by = self.request.query_params.get('favorited', None)
        if favorited_by is not None:
            queryset = queryset.filter(
                favorited_by__user__username=favorited_by
            )

        return queryset

    def create(self, request):
        serializer_context = {
            'author': request.user.profile,
            'request': request
        }
        serializer_data = request.data.get('algorithm', {})
        serializer = self.serializer_class(
        data=serializer_data, context=serializer_context
        )
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def list(self, request):
        serializer_context = {'request': request}
        page = self.paginate_queryset(self.get_queryset())

        serializer = self.serializer_class(
            page,
            context=serializer_context,
            many=True
        )

        return self.get_paginated_response(serializer.data)

    def retrieve(self, request, slug):
        serializer_context = {'request': request}

        try:
            serializer_instance = self.queryset.get(slug=slug)
        except Algorithm.DoesNotExist:
            raise NotFound('An algorithm with this slug does not exist.')

        serializer = self.serializer_class(
            serializer_instance,
            context=serializer_context
        )

        return Response(serializer.data, status=status.HTTP_200_OK)

    def update(self, request, slug):
        serializer_context = {'request': request}

        try:
            serializer_instance = self.queryset.get(slug=slug)
        except Algorithm.DoesNotExist:
            raise NotFound('An algorithm with this slug does not exist.')

        serializer_data = request.data.get('algorithm', {})

        serializer = self.serializer_class(
            serializer_instance,
            context=serializer_context,
            data=serializer_data,
            partial=True
        )
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_200_OK)

class AlgorithmsFavoriteAPIView(APIView):
    permission_classes = (IsAuthenticated,)
    renderer_classes = (AlgorithmJSONRenderer,)
    serializer_class = AlgorithmSerializer

    def delete(self, request, algorithm_slug=None):
        profile = self.request.user.profile
        serializer_context = {'request': request}

        try:
            algorithm = Algorithm.objects.get(slug=algorithm_slug)
        except Algorithm.DoesNotExist:
            raise NotFound('An algorithm with this slug was not found.')

        profile.unfavorite(algorithm)

        serializer = self.serializer_class(algorithm, context=serializer_context)

        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request, algorithm_slug=None):
        profile = self.request.user.profile
        serializer_context = {'request': request}

        try:
            algorithm = Algorithm.objects.get(slug=algorithm_slug)
        except Algorithm.DoesNotExist:
            raise NotFound('An algorithm with this slug was not found.')

        profile.favorite(algorithm)

        serializer = self.serializer_class(algorithm, context=serializer_context)

        return Response(serializer.data, status=status.HTTP_201_CREATED)

class AlgorithmsFeedAPIView(generics.ListAPIView):
    permission_classes = (IsAuthenticated,)
    queryset = Algorithm.objects.all()
    renderer_classes = (AlgorithmJSONRenderer,)
    serializer_class = AlgorithmSerializer

    def get_queryset(self):
        return Algorithm.objects.filter(
            author__in=self.request.user.profile.follows.all()
        )

    def list(self, request):
        queryset = self.get_queryset()
        page = self.paginate_queryset(queryset)

        serializer_context = {'request': request}
        serializer = self.serializer_class(
            page, context=serializer_context, many=True
        )

        return self.get_paginated_response(serializer.data)


#!/usr/bin/env python
# coding=utf-8

"""
@author: zhangyp
@project: gp_api_test
@file: output_tool
@time: 2020/9/21 17:34
@desc:
"""
import os
from util.data_type_data.edit_json import jiexi_json, json_to_dict

def get_output_list(case_data, response_text):
    output_list = []
    gc_path = case_data.get("testdatafile")
    relative_path = case_data.get("gc_globle_data").get("save_path").get("output")
    filename = case_data.get("output")
    filename_path = os.path.join(gc_path, relative_path, filename)
    with open(filename_path, "r") as f:
        output_str = f.read().replace(" ", "").replace("\n", "")
    output_filte_list = output_str.split(";")
    for i in range(len(output_filte_list)):
        de_data_dict = {}
        filte_list = output_filte_list[i].split(">")
        if filte_list[0] == "response":
            de_data_dict = json_to_dict(response_text)
        if filte_list[0] == "bodydata":
            de_data_dict = json_to_dict(case_data.get("bodydata"))
        if filte_list[0] == "urldata":
            de_data_dict = json_to_dict(case_data.get("urldata"))
        filte_value = jiexi_json(de_data_dict, filte_list[1])
        filte_value_dict = {}
        filte_value_dict[filte_list[1].split(".")[-1]] = filte_value
        output_list.append(filte_value_dict)
    return output_list


import arrow
from . import Data
from gcore import const, mongoapi, global_vars

# this class encapsulates the logic for a mission
# it is initialized with a Mongo Object
dbtype = "files"
class File(Data):

    def __init__(self, obj):

        #creator_id: string;
        #ext: string; // extension, 3 letters
        #filetype:string; // image, report, contract
        #url: string;
        #key:string;  // encryption key ? or name in bucket
        #date:string; // as YYYYMMDD
        #bucket:string,
        #target_id:string,
        #target_type:string

        self.creator_id = None
        self.ext = ""
        self.url = ""
        self.state = ""
        self.filetype = ""
        self.bucket = ""
        self.key = ""
        self.target_id = ""
        self.date = "" # akshully a date. duh

        super(File, self).__init__(obj)
        self.dbtype = dbtype
        if 'date' in obj: # cron jobs don't have a 'created'
            self.date_arrow = arrow.get(obj["date"])

        self.date = self.date_arrow.format(const.DEFAULT_FMT)

    @staticmethod
    def create(path, ext, target_id, target_type , bucket = "local", filetype="report", creator_id=None):
        if creator_id is None:
            creator_id= mongoapi.tool_user['_id'],
        data = {
            "creator_id": creator_id,
            "ext": ext,
            "filetype":filetype,
            'key': path,
            'date':arrow.now().format("YYYYMMDD"),
            'bucket':"local",
            'target_id':target_id,
            'target_type': target_type
        }
        # make move to s3 job ?
        fileobj = mongoapi.make_object(global_vars.db, 'files',data)
        return File(fileobj)

    @property
    def filename(self):
        fname = self.key.split("/")[-1]
        if "." in fname:
            return fname
        else:
            return "{}.{}".format(fname, self.ext)

    def update(self, key=None, bucket = None, save=True):

        if bucket is not None:
            self.bucket = bucket
            self.data["bucket"] = bucket

        if key is not None:
            self.key = key
            self.data["key"] = key

        if save:
            self.save()

    @staticmethod
    def get(_id):
        '''gets mongo api object and creates the dataclass

        Arguments:
            _id {ObjectId} -- user _id
        '''
        _obj = global_vars.db.files.find_one({"_id":_id})
        if _obj is None:
            return None
        return File(_obj)


from rest_framework import permissions

class UpdateOwnProfile(permissions.BasePermission):
    """" Allow user to edit their own profile """
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS :
        #    print(obj.id ,"idddddddddddddddddddddd////////")
       #     print(request.user.id ,"idddddddddddddddd222222222222////////")
            return True
     #   print(obj ,"opjjjjjjjjjjjjj")
    #    print(request.user.id,"idddddddddddddddd222222222222")
        return obj.id==request.user.id

class UpdateOwnStatus(permissions.BasePermission):
    """" Allow user to update their own status """
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS :
            return True
        print(obj ,"opjjjjjjjjjjjjj")
        print(request.user.id,"idddddddddddddddd222222222222")
        return obj.user_profile.id==request.user.id


from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.shortcuts import render, redirect
from django.core.cache import cache
from django.views import View
from math_exercises.exercises import *
from math_exercises.forms import *
from sitepanel.models import Kids

class MatchTestView(View):
    def get(self, request):
        operation = FractionAdd(1, 10)
        # numbers = operation.draw_numbers()
        operations = operation.get_operations()
        return render(request, 'test.html', {'operations': operations})

    def post(self):
        return redirect('test')

class CategoryView(LoginRequiredMixin, View):
    def get(self, request):
        form = CategoryForm()
        return render(request, 'category.html', {'form': form})

    def post(self, request):
        category = request.POST['category']
        operations = request.POST['operations']
        range_from = int(request.POST['from'])
        range_to = int(request.POST['to'])
        return redirect('play', category, operations, range_from, range_to)

class PlayView(View):
    def get(self, request, **kwargs):
        category = int(kwargs['category'])
        typ_of_operations = int(kwargs['operations'])
        range_from = int(kwargs['range_from'])
        range_to = int(kwargs['range_to'])
        if range_to - range_from < 9:
            print(range_to - range_from)
            messages.warning(request, 'Zbyt mały zakres')
            return redirect('category')

        if category == 1:
            operation_type = 'total'
            if typ_of_operations == 1:
                operation = Add(range_from, range_to)
            elif typ_of_operations == 2:
                operation = Subtraction(range_from, range_to)
            elif typ_of_operations == 3:
                operation = Multiplication(range_from, range_to)
            else:
                operation = Division(range_from, range_to)

        elif category == 2:
            operation_type = 'fraction'
            if typ_of_operations == 1:
                operation = FractionAdd(range_from, range_to)
            elif typ_of_operations == 2:
                operation = FractionSubtraction(range_from, range_to)
            elif typ_of_operations == 3:
                operation = FractionMultiplication(range_from, range_to)
            else:
                operation = FractionDivision(range_from, range_to)

        else:
            operation_type = 'decimal'
            if typ_of_operations == 1:
                operation = DecimalFractionsAdd(range_from, range_to)
            elif typ_of_operations == 2:
                operation = DecimalFractionsSubtraction(range_from, range_to)
            elif typ_of_operations == 3:
                operation = DecimalFractionsMultiplication(range_from, range_to)
            else:
                operation = DecimalFractionsDivision(range_from, range_to)

        numbers = operation.draw_numbers()
        operations = operation.get_operations()
        cache.set('numbers', numbers)
        return render(request, 'play.html', {'operations': operations, 'operation_type': operation_type})

    def post(self, request, **kwargs):
        category = int(kwargs['category'])
        operations = int(kwargs['operations'])
        user = request.user.pk
        kids = Kids.objects.get(kids_id=user)
        numbers = cache.get('numbers')
        answers = request.POST.getlist('results')
        numerator = request.POST.getlist('numerator')
        denominator = request.POST.getlist('denominator')
        if category == 2:
            if operations == 1:
                results = FractionAdd.checking_results(numbers, numerator, denominator, operations)
            elif operations == 2:
                results = FractionSubtraction.checking_results(numbers, numerator, denominator, operations)
            elif operations == 3:
                results = FractionMultiplication.checking_results(numbers, numerator, denominator, operations)
            else:
                results = FractionDivision.checking_results(numbers, numerator, denominator, operations)
        else:
            results = Operation.checking_results(numbers, answers, operations)

        points = Operation.add_points(results)

        kids.set_points(points)
        kids.save()
        return redirect('user')


#!/usr/bin/env python

"""
This script reads the apt cache and writes in-toto material provenance
to stdout in JSON format or argv[1] when provided.
"""

from __future__ import print_function
import apt.cache
import json
import sys

cache = apt.cache.Cache()
in_toto_data = list()

for pkg_name in cache.keys():
    pkg = cache[pkg_name]
    if not pkg.is_installed:
        continue
    # Generated by mk-build-deps in build-debs.sh
    # Has no digest, so let's ignore it
    if pkg_name.endswith('-build-deps'):
        continue

    in_toto_data.append(
        {
            "uri": "pkg:deb/{origin}/{name}@{version}?arch={arch}".format(
                origin=pkg.installed.origins[0].origin,
                name=pkg.shortname,
                version=pkg.installed.version,
                arch=pkg.installed.architecture
            ),
            "digest": {
                "sha256": pkg.installed.sha256
            }
        }
    )

if len(sys.argv) > 1:
    with open(sys.argv[1], 'w') as f:
        json.dump(in_toto_data, f)
else:
    print(json.dumps(in_toto_data))


import logging
from time import time_ns

import requests
from app.bootstrap import Bootstrap, bootstrap
from app.config import settings
from app.controllers import main_router
from app.schemas import StatefunTimeCreateRequest
from fastapi import FastAPI

logger = logging.getLogger()

app = FastAPI()
app.include_router(main_router)

def init_logger(level):
    logger.setLevel(level)
    ch = logging.StreamHandler()
    formatter = logging.Formatter(
        "%(asctime)s.%(msecs)03d %(levelname)s %(pathname)s:%(lineno)d: %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )
    ch.setFormatter(formatter)
    logger.addHandler(ch)

@app.on_event("startup")
async def startup():
    init_logger(settings.log_level)

    logger = logging.getLogger(__name__)
    start_time = time_ns()
    app.state.bootstrap: Bootstrap = await bootstrap(
        side_car_address="http://sidecar/statefun/",
        type_test_case="all-combination",
        benchmark_mode=True,
    )
    end_time = time_ns()
    bootstrap_object = app.state.bootstrap
    if bootstrap_object.benchmark_mode:
        elapsed_time = end_time - start_time
        requests.post(
            bootstrap_object.side_car_address,
            json=StatefunTimeCreateRequest(
                time_ns=elapsed_time,
                type_test_case=bootstrap_object.type_test_case,
                type_timer="bootstrap",
            ).dict(),
        )
        logger.info(f"elapsed statefun bootstrap: {end_time-start_time}")
    logger.info("Bootstrap is done")


from exceptions import *

def join(file_name,file_names):
    if file_name == '':
        raise NameErrorCustom()
    if len(file_names) < 2:
        raise LengthError()

    for file in file_names:
        with open(file, 'r') as f:
            text = f.read()
        with open(file_name, 'a') as fi:
            fi.write(text)


# file to assist in generating heyawake text files
# while the main part is running
# q: quit
# u: undo last operation (supports full undo history)
# w: write to file when finished
# type "<r> <c> [n]" to make a rxc rectangle with the number n (optional)
# command line usage: heyawake_helper <r> <c> <file>

import curses
import sys

R = int(sys.argv[1])
C = int(sys.argv[2])
outfile = sys.argv[3]

def get_box_dims(stdscr,y,x):
    s = ''
    while True:
        c = stdscr.getch(y,x)
        if chr(c) == 'q': return ('q','q','q') # termination
        if chr(c) == 'u': return ('u','u','u') # undo last operation
        if chr(c) == 'w': return ('w','w','w') # write to file (when done)
        if chr(c) == '\n': break
        if chr(c) in ' 0123456789': s += chr(c)
    try:
        r,c = map(int,s.split())
        n = -1
    except:
        try: r,c,n = map(int,s.split())
        except: raise Exception()
    assert -1 <= n <= 9 # -1 for unspecified, 0-9 for numbers
    # does not support larger numbers, special cases were handled separately
    # the only exceptions were 11 and 12 (B and C) in the last puzzle
    assert r > 0 and c > 0
    return (r,c,n)

def valid_rect(grid,r,c,br,bc): # rectangle fits in blank space available
    global R,C
    if r+br > R or c+bc > C: return False
    for rr in range(r,r+br):
        for cc in range(c,c+bc):
            if grid[rr][cc] != ' ': return False
    return True

def choose_fill(grid,r,c,br,bc): # pick fill char not used by adjacent region
    global R,C
    adj_chars = set()
    if r-1 >= 0:
        for cc in range(c,c+bc): adj_chars.add(grid[r-1][cc])
    if r+br < R:
        for cc in range(c,c+bc): adj_chars.add(grid[r+br][cc])
    if c-1 >= 0:
        for rr in range(r,r+br): adj_chars.add(grid[rr][c-1])
    if c+bc < C:
        for rr in range(r,r+br): adj_chars.add(grid[rr][c+bc])
    for c in '@#$%&*': # try to 4 color, but allow 2 extras just in case
        if not (c in adj_chars): return c
    raise Exception()

def main(stdscr): # wrapper handles initialization

#    stdscr = curses.initscr()
#    curses.noecho()
#    curses.cbreak()
#    stdscr.keypad(True)
#    stdscr.start_color()

    stdscr.clear()

    # create color pairs to use
    curses.init_pair(10,curses.COLOR_BLACK,curses.COLOR_WHITE)
    curses.init_pair(1,curses.COLOR_BLACK,curses.COLOR_YELLOW)
    curses.init_pair(2,curses.COLOR_BLACK,curses.COLOR_CYAN)
    curses.init_pair(3,curses.COLOR_BLACK,curses.COLOR_MAGENTA)
    curses.init_pair(4,curses.COLOR_BLACK,curses.COLOR_GREEN)
    curses.init_pair(5,curses.COLOR_BLACK,curses.COLOR_BLUE)
    curses.init_pair(6,curses.COLOR_BLACK,curses.COLOR_RED)
    charcolor = {'@':1,'#':2,'$':3,'%':4,'&':5,'*':6}

    global R,C,outfile

    # make white background
    for r in range(R): stdscr.addstr(r,0,' '*C,curses.color_pair(10))
    stdscr.refresh()

    grid = [list(' '*C) for _ in range(R)]
    nums = [list(' '*C) for _ in range(R)]

    #pr,pc,pbr,pbc = None,None,None,None # prev operation position and size
    undo = [] # undo history
    r,c = 0,0
    while True: # entire board

        if r == R: # check for undo only, otherwise complete board
            try: br,bc,bn = get_box_dims(stdscr,r,c)
            except: continue
            if br == 'u': # undo
                if len(undo) > 0: # can undo
                    pr,pc,pbr,pbc = undo.pop()
                    for rr in range(pr,pr+pbr):
                        for cc in range(pc,pc+pbc):
                            grid[rr][cc] = ' '
                            stdscr.addstr(rr,cc,' ',curses.color_pair(10))
                    nums[pr][pc] = ' '
                    r,c = pr,pc # so next iteration goes to same place
                continue
            if br == 'q': return # quit
            if br == 'w': break # go on, write to file
            continue # try again

        if grid[r][c] == ' ': # find blank space
            try: br,bc,bn = get_box_dims(stdscr,r,c)
            except: continue # try again for this space

            if br == 'q': return # end program

            if br == 'u': # undo
                if len(undo) > 0: # can undo
                    pr,pc,pbr,pbc = undo.pop()
                    for rr in range(pr,pr+pbr):
                        for cc in range(pc,pc+pbc):
                            grid[rr][cc] = ' '
                            stdscr.addstr(rr,cc,' ',curses.color_pair(10))
                    nums[pr][pc] = ' '
                    r,c = pr,pc # so next iteration goes to same place
                continue

            if br == 'w': continue # only allow write command at end

            # try to place rectangle, otherwise retry input
            if valid_rect(grid,r,c,br,bc):
                fc = choose_fill(grid,r,c,br,bc) # fill character
                for rr in range(r,r+br):
                    for cc in range(c,c+bc):
                        grid[rr][cc] = fc
                        stdscr.addstr(rr,cc,' ',curses.color_pair(charcolor[fc]))
                nums[r][c] = ' ' if bn == -1 else str(bn)
                stdscr.addstr(r,c,' ' if bn == -1 else str(bn),
                             curses.color_pair(charcolor[fc]))
                undo.append((r,c,br,bc)) # save undo data
                #pr,pc,pbr,pbc = r,c,br,bc # save undo data
            else: continue # fail, try again

        c += 1
        if c == C: r,c = r+1,0

    # done, write to file
    with open(outfile,"w") as outf:
        for row in grid: outf.write(''.join(row)+'\n')
        outf.write('-'*C+'\n')
        for row in nums: outf.write(''.join(row)+'\n')
        outf.close()

#    curses.nocbreak()
#    stdscr.keypad(False)
#    curses.echo()
#    curses.endwin()

curses.wrapper(main)


import os
from datetime import timedelta

from .core import DEBUG, INSTALLED_APPS, MIDDLEWARE, SECRET_KEY

# Celery

if 'BROKER_URL' in os.environ or 'REDIS_CONNECTION' in os.environ:
    CELERY_BROKER_URL = BROKER_URL = os.environ.get('BROKER_URL', os.environ.get("REDIS_CONNECTION") + "1")
    CELERY_RETRY_TIMEOUT = int(os.environ.get('CELERY_RETRY_TIMEOUT', 30))

# DRF

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PAGINATION_CLASS': 'core.pagination.PageNumberPagination',
    'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}

# Simple JWT

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

# Swagger

SWAGGER_SETTINGS = {
    'DEFAULT_API_URL': os.environ.get('DEFAULT_API_URL', "https://localhost:8000/api/v1"),
    'DOC_EXPANSION': None,
    'DEEP_LINKING': True,
    'SECURITY_DEFINITIONS': {
        'basic': {
            'type': 'basic'
        },
        'api_key': {
            'type': 'apiKey',
            'description': 'Bearer <token>',
            'name': 'Authorization',
            'in': 'header',
        }
    },
}

# Debug toolbar

if DEBUG:
    INSTALLED_APPS.append('debug_toolbar')
    MIDDLEWARE.insert(1, 'debug_toolbar.middleware.DebugToolbarMiddleware')

DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK": lambda x: DEBUG,
    "DISABLE_PANELS": {
        'debug_toolbar.panels.versions.VersionsPanel',
        'debug_toolbar.panels.settings.SettingsPanel',
        'debug_toolbar.panels.request.RequestPanel',
        'debug_toolbar.panels.staticfiles.StaticFilesPanel',
        'debug_toolbar.panels.templates.TemplatesPanel',
        'debug_toolbar.panels.cache.CachePanel',
        'debug_toolbar.panels.signals.SignalsPanel',
        'debug_toolbar.panels.logging.LoggingPanel',
        'debug_toolbar.panels.redirects.RedirectsPanel',
    }
}

__all__ = list(locals().keys())
for k in ('os', 'DEBUG', 'INSTALLED_APPS', 'MIDDLEWARE', 'SECRET_KEY'):
    __all__.remove(k)