from pathlib import Path

import math
import sys
import torch
import torch.nn.functional as F
from timm.models.helpers import named_apply, checkpoint_seq
from timm.models.layers import trunc_normal_
from timm.models.vision_transformer import VisionTransformer, get_init_weights_vit, PatchEmbed, Block
from torch import nn
from typing import Callable

from posrecon.pos_embed import get_2d_sincos_pos_embed

path = str(Path(Path(__file__).parent.absolute()).parent.absolute())
sys.path.insert(0, path)

from simclr.models import SimCLRBase

class SyncFunction(torch.autograd.Function):
    @staticmethod
    def forward(ctx, tensor):
        ctx.batch_size = tensor.shape[0]

        gathered_tensor = [torch.zeros_like(tensor)
                           for _ in range(torch.distributed.get_world_size())]

        torch.distributed.all_gather(gathered_tensor, tensor)
        gathered_tensor = torch.cat(gathered_tensor, 0)

        return gathered_tensor

    @staticmethod
    def backward(ctx, grad_output):
        grad_input = grad_output.clone()
        torch.distributed.all_reduce(grad_input,
                                     op=torch.distributed.ReduceOp.SUM,
                                     async_op=False)

        idx_from = torch.distributed.get_rank() * ctx.batch_size
        idx_to = (torch.distributed.get_rank() + 1) * ctx.batch_size
        return grad_input[idx_from:idx_to]

class MaskedPosReconCLRViT(nn.Module):
    """
    Masked contrastive learning Vision Transformer w/ positional reconstruction
    Default params are from ViT-Base.
    """

    def __init__(
            self,
            img_size: int = 224,
            patch_size: int = 16,
            in_chans: int = 3,
            embed_dim: int = 768,
            depth: int = 12,
            num_heads: int = 12,
            mlp_ratio: int = 4,
            proj_dim: int = 128,
            norm_layer: Callable = nn.LayerNorm,
    ):
        super(MaskedPosReconCLRViT, self).__init__()

        # Encoder
        self.patch_embed = PatchEmbed(img_size, patch_size, in_chans, embed_dim)
        num_patches = self.patch_embed.num_patches

        self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
        # Following DeiT-3, exclude pos_embed from cls_token
        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim),
                                      requires_grad=False)

        self.blocks = nn.Sequential(*[
            Block(embed_dim, num_heads, mlp_ratio,
                  qkv_bias=True, norm_layer=norm_layer)
            for _ in range(depth)
        ])
        self.norm = norm_layer(embed_dim)

        # Position predictor (linear layer equiv.)
        self.pos_decoder = nn.Conv1d(embed_dim, embed_dim, kernel_size=1)

        # Projection head
        self.proj_head = nn.Sequential(
            nn.Linear(embed_dim, embed_dim),
            nn.GELU(),
            nn.Linear(embed_dim, proj_dim),
        )

        self.init_weights()

    def init_weights(self):
        pos_embed = get_2d_sincos_pos_embed(
            self.pos_embed.size(-1), int(self.patch_embed.num_patches ** .5)
        )
        self.pos_embed.data.copy_(torch.from_numpy(pos_embed).float().unsqueeze(0))

        # Init weights in convolutional layers like in MLPs
        patch_conv_weight = self.patch_embed.proj.weight.data
        pos_conv_weight = self.pos_decoder.weight.data
        nn.init.xavier_uniform_(patch_conv_weight.view(patch_conv_weight.size(0), -1))
        nn.init.xavier_uniform_(pos_conv_weight.view(pos_conv_weight.size(0), -1))

        nn.init.normal_(self.cls_token, std=.02)

        self.apply(self._init_other_weights)

    def _init_other_weights(self, m):
        if isinstance(m, nn.Linear):
            # we use xavier_uniform following official JAX ViT:
            nn.init.xavier_uniform_(m.weight)
            if isinstance(m, nn.Linear) and m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.LayerNorm):
            nn.init.constant_(m.bias, 0)
            nn.init.constant_(m.weight, 1.0)

    @staticmethod
    def rand_shuffle(x, pos_embed):
        batch_size, seq_len, embed_dim = x.size()
        # pos_embed: [1, seq_len, embed_dim]
        batch_pos_embed = pos_embed.expand(batch_size, -1, -1)
        # batch_pos_embed: [batch_size, seq_len, embed_dim]
        noise = torch.rand(batch_size, seq_len, device=x.device)
        shuffled_indices = noise.argsort()
        # shuffled_indices: [batch_size, seq_len]
        expand_shuffled_indices = shuffled_indices.unsqueeze(-1).expand(-1, -1, embed_dim)
        # expand_shuffled_indices: [batch_size, seq_len, embed_dim]
        batch_shuffled_pos_embed = batch_pos_embed.gather(1, expand_shuffled_indices)
        # batch_shuffled_pos_embed: [batch_size, seq_len, embed_dim]
        return x + batch_shuffled_pos_embed

    @staticmethod
    def rand_mask(x, mask_ratio):
        batch_size, seq_len, embed_dim = x.size()
        visible_len = int(seq_len * (1 - mask_ratio))
        noise = torch.rand(batch_size, seq_len, device=x.device)
        shuffled_indices = noise.argsort()
        # shuffled_indices: [batch_size, seq_len]
        unshuffled_indices = shuffled_indices.argsort()
        # unshuffled_indices: [batch_size, seq_len]
        visible_indices = shuffled_indices[:, :visible_len]
        # visible_indices: [batch_size, seq_len * mask_ratio]
        expand_visible_indices = visible_indices.unsqueeze(-1).expand(-1, -1, embed_dim)
        # expand_visible_indices: [batch_size, seq_len * mask_ratio, embed_dim]
        x_masked = x.gather(1, expand_visible_indices)
        # x_masked: [batch_size, seq_len * mask_ratio, embed_dim]

        return x_masked, expand_visible_indices

    def forward_encoder(self, x, mask_ratio):
        x = self.patch_embed(x)

        x = self.rand_shuffle(x, self.pos_embed)
        # batch_size*2, seq_len, embed_dim
        x, visible_indices = self.rand_mask(x, mask_ratio)
        # batch_size*2, seq_len * mask_ratio, embed_dim

        # Concatenate [CLS] tokens w/o pos_embed
        cls_tokens = self.cls_token.expand(x.size(0), -1, -1)
        x = torch.cat((cls_tokens, x), dim=1)
        # batch_size*2, 1 + seq_len * mask_ratio, embed_dim

        x = self.blocks(x)
        x = self.norm(x)

        return x, visible_indices

    def forward_pos_decoder(self, latent):
        # Exchange channel and length dimension for Conv1d
        latent = latent.permute(0, 2, 1)
        pos_embed_pred = self.pos_decoder(latent)
        # Restore dimension
        pos_embed_pred = pos_embed_pred.permute(0, 2, 1)

        return pos_embed_pred

    def pos_recon_loss(self, batch_pos_embed_pred, vis_ids):
        batch_size = batch_pos_embed_pred.size(0)
        # self.pos_embed: [1, seq_len, embed_dim]
        # batch_pos_embed_pred: [batch_size*2, seq_len, embed_dim]
        # vis_ids: [batch_size*2, seq_len * mask_ratio, embed_dim]
        batch_pos_embed_targ = self.pos_embed.expand(batch_size, -1, -1)
        # batch_pos_embed_targ: [batch_size*2, seq_len, embed_dim]
        # Only compute loss on visible patches
        visible_pos_embed_targ = batch_pos_embed_targ.gather(1, vis_ids)
        # visible_pos_embed_targ: [batch_size*2, seq_len * mask_ratio, embed_dim]
        loss = F.mse_loss(batch_pos_embed_pred, visible_pos_embed_targ)
        return loss

    @staticmethod
    def info_nce_loss(features, temp, eps=1e-6):
        feat = F.normalize(features)
        # feat: [batch_size*2, proj_dim]
        feat = torch.stack(feat.chunk(2), dim=1)
        # feat: [batch_size, 2, proj_dim]
        if torch.distributed.is_available() and torch.distributed.is_initialized():
            feat = SyncFunction.apply(feat)
        # feat: [batch_size (* world_size), 2, proj_dim]
        feat1, feat2 = feat[:, 0, :], feat[:, 1, :]
        # feat{1,2}: [batch_size (* world_size), proj_dim]
        feat = torch.cat((feat1, feat2))
        # feat: [batch_size*2 (* world_size), proj_dim]

        # All samples, filling diagonal to remove identity similarity ((2N)^2 - 2N)
        all_sim = (feat @ feat.T).fill_diagonal_(0)
        # all_sim: [batch_size*2 (* world_size), batch_size*2 (* world_size)]
        all_ = torch.exp(all_sim / temp).sum(-1)
        # all_: [batch_size*2 (* world_size)]

        # Positive samples (2N)
        pos_sim = (feat1 * feat2).sum(-1)
        # pos_sim: [batch_size (* world_size)]
        pos = torch.exp(pos_sim / temp)
        # Following all samples, compute positive similarity twice
        pos = torch.cat((pos, pos))
        # pos: [batch_size*2 (* world_size)]

        loss = -torch.log(pos / (all_ + eps)).mean()

        return loss

    def forward_loss(self, batch_pos_embed_pred, vis_ids, features, temp=0.1):
        loss_recon = self.pos_recon_loss(batch_pos_embed_pred, vis_ids)
        loss_clr = self.info_nce_loss(features, temp)
        return loss_recon, loss_clr

    def forward(self, img, mask_ratio=0.75, temp=0.01):
        # img: [batch_size*2, in_chans, height, weight]
        latent, vis_ids = self.forward_encoder(img, mask_ratio)
        # latent: [batch_size*2, 1 + seq_len * mask_ratio, embed_dim]
        pos_pred = self.forward_pos_decoder(latent[:, 1:, :])
        # pos_pred: [batch_size*2, seq_len * mask_ratio, embed_dim]
        feat = self.proj_head(latent[:, 0, :])
        # reps: [batch_size*2, proj_dim]
        loss_recon, loss_clr = self.forward_loss(pos_pred, vis_ids, feat, temp)
        return latent, pos_pred, feat, loss_recon, loss_clr

class ShuffledVisionTransformer(VisionTransformer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        del self.pos_embed

    def init_weights(self, mode=''):
        assert mode in ('jax', 'jax_nlhb', 'moco', '')
        head_bias = -math.log(self.num_classes) if 'nlhb' in mode else 0.
        if self.cls_token is not None:
            nn.init.normal_(self.cls_token, std=1e-6)
        named_apply(get_init_weights_vit(mode, head_bias), self)

    @staticmethod
    def fixed_positional_encoding(embed_dim, embed_len, max_embed_len=5000):
        """Fixed positional encoding from vanilla Transformer"""
        position = torch.arange(max_embed_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, embed_dim, 2) * (-math.log(10_000.) / embed_dim))
        pos_embed = torch.zeros(1, max_embed_len, embed_dim)
        pos_embed[:, :, 0::2] = torch.sin(position * div_term)
        pos_embed[:, :, 1::2] = torch.cos(position * div_term)

        return pos_embed[:, :embed_len, :]

    def init_pos_embed(self, device, fixed=False):
        num_patches = self.patch_embed.num_patches
        embed_len = num_patches if self.no_embed_class else num_patches + self.num_prefix_tokens
        if fixed:
            pos_embed = self.fixed_positional_encoding(self.embed_dim, embed_len).to(device)
        else:
            pos_embed = (torch.randn(1, embed_len, self.embed_dim,
                                     device=device) * .02).requires_grad_()
            trunc_normal_(pos_embed, std=.02)
        return pos_embed

    def shuffle_pos_embed(self, pos_embed, shuff_rate=0.75):
        embed_len = pos_embed.size(1)
        nshuffs = int(embed_len * shuff_rate)
        shuffled_indices = torch.randperm(embed_len)[:nshuffs]
        if not self.no_embed_class:
            shuffled_indices += self.num_prefix_tokens
        ordered_shuffled_indices, unshuffled_indices = shuffled_indices.sort()
        shuffled_pos_embed = pos_embed.clone()
        shuffled_pos_embed[:, ordered_shuffled_indices, :] = shuffled_pos_embed[:, shuffled_indices, :]
        return shuffled_pos_embed, unshuffled_indices, ordered_shuffled_indices

    @staticmethod
    def unshuffle_pos_embed(shuffled_pos_embed, unshuffled_indices, ordered_shuffled_indices):
        pos_embed = shuffled_pos_embed.clone()
        pos_embed[:, ordered_shuffled_indices, :] \
            = pos_embed[:, ordered_shuffled_indices, :][:, unshuffled_indices, :]
        return pos_embed

    @staticmethod
    def reshuffle_pos_embed(pos_embed, ordered_shuffled_indices):
        nshuffs = ordered_shuffled_indices.size(0)
        reshuffled_indices = ordered_shuffled_indices[torch.randperm(nshuffs)]
        _, unreshuffled_indices = reshuffled_indices.sort()
        reshuffled_pos_embed = pos_embed.clone()
        reshuffled_pos_embed[:, ordered_shuffled_indices, :] = reshuffled_pos_embed[:, reshuffled_indices, :]
        return reshuffled_pos_embed, unreshuffled_indices

    def _pos_embed(self, x, pos_embed=None):
        if self.no_embed_class:
            # deit-3, updated JAX (big vision)
            # position embedding does not overlap with class token, add then concat
            x = x + pos_embed
            if self.cls_token is not None:
                x = torch.cat((self.cls_token.expand(x.shape[0], -1, -1), x), dim=1)
        else:
            # original timm, JAX, and deit vit impl
            # pos_embed has entry for class token, concat then add
            if self.cls_token is not None:
                x = torch.cat((self.cls_token.expand(x.shape[0], -1, -1), x), dim=1)
            x = x + pos_embed
        return self.pos_drop(x)

    def forward_features(self, x, pos_embed=None, probe=False):
        patch_embed = self.patch_embed(x)
        x = self._pos_embed(patch_embed, pos_embed)
        if self.grad_checkpointing and not torch.jit.is_scripting():
            x = checkpoint_seq(self.blocks, x)
        else:
            x = self.blocks(x)
        x = self.norm(x)
        if probe:
            return x, patch_embed
        else:
            return x

    def forward(self, x, pos_embed=None, probe=False):
        assert pos_embed is not None
        if probe:
            features, patch_embed = self.forward_features(x, pos_embed, probe)
            x = self.forward_head(features)
            return x, features, patch_embed
        else:
            features = self.forward_features(x, pos_embed, probe)
            x = self.forward_head(features)
            return x

class MaskedShuffledVisionTransformer(ShuffledVisionTransformer):
    def __init__(self, *args, **kwargs):
        super(MaskedShuffledVisionTransformer, self).__init__(*args, **kwargs)
        self.mask_token = nn.Parameter(torch.zeros(1, 1, self.embed_dim) * 0.02)
        trunc_normal_(self.mask_token, std=.02)

    def generate_masks(self, mask_rate=0.75):
        nmasks = int(self.patch_embed.num_patches * mask_rate)
        shuffled_indices = torch.randperm(self.patch_embed.num_patches) + self.num_prefix_tokens
        visible_indices, _ = shuffled_indices[:self.patch_embed.num_patches - nmasks].sort()
        return visible_indices

    def mask_embed(self, embed, visible_indices):
        nmasks = self.patch_embed.num_patches - len(visible_indices)
        mask_tokens = self.mask_token.expand(embed.size(0), nmasks, -1)
        masked_features = torch.cat([embed[:, visible_indices, :], mask_tokens], dim=1)
        return masked_features

    def forward_features(self, x, pos_embed=None, visible_indices=None, probe=False):
        patch_embed = self.patch_embed(x)
        x = self._pos_embed(patch_embed, pos_embed)
        x = self.mask_embed(x, visible_indices)
        if self.grad_checkpointing and not torch.jit.is_scripting():
            x = checkpoint_seq(self.blocks, x)
        else:
            x = self.blocks(x)
        x = self.norm(x)
        if probe:
            return x, patch_embed.detach().clone()
        else:
            return x

    def forward(self, x, pos_embed=None, visible_indices=None, probe=False):
        assert pos_embed is not None
        assert visible_indices is not None
        if probe:
            features, patch_embed = self.forward_features(x, pos_embed, visible_indices, probe)
            x = self.forward_head(features)
            return x, features.detach().clone(), patch_embed
        else:
            features = self.forward_features(x, pos_embed, visible_indices, probe)
            x = self.forward_head(features)
            return x

class SimCLRPosRecon(SimCLRBase):
    def __init__(
            self,
            vit: MaskedShuffledVisionTransformer,
            hidden_dim: int = 2048,
            probe: bool = False,
            *args, **kwargs
    ):
        super(SimCLRPosRecon, self).__init__(vit, hidden_dim, *args, **kwargs)
        self.hidden_dim = hidden_dim
        self.probe = probe

    def forward(self, x, pos_embed=None, visible_indices=None):
        if self.probe:
            output, features, patch_embed = self.backbone(x, pos_embed, visible_indices, True)
        else:
            output = self.backbone(x, pos_embed, visible_indices, False)
        h = output[:, :self.hidden_dim]
        flatten_pos_embed = output[:, self.hidden_dim:]
        if self.pretrain:
            z = self.projector(h)
            if self.probe:
                return z, flatten_pos_embed, h.detach().clone(), features, patch_embed
            else:
                return z, flatten_pos_embed
        else:
            return h

def simclr_pos_recon_vit(vit_config: dict, *args, **kwargs):
    vit = MaskedShuffledVisionTransformer(**vit_config)
    return SimCLRPosRecon(vit, *args, **kwargs)


#!/usr/bin/python3

import cv2

from picamera2 import Picamera2

# Grab images as numpy arrays and leave everything else to OpenCV.

face_detector = cv2.CascadeClassifier(cv2.data.haarcascades +
        "haarcascade_frontalface_default.xml")
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades +
        "haarcascade_eye.xml"
    )
cv2.startWindowThread()

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"format": 'RGB888', "size": (720, 480)}))
picam2.start()

def face_detect():
    window_title = "Face Detect"

    try:
        cv2.namedWindow(window_title, cv2.WINDOW_AUTOSIZE)
        while True:
            im = picam2.capture_array()
            im = cv2.flip(im, 1)

            grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
            faces = face_detector.detectMultiScale(grey, 1.3, 5)

            for (x, y, w, h) in faces:
                cv2.rectangle(im, (x, y), (x + w, y + h), (250, 0, 0), 2)
                roi_gray = grey[y : y + h, x : x + w]
                roi_color = im[y : y + h, x : x + w]
                eyes = eye_cascade.detectMultiScale(roi_gray)
                for (ex, ey, ew, eh) in eyes:
                    cv2.rectangle(
                        roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2
                    )

            if cv2.getWindowProperty(window_title, cv2.WND_PROP_AUTOSIZE) >= 0:
                cv2.imshow(window_title, im)
            else:
                break
            keyCode = cv2.waitKey(10) & 0xFF
            # Stop the program on the ESC key or 'q'
            if keyCode == 27 or keyCode == ord('q'):
                break
    finally:
        cv2.destroyAllWindows()

if __name__ == "__main__":
    face_detect()


import sys
import pymongo
import urllib.request
import json
import time
from datetime import datetime
from bs4 import BeautifulSoup # To get everything
from pymongo import MongoClient

#connect to MongoDB
client = MongoClient()
db = client.Stocks
articles = db.Articles

def main(arg1):
	#Query site for HTML
	ticker = arg1
	sourceSite = 'CNN'
	url = 'http://money.cnn.com/quote/quote.html?symb=' + ticker
	#print(url)
	response = urllib.request.urlopen(url)

	html = ''
	for line in response.fp:
		html += line.decode('utf-8')
	#Parse and store Article information from Yahoo
	htmlArticles = []
	soup = BeautifulSoup(html)
	ul = soup.find('table', { 'class' : 'wsod_newsTable'})
	if(ul is not None):
		for q in ul.find_all('td'): #All articles for a day
			#print("q\t",q)
			if(hasattr(q, 'a') and q.a is not None):
				title = q.a.string
				link = q.a['href']
				citeFullForm = q.div.text
				cite = citeFullForm[citeFullForm.rindex('/')+2:]
				date =  citeFullForm[:citeFullForm.rindex('/')-1]
				article = [title, link, cite, date]
				htmlArticles.append(article)

	#Setup for storage in Mongodb
	for article in htmlArticles:
		jsonArticle = {}
		jsonArticle['ticker'] = ticker
		jsonArticle['title'] = article[0]
		jsonArticle['url'] = article[1]
		jsonArticle['cite'] = article[2]
		jsonArticle['date'] = article[3]
		jsonArticle['source'] = sourceSite
		jsonArticle['weight'] = "0"
		jsonArticle['createTimeInMillis'] = datetime.now().microsecond
		#print(jsonArticle)
		articles.update({ 'ticker': ticker, 'url' : jsonArticle['url'] }, jsonArticle , upsert=True) #Insert into Mongo

	#Document, in the form of a Python dictionary....it's just JSON...
	#insertValue = {          "url": "http://www.wsj.com/articles/u-s-chinese-universities-to-launch-technology-design-program-1434657616?ru=yahoo?mod=yahoo_itp",
							  #"title": "U.S., Chinese Universities to Launch Technology, Design Program",
							  #"date": "June 18, 2015 4:00 p.m. ET",
							  #"cite": "",
							  #"weight": "1"
							  #"id": "0"
							  #ticker: ""
							  #"last_updated": datetime.datetime.utcnow()}

	#print(articles.find_one({'ticker': ticker}))


import click

FILE = "d3/d3_input.txt"

def _get_file():
    with open(FILE, 'r') as fh:
        contents = fh.readlines()
    return contents

def _convert_letter(letter):
    if letter.islower():
        return ord(letter) - 96
    else:
        return ord(letter) - 38

@click.command("d3p1")
@click.pass_context
def p1(ctx):
    contents = _get_file()

    total = 0

    for item in contents:
        item = item.strip()
        half_len = len(item) // 2
        p1 = item[:half_len]
        p2 = item[half_len:]

        common = None

        for letter in p1:
            if letter in p2:
                common = letter
                break

        total += _convert_letter(common)

    print(total)

@click.command("d3p2")
@click.pass_context
def p2(ctx):
    contents = _get_file()
    len_contents = len(contents)

    total = 0
    ind = 0

    while ind < len_contents:
        item0 = contents[ind]
        item1 = contents[ind+1]
        item2 = contents[ind+2]

        common = None

        for letter in item0:
            if letter in item1 and letter in item2:
                common = letter
                break

        total += _convert_letter(common)
        ind += 3

    print(total)


#!/usr/bin/env python2
"""
Defines alpha 1.0
"""

from .abstract_alpha import AbstractAlpha
from Alfarvis.parsers.parser_class import AlfaDataParser
from Alfarvis.data_handlers.read_database import ReadDatabase
from pathlib import Path
from Alfarvis import package_directory
from Alfarvis.basic_definitions import DataObject, DataType
import os

def add_basic_database(history):
    data_base_path = os.path.join(str(Path.home()),
                                  'AlfaDatabase/file_database.csv')
    if not os.path.isfile(data_base_path):
        data_base_path = os.path.join(package_directory,
                'resources/file_database.csv')
    if os.path.isfile(data_base_path):
        reader = ReadDatabase()
        data_base_object = DataObject(data_base_path,
                                      ['startup', 'database'])
        history.add(DataType.data_base, data_base_object.keyword_list,
                    data_base_object)
        results = reader.read(data_base_object.data,
                              data_base_object.keyword_list)
        if type(results) == list:
            for result in results:
                history.add(result.data_type, result.keyword_list,
                            result.data, name=result.name)
            print("Loaded basic file database")
        else:
            print("Failed to load file database")

class Alphav1_1(AbstractAlpha):
    """
    Simple alpha that uses basic parser
    """
    __version__ = 1.1

    @classmethod
    def _get_version(self):
        """
        Return current version
        """
        return self.__version__

    def __init__(self):
        self.parser = AlfaDataParser()
        add_basic_database(self.parser.history)
        self.history = self.parser.history

    def __call__(self, text):
        """
        Parse a provided text and return the  output in the form text
        Parameters:
            text - 'String input from user'
        Returns:
            output from Alpha
        """
        self.parser.parse(text)
        return ''


"""
Compute sampling
"""

from fennel.core.program import Program

from fennel.tasks.start import StartTask
from fennel.tasks.proxy import ProxyTask
from fennel.tasks.compute import ComputeTask

from fennel.core.machine import Machine
from fennel.computes.gamma import NoisyGammaModel
from fennel.networks.lbmodel import LBModel

import statistics

def sample():
    program = Program()

    program.add_node(StartTask('c0', 0))

    for idx in range(1, 10):
        program.add_node(ComputeTask(f'c{idx}', 0, size=10000))
        program.add_edge(f'c{idx-1}', f'c{idx}')

    # bytes 10000, 10kb

    program.add_node(ProxyTask('x', 0))
    program.add_edge('c9', 'x')

    machine = Machine(1, 1, NoisyGammaModel(0.1, 0.05), None)
    machine.run(program)

    return machine.maximum_time

def main() -> None:
    """
    Main function.
    """

    samples = []

    for _ in range(1000):
        samples.append(sample())

    assert samples

    m = statistics.mean(samples)
    assert m != 0.0

    print(m, statistics.median(samples), min(samples), max(samples))
    print((min(samples) - m) / m)
    print((max(samples) - m) / m)

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('my_game', '0004_basicgenerator_fuel'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='fuelpattern',
            name='fuel_id',
        ),
    ]


from django.urls import URLPattern, path
from . import views

app_name = 'sneakers_app'
urlpatterns = [
    path('', views.index, name='index'),
    path('login/', views.user_login, name='user_login'),
    path('register/', views.register, name='register'),
    path('profile/', views.profile, name='profile'),
    path('logout/', views.user_logout, name='logout'),
    path('favorite/', views.favorite, name='favorite'),
    path('favorite/<int:id>', views.favorite_detail,
         name='favorite_page_detail'),
]


from PyQt5.QtCore import pyqtSignal, QMimeData, Qt
from PyQt5.QtGui import QPalette, QPixmap
from PyQt5.QtWidgets import (QAbstractItemView, QApplication, QDialogButtonBox,
        QFrame, QLabel, QPushButton, QTableWidget, QTableWidgetItem,
        QVBoxLayout, QWidget)

class DropArea(QLabel):

    changed = pyqtSignal(QMimeData)

    def __init__(self, parent = None):
        super(DropArea, self).__init__(parent)

        self.setMinimumSize(200, 200)
        self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel)
        self.setAlignment(Qt.AlignCenter)
        self.setAcceptDrops(True)
        self.setAutoFillBackground(True)
        self.clear()

    def dragEnterEvent(self, event):
        self.setText("<drop content>")
        self.setBackgroundRole(QPalette.Highlight)
        event.acceptProposedAction()
        self.changed.emit(event.mimeData())

    def dragMoveEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        mimeData = event.mimeData()
        if mimeData.hasImage():
            self.setPixmap(QPixmap(mimeData.imageData()))
        elif mimeData.hasHtml():
            self.setText(mimeData.html())
            self.setTextFormat(Qt.RichText)
        elif mimeData.hasText():
            self.setText(mimeData.text())
            self.setTextFormat(Qt.PlainText)
        elif mimeData.hasUrls():
            self.setText("\n".join([url.path() for url in mimeData.urls()]))
        else:
            self.setText("Cannot display data")

        self.setBackgroundRole(QPalette.Dark)
        event.acceptProposedAction()

    def dragLeaveEvent(self, event):
        self.clear()
        event.accept()

    def clear(self):
        self.setText("<drop content>")
        self.setBackgroundRole(QPalette.Dark)
        self.changed.emit(None)

class DropSiteWindow(QWidget):

    def __init__(self):
        super(DropSiteWindow, self).__init__()

        self.abstractLabel = QLabel(
                "This example accepts drags from other applications and "
                "displays the MIME types provided by the drag object.")
        self.abstractLabel.setWordWrap(True)
        self.abstractLabel.adjustSize()

        self.dropArea = DropArea()
        self.dropArea.changed.connect(self.updateFormatsTable)

        self.formatsTable = QTableWidget()
        self.formatsTable.setColumnCount(2)
        self.formatsTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.formatsTable.setHorizontalHeaderLabels(["Format", "Content"])
        self.formatsTable.horizontalHeader().setStretchLastSection(True)

        self.clearButton = QPushButton("Clear")
        self.quitButton = QPushButton("Quit")

        self.buttonBox = QDialogButtonBox()
        self.buttonBox.addButton(self.clearButton, QDialogButtonBox.ActionRole)
        self.buttonBox.addButton(self.quitButton, QDialogButtonBox.RejectRole)

        self.quitButton.pressed.connect(self.close)
        self.clearButton.pressed.connect(self.dropArea.clear)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.abstractLabel)
        mainLayout.addWidget(self.dropArea)
        mainLayout.addWidget(self.formatsTable)
        mainLayout.addWidget(self.buttonBox)
        self.setLayout(mainLayout)

        self.setWindowTitle("Drop Site")
        self.setMinimumSize(350, 500)

    def updateFormatsTable(self, mimeData=None):
        self.formatsTable.setRowCount(0)

        if mimeData is None:
            return

        for format in mimeData.formats():
            formatItem = QTableWidgetItem(format)
            formatItem.setFlags(Qt.ItemIsEnabled)
            formatItem.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)

            if format == 'text/plain':
                text = mimeData.text().strip()
            elif format == 'text/html':
                text = mimeData.html().strip()
            elif format == 'text/uri-list':
                text = " ".join([url.toString() for url in mimeData.urls()])
            else:
                text = " ".join(["%02X" % ord(datum) for datum in mimeData.data(format)])

            row = self.formatsTable.rowCount()
            self.formatsTable.insertRow(row)
            self.formatsTable.setItem(row, 0, QTableWidgetItem(format))
            self.formatsTable.setItem(row, 1, QTableWidgetItem(text))

        self.formatsTable.resizeColumnToContents(0)

if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = DropSiteWindow()
    window.show()
    sys.exit(app.exec_())


import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import plot_confusion_matrix
import json

from sklearn.feature_extraction.text import TfidfVectorizer
with open("/Users/hugo/Cincinnati/ADV_ENGR/my_env/Project_ADV_ENGR/json/all.json", "r") as read_file:
    data = json.load(read_file)

import nltk
from nltk.corpus import stopwords

Review_label = []

for i in range(len(data)):
    a = data[i]["comment"]
    b = data[i]["label"]
    Review_label.append([a,b])

df = pd.DataFrame(Review_label)
df.columns = ["review","label"]

for i in range(len(df)):
    if df["label"][i] == "Bug":
        df["label"][i] = 1
    elif df["label"][i] == "Feature":
        df["label"][i] = 2
    elif df["label"][i] == "Rating":
        df["label"][i] = 3
    elif df["label"][i] == "UserExperience":
        df["label"][i] = 4

X_train, X_test, Y_train, Y_test = train_test_split(df['review'],
                                                    df['label'].array,
                                                    test_size=0.2,
                                                    stratify=df['label'])

print('Size of Training Data ', X_train.shape[0])
print('Size of Test Data ', X_test.shape[0])

Y_train = Y_train.astype('int')
Y_test = Y_test.astype('int')

countv = CountVectorizer(min_df = 1, ngram_range=(1,5), stop_words="english")
X_train_tf = countv.fit_transform(X_train)

model1 = MultinomialNB()
model1.fit(X_train_tf, Y_train)

X_test_tf = countv.transform(X_test)
Y_pred_NB = model1.predict(X_test_tf)
print ('Accuracy Score MultinomialNB  mind_df = 1, ngram_range=(1,1) : - ', accuracy_score(Y_test, Y_pred_NB)*100)

plot_confusion_matrix(model1,X_test_tf,
                      Y_test, values_format='d',
                      cmap=plt.cm.Blues)
plt.title("Confusion matrix for MultinomialNB, mind_df = 1, ngram_range=(1,5)")
plt.show()

df_t = pd.read_csv("/Users/hugo/Cincinnati/ADV_ENGR/my_env/Project_ADV_ENGR/Database/reviews.csv",sep =";")
X_testing = df["review"]

X_l =  countv.transform(X_testing)

Y_l = model1.predict(X_l)

Bug = []
Feature = []
Rating = []
UserExperience = []
for i in range(len(X_test)):
    if Y_l[i] == 1:
        Bug.append(X_testing.iloc[i])
    elif Y_l[i] == 2:
        Feature.append(X_testing.iloc[i])
    elif Y_l[i] == 3:
        Rating.append(X_testing.iloc[i])
    elif Y_l[i] == 4:
        UserExperience.append(X_testing.iloc[i])

bug_keyword = {}
feature_keyword = {}
rating_keyword = {}
userexperience_keyword = {}

stops = set(stopwords.words('english'))
stops.add('I')
stops.add('')
stops.add('The')
stops.add('This')

for i in Bug:
    words = i.split(' ')
    for j in words:
        if j not in stops:
            if (j not in bug_keyword):
                bug_keyword[j] = 1
            else:
                bug_keyword[j]+=1

for i in Feature:
    words = i.split(' ')
    for j in words:
        if j not in stops:
            if (j not in feature_keyword):
                feature_keyword[j] = 1
            else:
                feature_keyword[j]+=1

for i in Rating:
    words = i.split(' ')
    for j in words:
        if j not in stops:
            if (j not in rating_keyword):
                rating_keyword[j] = 1
            else:
                rating_keyword[j]+=1

for i in UserExperience:
    words = i.split(' ')
    for j in words:
        if j not in stops:
            if (j not in userexperience_keyword):
                userexperience_keyword[j] = 1
            else:
                userexperience_keyword[j]+=1

Bug = sorted(bug_keyword.items(), key=lambda t: t[1])
Feature = sorted(feature_keyword.items(), key=lambda t: t[1])
Rating = sorted(rating_keyword.items(), key=lambda t: t[1])
UserExperience = sorted(userexperience_keyword.items(), key=lambda t: t[1])

""" j = 20
print("Top " + str(j)+ " keywords for Bugs Reviews : ")
for i in range(1,j+1):
    print(Bug[len(Bug)-i][0])

print()
print("Top " + str(j)+ " keywords for Feature Reviews : ")
for i in range(1,j+1):
    print(Feature[len(Feature)-i][0])
print()
print("Top " + str(j)+ " keywords for Rating Reviews : ")
for i in range(1,j+1):
    print(Rating[len(Rating)-i][0])
print()
print("Top " + str(j)+ " keywords for UserExperience Reviews : ")
for i in range(1,j+1):
    print(UserExperience[len(UserExperience)-i][0]) """

from wordcloud import WordCloud

def wordcloud_topics(model, features, no_top_words=40):
    for topic, words in enumerate(model.components_):
        size = {}
        largest = words.argsort()[::-1] # invert sort order
        for i in range(0, no_top_words):
            size[features[largest[i]]] = abs(words[largest[i]])
        wc = WordCloud(background_color="white", max_words=100, width=960, height=540)
        wc.generate_from_frequencies(size)
        plt.imshow(wc, interpolation='bilinear')
        plt.axis("off")
        plt.show()

wc_bug = WordCloud(background_color="white", max_words=100, width=960, height=540)
wc_bug.generate_from_frequencies(bug_keyword)

plt.imshow(wc_bug, interpolation='bilinear')
plt.axis("off")
plt.title('Bug keywords')
plt.show()

wc_feature = WordCloud(background_color="white", max_words=100, width=960, height=540)
wc_feature.generate_from_frequencies(feature_keyword)

plt.imshow(wc_feature, interpolation='bilinear')
plt.axis("off")
plt.title('Feature keywords')
plt.show()

wc_rating = WordCloud(background_color="white", max_words=100, width=960, height=540)
wc_rating.generate_from_frequencies(rating_keyword)

plt.imshow(wc_rating, interpolation='bilinear')
plt.axis("off")
plt.title('Rating keywords')
plt.show()

wc_userexperience = WordCloud(background_color="white", max_words=100, width=960, height=540)
wc_userexperience.generate_from_frequencies(userexperience_keyword)

plt.imshow(wc_userexperience, interpolation='bilinear')
plt.axis("off")
plt.title('User Experience keywords')
plt.show()


# 레벨2     Summer/Winter Coding(~2018)     방문 길이
# 19분 40초 소요

from collections import defaultdict

def solution(dirs):
    y, x = 0, 0
    cnt = 0
    check = defaultdict(lambda: defaultdict(lambda: 0))
    for i in dirs:
        if i == "U":
            dy, dx = y - 1, x
        elif i == "D":
            dy, dx = y + 1, x
        elif i == "L":
            dy, dx = y, x - 1
        elif i == "R":
            dy, dx = y, x + 1

        if -5 <= dy <= 5 and -5 <= dx <= 5:
            if check[(y, x)][(dy, dx)] == 0:
                cnt += 1
                check[(y, x)][(dy, dx)] = 1
                check[(dy, dx)][(y, x)] = 1
            y, x = dy, dx
    return cnt

if __name__ == "__main__":
    print(solution("UD"))

모든 문제/SummerWinter Coding(~2018)/방문 길이.py


import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np

from lxml import html
import requests
import datetime

days = 150
deathrate = .0175

def func(x, a, b, c):
     #return 1 / (1 + np.exp(-k*(x-x0)))

	 #return np.array(a) * np.exp(np.array(b) * x) + np.array(c)
	 return a * x**2 + b * x + c

page = requests.get('https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/total-cases-onset.json')
tree = html.fromstring(page.content)
data = page.json()

total_cases_web = tree.xpath("//*[@id='cdc-chart-1-data']")

#total_cases_web[0] = total_cases_web[0].replace('Total cases: ', '')
#total_cases_web[0] = total_cases_web[0].replace(',', '')

#for range(1, len(data['data']['columns'][1])

#f = open("cases.data", "r")
#new = f.readline()
#newcases = [int(x) for x in new.split(",")]
#total = f.readline()
#totalcases = [int(x) for x in total.split(",")]
#date = f.readline()
#year, month, day = [int(x) for x in date.split(" ")]
#f.close()

#print(newcases)

totalcases = data['data']['columns'][1][38:]

for i in range(0, len(totalcases)):
  totalcases[i] = int(totalcases[i])

print(totalcases)

new = [1]
for i in range(1, len(totalcases)):
  case = totalcases[i] - totalcases[i-1]
  if case == 0:
    totalcases = totalcases[:-1]
    continue
  new.append(case)

newcases = new

print(newcases)

ydata = np.array(newcases)
ydataTotal = np.array(totalcases)

print(len(totalcases))
print(len(ydataTotal))

#lastdate = datetime.datetime(year, month, day).date()

#if total_cases > totalcases[-1]:
#  if datetime.datetime.now().date() > lastdate:
#    ydataTotal = np.append(ydataTotal, total_cases)
#    ydata = np.append(ydata, total_cases - totalcases[-1])
#  else:
#    totalcases[-1] = total_cases
#    newcases[-1] = totalcases[-1] - totalcases[-2]
#    ydata = np.array(newcases)
#    ydataTotal = np.array(totalcases)

#f = open("cases.data", "w")
#total_string = np.array2string(ydata, separator=' ', max_line_width=-1)
#for x in ydata:
#  f.write(str(x))
#  if x != ydata[len(ydata) - 1]:
#    f.write(",")

#f.write("\n")

#for x in ydataTotal:
#  f.write(str(x))
#  if x != ydataTotal[len(ydataTotal) - 1]:
#    f.write(",")

#f.write("\n")

#currentdate = datetime.datetime.now()
#f.write(currentdate.strftime("%Y %m %d"))

#f.close()

#if datetime.datetime.now().date() > lastdate:
#  if total_cases > totalcases[-1]:
#    ydataTotal = np.append(ydataTotal, total_cases)
#    ydata = np.append(ydata, total_cases - totalcases[-1])
#elif total_cases > totalcases[-1]:
#  totalcases[-1] = total_cases
#  newcases[-1] = total_cases[-1] - total_cases[-2]
#  ydata = np.array(newcases)
#  ydataTotal = np.array(totalcases)

xpredict = np.array(list(range(0,days)))
#ydata = np.array([8, 6, 23, 19, 31, 68, 40, 149, 117, 250, 270, 328, 388, 529, 599, 802, 959, 1511, 2884, 4978, 4862, 7347, 7285, 10075, 10008, 14693, 16437, 17620, 20395, 18207, 22291])
#ydataTotal = np.array([24, 30, 53, 72, 103, 171, 211, 360, 477, 727, 997, 1325, 1713, 2242, 2841, 3643, 4602, 6113, 8997, 13975, 18837, 26184, 33469, 43544, 53552, 68245, 84682, 102302, 122697, 140904, 163195])
ydatalog = np.log(ydata)
xdataTotal = np.array(list(range(0,len(ydataTotal))))
xdata = np.array(list(range(0,len(ydata))))
params, pcov = curve_fit(func, xdata, ydatalog)
print(params)
predictfit = func(xpredict, *params)
predictfithigh = func(xpredict, *(1.1*params))
predictfitlow = func(xpredict, *(0.9*params))
fit = func(xdata, *params)
fitlog = np.log(fit)

#plt.plot(xpredict, predictfithigh, 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(params))
#plt.plot(xpredict, predictfitlow, 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(params))
#plt.plot(xdata, fit, 'r-', label='fit: x0=%5.3f, k=%5.3f' % tuple(params))
print(predictfit)
ydatapredict = np.exp(predictfit)
# ydatapredicthigh = np.exp(predictfithigh)
# ydatapredictlow = np.exp(predictfitlow)
print(ydatapredict)
# logtotalCases = np.zeros(days)
totalCases = np.zeros(days)
# totalCaseshigh = np.zeros(days)
# totalCaseslow = np.zeros(days)
for i in range(0, days):
	totalCases[i] = totalCases[i-1] + ydatapredict[i]
	# totalCaseshigh[i] = totalCases[i-1] + ydatapredicthigh[i]
	# totalCaseslow[i] = totalCases[i-1] + ydatapredictlow[i]

print(totalCases)
max = np.amax(predictfit)
print(max)
print(np.argmax(predictfit))
print(np.argmax(predictfit) - len(xdata))
print(np.amax(totalCases))
print(deathrate * np.amax(totalCases))
#plotting
plt.figure()
#total
plt.subplot(211)
plt.plot(xpredict, totalCases)
plt.plot(xdataTotal, ydataTotal)
plt.xlabel('')
plt.ylabel('Total Infected')
#new
plt.subplot(212)
plt.plot(xpredict, predictfit, 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(params))
plt.plot(xdata, ydatalog, 'b-', label='data')
plt.xlabel('day')
plt.ylabel('ln(New Cases)')
plt.legend()

plt.show()

# plt.plot(xpredict, totalCaseshigh)
# plt.plot(xpredict, totalCaseslow)


from flask import Flask

from opencensus.ext.flask.flask_middleware import FlaskMiddleware

app = Flask(__name__)
middleware = FlaskMiddleware(app)

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    import logging
    logger = logging.getLogger('werkzeug')
    logger.setLevel(logging.ERROR)
    app.run(host='localhost', port=8080, threaded=True)


from binance.client import Client
import config
client = Client(config.api_key, config.api_secret)
print("logged in")

info = client.get_account()

#for i in info:
 #   print(i)

bal= info['balances']
for b in bal:
    if float(b['free']) > 0:
        print(b)


import gtk
import os
import cairo

from itertools import izip
from urllib import unquote
from gettext import ngettext, gettext as _
from xml.sax.saxutils import escape
from decimal import Decimal

from loggable import doLog, ERROR

# ---------------------- Constants -------------------------------------------#

##
# UI pixels information constants
##
LAYER_HEIGHT_EXPANDED = 50
LAYER_HEIGHT_COLLAPSED = 15
LAYER_SPACING = 15
TRACK_SPACING = 8

SPACING = 6
PADDING = 6

##
#   Drag'n drop constants
##
TYPE_TEXT_PLAIN = 24
TYPE_URI_LIST = 25

# FileSourceFactory (or subclasses)
TYPE_PITIVI_FILESOURCE = 26

# What objects to these correspond to ???
TYPE_PITIVI_EFFECT = 27
TYPE_PITIVI_AUDIO_EFFECT = 28
TYPE_PITIVI_VIDEO_EFFECT = 29
TYPE_PITIVI_AUDIO_TRANSITION = 30
TYPE_PITIVI_VIDEO_TRANSITION = 31

FILE_TUPLE = ("text/plain", 0, TYPE_TEXT_PLAIN)
URI_TUPLE = ("text/uri-list", 0, TYPE_URI_LIST)
FILESOURCE_TUPLE = ("pitivi/file-source", 0, TYPE_PITIVI_FILESOURCE)
EFFECT_TUPLE = ("pitivi/effect", 0, TYPE_PITIVI_EFFECT)
AUDIO_EFFECT_TUPLE = ("pitivi/audio-effect", 0, TYPE_PITIVI_AUDIO_EFFECT)
VIDEO_EFFECT_TUPLE = ("pitivi/video-effect", 0, TYPE_PITIVI_VIDEO_EFFECT)
AUDIO_TRANSITION_TUPLE = ("pitivi/audio-transition", 0, TYPE_PITIVI_AUDIO_TRANSITION)
VIDEO_TRANSITION_TUPLE = ("pitivi/video-transition", 0, TYPE_PITIVI_VIDEO_TRANSITION)

# ---------------------- ARGB color helper-------------------------------------#
def pack_color_32(red, green, blue, alpha=0xFFFF):
    """Packs the specified 16bit color values in a 32bit RGBA value."""
    red = red >> 8
    green = green >> 8
    blue = blue >> 8
    alpha = alpha >> 8
    return (red << 24 | green << 16 | blue << 8 | alpha)

def pack_color_64(red, green, blue, alpha=0xFFFF):
    """Packs the specified 16bit color values in a 64bit RGBA value."""
    return (red << 48 | green << 32 | blue << 16 | alpha)

def unpack_color(value):
    """Unpacks the specified RGBA value into four 16bit color values.

    Args:
      value: A 32bit or 64bit RGBA value.
    """
    if not (value >> 32):
        return unpack_color_32(value)
    else:
        return unpack_color_64(value)

def unpack_color_32(value):
    """Unpacks the specified 32bit RGBA value into four 16bit color values."""
    red = (value >> 24) << 8
    green = ((value >> 16) & 0xFF) << 8
    blue = ((value >> 8) & 0xFF) << 8
    alpha = (value & 0xFF) << 8
    return red, green, blue, alpha

def unpack_color_64(value):
    """Unpacks the specified 64bit RGBA value into four 16bit color values."""
    red = (value >> 48) & 0xFFFF
    green = (value >> 32) & 0xFFFF
    blue = (value >> 16) & 0xFFFF
    alpha = value & 0xFFFF
    return red, green, blue, alpha

def unpack_cairo_pattern(value):
    """Transforms the specified RGBA value into a SolidPattern object."""
    red, green, blue, alpha = unpack_color(value)
    return cairo.SolidPattern(
        red / 65535.0,
        green / 65535.0,
        blue / 65535.0,
        alpha / 65535.0)

def unpack_cairo_gradient(value):
    """Creates a LinearGradient object out of the specified RGBA value."""
    red, green, blue, alpha = unpack_color(value)
    gradient = cairo.LinearGradient(0, 0, 0, 50)
    gradient.add_color_stop_rgba(
        1.0,
        red / 65535.0,
        green / 65535.0,
        blue / 65535.0,
        alpha / 65535.0)
    gradient.add_color_stop_rgba(
        0,
        (red / 65535.0) * 1.5,
        (green / 65535.0) * 1.5,
        (blue / 65535.0) * 1.5,
        alpha / 65535.0)
    return gradient

def hex_to_rgb(value):
    return tuple(float(int(value[i:i + 2], 16)) / 255.0 for i in range(0, 6, 2))

def info_name(info):
    """Return a human-readable filename (without the path and quoting)."""
    return escape(unquote(os.path.basename(info.get_uri())))

def beautify_time_delta(seconds):
    """
    Converts the given time in seconds to a human-readable estimate.

    This is intended for "Unsaved changes" and "Backup file found" dialogs.
    """
    mins = seconds / 60
    sec = int(seconds % 60)
    hours = mins / 60
    mins = int(mins % 60)
    days = int(hours / 24)
    hours = int(hours % 24)

    parts = []
    if days > 0:
        parts.append(ngettext("%d day", "%d days", days) % days)
    if hours > 0:
        parts.append(ngettext("%d hour", "%d hours", hours) % hours)

    if days == 0 and mins > 0:
        parts.append(ngettext("%d minute", "%d minutes", mins) % mins)

    if hours == 0 and mins < 2 and sec:
        parts.append(ngettext("%d second", "%d seconds", sec) % sec)

    return ", ".join(parts)

#--------------------- UI drawing helper -------------------------------------#
# from http://cairographics.org/cookbook/roundedrectangles/
def roundedrec(context, x, y, w, h, r=10):
    "Draw a rounded rectangle"
    #   A****BQ
    #  H      C
    #  *      *
    #  G      D
    #   F****E

    context.move_to(x + r, y)      # Move to A
    context.line_to(x + w - r, y)  # Straight line to B

    # Curve to C, Control points are both at Q
    context.curve_to(x + w, y, x + w, y, x + w, y + r)
    context.line_to(x + w, y + h - r)                               # Move to D
    context.curve_to(x + w, y + h, x + w, y + h, x + w - r, y + h)  # Curve to E
    context.line_to(x + r, y + h)                                   # Line to F
    context.curve_to(x, y + h, x, y + h, x, y + h - r)              # Curve to G
    context.line_to(x, y + r)                                       # Line to H
    context.curve_to(x, y, x, y, x + r, y)                          # Curve to A
    return

#--------------------- Gtk widget helpers ------------------------------------#
def model(columns, data):
    ret = gtk.ListStore(*columns)
    for datum in data:
        ret.append(datum)
    return ret

def set_combo_value(combo, value, default_index=-1):
    model = combo.props.model
    for i, row in enumerate(model):
        if row[1] == value:
            combo.set_active(i)
            return
    combo.set_active(default_index)

def get_combo_value(combo):
    active = combo.get_active()
    return combo.props.model[active][1]

# ---------------------- Classes ---------------------------------------------#
class Point(tuple):

    def __new__(cls, x, y):
        return tuple.__new__(cls, (x, y))

    def __pow__(self, scalar):
        """Returns the scalar multiple self, scalar"""
        return Point(self[0] * scalar, self[1] * scalar)

    def __rpow__(self, scalar):
        """Returns the scalar multiple of self, scalar"""
        return self ** scalar

    def __mul__(self, p2):
        return Point(*(a * b for a, b in izip(self, p2)))

    def __div__(self, other):
        return Point(*(a / b for a, b in izip(self, p2)))

    def __floordiv__(self, scalar):
        """Returns the scalar division of self and scalar"""
        return Point(self[0] / scalar, self[1] / scalar)

    def __add__(self, p2):
        """Returns the 2d vector sum self + p2"""
        return Point(*(a + b for a, b in izip(self, p2)))

    def __sub__(self, p2):
        """Returns the 2-dvector difference self - p2"""
        return Point(*(a - b for a, b in izip(self, p2)))

    def __abs__(self):
        return Point(*(abs(a) for a in self))

    @classmethod
    def from_item_bounds(self, item):
        bounds = item.get_bounds()
        return Point(bounds.x1, bounds.y1), Point(bounds.x2, bounds.y2)

    @classmethod
    def from_widget_bounds(self, widget):
        x1, y1, x2, y2 = widget.get_bounds()
        return Point(x1, y1), Point(x2, y2)


""""
Pattern Recongition Courese
Homework 1

Requirment:
    1.Use MAE and MSE as the loss function to do linear regression.
    2.Calculate loss and weights.
    3.Plot the learning curve.
    4.Use numpy only and follow PEP8 coding style
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def model(x, b0, b1):
    return x * b1 + b0

def MAE(pre, y):
    return np.average(abs(pre - y))

def MSE(pre, y):
    return np.average((pre - y)**2)

def MSE_main(
        b0, b1, lr, batch_size, batch_num,
        converge_count, converge_thres,
        x_train, y_train):
    log = {'b0': [], 'b1': [], 'loss': []}
    count = 0

    while count < converge_count:  # loop until convergence

        # Predict and Criterion
        py = model(x_train, b0, b1)
        loss = MSE(py, y_train)
        if len(log['loss']) > 0:
            if abs(loss - log['loss'][-1]) < converge_thres:
                count += 1
            else:
                count = 0

        log['b0'].append(b0)
        log['b1'].append(b1)
        log['loss'].append(loss)

        # Gradient descent and learn
        batch = np.random.randint(batch_num)  # randomly pick a batch
        da, db = 0.0, 0.0  # a:b1, b:b0
        for k in range(batch*batch_size, (batch+1)*batch_size):
            da += (model(x_train[k], b0, b1) - y_train[k]) * x_train[k]
            db += model(x_train[k], b0, b1) - y_train[k]
        da = da/batch_size
        db = db/batch_size

        b0 = b0 - lr * db
        b1 = b1 - lr * da

    return log, b0, b1

def MAE_main(
        b0, b1, lr, batch_size, batch_num,
        converge_count, converge_thres,
        x_train, y_train):
    log = {'b0': [], 'b1': [], 'loss': []}
    count = 0

    while count < converge_count:  # loop until convergence

        # Predict and Criterion
        py = model(x_train, b0, b1)
        loss = MAE(py, y_train)
        if len(log['loss']) > 0:
            if abs(loss - log['loss'][-1]) < converge_thres:
                count += 1
            else:
                count = 0

        log['b0'].append(b0)
        log['b1'].append(b1)
        log['loss'].append(loss)

        # Gradient descent and learn
        batch = np.random.randint(batch_num)  # randomly pick a batch
        da, db = 0.0, 0.0  # a:b1, b:b0
        for k in range(batch*batch_size, (batch+1)*batch_size):
            if model(x_train[k], b0, b1) >= y_train[k]:
                da += x_train[k]
                db += 1
            else:
                da -= x_train[k]
                db -= 1
        da = da/batch_size
        db = db/batch_size

        b0 = b0 - lr * db
        b1 = b1 - lr * da

    return log, b0, b1

if __name__ == '__main__':
    # Load data
    train_df = pd.read_csv('train_data.csv')
    x_train, y_train = train_df['x_train'], train_df['y_train']

    # Train model
    lr = 1e-2
    batch_size = 50
    batch_num = len(x_train)//batch_size
    converge_count = 20
    converge_thres = 1e-5
    b0 = np.random.normal()
    b1 = np.random.normal()

    mse_log, mse_b0, mse_b1 = MSE_main(b0, b1, lr, batch_size, batch_num,
                                       converge_count, converge_thres,
                                       x_train, y_train)
    mae_log, mae_b0, mae_b1 = MAE_main(b0, b1, lr, batch_size, batch_num,
                                       converge_count, converge_thres,
                                       x_train, y_train)

    # Test model
    test_data = pd.read_csv("test_data.csv")
    x_test, y_test = test_data['x_test'], test_data['y_test']
    mse_y_pred = model(x_test, mse_b0, mse_b1)
    mae_y_pred = model(x_test, mae_b0, mae_b1)
    mse_loss = MSE(mse_y_pred, y_test)
    mae_loss = MAE(mae_y_pred, y_test)

    # Output result
    print("MSE (run %d times)" % (len(mse_log['loss'])))
    print("\tloss:", mse_loss)
    print("\tb0: %.10f, b1:%.10f" % (mse_b0, mse_b1))
    print("MAE (run %d times)" % (len(mae_log['loss'])))
    print("\tloss:", mae_loss)
    print("\tb0: %.10f, b1:%.10f" % (mae_b0, mae_b1))

    # Visualize
    fig = plt.figure()

    ax = fig.add_subplot(2, 1, 1)
    plt.xlabel('X')
    plt.ylabel('Y')
    ax.plot(x_test, y_test, '.k')
    ax.plot(x_test, mse_b1 * x_test + mse_b0, 'r', label='MSE line')
    ax.plot(x_test, mae_b1 * x_test + mae_b0, 'g', label='MAE line')
    plt.legend(loc='lower right')

    ax = fig.add_subplot(2, 1, 2)
    plt.xlabel('Iteration')
    plt.ylabel('Loss')
    ax.plot(mse_log['loss'], 'r', label='MSE loss')
    ax.plot(mae_log['loss'], 'g', label='MAE loss')
    plt.legend()


#!usr/bin/env python3
#-*- coding: utf-8 -*-
"""
'trainer.py' (relation_extractor/src/training)

Class for training relation extraction models

2019 Steve Neale <steveneale3000@gmail.com>

"""

import math

import numpy as np

import tensorflow as tf

from sklearn.metrics import f1_score

from src.training import Optimiser
from src.io.utils import create_directory

class Trainer():

    def __init__(self, epochs, batch_size=1):

        # Tensorflow objects (session, model and optimisation)
        self.session = None
        self.model = None
        self.model_name = None
        self.optimisation = None
        # Training data / parameters
        self.epochs = epochs
        self.batch_size = batch_size
        self.batches = None
        self.batch_count = 1
        # Test data
        self.test_data = None
        # Training values (loss / accuracy)
        self.training_loss = []
        self.training_accuracy = []
        self.test_loss = []
        self.test_accuracy = []
        # Output directories / saver
        self.output_directory = None
        self.checkpoint_directory = None
        self.saver = None
        # Metrics
        self.best_f1 = 0.0

    def train(self, model, train_data, test_data, name, embeddings=None):

        self.setup_directories_and_saver(name, train_data.vocab_processor)
        self.setup_train_and_test_data(train_data, test_data)
        self.setup_model_and_optimiser(model)
        self.initialise_tensorflow_session_and_variables(embeddings)
        self.train_model_on_batches_using_optimiser()
        self.session.close()

    def setup_directories_and_saver(self, name, vocab_processor):

        self.model_name = name
        self.output_directory = create_directory("output/{}".format(self.model_name))
        self.checkpoint_directory = create_directory("{}/checkpoints".format(self.output_directory))
        vocab_processor.save("{}/vocab".format(self.output_directory))
        self.saver = tf.train.Saver(tf.global_variables())

    def setup_train_and_test_data(self, train_data, test_data):

        self.batches = self.batch_iterator(train_data)
        self.test_data = test_data

    def setup_model_and_optimiser(self, model):

        self.model = model
        optimiser = Optimiser(algorithm="adadelta", learning_rate=1.0).optimiser
        gradients, variables = zip(*optimiser.compute_gradients(self.model.loss))
        gradients, _ = tf.clip_by_global_norm(gradients, 4.0)
        self.optimisation = optimiser.apply_gradients(zip(gradients, variables))

    def initialise_tensorflow_session_and_variables(self, embeddings=None):

        self.session = tf.Session()
        self.session.run(tf.global_variables_initializer())
        if type(embeddings) != None:
            self.session.run(self.model.embedding_matrix.assign(embeddings))

    def batch_iterator(self, train_data, shuffle=True):

        self.batch_count = math.ceil(train_data.x.shape[0] / self.batch_size)
        data = np.array(list(zip(train_data.x, train_data.y)))
        data_size = len(data)
        batches_per_epoch = math.ceil(data_size / self.batch_size)
        for epoch in range(self.epochs):
            if shuffle:
                shuffle_indices = np.random.permutation(np.arange(data_size))
                data = data[shuffle_indices]
            for batch_id in range(batches_per_epoch):
                start_index = batch_id * self.batch_size
                end_index = min((batch_id+1) * self.batch_size, data_size)
                yield data[start_index:end_index]

    def train_model_on_batches_using_optimiser(self):

        epoch_id, batch_id = 1, 0
        for batch in self.batches:
            x_batch, y_batch = zip(*batch)
            loss, accuracy = self.optimise_on_batch(x_batch, y_batch)
            if batch_id % int(self.batch_count / 10) == 0 and batch_id > 0:
                if batch_id % self.batch_count == 0 and batch_id > 0:
                    self.training_loss.append(loss)
                    self.training_accuracy.append(accuracy)
                    test_loss, test_accuracy, test_f1 = self.test_model()
                    print("Epoch {} of {} | Test loss: {:.2f} | Test accuracy: {:.2f} | Test F1: {}\n".format(epoch_id, self.epochs, test_loss, test_accuracy, test_f1))
                    epoch_id += 1
                    batch_id = 0
                else:
                    print("--- {}% of batches from epoch {} complete | Train loss: {:.2f} | Train accuracy: {:.2f}".format(int(((100 / self.batch_count) * batch_id)), epoch_id, loss, accuracy))
            batch_id += 1

    def optimise_on_batch(self, x_batch, y_batch):

        training_dict = { self.model.x_train: x_batch,
                          self.model.y_train: y_batch,
                          self.model.embedding_dropout_prob: 0.7,
                          self.model.cell_dropout_prob: 0.7,
                          self.model.dropout_prob: 0.5 }
        _, loss, accuracy = self.session.run([self.optimisation, self.model.loss, self.model.accuracy], feed_dict=training_dict)
        return loss, accuracy

    def test_model(self):

        test_dict = { self.model.x_train: self.test_data.x,
                      self.model.y_train: self.test_data.y,
                      self.model.embedding_dropout_prob: 1.0,
                      self.model.cell_dropout_prob: 1.0,
                      self.model.dropout_prob: 1.0 }

        loss, accuracy, predictions = self.session.run([self.model.loss, self.model.accuracy, self.model.predictions], feed_dict=test_dict)
        self.test_loss.append(loss)
        self.test_accuracy.append(accuracy)
        f1 = f1_score(np.argmax(self.test_data.y, axis=1), predictions, labels=np.array(range(1, 19)), average="macro")
        if self.best_f1 < f1:
            self.best_f1 = f1
            saved_checkpoint_path = self.saver.save(self.session, self.checkpoint_directory + "/model-{:.3g}-f1".format(self.best_f1))
            print("Saved model checkpoint to {}".format(saved_checkpoint_path))
        return loss, accuracy, f1


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import functools
print = functools.partial(print, flush=True)

from utils import deviation_strategy, mixed_strategy_payoff_2p

def _approx_simplex_projection(updated_strategy, gamma=0.0):
  """Approximately projects the distribution in updated_x to have minimal probabilities.

  Minimal probabilities are set as gamma, and the probabilities are then
  renormalized to sum to 1.

  Args:
    updated_strategy: New distribution value after being updated by update rule.
    gamma: minimal probability value when divided by number of actions.

  Returns:
    Projected distribution.
  """
  # Epsilon approximation of L2-norm projection onto the Delta_gamma space.
  updated_strategy[updated_strategy < gamma] = gamma
  updated_strategy = updated_strategy / np.sum(updated_strategy)
  return updated_strategy

def _partial_multi_dot(player_payoff_tensor, strategies, index_avoided):
  """Computes a generalized dot product avoiding one dimension.

  This is used to directly get the expected return of a given action, given
  other players' strategies, for the player indexed by index_avoided.
  Note that the numpy.dot function is used to compute this product, as it ended
  up being (Slightly) faster in performance tests than np.tensordot. Using the
  reduce function proved slower for both np.dot and np.tensordot.

  Args:
    player_payoff_tensor: payoff tensor for player[index_avoided], of dimension
      (dim(vector[0]), dim(vector[1]), ..., dim(vector[-1])).
    strategies: Meta strategy probabilities for each player.
    index_avoided: Player for which we do not compute the dot product.

  Returns:
    Vector of expected returns for each action of player [the player indexed by
      index_avoided].
  """
  new_axis_order = [index_avoided] + [
      i for i in range(len(strategies)) if (i != index_avoided)
  ]
  accumulator = np.transpose(player_payoff_tensor, new_axis_order)
  for i in range(len(strategies) - 1, -1, -1):
    if i != index_avoided:
      accumulator = np.dot(accumulator, strategies[i])
  return accumulator

def _replicator_dynamics_step(payoff_tensors, strategies, dt):
  """Does one step of the projected replicator dynamics algorithm.

  Args:
    payoff_tensors: List of payoff tensors for each player.
    strategies: List of the strategies used by each player.
    dt: Update amplitude term.
    gamma: Minimum exploratory probability term.

  Returns:
    A list of updated strategies for each player.
  """

  new_strategies = []
  for player in range(len(payoff_tensors)):
    current_payoff_tensor = payoff_tensors[player]
    current_strategy = strategies[player]

    values_per_strategy = _partial_multi_dot(current_payoff_tensor, strategies,
                                             player)
    average_return = np.dot(values_per_strategy, current_strategy)

    # print(values_per_strategy - average_return, values_per_strategy, average_return, current_strategy)

    delta = current_strategy * (values_per_strategy - average_return)
    updated_strategy = current_strategy + dt * delta
    updated_strategy = _approx_simplex_projection(updated_strategy, 0)

    new_strategies.append(updated_strategy)
  return new_strategies

def replicator_dynamics(payoff_tensors,
                        prd_initial_strategies=None,
                        prd_iterations=int(1e5),
                        prd_dt=1e-3,
                        average_over_last_n_strategies=None,
                        **unused_kwargs):
  """The Projected Replicator Dynamics algorithm.

  Args:
    payoff_tensors: List of payoff tensors for each player.
    prd_initial_strategies: Initial list of the strategies used by each player,
      if any. Could be used to speed up the search by providing a good initial
      solution.
    prd_iterations: Number of algorithmic steps to take before returning an
      answer.
    prd_dt: Update amplitude term.
    prd_gamma: Minimum exploratory probability term.
    average_over_last_n_strategies: Running average window size for average
      policy computation. If None, use the whole trajectory.
    **unused_kwargs: Convenient way of exposing an API compatible with other
      methods with possibly different arguments.

  Returns:
    PRD-computed strategies.
  """
  number_players = len(payoff_tensors)
  # Number of actions available to each player.
  action_space_shapes = payoff_tensors[0].shape

  # If no initial starting position is given, start with uniform probabilities.
  new_strategies = prd_initial_strategies or [
      np.ones(action_space_shapes[k]) / action_space_shapes[k]
      for k in range(number_players)
  ]

  average_over_last_n_strategies = average_over_last_n_strategies or prd_iterations

  meta_strategy_window = []
  for i in range(prd_iterations):
    new_strategies = _replicator_dynamics_step(
        payoff_tensors, new_strategies, prd_dt)
    if i >= prd_iterations - average_over_last_n_strategies:
      meta_strategy_window.append(new_strategies)
  average_new_strategies = np.mean(meta_strategy_window, axis=0)
  nash_list = [average_new_strategies[i] for i in range(number_players)]
  # return average_new_strategies
  return nash_list

def dev_regret(meta_games, probs):
  """
  Calculate the regret of a profile in an empirical game.
  :param meta_games:
  :param probs:
  :return:
  """
  num_players = 2
  payoffs = mixed_strategy_payoff_2p(meta_games, probs)
  dev_strs, dev_payoff = deviation_strategy(meta_games, probs)
  nashconv = 0
  for player in range(num_players):
    nashconv += np.maximum(dev_payoff[player] - payoffs[player], 0)
  return nashconv

def controled_replicator_dynamics(payoff_tensors,
                                  regret_threshold,
                                  prd_initial_strategies=None,
                                  prd_iterations=int(2e5),
                                  prd_dt=1e-3,
                                  average_over_last_n_strategies=None,
                                  **unused_kwargs):
  """The Projected Replicator Dynamics algorithm.

  Args:
    payoff_tensors: List of payoff tensors for each player.
    prd_initial_strategies: Initial list of the strategies used by each player,
      if any. Could be used to speed up the search by providing a good initial
      solution.
    prd_iterations: Number of algorithmic steps to take before returning an
      answer.
    prd_dt: Update amplitude term.
    prd_gamma: Minimum exploratory probability term.
    average_over_last_n_strategies: Running average window size for average
      policy computation. If None, use the whole trajectory.
    **unused_kwargs: Convenient way of exposing an API compatible with other
      methods with possibly different arguments.

  Returns:
    PRD-computed strategies.
  """
  number_players = len(payoff_tensors)
  # Number of actions available to each player.
  action_space_shapes = payoff_tensors[0].shape

  # If no initial starting position is given, start with uniform probabilities.
  new_strategies = prd_initial_strategies or [
      np.ones(action_space_shapes[k]) / action_space_shapes[k]
      for k in range(number_players)
  ]

  average_over_last_n_strategies = average_over_last_n_strategies or prd_iterations

  meta_strategy_window = []
  for i in range(prd_iterations):
    new_strategies = _replicator_dynamics_step(
        payoff_tensors, new_strategies, prd_dt)

    if i >= prd_iterations - average_over_last_n_strategies:
      meta_strategy_window.append(new_strategies)

    if i > 1e3:
      # return average_new_strategies
      average_new_strategies = np.mean(meta_strategy_window, axis=0)
      nash_list = [average_new_strategies[i] for i in range(number_players)]

      # Regret Control
      current_regret = dev_regret(payoff_tensors, nash_list)
      if current_regret < regret_threshold:
        break

  print("Inner Iter#:", i)
  return nash_list


# A/B Testing of Website Engagement
#dataset location = https://www.kaggle.com/datasets/zhangluyuan/ab-testing?select=ab_data.csv

#Importing Required Libraries
import numpy as np
import pandas as pd
import scipy.stats as stats
import statsmodels.stats.api as sms
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
from math import ceil

#Setting plot params
plt.style.use('seaborn-whitegrid')
font = {'family' : 'Arial',
        'weight' : 'bold',
        'size'   : 12}

#Sample size calculation
effect_size = sms.proportion_effectsize(0.13, 0.15)

required_n = sms.NormalIndPower().solve_power(
    effect_size,
    power=0.8,
    alpha=0.05,
    ratio=1
    )

required_n = ceil(required_n)

print(required_n)

#Importing dataset
df = pd.read_csv('ab_data.csv')

#Identifying multiple visit users
session_counts = df['user_id'].value_counts(ascending=False)
multi_users = session_counts[session_counts > 1].count()

#Dropping multiple visit users
users_to_drop = session_counts[session_counts > 1].index
df = df[~df['user_id'].isin(users_to_drop)]

#Seperating groups, obtaining sample size
control_sample = df[df['group'] == 'control'].sample(n=required_n, random_state=22)
treatment_sample = df[df['group'] == 'treatment'].sample(n=required_n, random_state=22)

ab_test = pd.concat([control_sample, treatment_sample], axis=0)
ab_test.reset_index(drop=True, inplace=True)

#Identifying converted users
conversion_rates = ab_test.groupby('group')['converted']

#Generating some basic statistics
std_p = lambda x: np.std(x, ddof=0)
se_p = lambda x: stats.sem(x, ddof=0)
conversion_rates = conversion_rates.agg([np.mean, std_p, se_p])
conversion_rates.columns = ['conversion_rate', 'std_deviation', 'std_error']

#Plotting conversion rates
plt.figure(figsize=(8,6))

sns.barplot(x=ab_test['group'], y=ab_test['converted'], ci=False, color="red")

plt.ylim(0, 0.17)
plt.title('Conversion rate by group', pad=20)
plt.xlabel('Group', labelpad=15)
plt.ylabel('Converted (proportion)', labelpad=15);

#Testing hypothesis
from statsmodels.stats.proportion import proportions_ztest, proportion_confint
control_results = ab_test[ab_test['group'] == 'control']['converted']
treatment_results = ab_test[ab_test['group'] == 'treatment']['converted']
n_con = control_results.count()
n_treat = treatment_results.count()
successes = [control_results.sum(), treatment_results.sum()]
nobs = [n_con, n_treat]
z_stat, pval = proportions_ztest(successes, nobs=nobs)
(lower_con, lower_treat), (upper_con, upper_treat) = proportion_confint(successes, nobs=nobs, alpha=0.05)

#Printing z-stat, p-value, and ci's
print(f'z statistic: {z_stat:.2f}')
print(f'p-value: {pval:.3f}')
print(f'ci 95% for control group: [{lower_con:.3f}, {upper_con:.3f}]')
print(f'ci 95% for treatment group: [{lower_treat:.3f}, {upper_treat:.3f}]')


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: yuandunlong
# @Date:   2015-09-11 16:38:41
# @Last Modified by:   yuandunlong
# @Last Modified time: 2015-09-18 10:01:35

from flask import request,Blueprint
from utils.decorator import json_response
from services import category_service
category_api=Blueprint('category_api',__name__)

@category_api.route('/public/category/get_all_categories',methods=['GET'])
@json_response
def get_all_categories(result):
    cats=category_service.get_all_categories()
    cats_arr=[]
    for cat in cats:
        cats_arr.append(cat.as_map())
    result['categories']=cats_arr


"""
A shuffling implementation which doesn't read a fixed
amount of bits for each rng call, instead only reads the
minimum required bits for the specified range.
"""
import math
from bitstring import BitArray
from src.utils import keccak256

def shuffle(lst, seed):
    rng = ShuffleRng(seed)
    o = [x for x in lst]
    durstenfeld_shuffle(o, rng.rand_range)
    return o

def durstenfeld_shuffle(lst, rand_range):
    for i in range(len(lst) - 1):
        j = rand_range(i, len(lst))
        lst[i], lst[j] = lst[j], lst[i]

class ShuffleRng:
    def __init__(self, seed):
        self.seed = BitArray(keccak256(seed))
        self.seed_idx = 0

    def rehash_seed(self):
        self.seed = BitArray(keccak256(self.seed.bytes))
        self.seed_idx = 0

    def rand(self, num_bits):
        first = self.seed_idx
        last = self.seed_idx + num_bits
        if last >= len(self.seed):
            self.rehash_seed()
            return self.rand(num_bits)
        x = self.seed[first:last].uint
        self.seed_idx += num_bits
        return x

    def rand_range(self, a, b):
        n = b - a
        bits = math.ceil(math.log2(n))
        rand_max = 2**bits
        x = 0
        while True:
            x = self.rand(bits)
            if x < rand_max - rand_max % n:
                break
        return (x % n) + a