# build.py
# pre-build script, setting up build environment and fetch hal file for user's board

import sys
import os
import os.path
import requests
from os.path import basename
from platformio import util
from SCons.Script import DefaultEnvironment

try:
    import configparser
except ImportError:
    import ConfigParser as configparser

# get platformio environment variables
env = DefaultEnvironment()
config = configparser.ConfigParser()
config.read("platformio.ini")

# get platformio project directory
prjdir = env.get("PROJECT_DIR")

# get platformio shared path
shareddir = os.path.join (prjdir, "shared")

# get hal path
haldir = os.path.join (shareddir, "hal")

# check if hal file is present in source directory
halconfig = config.get("board", "halfile")

# check if hal file is set by ENV CI_HALFILE
if os.getenv("CI_HALFILE"):
    # if set, use ENV CI_HALFILE
    print("CI_HALFILE ENV FOUND")
    # override halconfig
    halconfig = os.getenv("CI_HALFILE")

halconfigfile = os.path.join (haldir, halconfig)

if os.path.isfile(halconfigfile) and os.access(halconfigfile, os.R_OK):
    print("Parsing hardware configuration from " + halconfigfile)
else:
    sys.exit("Missing file " + halconfigfile + ", please create it! Aborting.")

# check if lmic config file is present in shared directory
lmicconfig = config.get("common", "lmicconfigfile")
lmicconfigfile = os.path.join (shareddir, lmicconfig)
if os.path.isfile(lmicconfigfile) and os.access(lmicconfigfile, os.R_OK):
    print("Parsing LMIC configuration from " + lmicconfigfile)
else:
    sys.exit("Missing file " + lmicconfigfile + ", please create it! Aborting.")

# check if lora key file is present in shared directory
lorakeyfile = os.path.join (shareddir, config.get("common", "lorakeyfile"))
if os.path.isfile(lorakeyfile) and os.access(lorakeyfile, os.R_OK):
    print("Parsing LORAWAN keys from " + lorakeyfile)
else:
    sys.exit("Missing file " + lorakeyfile + ", please create it! Aborting.")

# check if ota key file is present in shared directory
otakeyfile = os.path.join (shareddir, config.get("common", "otakeyfile"))
if os.path.isfile(otakeyfile) and os.access(otakeyfile, os.R_OK):
    print("Parsing OTA keys from " + otakeyfile)
else:
    sys.exit("Missing file " + otakeyfile + ", please create it! Aborting.")

# parse hal file
mykeys = {}
with open(halconfigfile) as myfile:
    for line in myfile:
        line2 = line.strip("// ")
        key, value = line2.partition(" ")[::2]
        mykeys[key.strip()] = str(value).strip()
myboard = mykeys["board"]
myuploadspeed = mykeys["upload_speed"]
env.Replace(BOARD=myboard)
env.Replace(UPLOAD_SPEED=myuploadspeed)
print('\033[94m' + "Target board: " + myboard + " @ " + myuploadspeed + "bps" + '\033[0m')

# re-set partition table
mypartitiontable = config.get("env", "board_build.partitions")
board = env.BoardConfig(myboard)
board.manifest['build']['partitions'] = mypartitiontable
print('\033[94m' + "Partition table: " + mypartitiontable + '\033[0m')

# parse ota key file
with open(otakeyfile) as myfile:
    for line in myfile:
        key, value = line.partition("=")[::2]
        mykeys[key.strip()] = str(value).strip()

# usage of paxexpress: see https://github.com/paxexpress/docs

# get paxexpress credentials from ota key file
user = mykeys["PAXEXPRESS_USER"]
repository = mykeys["PAXEXPRESS_REPO"]
apitoken = mykeys["PAXEXPRESS_API_TOKEN"]

# get paxexpress upload parameters from platformio environment
version = config.get("common", "release_version")
package, dummy = halconfig.partition(".")[::2]

# put paxexpress user credentials to platformio environment
env.Replace(PAXEXPRESS_USER=user)
env.Replace(PAXEXPRESS_REPO=repository)
env.Replace(PAXEXPRESS_API_TOKEN=apitoken)

# get runtime credentials and put them to compiler directive
env.Append(BUILD_FLAGS=[
    u'-DWIFI_SSID=\\"' + mykeys["OTA_WIFI_SSID"] + '\\"',
    u'-DWIFI_PASS=\\"' + mykeys["OTA_WIFI_PASS"] + '\\"',
    u'-DPAXEXPRESS_USER=\\"' + mykeys["PAXEXPRESS_USER"] + '\\"',
    u'-DPAXEXPRESS_REPO=\\"' + mykeys["PAXEXPRESS_REPO"] + '\\"',
    u'-DPAXEXPRESS_PACKAGE=\\"' + package + '\\"',
    u'-DARDUINO_LMIC_PROJECT_CONFIG_H=' + lmicconfig,
    u'-I \"' + shareddir + '\"'
    ])

# function for pushing new firmware to paxexpress storage using API
def publish_paxexpress(source, target, env):
    firmware_path = str(source[0])
    firmware_name = basename(firmware_path)
    url = "/".join([
        "https://pax.express", "content",
        user, repository, package, version, firmware_name
    ])

    print("Uploading {0} to PAX.express. Version: {1}".format(
        firmware_name, version))
    print(url)

    headers = {
        "Content-type": "application/octet-stream",
        "X-Bintray-Publish": "1",
        "X-Bintray-Override": "1"
    }

    r = None

    try:
        r = requests.put(url,
                         data=open(firmware_path, "rb"),
                         headers=headers,
                         auth=(user,apitoken))
        r.raise_for_status()
    except requests.exceptions.RequestException as e:
        sys.stderr.write("Failed to submit package: %s\n" %
                         ("%s\n%s" % (r.status_code, r.text) if r else str(e)))
        env.Exit(1)

    print("Firmware has been successfully published at PAX.express!")

# put build file name and upload command to platformio environment
env.Replace(
    PROGNAME="firmware_" + package + "_v%s" % version,
    UPLOADCMD=publish_paxexpress)


from db_helpers import create_age_table, create_connection, query1, query2, query3, query4, query5
from people_helpers import retrieve_people_data
import yaml

"""
To begin, we must extract data form the RandomUser API. Once extracted, we supplement the data in 2 ways:

1) We use the Agify.io API to predict a person's age based on their first name.
    NOTE: If we already know a person's predicted age from a previous API call, we will NOT re-call
    the API to save time and (theoretical) money.
2) We use haversine package to calculate the distance of each person's latitude and longitude from Ford Field in miles.
    NOTE: Unfortunately, the latitude and longitude values from RandomUser do not correspond to the person's listed
    address it provides, so haversine produces unusual results often.

"""

# Produce and/or append to two tables: people and names
num_of_people = 200

conn = create_connection('db.sqlite')
people = retrieve_people_data(num_of_people, conn)
create_age_table(conn)

"""
Now, let's analyze some of our data using SQL. We have a file (sql_queries.yml) that contains our queries.
As we cycle through these queries, we will print a description of the query being run, and insights/results gathered in terminal.

"""

# Open and read the yml file of queries to pass to our db_helpers
with open('sql_queries.yml', 'r') as f:
    doc = yaml.load(f, Loader=yaml.FullLoader)

for i in range(1,6):
    successful = False
    while not successful:
        if input(doc[f'query{i}']['prompt']).lower() in ['y','yes']:
            if i == 1:
                query1(conn, doc)
            elif i ==2:
                query2(conn, doc)
            elif i == 3:
                query3(conn, doc)
            elif i == 4:
                query4(conn, doc)
            elif i == 5:
                query5(conn, doc)
            successful = True
    continue

conn.close()


import pandas as pd
import numpy as np
import pvlib
import datetime
from pvlib import irradiance
from pvlib import location
from pvlib.pvsystem import PVSystem
#from pvlib.location import Location
from pvlib.modelchain import ModelChain
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
import weatherData

latitude, longitude, tz = 63.42024, 10.40122, 'Europe/Oslo' # specify location
start = pd.Timestamp(datetime.date.today(), tz=tz)
end = start + pd.Timedelta(days=1)
irrad_vars = ['ghi', 'dni', 'dhi']

# Create location object to store lat, lon, timezone
#location = Location(latitude=63.42024, longitude=10.40122) # Bredd/lengde-grad for Trondheim
site = location.Location(latitude, longitude, tz=tz)

temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
# Bestemmer hvilke moduler og invertere vi ønsker å modelere.
sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
cec_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')
sandia_module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
cec_inverter = cec_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']

# Calculate clear-sky GHI and transpose to plane of array
def get_irradiance(site_location, date, tilt, surface_azimuth):
    # Creates one day's worth of 10 min intervals
    times = pd.date_range(date, freq='10min', periods=6*24,
                          tz=site_location.tz)
    # Generate clearsky data using the Ineichen model, which is the default
    # The get_clearsky method returns a dataframe with values for GHI, DNI,
    # and DHI

    clearsky = site_location.get_clearsky(times)
    # Get solar azimuth and zenith to pass to the transposition function
    solar_position = site_location.get_solarposition(times=times)
    # Use the get_total_irradiance function to transpose the GHI to POA
    POA_irradiance = irradiance.get_total_irradiance(
        surface_tilt=tilt,
        surface_azimuth=surface_azimuth,
        dni=clearsky['dni'],
        ghi=clearsky['ghi'],
        dhi=clearsky['dhi'],
        solar_zenith=solar_position['apparent_zenith'],
        solar_azimuth=solar_position['azimuth'])
    # Return DataFrame with only GHI and POA
    return pd.DataFrame({'GHI': clearsky['ghi'],
                         'DNI' : clearsky['dni'],
                         'DHI' : clearsky['dhi'],
                         'POA': POA_irradiance['poa_global']})

system = PVSystem(surface_tilt=20, surface_azimuth=180, # vinkel og vridning for panel. Sør = 180
        module_parameters = sandia_module,
        inverter_parameters = cec_inverter,
        temperature_model_parameters = temperature_model_parameters)

###____ Kjør ____ ###

def getIndexIntoDay():
    now = datetime.datetime.now()
    start = datetime.datetime(now.year, now.month, now.day)
    diff = now - start
    seconds_in_day = 24 * 60 * 60
    return int((144 / seconds_in_day) * diff.seconds) # converts seconds to intervals of 144 (10 min) and throws away decimal.

def solarPanelPower(date, index):
    """
    Returns solarPower generation in Watt
     """

    irradiance = get_irradiance(site, date, 20, 180) # irradiance i Trondheim, i dag
    wattPerSquareMeter = irradiance["POA"][index]
    solarPanelArrayPower = wattPerSquareMeter * 150 * 0.19 # times square meters * solar panel efficiency.
    cloudCover = weatherData.Get_data_now().variables["cloud_area_fraction"]
    cloudCover = float(str(cloudCover).split()[1][:-1])/100
    solarPanelArrayPower = solarPanelArrayPower * (1 - cloudCover) # power * 1 - cloud coverage
    return solarPanelArrayPower

#power = solarPanelPower('14-05-2021', getIndexIntoDay())
#print(power)
''

"""
weatherList = [irradiance["GHI"], irradiance["DHI"], irradiance["DNI"], 30, 5]

#print(weatherList)

weather = pd.DataFrame([[irradiance["GHI"], irradiance["DHI"], irradiance["DNI"], 30, 5]],
                         columns=['ghi', 'dni', 'dhi', 'temp_air', 'wind_speed'],
                         index=[pd.Timestamp('20210401 1200', tz='Europe/Oslo')])

print(weather)

#MÅ FIKSES MER PÅ. Må få tatt innn riktige verdier i weather DF og ikke arrays.
mc = ModelChain(system, site)

mc.run_model(weather)
print(mc.ac)
"""


import readData
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from scipy.spatial.distance import cdist

data = readData.readDataAsDataFrame()

data2 = readData.get2DimensionValue(data)
print(data2)

def elbow_rule(data):
    # 肘部法则 求解最佳分类数
    # K-Means参数的最优解也是以成本函数最小化为目标
    # 成本函数是各个类畸变程度（distortions）之和。每个类的畸变程度等于该类重心与其内部成员位置距离的平方和
    a = []
    x = []
    y = []
    for k in range(1, 10):
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(data)
        value = sum(np.min(cdist(data, kmeans.cluster_centers_, 'euclidean'), axis=1)) / data.shape[0]
        print(k, value)
        x.append(k)
        y.append(value)
        a.append(value)

    cha = [a[i] - a[i + 1] for i in range(len(a) - 1)]
    a_v = a[cha.index(max(cha)) + 1]
    index = a.index(a_v) + 1
    print()
    print(max(cha), a_v,index)

    return index, x, y

def getK():
    index, x, y = elbow_rule(data2)
    plt.xlabel('k')
    plt.ylabel('SSE')
    plt.plot(x, y, 'o-')
    plt.show()

getK()


from __future__ import annotations
from PIL import Image
import torch
from torchvision import datasets
from torchvision import transforms
from typing import Tuple
from torch.utils.data import Dataset, DataLoader
from torch import Tensor
import matplotlib.pyplot as plt
from torch import optim
from torch import nn
import torch.nn.functional as F
import numpy as np
from tqdm import tqdm
import pandas as pd
from typing import Optional
import sys

def main() -> None:
    (train_set, test_set) = get_dataset()
    check_data(train_set)
    train_loader, test_loader = get_dataloader(train_set, test_set)
    print(len(train_loader))
    print(len(test_loader))
    images, labels = iter(train_loader).next()
    print(labels.shape)
    print(torch.max(labels, 0)[0])
    print(torch.min(labels, 0)[0])

    device = get_device()
    print(device)

    net = Net(100).to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.001)

    history = train(train_loader, test_loader, optimizer,
                    criterion, net, device)
    print(history.shape)
    torch.save(net.state_dict(), "param.pt")
    pd.to_pickle(history, "history.pkl")

Loader = DataLoader[Tuple[Tensor, Tensor]]

def train(train_loader: Loader, test_loader: Loader, optimizer: optim.Adam, criterion: nn.CrossEntropyLoss, net: Net, device, num_epoch: int = 20) -> np.ndarray:
    batch_size: int = iter(train_loader).next()[0].shape[0]
    history = np.zeros(5)
    for epoch in range(num_epoch):
        train_acc, train_loss = 0.0, 0.0  # train data
        val_acc, val_loss = 0.0, 0.0  # validation data
        num_train, num_test = 0, 0  # the number of data

        inputs: Tensor
        labels: Tensor
        for inputs, labels in tqdm(train_loader):
            num_train += len(labels)

            inputs = inputs.to(device)
            labels = labels.to(device)

            optimizer.zero_grad()
            outputs = net(inputs).to(device)
            loss: Tensor = criterion(outputs, labels)
            loss.backward()

            optimizer.step()
            _, predicted = torch.max(outputs, 1)

            train_loss += loss.item()
            train_acc += (predicted == labels).sum().item()

        inputs_test: Tensor
        labels_test: Tensor
        for inputs_test, labels_test in test_loader:
            num_test += len(labels_test)
            inputs_test = inputs_test.to(device)
            labels_test = labels_test.to(device)

            outputs_test = net(inputs_test)
            loss_test: Tensor = criterion(outputs_test, labels_test)
            _, predicted_test = torch.max(outputs_test, 1)

            val_loss += loss_test.item()
            val_acc += (predicted_test == labels_test).sum().item()

        train_acc = train_acc / num_train
        val_acc = val_acc / num_test
        train_loss = train_loss * batch_size / num_train
        val_loss = val_loss * batch_size / num_test

        print(
            f"Epoch [{epoch + 1}/{num_epoch}], loss: {train_loss:.5f}, acc: {train_acc:.5f}, val_loss: {val_loss:.5f}, val_acc: {val_acc:.5f}"
        )
        items = np.array(
            [epoch + 1, train_loss, train_acc, val_loss, val_acc]
        )
        history = np.vstack((history, items))
    # [[index, train_loss, train_acc, val_loss, val_acc]], len(history) == num_epoch + 1, len(history[0]) == 5
    return history

class Net(nn.Module):
    def __init__(self, kind:int = 10) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(
            in_channels=3, out_channels=32, kernel_size=(3, 3), padding="same"
        )
        self.conv2 = nn.Conv2d(
            in_channels=32, out_channels=32, kernel_size=(3, 3), padding="same"
        )
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.drop1 = nn.Dropout2d(p=0.25)

        self.conv3 = nn.Conv2d(
            in_channels=32, out_channels=64, kernel_size=(3, 3), padding="same"
        )
        self.conv4 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=(3, 3), padding="same"
        )
        self.drop2 = nn.Dropout2d(p=0.25)

        self.fc1 = nn.Linear(in_features=64*32*32, out_features=512)
        self.drop3 = nn.Dropout(p=0.5)
        self.fc2 = nn.Linear(in_features=512, out_features=kind)

    def forward(self, x: Tensor) -> Tensor:
        x = F.relu(self.conv1(x))
        x = F.relu(self.conv2(x))
        x = self.drop1(x)

        x = F.relu(self.conv3(x))
        x = F.relu(self.conv4(x))
        x = self.drop2(x)
        x = torch.flatten(x, 1)

        x = F.relu(self.fc1(x))
        x = self.drop3(x)
        x = self.fc2(x)

        return x

def get_dataset() -> Tuple[Dataset[Tuple[Tensor, int]],
                           Dataset[Tuple[Tensor, int]]]:
    data_root = "./data"

    transform: transforms.Compose = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize(0.5, 0.5),
    ])

    train_set: Dataset[Tuple[Tensor, int]] = datasets.CIFAR100(
        root=data_root,
        train=True,
        download=True,
        transform=transform
    )

    test_set = datasets.CIFAR100(
        root=data_root,
        train=True,
        download=False,
        transform=transform
    )

    return (train_set, test_set)

def get_dataloader(train_set: Dataset[Tuple[Tensor, int]], test_set: Dataset[Tuple[Tensor, int]],
                   batch_size=128) -> Tuple[DataLoader[Tuple[Tensor, Tensor]], DataLoader[Tuple[Tensor, Tensor]]]:
    train_loader: DataLoader[Tuple[Tensor, Tensor]] = DataLoader(
        train_set, batch_size=batch_size, shuffle=True)  # type: ignore

    test_loader: DataLoader[Tuple[Tensor, Tensor]] = DataLoader(
        test_set, batch_size=batch_size, shuffle=False)  # type: ignore

    return (train_loader, test_loader)

def check_data(data: Dataset[Tuple[Tensor, int]]):
    for i in range(10):
        image, _ = data[i]
        plt.subplot(2, 5, i + 1)
        # (rgb, height, length) -> (length, height, rgb) -> (height, length, rgb)
        plt.imshow(image.transpose(0, 2).transpose(0, 1))
    plt.savefig("pic.png")

def get_device() -> torch.device:
    return torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # return torch.device("cuda:0" if False else "cpu")

def check_history():
    # [[index, train_loss, train_acc, val_loss, val_acc]], len(history) == num_epoch + 1, len(history[0]) == 5
    history: np.ndarray = pd.read_pickle("history.pkl")
    plt.plot(history[1:, 0], history[1:, 1], "b", label="train")
    plt.plot(history[1:, 0], history[1:, 3], "k", label="test")
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.title("loss curve")
    plt.legend()
    plt.savefig("loss_curve.png")
    plt.close()

    plt.plot(history[:, 0], history[:, 2], "b", label="train")
    plt.plot(history[:, 0], history[:, 4], "k", label="test")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.title("accuracy")
    plt.legend()
    plt.savefig("acc_curve.png")

    print(f"initial: loss: {history[1, 3]}, acc: {history[1, 4]}")
    print(f"last: loss: {history[-1, 3]}, acc: {history[-1, 4]}")
    print(f"eval mode acc: {check_acc()}")

def check_acc() -> float:
    device = get_device()
    net = load_model(device)
    _, test_loader = get_dataloader(*get_dataset())
    acc: float = 0.0
    num_test: int = 0
    images: Tensor
    labels: Tensor
    for images, labels in test_loader:
        num_test += len(labels)
        images = images.to(device)
        labels = labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        acc += (predicted == labels).sum().item()
    return acc / num_test

def check_model(test_loader: Optional[Loader] = None, net: Optional[Net] = None, index: int = 0):
    device = get_device()
    if net is None:
        net = load_model(device)
    if test_loader is None:
        _, test_loader = get_dataloader(*get_dataset())
    images, labels = list(iter(test_loader))[index]
    print(images.shape)
    images: Tensor = images.to(device)
    labels: Tensor = labels.to(device)
    outputs: Tensor = net(images)
    predicteds: Tensor = torch.max(outputs, 1)[1]

    acc = (labels == predicteds).sum().item() / len(labels)
    print(acc)
    if acc == 1:
        check_model(test_loader, net, index + 1)
        sys.exit(0)

    plt.figure(figsize=(30, 24))
    acc: float = 0
    for i in range(50):
        ax = plt.subplot(5, 10, i + 1)

        image = images[i].cpu()
        label = labels[i].cpu()
        predicted = predicteds[i].cpu()
        if (predicted == label):
            c = "k"
            acc += 1
        else:
            c = "b"

        plt.imshow(image.reshape(3, 32, 32).transpose(0, 2).transpose(0, 1))
        label_name = ["airplane", "automobile", "bird", "cat",
                      "deer", "dog", "frog", "horse", "ship", "truck"]
        ax.set_title(f"{label_name[label]}:{label_name[predicted]}", c=c)
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
    acc = acc / 50
    print(f"acc: {acc}")
    plt.savefig("pred.png")

def check_my_image(path="my.png"):
    img = Image.open(path)
    img = img.resize((32, 32))
    print(np.array(img).shape)
    img = transforms.Normalize(0.5, 0.5)(transforms.ToTensor()(img))
    input = Tensor(img)
    device = get_device()
    print(input.shape)
    # (height, length, rgb) -> (rgb, height, length)
    # input = input.transpose(0, 2).transpose(1, 2)
    input = input[:3, ]  # for image that have 4 dim color
    plt.imshow(input.transpose(0, 2).transpose(0, 1))
    plt.savefig("conversion.png")
    print(input.shape)
    input = input.reshape(1, 3, 32, 32).to(device)
    print(input.shape)
    label_name = ["airplane", "automobile", "bird", "cat",
                  "deer", "dog", "frog", "horse", "ship", "truck"]
    net = load_model(device)
    output = net(input)
    pred = torch.max(output, 1)
    print(pred)
    print(label_name[pred[1]])

def load_model(device: torch.device) -> Net:
    net = Net(100).to(device)
    net.load_state_dict(torch.load("param.pt"))
    net.eval()
    return net

if __name__ == "__main__":

    # predict image in conv/`path`
    # check_my_image(my.jpg)

    # check acc in eval mode
    # check_model()

    # create png which was generated while train phase
    check_history()

    # train
    # main()


import argparse
import os
import random
from pathlib import Path

from tqdm import tqdm

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Break a large data file into a specified number of shards"
    )
    parser.add_argument('input_file', type=str)
    parser.add_argument('output_dir', type=str)
    parser.add_argument('num_shards', type=int)
    parser.add_argument('--seed', type=int, default=1)
    parser.add_argument('--shuffle_first', action='store_true')
    args = parser.parse_args()

    print("Reading in lines")
    lines = [
        line.strip()
        for line in open(args.input_file, 'r') if line.strip() != ''
    ]
    num_lines = len(lines)

    if args.shuffle_first:
        print("Shuffling lines")
        random.seed(args.seed)
        random.shuffle(lines)

    quotient, remainder = divmod(num_lines, args.num_shards)
    lower_elements = [quotient for i in range(args.num_shards - remainder)]
    higher_elements = [quotient + 1 for i in range(remainder)]
    shard_lengths = lower_elements + higher_elements

    os.makedirs(args.output_dir, exist_ok=True)

    print("Writing shards")
    for shard_num, shard_length in tqdm(zip(range(args.num_shards), shard_lengths), desc="shard progress", unit="shard"):
        filestem = Path(args.input_file).stem
        filename = os.path.join(
            args.output_dir, f'{filestem}_shard{shard_num+1}.txt'
        )
        start_index = sum(shard_lengths[:shard_num])
        with open(filename, 'w') as fout:
            for line in lines[start_index:start_index+shard_length]:
                print(line, file=fout)


import threading
from flask import Flask
import os
import sys
import logging

app = Flask("keepalive")

@app.route('/', methods=['GET', 'POST', 'CONNECT', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'TRACE', 'HEAD'])
def main():
    repl_owner = os.environ.get('REPL_OWNER')
    return f'''Hey there, {repl_owner}! To keep your Replit running continuously, you'll need to use an uptime monitoring service like UptimeRobot'''

log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
app.logger.disabled = True
cli = sys.modules['flask.cli']
cli.show_server_banner = lambda *x: None

def run_flask_app():
    app.run(host='0.0.0.0', port=3000, debug=False, use_reloader=False)

Welcomer = """\033[1;31m⚠ Looks like you are running this project on Replit\033[0m
\033[1;33mPlease note that the .env file cannot exist on Replit.
Instead, create environment variable DISCORD_TOKEN in the "Secrets" tab under "Tools". \033[0m
"""

def run_flask_in_thread():
    threading.Thread(target=run_flask_app).start()
    print(Welcomer)
    repl_owner_name = os.environ.get('REPL_OWNER')
    repl_project_name = os.environ.get('REPL_SLUG')
    print(f"\033[1;32m\n\nTo ensure your bot runs 24/7 on Replit, you can use services like Uptime Robot to ping the following URL:\033[0m \n\n https://{repl_project_name}.{repl_owner_name}.repl.co\n\n")

if __name__ == "__main__":
    run_flask_in_thread()


import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    """docstring for Alien."""

    def __init__(self, ai_settings, screen):
        super(Alien, self).__init__()
        self.screen = screen
        self.rect = screen
        self.ai_settings = ai_settings
        # load alien image and set attributes
        self.image = pygame.image.load('images/alien.bmp')
        self.rect = self.image.get_rect()
        # set every alien in screen left the up
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        # store alien accurate
        self.x = float(self.rect.x)

    def blitme(self):
        self.screen.blit(self.image, self.rect)

    def update(self):
        """move right"""
        self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction)
        self.rect.x = self.x

    def check_edges(self):
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True


#libraries
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split #splits data
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
from string import punctuation
from sklearn.pipeline import Pipeline #steps can be run in series
from sklearn.feature_extraction.text import CountVectorizer #converts text into number vectors
from sklearn.feature_extraction.text import TfidfTransformer #transforms count vectors into tfidf
from sklearn.svm import SVC #SVM model
import matplotlib.pyplot as plt

path = 'comedy_central.csv'
data = pd.read_csv(path)
joke_content = data.content.tolist() #actual joke
categories = data.flattened_categories.tolist()

#creates list of most relevant category label for each joke
categories_1 = []
for comma_categ in categories:
    categ_split = comma_categ.split(',') #splits into list of categories
    categories_1.append(categ_split[0]) #appends 1st (most relevant) category

#list of unique most relevant categories of all jokes
unique_categ = []
for categ in categories_1:
    if categ not in unique_categ:
        unique_categ.append(categ)

#cleans jokes of stopwords, punctuation, and irrelevant info
print('Cleaning jokes ...')
stop_words = set(stopwords.words('english')) #set of predefined english stop words
joke_content_cleaned = []
for sent in joke_content:
    words = word_tokenize(sent) #splits into words
    #print('joke content before being cleaned: ', words)
    words_cleaned = [] #joke, list of meaningful words
    for word in words:
        if word not in stop_words and word not in punctuation and word not in ['Q', 'A', '``']:
            words_cleaned.append(word)
    words_cleaned = ' '.join(words_cleaned)
    #print('joke content after being cleaned: ', words_cleaned)
    joke_content_cleaned.append(words_cleaned.strip())

# pipeline to transform words into tf-idf vectors, then trains SVM model
print('Creating pipeline ...')
model = Pipeline([('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', SVC(kernel='rbf'))])

#splits jokes and categories into testing and training sets
print('Splitting into testing and training sets ...')
X_train, X_test, y_train, y_test = train_test_split(joke_content_cleaned, categories_1, test_size=0.1)

#trains model
print('Training model ...')
model.fit(X_train, y_train)
#prints accuracy score when tested against testing data and labels
print('Accuracy: ', model.score(X_test, y_test))


import logging
import re
import time
from json import loads as json_parse
from os import walk as walkdir

from django.conf import settings
from django.contrib.admin.views.decorators import staff_member_required
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator
from django.core.validators import validate_email
from django.db.models import Count, Q, Subquery
from django.http import Http404, JsonResponse
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.templatetags.static import static
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _
from django.views.decorators.csrf import csrf_exempt

from app.utils import get_default_network, get_profiles_from_text
from cacheops import cached_as, cached_view, cached_view_as
from dashboard.models import Activity, Bounty, HackathonEvent, Profile, get_my_earnings_counter_profiles, get_my_grants
from dashboard.notifications import amount_usdt_open_work, open_bounties
from dashboard.tasks import grant_update_email_task
from economy.models import Token
from marketing.mails import mention_email, new_funding_limit_increase_request, new_token_request, wall_post_email
from marketing.models import Alumni, Job, LeaderboardRank
from marketing.utils import get_or_save_email_subscriber, invite_to_slack
from perftools.models import JSONStore
from ratelimit.decorators import ratelimit
from retail.emails import render_nth_day_email_campaign
from retail.helpers import get_ip
from townsquare.tasks import increment_view_counts

from .forms import FundingLimitIncreaseRequestForm
from .utils import programming_languages

logger = logging.getLogger(__name__)

connect_types = ['status_update', 'wall_post', 'new_bounty', 'created_quest', 'new_grant', 'created_kudos', 'consolidated_leaderboard_rank', 'consolidated_mini_clr_payout']

def get_activities(tech_stack=None, num_activities=15):
    # get activity feed

    activities = Activity.objects.select_related('bounty').filter(bounty__network='mainnet').order_by('-created')
    if tech_stack:
        activities = activities.filter(bounty__metadata__icontains=tech_stack)
    activities = activities[0:num_activities]
    return activities

def index(request):

    products = [
        {
            'group' : 'grow_oss',
            'products': [
                {
                    'img': static('v2/images/home/bounties.svg'),
                    'name': 'BOUNTIES',
                    'description': 'Get paid for solving open source bounties.',
                    'link': '/bounties/funder'
                }
            ]
        },
        {
            'group' : 'maintain_oss',
            'products': [
                {
                    'img': static('v2/images/home/codefund.svg'),
                    'name': 'CODEFUND',
                    'description': 'Ethical advertising for open source.',
                    'link': 'https://codefund.app'
                },
                {
                    'img': static('v2/images/home/grants.svg'),
                    'name': 'GRANTS',
                    'description': 'Sustainable funding for open source.',
                    'link': '/grants'
                }
            ]
        },
        {
            'group' : 'build_oss',
            'products': [
                {
                    'img': static('v2/images/home/kudos.svg'),
                    'name': 'KUDOS',
                    'description': 'A new way to show appreciation.',
                    'link': '/kudos'
                }
            ]
        }
    ]

    know_us = [
        {
            'text': 'Our Vision',
            'link': '/vision'
        },
        {
            'text': 'Our Products',
            'link': '/products'
        },
        {
            'text': 'Our Team',
            'link': '/about#team'
        },
        {
            'text': 'Our Results',
            'link': '/results'
        },
        {
            'text': 'Our Values',
            'link': '/mission'
        },
        {
            'text': 'Our Token',
            'link': '/not_a_token'
        }
    ]

    press = [
        {
            'link': 'https://twit.tv/shows/floss-weekly/episodes/474',
            'img' : 'v2/images/press/floss_weekly.jpg'
        },
        {
            'link': 'https://epicenter.tv/episode/257/',
            'img' : 'v2/images/press/epicenter.jpg'
        },
        {
            'link': 'http://www.ibtimes.com/how-web-30-will-protect-our-online-identity-2667000',
            'img': 'v2/images/press/ibtimes.jpg'
        },
        {
            'link': 'https://www.forbes.com/sites/jeffersonnunn/2019/01/21/bitcoin-autonomous-employment-workers-wanted/',
            'img': 'v2/images/press/forbes.jpg'
        },
        {
            'link': 'https://unhashed.com/cryptocurrency-news/gitcoin-introduces-collectible-kudos-rewards/',
            'img': 'v2/images/press/unhashed.jpg'
        },
        {
            'link': 'https://www.coindesk.com/meet-dapp-market-twist-open-source-winning-developers/',
            'img': 'v2/images/press/coindesk.png'
        },
        {
            'link': 'https://softwareengineeringdaily.com/2018/04/03/gitcoin-open-source-bounties-with-kevin-owocki/',
            'img': 'v2/images/press/se_daily.png'
        },
        {
            'link': 'https://www.ethnews.com/gitcoin-offers-bounties-for-ens-integration-into-dapps',
            'img': 'v2/images/press/ethnews.jpg'
        },
        {
            'link': 'https://www.hostingadvice.com/blog/grow-open-source-projects-with-gitcoin/',
            'img': 'v2/images/press/hosting-advice.png'
        }
    ]

    articles = [
        {
            'link': 'https://medium.com/gitcoin/progressive-elaboration-of-scope-on-gitcoin-3167742312b0',
            'img': static("v2/images/medium/1.png"),
            'title': _('Progressive Elaboration of Scope on Gitcoin'),
            'description': _('What is it? Why does it matter? How can you deal with it on Gitcoin?'),
            'alt': 'gitcoin scope'
        },
        {
            'link': 'https://gitcoin.co/blog/commit-reveal-scheme-on-ethereum/',
            'img': static("v2/images/medium/2.png"),
            'title': _('Commit Reveal Scheme on Ethereum'),
            'description': _('Hiding Actions and Generating Random Numbers'),
            'alt': 'commit reveal scheme'
        },
        {
            'link': 'https://medium.com/gitcoin/announcing-open-kudos-e437450f7802',
            'img': static("v2/images/medium/3.png"),
            'title': _('Announcing Open Kudos'),
            'description': _('Our vision for integrating Kudos in any (d)App'),
            'alt': 'open kudos'
        }
    ]

    context = {
        'products': products,
        'know_us': know_us,
        'press': press,
        'articles': articles,
        'hide_newsletter_caption': True,
        'hide_newsletter_consent': True,
        'newsletter_headline': _("Get the Latest Gitcoin News! Join Our Newsletter."),
        'title': _('Grow Open Source: Get crowdfunding and find freelance developers for your software projects, paid in crypto')
    }
    return TemplateResponse(request, 'home/index.html', context)

def funder_bounties_redirect(request):
    return redirect(funder_bounties)

def funder_bounties(request):

    onboard_slides = [
        {
            'img': static("v2/images/presskit/illustrations/prime.svg"),
            'title': _('Are you a developer or designer?'),
            'subtitle': _('Contribute to exciting OSS project and get paid!'),
            'type': 'contributor',
            'active': 'active',
            'more': '/bounties/contributor'
        },
        {
            'img': static("v2/images/presskit/illustrations/regulus-white.svg"),
            'title': _('Are you a funder or project organizer?'),
            'subtitle': _('Fund your OSS bounties and get work done!'),
            'type': 'funder',
            'more': '/how/funder'
        }
    ]

    slides = [
        ("Dan Finlay", static("v2/images/testimonials/dan.jpg"),
         _("Once we had merged in multiple language support from a bounty, it unblocked the \
         path to all other translations, and what better way to get lots of dif erent \
         translations than with bounties from our community? A single tweet of publicity \
         and we had something like 20 language requests, and 10 language pull requests. It’s been total magic."),
         'https://github.com/danfinlay', "Metamask -- Internationalization"),
        ("Phil Elsasser", static("v2/images/testimonials/phil.jpg"),
         _("By design or not, there is an element of trust inherent within Gitcoin. This isn’t \
         the bad kind of “trust” that we are all trying to move away from in a centralized world, \
         but a much better sense of community trust that gets established through the bounty process."),
         'http://www.marketprotocol.io/', 'Market'),
        ("John Maurelian", static("v2/images/testimonials/maurelian.jpg"),
         _("Gitcoin helps us to finally close out the issues we've been meaning to get around to for too long"),
         "https://consensys.github.io/smart-contract-best-practices/", 'Consensys Diligence -- Documentation Bounties'),
        ("Kames CG", static("v2/images/testimonials/kames.jpg"),
         _("uPort is still in the process of Open Sourcing all of our code, so Gitcoin at the present moment, \
         helps uPort plant seeds within the growing Ethereum developer community, that we expect will blossom \
         into flourishing opportunities in the future. Put simply, as opposed to running marketing campaign, \
         we can use bounties to stay present in front of potential developers we want to engage with."),
         'https://github.com/KamesCG', 'Uport'),
        ("Piper", static("v2/images/testimonials/pipermerriam.jpg"),
         _("Although we’ve only hired two developers, there is no doubt that we could have sourced more. \
         Gitcoin has been the strongest hiring signal in all of the hiring I’ve ever done."),
         'https://github.com/pipermerriam', 'Pipermerriam'),
        ("Joseph Schiarizzi", static("v2/images/testimonials/jschiarizzi.jpeg"),
         _("On a Friday I needed a front end done for a project due in 48 hours.  When everyone I knew was busy, \
         gitcoiners were able to help me make my deadline, with fast, affordable, & high quality work."),
         'https://github.com/jschiarizzi', 'Fourth Wave')
    ]

    gitcoin_description = _(
        "A community at the intersection of blockchain and open source. A place for developers to collaborate in a new system, where open source money builds in monetization for open source repositories."
    )

    context = {
        'onboard_slides': onboard_slides,
        'activities': get_activities(),
        'is_outside': True,
        'slides': slides,
        'slideDurationInMs': 6000,
        'active': 'bounties_funder',
        'hide_newsletter_caption': True,
        'hide_newsletter_consent': True,
        'gitcoin_description': gitcoin_description,
        'newsletter_headline': _("Get the Latest Gitcoin News! Join Our Newsletter."),
        'meta_title': "Grow Open Source: Find Freelance Developers & Open Source Bug Bounties - Gitcoin",
        'meta_description': "The Gitcoin platform connects freelance developers with open bug bounties or online jobs, paid in crypto (ETH). Leverage a global workforce to quickly complete software development and coding jobs."
    }
    return TemplateResponse(request, 'bounties/funder.html', context)

def contributor_bounties_redirect(request, tech_stack):
    return redirect(contributor_bounties, tech_stack= '/'+ tech_stack)

def contributor_bounties(request, tech_stack):

    onboard_slides = [
        {
            'img': static("v2/images/presskit/illustrations/regulus-white.svg"),
            'title': _('Are you a funder or project organizer?'),
            'subtitle': _('Fund your OSS bounties and get work done!'),
            'type': 'funder',
            'active': 'active',
            'more': '/bounties/funder'
        },
        {
            'img': static("v2/images/presskit/illustrations/prime.svg"),
            'title': _('Are you a developer or designer?'),
            'subtitle': _('Contribute to exciting OSS project and get paid!'),
            'type': 'contributor',
            'more': '/how/contributor'
        }
    ]

    slides = [
        ("Daniel", static("v2/images/testimonials/gitcoiners/daniel.jpeg"),
         _("When I found Gitcoin I was gladly surprised that it took one thing and did it well. \
         It took the Ethereum tech and used it as a bridge to technology with open source Jobs.  \
         Even though Gitcoin is still in it’s early stages, I think it’s filled with potential to grow."),
         'https://github.com/dmerrill6'),
        ("CryptoMental", static("v2/images/testimonials/gitcoiners/cryptomental.png"),
         _(" think the great thing about GitCoin is how easy it is for projects to reach out to worldwide talent. \
         GitCoin helps to find people who have time to contribute and increase speed of project development. \
         Thanks to GitCoin a bunch of interesting OpenSource projects got my attention!"),
         'https://github.com/cryptomental'),
        ("Elan", static("v2/images/testimonials/gitcoiners/elan.jpeg"),
         _("The bounty process with Gitcoin is pretty amazing.  Just go on the website, find an issue you can \
         work on, you claim it.  All you do then is submit your code to Github, get the code merged.  \
         Once it’s merged, the smart contract kicks in and sends the money to your Ethereum account.  \
         The whole process is pretty smooth.  There’s a giant slack community.  It puts the freelance \
         market back in the hands of the community!"),
         "https://github.com/elaniobro"),
        ("Jack", static("v2/images/testimonials/gitcoiners/jack.jpeg"),
         _("I really like Gitcoin because it’s allowed me to get involved in some really interesting \
         Open Source Projects.  I’ve written code for MyEtherWallet and Gitcoin itself.  \
         I think Gitcoin is becoming a great asset for the Ethereum ecosystem."),
         'https://github.com/jclancy93'),
        ("Miguel Angel Rodriguez Bermudez", static("v2/images/testimonials/gitcoiners/miguel.jpeg"),
         _("I came across Gitcoin 3 months ago.  I was hearing lots of ideas about projects involving \
         cryptocurrencies, and I kept thinking \"what about open source projects?\".  I see Gitcoin as \
         the next level of freelance, where you can not only help repos on Github, but get money out of \
         it.  It is that simple and it works."),
         'https://github.com/marbrb'),
        ("Octavio Amuchástegui", static("v2/images/testimonials/gitcoiners/octavioamu.jpeg"),
         _("I'm in love with Gitcoin. It isn't only a platform, it's a community that gives me the \
         opportunity to open my network and work with amazing top technology projects and earn some \
         money in a way I'm visible to the dev community and work opportunities. Open source is amazing, \
         and is even better to make a living from it, I think is the future of development."),
         'https://github.com/octavioamu')
    ]

    gitcoin_description = _(
        "A community for developers to collaborate and monetize their skills while working \
        on Open Source projects through bounties."
    )

    projects = [
        {
            'name': 'Augur Logo',
            'source': 'v2/images/project_logos/augur.png'
        },
        {
            'name': 'Bounties Logo',
            'source': 'v2/images/project_logos/bounties.png'
        },
        {
            'name': 'Balance Logo',
            'source': 'v2/images/project_logos/balance.png'
        },
        {
            'name': 'Metamask Logo',
            'source': 'v2/images/project_logos/metamask.png'
        },
        {
            'name': 'uPort Logo',
            'source': 'v2/images/project_logos/uport.png'
        },
        {
            'name': 'Market Protocol Logo',
            'source': 'v2/images/project_logos/market.png'
        },
        {
            'name': 'Trust Wallet Logo',
            'source': 'v2/images/project_logos/trust.png'
        },
        {
            'name': 'MCrypto Logo',
            'source': 'v2/images/project_logos/mycrypto.png'
        },
        {
            'name': 'Truffle Logo',
            'source': 'v2/images/project_logos/truffle.png'
        },
        {
            'name': 'Solidity Logo',
            'source': 'v2/images/project_logos/solidity.png'
        },
        {
            'name': 'Casper Logo',
            'source': 'v2/images/project_logos/casper.png'
        },
        {
            'name': 'Wyvern Logo',
            'source': 'v2/images/project_logos/wyvern.png'
        },
        {
            'name': 'Ethereum Logo',
            'source': 'v2/images/project_logos/eth.png'
        },
        {
            'name': 'Livepeer Logo',
            'source': 'v2/images/project_logos/livepeer.png'
        },
        {
            'name': 'Raiden Logo',
            'source': 'v2/images/project_logos/raiden.png'
        },
        {
            'name': 'Databroker Logo',
            'source': 'v2/images/project_logos/databroker.png'
        }
    ]

    # tech_stack = '' #uncomment this if you wish to disable contributor specific LPs
    context = {
        'onboard_slides': onboard_slides,
        'slides': slides,
        'slideDurationInMs': 6000,
        'active': 'bounties_coder',
        'newsletter_headline': _("Be the first to find out about newly posted freelance jobs."),
        'hide_newsletter_caption': True,
        'hide_newsletter_consent': True,
        'gitcoin_description': gitcoin_description,
        'projects': projects,
        'contributor_list': [
            { 'link': "/python", 'text': "Python"},
            { 'link': "/javascript", 'text': "JavaScript"},
            { 'link': "/rust", 'text': "Rust"},
            { 'link': "/solidity", 'text': "Solidity"},
            { 'link': "/design", 'text': "Design"},
            { 'link': "/html", 'text': "HTML"},
            { 'link': "/ruby", 'text': "Ruby"},
            { 'link': "/css", 'text': "CSS"},
        ]
    }

    if tech_stack == 'new':
        return redirect('new_funding_short')

    try:
        new_context = JSONStore.objects.get(view='contributor_landing_page', key=tech_stack).data

        for key, value in new_context.items():
            context[key] = value
    except Exception as e:
        logger.exception(e)
        raise Http404

    return TemplateResponse(request, 'bounties/contributor.html', context)

def get_contributor_landing_page_context(tech_stack):
    available_bounties_count = open_bounties().count()
    available_bounties_worth = amount_usdt_open_work()
    activities = get_activities(tech_stack)
    return {
        'activities': activities,
        'title': tech_stack.title() + str(_(" Open Source Opportunities")) if tech_stack else str(_("Open Source Opportunities")),
        'available_bounties_count': available_bounties_count,
        'available_bounties_worth': available_bounties_worth,
        'tech_stack': tech_stack,

    }

def how_it_works(request, work_type):
    """Show How it Works / Funder page."""
    if work_type not in ['funder', 'contributor']:
        raise Http404
    if work_type == 'contributor':
        title = _('How to Find & Complete Open Bounties | Gitcoin')
        desc = _('Learn how to get paid for open bug bounties and get paid in crypto (ETH or any ERC-20 token)')
    elif work_type == 'funder':
        title = _('How to Create & Fund Issues/Bounties | Gitcoin')
        desc = _('Learn how to create open bug bounties and get freelance developers to complete your job/task.')
    context = {
        'active': f'how_it_works_{work_type}',
        'title': title,
        'desc': desc
    }
    return TemplateResponse(request, 'how_it_works/index.html', context)

def robotstxt(request):
    hidden_profiles = list(JSONStore.objects.get(view='hidden_profiles').data)
    context = {
        'settings': settings,
        'hidden_profiles': hidden_profiles,
    }
    return TemplateResponse(request, 'robots.txt', context, content_type='text')

def about(request):
    core_team = [
        (
            "Kevin Owocki",
            "All the things",
            "owocki",
            "owocki",
            "The Community",
            "Avocado Toast",
            "kevin",
            "Summoner of Bots",
            "owocki",
            True
        ),
        (
            "Joe Lubin",
            "Consensys",
            "",
            "",
            "Meshiness",
            "",
            "joe",
            "Harbringer of Decentralization",
            "ethereumJoseph",
            True
        ),
        (
            "Alisa March",
            "User Experience Design",
            "PixelantDesign",
            "pixelant",
            "Tips",
            "Apple Cider Doughnuts",
            "alisa",
            "Pixel Mage",
            "pixelant",
            True
        ),
        (
            "Eric Berry",
            "OSS Funding",
            "coderberry",
            "ericberry",
            "Chrome/Firefox Extension",
            "Pastel de nata",
            "eric",
            "Burnout Healer",
            "coderberry",
            True
        ),
        (
            "Vivek Singh",
            "Community Buidl-er",
            "vs77bb",
            "vivek-singh-b5a4b675",
            "Gitcoin Requests",
            "Tangerine Gelato",
            "vivek",
            "Campfire StoryTeller",
            "vsinghdothings",
            True
        ),
        (
            "Aditya Anand M C",
            "Engineering",
            "thelostone-mc",
            "aditya-anand-m-c-95855b65",
            "The Community",
            "Cocktail Samosa",
            "aditya",
            "Block Welder",
            "thelostone_mc",
            True
        ),
        (
            "Scott Moore",
            "Biz Dev",
            "ceresstation",
            "scott-moore-a2970075",
            "Issue Explorer",
            "Teriyaki Chicken",
            "scott",
            "Phase Shifter",
            "notscottmoore",
            True
        ),
        (
            "Octavio Amuchástegui",
            "Front End Dev",
            "octavioamu",
            "octavioamu",
            "The Community",
            "Homemade italian pasta",
            "octavio",
            "Bugs Breeder",
            "octavioamu",
            True
        ),
        (
            "Frank Chen",
            "Data & Product",
            "frankchen07",
            "frankchen07",
            "Kudos!",
            "Crispy pork belly",
            "frank",
            "Hashed Scout",
            "",
            True
        ),
        (
            "Nate Hopkins",
            "Engineering",
            "hopsoft",
            None,
            "Bounties",
            "Chicken tikka masala",
            "nate",
            "Lord of Night's Watch",
            "hopsoft",
            True
        ),
        (
            "Alessandro Voto",
            "DevRel",
            "alexvotofuture",
            None,
            "Devvies",
            "Tacos",
            "alex",
            "Starship Captain",
            "avotofuture",
            True
        ),
        (
            "Dan Lipert",
            "Engineering",
            "danlipert",
            "danlipert",
            "EIP 1337",
            "Tantan Ramen",
            "dan",
            "Blockchain Artificer",
            "dan_lipert",
            True
        ),
        (
            "Connor O'Day",
            "DevRel",
            "connoroday",
            "connoroday",
            "the lols",
            "Robertas Pizza",
            "connor",
            "Druid of The Chain",
            "connoroday0",
            True
        ),
        (
            "Joseph Chen",
            "Operations",
            "josephchen",
            "josephchen",
            "Ethical Ads",
            "DIY",
            "joseph",
            "Arithmagician",
            "",
            True
        ),
        (
            "gitcoinbot",
            "beep boop bop",
            "gitcoinbot",
            "gitcoinbot",
            "everything that's automated",
            "bits",
            "gitcoinbot",
            "Loveable Companion",
            "",
            False
        )

    ]
    exclude_community = ['kziemiane', 'owocki', 'mbeacom']
    community_members = [
    ]
    leadeboardranks = LeaderboardRank.objects.filter(active=True, product='all', leaderboard='quarterly_earners').exclude(github_username__in=exclude_community).order_by('-amount').cache()[0: 15]
    for lr in leadeboardranks:
        package = (lr.avatar_url, lr.github_username, lr.github_username, '')
        community_members.append(package)

    alumnis = [
    ]
    for alumni in Alumni.objects.select_related('profile').filter(public=True).exclude(organization='gitcoinco').cache():
        package = (alumni.profile.avatar_url, alumni.profile.username, alumni.profile.username, alumni.organization)
        alumnis.append(package)

    context = {
        'core_team': core_team,
        'community_members': community_members,
        'alumni': alumnis,
        'total_alumnis': str(Alumni.objects.count()),
        'active': 'about',
        'title': 'About',
        'is_outside': True,
    }
    return TemplateResponse(request, 'about.html', context)

def mission(request):
    """Render the Mission response."""

    values = [
        {
            'name': _('Self Reliance'),
            'img': 'v2/images/mission/value/collaborative.svg',
            'alt': 'we-collobarate-icon'
        },
        {
            'name': _('Intellectual honesty'),
            'img': 'v2/images/mission/value/love_hands.svg',
            'alt': 'intellectual-honesty-icon'
        },
        {
            'name': _('Collaboration'),
            'img': 'v2/images/mission/value/humble.svg',
            'alt': 'humble-icon'
        },
        {
            'name': _('Empathy'),
            'img': 'v2/images/mission/value/empathetic.svg',
            'alt': 'empathy-icon'
        },
        {
            'name': _('Stress Reducers'),
            'img': 'v2/images/mission/value/stress_reducing.svg',
            'alt': 'stress-reduce-icon'
        },
        {
            'name': _('Inclusivity'),
            'img': 'v2/images/mission/value/inclusive.svg',
            'alt': 'inclusive-icon'
        },
        {
            'name': _('Giving first'),
            'img': 'v2/images/mission/value/give_first.svg',
            'alt': 'give-first-icon'
        }
    ]

    interactions = [
        {
            'text': _('We happen to the world. We don\'t let the world happen to us.'),
            'img': 'v2/images/mission/interact/world.svg',
            'alt': 'world-icon'
        },
        {
            'text': _('We show, don\'t tell.'),
            'img': 'v2/images/mission/interact/book.svg',
            'alt': 'openness-icon'
        },
        {
            'text': _('We are thoughtful, clear, and direct.'),
            'img': 'v2/images/mission/interact/head.svg',
            'alt': 'thoughtful-icon'
        },
        {
            'text': _('We seek balance.'),
            'img': 'v2/images/mission/interact/scale.svg',
            'alt': 'balance-icon'
        },
        {
            'text': _('We challenge the status quo & are willing to be challenged.'),
            'img': 'v2/images/mission/interact/goal.svg',
            'alt': 'goal-icon'
        },
        {
            'text': _('We fix things twice.'),
            'img': 'v2/images/mission/interact/hammer.svg',
            'alt': 'fix-twicw-icon'
        },
        {
            'text': _('We identify and validate our assumptions.'),
            'img': 'v2/images/mission/interact/microscope.svg',
            'alt': 'microscope-icon'
        },
        {
            'text': _('We care about people (not just tasks).'),
            'img': 'v2/images/mission/interact/people_care.svg',
            'alt': 'care-icon'
        },
        {
            'text': _('We listen.'),
            'img': 'v2/images/mission/interact/hear.svg',
            'alt': 'microscope-icon'
        },
        {
            'text': _('We value pragmatism over dogmatism.'),
            'img': 'v2/images/mission/interact/swiss_army.svg',
            'alt': 'pargma-icon'
        }
    ]

    context = {
        'is_outside': True,
        'active': 'mission',
        'title': 'Mission',
        'card_title': _('Gitcoin is a mission-driven organization.'),
        'card_desc': _('Our mission is to grow open source.'),
        'avatar_url': static('v2/images/grow_open_source.png'),
        'values': values,
        'interactions': interactions
    }
    return TemplateResponse(request, 'mission.html', context)

def jobs(request):
    job_listings = Job.objects.filter(active=True)
    context = {
        'active': 'jobs',
        'title': 'Jobs',
        'job_listings': job_listings
    }
    return TemplateResponse(request, 'jobs.html', context)

def vision(request):
    """Render the Vision response."""
    videoLinks = [
        'https://www.youtube.com/embed/wo0KkSH-6eg',
        'https://www.youtube.com/embed/nZTVMEh9k5U',
        'https://www.youtube.com/embed/F2yeOFlRE0E'
    ]
    context = {
        'is_outside': True,
        'active': 'vision',
        'avatar_url': static('v2/images/vision/triangle.jpg'),
        'title': 'Vision',
        'videoLinks': videoLinks,
        'card_title': _("Gitcoin's Vision for a Web3 World"),
        'card_desc': _("Gitcoin's Vision for a web3 world is to make it easy for developers to find paid work in open source."),
    }
    return TemplateResponse(request, 'vision.html', context)

def avatar(request):
    """Render the avatar response."""
    from avatar.models import AvatarTheme

    default_back = get_leaderboard_back(request)
    back = request.GET.get('back', default_back[1])
    img = request.GET.get('img', default_back[0])

    context = {
        'is_outside': True,
        'active': 'avatar',
        'title': 'Avatar Builder',
        'card_title': _("Free Avatar Builder"),
        'card_desc': _('Gitcoin\'s Free Avatar Creator is an online tool to build a character for yourself.  It has dozens of options to show off your bad-self.  No strings attached, Always free.'),
        'avatar_url': "https://c.gitcoin.co/avatars/d1a33d2bcb7bbfef50368bca73111fae/fryggr.png",
        'back': back,
        'img': img,
        'avatar_options': AvatarTheme.objects.filter(active=True).order_by('-popularity'),
    }
    return TemplateResponse(request, 'avatar_landing.html', context)

def get_leaderboard_back(request):
    default_back_safe = [['s10.png', i] for i in range(24, 33)]
    default_back_crazy = [['s9.png', 3], ['s10.png', 10], ['s10.png', 25], ['s10.png', 33], ['s10.png', 4], ['s10.png', 8], ['s9.png', 14]]
    default_back = default_back_safe

    default_back_i = int(request.GET.get('i', int(timezone.now().strftime("%j")))) % len(default_back)
    default_back = default_back[default_back_i]
    return default_back

def products(request):
    """Render the Products response."""
    products = [
        {
            'name': 'Town Square',
            'heading': _("A Web3-enabled social networking bazaar."),
            'description': _("Gitcoin offers social features that uses mechanism design create a community that #GivesFirst."),
            'link': 'https://gitcoin.co/townsquare',
            'img': static('v2/images/products/social.png'),
            'logo': static('v2/images/helmet.svg'),
            'service_level': '',
            'traction': '100s of posts per day',
        },
        {
            'name': 'Chat',
            'heading': _("Reach your favorite Gitcoiner's in realtime.."),
            'description': _("Gitcoin Chat is an enterprise-grade solution to connect with your favorite Gitcoiners in realtime.  Download the mobile apps to stay connected on the go!"),
            'link': 'https://gitcoin.co/chat/landing',
            'img': static('v2/images/products/chat.png'),
            'logo': static('v2/images/helmet.svg'),
            'service_level': '',
            'traction': '100s of DAUs',
        },
        {
            'name': 'hackathons',
            'heading': _("Hack with the best companies in web3."),
            'description': _("Gitcoin offers Virtual Hackathons about once a month; Earn Prizes by working with some of the best projects in the decentralization space."),
            'link': 'https://hackathons.gitcoin.co',
            'img': static('v2/images/products/graphics-hackathons.png'),
            'logo': static('v2/images/products/hackathons-logo.svg'),
            'service_level': 'Full Service',
            'traction': '1-3 hacks/month worth $40k/mo',
        },
        {
            'name': 'grants',
            'heading': _("Sustainable funding for open source"),
            'description': _("Gitcoin Grants are a fast, easy & secure way to provide recurring token \
                            contributions to your favorite OSS maintainers. Plus, with our NEW quarterly $100k+ matching funds it's now even easier to fund your OSS work! "),
            'link': '/grants',
            'img': static('v2/images/products/graphics-Grants.png'),
            'logo': static('v2/images/products/grants-logo.svg'),
            'service_level': 'Self Service',
            'traction': 'over $1mm in GMV',
        },
        {
            'name': 'kudos',
            'heading': _("Show your appreciation with collectible tokens"),
            'description': _("Kudos is a way of showing your appreciation to another Gitcoin member.\
                            It's also a way to showcase special skills that a member might have."),
            'link': '/kudos',
            'img': static('v2/images/products/graphics-Kudos.png'),
            'logo': static('v2/images/products/kudos-logo.svg'),
            'service_level': 'Self Service',
            'traction': '1200+ kudos sent/month',
        },
        {
            'name': 'bounties',
            'heading': _("Solve bounties. Get paid. Contribute to open source"),
            'description': _("Collaborate and monetize your skills while working on Open Source projects \
                            through bounties."),
            'link': '/explorer',
            'img': static('v2/images/products/graphics-Bounties.png'),
            'logo': static('v2/images/products/gitcoin-logo.svg'),
            'service_level': 'Self Service',
            'traction': '$25k/mo',
        },
        {
            'name': 'codefund',
            'heading': _("Ethical advertising for developers"),
            'description': _("CodeFund is an open source ad platform that funds contributors of the open \
                            source ecosystem"),
            'link': 'https://codefund.app/',
            'img': static('v2/images/products/graphics-Codefund.svg'),
            'logo': static('v2/images/products/codefund-logo.svg'),
            'service_level': 'Self Service or Full Service',
            'traction': 'over 300mm impressions',
        },
        {
            'name': 'matching engine',
            'heading': _("Find the Right Dev. Every Time."),
            'description': _("It's not about finding *a* developer.  It's about finding *the right developer for your needs*. Our matching engine powers each of our products, and can target the right community members for you."),
            'link': '/users',
            'img': static('v2/images/products/engine.svg'),
            'logo': static('v2/images/products/engine-logo.png'),
            'service_level': 'Integrated',
            'traction': 'Matching 20k devs/mo',
        },
        {
            'name': 'labs',
            'heading': _("Tools for busy developers"),
            'description': _("Gitcoin Labs provides research reports and toolkits for busy developers, \
                            making Ethereum dapps fast, usable, and secure."),
            'link': '/labs',
            'img': static('v2/images/products/graphics-Labs.png'),
            'logo': static('v2/images/products/labs-logo.svg'),
            'service_level': 'Self Service',
            'traction': '12 Articles Shipped',
        }
    ]

    if settings.QUESTS_LIVE:
        products.append({
            'name': 'quests',
            'heading': _("Engaging Onboarding Experiences for the Web3 Ecosystem"),
            'description': _("Gitcoin Quests is a fun, gamified way to learn about the web3 ecosystem, earn rewards, and level up your decentralization-fu!"),
            'link': '/quests',
            'img': static('v2/images/products/graphics-Quests.png'),
            'logo': static('v2/images/products/quests-symbol.svg'),
            'service_level': 'Self Service',
            'traction': 'over 3000 plays/month',
        })

    default_back = get_leaderboard_back(request)
    back = request.GET.get('back', default_back[1])
    img = request.GET.get('img', default_back[0])

    context = {
        'is_outside': True,
        'active': 'products',
        'title': 'Products',
        'card_title': _("Gitcoin's Products."),
        'card_desc': _('At Gitcoin, we build products that allow for better incentivized collaboration \
                        in the realm of open source software'),
        'avatar_url': f"/static/v2/images/quests/backs/back{back}.jpeg",
        'back': back,
        'img': img,
        'products': products,
    }
    return TemplateResponse(request, 'products.html', context)

def not_a_token(request):
    """Render the not_a_token response."""
    context = {
        'is_outside': True,
        'active': 'not_a_token',
        'avatar_url': static('v2/images/no-token/no-token.jpg'),
        'title': 'Gitcoin is not a token',
        'card_title': _("Gitcoin is not a token"),
        'card_desc': _("We didn't do a token because we felt it wasn't the right way to align incentives \
                        with our user base.  Read more about the future of monetization in web3."),
    }
    return TemplateResponse(request, 'not_a_token.html', context)

def results(request, keyword=None):
    """Render the Results response."""
    if keyword and keyword not in programming_languages:
        raise Http404
    js = JSONStore.objects.get(view='results', key=keyword)
    context = js.data
    context['updated'] = js.created_on
    context['is_outside'] = True
    context['prefix'] = 'data-'
    import json
    context['avatar_url'] = static('v2/images/results_preview.gif')
    return TemplateResponse(request, 'results.html', context)

def get_specific_activities(what, trending_only, user, after_pk, request=None):
    # create diff filters
    activities = Activity.objects.filter(hidden=False).order_by('-created_on')
    view_count_threshold = 10

    is_auth = user and user.is_authenticated

    ## filtering
    relevant_profiles = []
    relevant_grants = []
    if what == 'tribes':
        relevant_profiles = get_my_earnings_counter_profiles(user.profile.pk) if is_auth else []
    elif what == 'all_grants':
        activities = activities.filter(grant__isnull=False)
    elif what == 'grants':
        relevant_grants = get_my_grants(user.profile) if is_auth else []
    elif what == 'my_threads' and is_auth:
        activities = user.profile.subscribed_threads.all().order_by('-created') if is_auth else []
    elif what == 'my_favorites' and is_auth:
        favorites = user.favorites.all().values_list('activity_id')
        activities = Activity.objects.filter(id__in=Subquery(favorites)).order_by('-created')
    elif 'keyword-' in what:
        keyword = what.split('-')[1]
        relevant_profiles = Profile.objects.filter(keywords__icontains=keyword)
    elif 'search-' in what:
        keyword = what.split('-')[1]
        view_count_threshold = 5
        base_filter = Q(metadata__icontains=keyword, activity_type__in=connect_types)
        keyword_filter = Q(pk=0) #noop
        if keyword == 'meme':
            keyword_filter = Q(metadata__type='gif') | Q(metadata__type='png') | Q(metadata__type='jpg')
        if keyword == 'meme':
            keyword_filter = Q(metadata__icontains='spotify') | Q(metadata__type='soundcloud') | Q(metadata__type='pandora')
        activities = activities.filter(keyword_filter | base_filter)
    elif 'tribe:' in what:
        key = what.split(':')[1]
        profile_filter = Q(profile__handle=key.lower())
        other_profile_filter = Q(other_profile__handle=key.lower())
        keyword_filter = Q(metadata__icontains=key)
        activities = activities.filter(keyword_filter | profile_filter | other_profile_filter)
    elif 'activity:' in what:
        view_count_threshold = 0
        pk = what.split(':')[1]
        activities = Activity.objects.filter(pk=pk)
        if request:
            page = int(request.GET.get('page', 1))
            if page > 1:
                activities = Activity.objects.none()
    elif 'hackathon:' in what:
        pk = what.split(':')[1]
        activities = activities.filter(activity_type__in=connect_types).filter(Q(hackathonevent=pk) | Q(bounty__event=pk))
    elif ':' in what:
        pk = what.split(':')[1]
        key = what.split(':')[0] + "_id"
        if key == 'activity_id':
            key = 'pk'
        kwargs = {}
        kwargs[key] = pk
        activities = activities.filter(**kwargs)

    # filters
    if len(relevant_profiles):
        activities = activities.filter(profile__in=relevant_profiles)
    if len(relevant_grants):
        activities = activities.filter(grant__in=relevant_grants)
    if what == 'connect':
        activities = activities.filter(activity_type__in=connect_types)
    if what == 'kudos':
        activities = activities.filter(activity_type__in=['new_kudos', 'receive_kudos'])

    # after-pk filters
    if after_pk:
        activities = activities.filter(pk__gt=after_pk)
    if trending_only:
        if what == 'everywhere':
            view_count_threshold = 40
        activities = activities.filter(view_count__gt=view_count_threshold)

    return activities

def activity(request):
    """Render the Activity response."""
    page_size = 7
    page = int(request.GET.get('page', 1))
    what = request.GET.get('what', 'everywhere')
    trending_only = int(request.GET.get('trending_only', 0))

    activities = get_specific_activities(what, trending_only, request.user, request.GET.get('after-pk'), request)
    activities = activities.prefetch_related('profile', 'likes', 'comments', 'kudos', 'grant', 'subscription', 'hackathonevent')

    # store last seen
    if activities.exists():
        last_pk = activities.first().pk
        current_pk = request.session.get(what)
        next_pk = last_pk if (not current_pk or current_pk < last_pk) else current_pk
        request.session[what] = next_pk
    # pagination
    next_page = page + 1
    start_index = (page-1) * page_size
    end_index = page * page_size

    #p = Paginator(activities, page_size)
    #page = p.get_page(page)
    page = activities[start_index:end_index]
    suppress_more_link = not len(page)

    # increment view counts
    activities_pks = [obj.pk for obj in page]
    if len(activities_pks):
        increment_view_counts.delay(activities_pks)

    context = {
        'suppress_more_link': suppress_more_link,
        'what': what,
        'next_page': next_page,
        'page': page,
        'target': f'/activity?what={what}&trending_only={trending_only}&page={next_page}',
        'title': _('Activity Feed'),
        'my_tribes': list(request.user.profile.tribe_members.values_list('org__handle',flat=True)) if request.user.is_authenticated else [],
    }
    context["activities"] = [a.view_props_for(request.user) for a in page]

    return TemplateResponse(request, 'activity.html', context)

@ratelimit(key='ip', rate='30/m', method=ratelimit.UNSAFE, block=True)
def create_status_update(request):
    issue_re = re.compile(r'^(?:https?://)?(?:github\.com)/(?:[\w,\-,\_]+)/(?:[\w,\-,\_]+)/issues/(?:[\d]+)')
    response = {}

    if request.POST:
        profile = request.user.profile
        title = request.POST.get('data')
        resource = request.POST.get('resource', '')
        provider = request.POST.get('resourceProvider', '')
        resource_id = request.POST.get('resourceId', '')

        kwargs = {
            'activity_type': 'status_update',
            'metadata': {
                'title': title,
                'ask': request.POST.get('ask'),
                'fund_able': provider and issue_re.match(provider) != None,
                'resource': {
                    'type': resource,
                    'provider': provider,
                    'id': resource_id
                }
            }
        }

        if resource == 'content':
            meta = kwargs['metadata']['resource']
            meta['title'] = request.POST.get('title', '')
            meta['description'] = request.POST.get('description', '')
            meta['image'] = request.POST.get('image', '')

        kwargs['profile'] = profile
        if ':' in request.POST.get('what'):
            what = request.POST.get('what')
            key = what.split(':')[0]
            result = what.split(':')[1]
            if key and result:
                key = f"{key}_id"
                kwargs[key] = result
                kwargs['activity_type'] = 'wall_post'

        if request.POST.get('has_video'):
            kwargs['metadata']['video'] = True
            kwargs['metadata']['gfx'] = request.POST.get('video_gfx')

        if request.POST.get('option1'):
            poll_choices = []
            for i in range(1, 5):
                key = "option" + str(i)
                val = request.POST.get(key)
                if val:
                    poll_choices.append({
                        'question': val,
                        'answers': [],
                        'i': i,
                        })
            kwargs['metadata']['poll_choices'] = poll_choices

        if ':' in request.POST.get('tab', ''):
            tab = request.POST.get('tab')
            key = tab.split(':')[0]
            result = tab.split(':')[1]
            if key == 'hackathon':
                kwargs['hackathonevent'] = HackathonEvent.objects.get(pk=result)
            if key == 'tribe':
                kwargs['other_profile'] = Profile.objects.get(handle=result.lower())

        try:
            activity = Activity.objects.create(**kwargs)
            response['status'] = 200
            response['message'] = 'Status updated!'

            mentioned_profiles = get_profiles_from_text(title).exclude(user__in=[request.user])
            to_emails = set(mentioned_profiles.values_list('email', flat=True))
            mention_email(activity, to_emails)

            if kwargs['activity_type'] == 'wall_post':
                if 'Email Grant Funders' in activity.metadata.get('ask'):
                    grant_update_email_task.delay(activity.pk)
                else:
                    wall_post_email(activity)

        except Exception as e:
            response['status'] = 400
            response['message'] = 'Bad Request'
            logger.error('Status Update error - Error: (%s) - Handle: (%s)', e, profile.handle if profile else '')
            return JsonResponse(response, status=400)
    return JsonResponse(response)

def grant_redir(request):
    return redirect('/grants/')

def help(request):
    return redirect('/wiki/')

def verified(request):
    user = request.user if request.user.is_authenticated else None
    profile = request.user.profile if user and hasattr(request.user, 'profile') else None

    context = {
        'active': 'verified',
        'title': _('Verified'),
        'profile': profile,
    }
    return TemplateResponse(request, 'verified.html', context)

def presskit(request):

    brand_colors = [
        (
            "Cosmic Teal",
            "#25e899",
            "37, 232, 153"
        ),
        (
            "Dark Cosmic Teal",
            "#0fce7c",
            "15, 206, 124"
        ),
        (
            "Milky Way Blue",
            "#15003e",
            "21, 0, 62"
        ),
        (
            "Stardust Yellow",
            "#FFCE08",
            "255,206, 8"
        ),
        (
            "Polaris Blue",
            "#3E00FF",
            "62, 0, 255"
        ),
        (
            "Vinus Purple",
            "#8E2ABE",
            "142, 42, 190"
        ),
        (
            "Regulus Red",
            "#F9006C",
            "249, 0, 108"
        ),
        (
            "Star White",
            "#FFFFFF",
            "23, 244, 238"
        ),
    ]

    context = {
        'brand_colors': brand_colors,
        'active': 'get',
        'title': _('Presskit'),
    }
    return TemplateResponse(request, 'presskit.html', context)

def handler403(request, exception=None):
    return error(request, 403)

def handler404(request, exception=None):
    return error(request, 404)

def handler500(request, exception=None):
    return error(request, 500)

def handler400(request, exception=None):
    return error(request, 400)

def error(request, code):
    context = {
        'active': 'error',
        'code': code,
        'nav': 'home',
    }
    context['title'] = "Error {}".format(code)
    return_as_json = 'api' in request.path

    if return_as_json:
        return JsonResponse(context, status=500)
    return TemplateResponse(request, 'error.html', context, status=code)

def portal(request):
    return redirect('https://gitcoin.co/help')

def community(request):
    return redirect('https://github.com/gitcoinco/community')

def onboard(request):
    return redirect('https://docs.google.com/document/d/1DQvek5TwASIp1njx5VZeLKEgSxfvxm871vctx1l_33M/edit?')

def podcast(request):
    return redirect('https://itunes.apple.com/us/podcast/gitcoin-community/id1360536677')

def feedback(request):
    return redirect('https://goo.gl/forms/9rs9pNKJDnUDYEeA3')

def wallpaper(request):
    return redirect('https://gitcoincontent.s3-us-west-2.amazonaws.com/Wallpapers.zip')

def help_dev(request):
    return redirect('/wiki')

def help_pilot(request):
    return redirect('/wiki')

def help_repo(request):
    return redirect('/wiki')

def help_faq(request):
    return redirect('/wiki')

def browser_extension_chrome(request):
    return redirect('https://chrome.google.com/webstore/detail/gdocmelgnjeejhlphdnoocikeafdpaep')

def browser_extension_firefox(request):
    return redirect('https://addons.mozilla.org/en-US/firefox/addon/gitcoin/')

def itunes(request):
    return redirect('https://itunes.apple.com/us/app/gitcoin/id1319426014')

def casestudy(request):
    return redirect('https://docs.google.com/document/d/1M8-5xCGoJ8u-k0C0ncx_dr9LtHwZ32Ccn3KMFtEnsBA/edit')

def schwag(request):
    return redirect('https://goo.gl/forms/X3jAtOVUUNAumo072')

def slack(request):
    context = {
        'active': 'slack',
        'msg': None,
        'nav': 'home',
    }

    if request.POST:
        email = request.POST.get('email')
        context['msg'] = _('You must provide an email address')
        if email:
            context['msg'] = _('Your invite has been sent.')
            context['success'] = True
            try:
                validate_email(email)
                get_or_save_email_subscriber(email, 'slack', send_slack_invite=False)
                response = invite_to_slack(email)

                if not response.get('ok'):
                    context['msg'] = response.get('error', _('Unknown error'))
                context['success'] = False
            except ValidationError:
                context['msg'] = _('Invalid email')

    return TemplateResponse(request, 'slack.html', context)

@csrf_exempt
def newtoken(request):
    context = {
        'active': 'newtoken',
        'msg': None,
    }

    if request.POST:
        required_fields = ['email', 'terms', 'not_security', 'address', 'symbol', 'decimals', 'network']
        validtion_passed = True
        for key in required_fields:
            if not request.POST.get(key):
                context['msg'] = str(_('You must provide the following fields: ')) + key
                validtion_passed = False
        if validtion_passed:
            obj = Token.objects.create(
                address=request.POST['address'],
                symbol=request.POST['symbol'],
                decimals=request.POST['decimals'],
                network=request.POST['network'],
                approved=False,
                priority=1,
                metadata={
                    'ip': get_ip(request),
                    'email': request.POST['email'],
                    }
                )
            new_token_request(obj)
            context['msg'] = str(_('Your token has been submitted and will be listed within 2 business days if it is accepted.'))

    return TemplateResponse(request, 'newtoken.html', context)

def btctalk(request):
    return redirect('https://bitcointalk.org/index.php?topic=2206663')

def reddit(request):
    return redirect('https://www.reddit.com/r/gitcoincommunity/')

def blog(request):
    return redirect('https://gitcoin.co/blog')

def livestream(request):
    return redirect('https://calendar.google.com/calendar/r?cid=N3JxN2dhMm91YnYzdGs5M2hrNjdhZ2R2ODhAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ')

def twitter(request):
    return redirect('http://twitter.com/gitcoin')

def fb(request):
    return redirect('https://www.facebook.com/GetGitcoin/')

def medium(request):
    return redirect('https://medium.com/gitcoin')

def refer(request):
    return redirect('https://gitcoin.co/funding/details?url=https://github.com/gitcoinco/gitcoinco/issues/1')

def gitter(request):
    return redirect('https://gitter.im/gitcoinco/Lobby')

def github(request):
    return redirect('https://github.com/gitcoinco/')

def youtube(request):
    return redirect('https://www.youtube.com/channel/UCeKRqRjzSzq5yP-zUPwc6_w')

def web3(request):
    return redirect('https://www.youtube.com/watch?v=cZZMDOrIo2k')

@cached_view_as(Token.objects.filter(network=get_default_network, approved=True))
def tokens(request):
    context = {}
    networks = ['mainnet', 'ropsten', 'rinkeby', 'unknown', 'custom']
    for network in networks:
        key = f"{network}_tokens"
        context[key] = Token.objects.filter(network=network, approved=True)
    return TemplateResponse(request, 'tokens_js.txt', context, content_type='text/javascript')

@csrf_exempt
@ratelimit(key='ip', rate='5/m', method=ratelimit.UNSAFE, block=True)
def increase_funding_limit_request(request):
    user = request.user if request.user.is_authenticated else None
    profile = request.user.profile if user and hasattr(request.user, 'profile') else None
    usdt_per_tx = request.GET.get('usdt_per_tx', None)
    usdt_per_week = request.GET.get('usdt_per_week', None)
    is_staff = user.is_staff if user else False

    if is_staff and usdt_per_tx and usdt_per_week:
        try:
            profile_pk = request.GET.get('profile_pk', None)
            target_profile = Profile.objects.get(pk=profile_pk)
            target_profile.max_tip_amount_usdt_per_tx = usdt_per_tx
            target_profile.max_tip_amount_usdt_per_week = usdt_per_week
            target_profile.save()
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=400)

        return JsonResponse({'msg': _('Success')}, status=200)

    if request.body:
        if not user or not profile or not profile.handle:
            return JsonResponse(
                {'error': _('You must be Authenticated via Github to use this feature!')},
                status=401)

        try:
            result = FundingLimitIncreaseRequestForm(json_parse(request.body))
            if not result.is_valid():
                raise
        except Exception as e:
            return JsonResponse({'error': _('Invalid JSON.')}, status=400)

        new_funding_limit_increase_request(profile, result.cleaned_data)

        return JsonResponse({'msg': _('Request received.')}, status=200)

    form = FundingLimitIncreaseRequestForm()
    params = {
        'form': form,
        'title': _('Request a Funding Limit Increase'),
        'card_title': _('Gitcoin - Request a Funding Limit Increase'),
        'card_desc': _('Do you hit the Funding Limit? Request a increasement!')
    }

    return TemplateResponse(request, 'increase_funding_limit_request_form.html', params)

@staff_member_required
def tribes(request):
    plans= [
        {
            'type': 'lite',
            'img': static('v2/images/tribes/landing/plan-lite.svg'),
            'price': '10k',
            'features': [
                '1 Hackthon Credit'
            ],
            'features_na': [
                'Access to Gitcoin Pro Tools'
            ]
        },
        {
            'type': 'pro',
            'img': static('v2/images/tribes/logo.svg'),
            'discount': '40%',
            'price': '6k',
            'features': [
                {
                    'title': '3 Hackathon Credits',
                    'info': '18k year total'
                },
                'Access to Gitcoin Pro Tools'
            ]
        },
        {
            'type': 'launch',
            'img': static('v2/images/tribes/landing/plan-launch.svg'),
            'price': '4k',
            'features': [
                {
                    'title': '5 Hackathon Credits',
                    'info': '20k year total'
                },
                'Access to Gitcoin Pro Tools'
            ]
        }
    ]

    tribes = JSONStore.objects.get(view='tribes', key='tribes').data

    testimonials = [
        {
            'text': 'I had a lot of fun (during Beyond Blockchain) meeting people and building tangible rapidly. Glad to have a winning submission!',
            'author': 'VirajA',
            'designation': 'Hacker',
            'photo': static('v2/images/tribes/landing/viraj.png')
        },
        {
            'text': 'Gitcoin has a fantastic community that is our target audience -- Web 3 developers who want to build.',
            'author': 'Sam Williams',
            'designation': 'CEO, Arweave',
            'photo':  static('v2/images/tribes/landing/sam.jpg'),
            'org_photo': static('v2/images/project_logos/arweave.svg')
        },
        {
            'text': 'Relationships with developers" is our guiding light. For both developers and ourselves, it’s great to work with GItcoin to see more working examples using Portis.',
            'author': 'Scott Gralnick',
            'designation': 'Co-Founder, Portis',
            'photo': static('v2/images/tribes/landing/scott.png'),
            'org_photo': static('v2/images/project_logos/portis.png')
        }
    ]

    reasons = [
        {
            'title': 'Hackathon',
            'img': static('v2/images/tribes/landing/hackathon.svg'),
            'info': 'See meaningful projects come to life on your dapp'
        },
        {
            'title': 'Suggest Bounty',
            'img': static('v2/images/tribes/landing/suggest.svg'),
            'info': 'Get bottoms up ideas from passionate contributors'
        },
        {
            'title': 'Grow Tribe',
            'img': static('v2/images/tribes/landing/grow.svg'),
            'info': 'Work seamlessly with your core contributors'
        },
        {
            'title': 'Workshops',
            'img': static('v2/images/tribes/landing/workshop.svg'),
            'info': 'Host workshops and learn together'
        },
        {
            'title': 'Chat',
            'img': static('v2/images/tribes/landing/chat.svg'),
            'info': 'Direct connection to your trusted tribe'
        },
        {
            'title': 'Town Square',
            'img': static('v2/images/tribes/landing/townsquare.svg'),
            'info': 'Broadcast your priorities and engagey our tribe'
        },
        {
            'title': 'Payout/Fund',
            'img': static('v2/images/tribes/landing/payout.svg'),
            'info': 'Easily co-manage hackathons with your team'
        },
        {
            'title': 'Stats Report',
            'img': static('v2/images/tribes/landing/stats.svg'),
            'info': 'See how your hackathons are performing'
        }
    ]

    context = {
        'plans': plans,
        'tribes': tribes,
        'testimonials': testimonials,
        'reasons': reasons
    }

    return TemplateResponse(request, 'tribes/landing.html', context)


import json
import os
import re
import threading
import time
from pathlib import Path

import cv2
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

from nonverbal_communication_analysis.environment import (DATASET_SYNC,
                                                          VALID_VIDEO_TYPES,
                                                          VIDEO_OUTPUT_DIR)
from nonverbal_communication_analysis.m0_Classes.Experiment import Experiment
from nonverbal_communication_analysis.utils import log

class Worker(threading.Thread):
    def __init__(self, worker_id, camera, video_cap, output_directory, verbose: bool = False, prettify: bool = False, display: bool = False):
        threading.Thread.__init__(self)
        self.worker_id = worker_id
        self.camera = camera
        self.video_cap = video_cap
        self.output_directory = output_directory

        self.verbose = verbose
        self.prettify = prettify
        self.display = display

        self.previous_frame = None
        self.current_frame = None
        self.frame_idx = 0

        self.cumulative_energy_frame = None

    def frame_energy(self, current_frame):
        frame_energy = np.zeros(current_frame.shape[:2], np.int)

        if self.previous_frame is None:
            return frame_energy

        frame_diff = cv2.absdiff(self.previous_frame, current_frame)
        gs_frame_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
        _, frame_energy = cv2.threshold(
            gs_frame_diff, 127, 1, cv2.THRESH_BINARY)
        return frame_energy

    def save_frame(self, frame_data, output_directory):
        os.makedirs(output_directory, exist_ok=True)
        output_frame_file = output_directory / \
            ("frame_%.12d_processed.json" % (self.frame_idx))

        metrics_dict = dict()
        metrics_dict["energy"] = int(np.sum(frame_data))

        obj = dict()
        obj["frame"] = self.frame_idx
        obj["group"] = metrics_dict

        if self.prettify:
            json.dump(obj, open(output_frame_file, 'w'), indent=2)
        else:
            json.dump(obj, open(output_frame_file, 'w'))

    def run(self):
        cap = self.video_cap
        cumulative_energy_frame = self.cumulative_energy_frame

        while(cap.isOpened()):
            ret, current_frame = cap.read()
            if ret == True:
                if self.display:
                    cv2.imshow('Camera %s' % self.camera, current_frame)
                    if cv2.waitKey(25) & 0xFF == ord('q'):
                        break

                if cumulative_energy_frame is None:
                    cumulative_energy_frame = np.zeros(
                        current_frame.shape[:2], np.int)

                frame_energy = self.frame_energy(
                    current_frame)
                cumulative_energy_frame += frame_energy

                output_path = self.output_directory / ('pc%s' % self.camera)
                self.save_frame(frame_energy, output_path)

                self.previous_frame = current_frame
                self.frame_idx += 1
            else:
                break

        cap.release()
        self.cumulative_energy_frame = cumulative_energy_frame
        # print("Worker %s finished with: %s" %
        #       (self.worker_id, np.unique(cumulative_energy_frame)))

class VideoProcess(object):

    def __init__(self, group_id: str, prettify: bool = False, verbose: bool = False):
        self.group_id = group_id
        self.prettify = prettify
        self.verbose = verbose

        self.experiment = Experiment(group_id)
        self.output_group_dir = VIDEO_OUTPUT_DIR / \
            group_id / (group_id + '_processed')
        os.makedirs(self.output_group_dir, exist_ok=True)
        json.dump(self.experiment.to_json(),
                  open(self.output_group_dir / (self.group_id + '.json'), 'w'))

    def save_output(self, metrics, task, camera):

        energy_heatmap_path = self.output_group_dir / task / \
            ('htmp_energy_pc%s.png' % camera)
        energy_heatmap = metrics['energy_htmp']

        masked_data = np.ma.masked_where(energy_heatmap == 0, energy_heatmap)

        scaled_heatmap = masked_data.astype('float64')
        scaled_heatmap *= 255.0/scaled_heatmap.max()
        scaled_heatmap = scaled_heatmap.astype(int)

        # cmap = plt.get_cmap('Reds')
        cmap = plt.get_cmap("Reds")
        cmap.set_under('k', alpha=0)

        if self.verbose:
            plt.imshow(scaled_heatmap, cmap=cmap)
            plt.show()

        plt.imsave(str(energy_heatmap_path), scaled_heatmap, cmap=cmap)

    def process(self, tasks_directories: dict, specific_frame: int = None, display: bool = False):

        if specific_frame is not None:
            log('WARN', 'Impossible to calculate energy in a single specific frame. Skipping video processing step')
        else:
            for task in tasks_directories:
                output_directory = self.output_group_dir / task.name
                os.makedirs(output_directory, exist_ok=True)
                if not output_directory.is_dir():
                    log('ERROR', 'Directory does not exist')

                task_video_files = [
                    x for x in task.iterdir() if x.suffix in VALID_VIDEO_TYPES]
                video_caps = {int(re.search(r'(?<=Videopc)(\d{1})(?=\d{12})', x.name).group(
                    0)): cv2.VideoCapture(str(x)) for x in task_video_files}

                thread_list = list()
                for cap_cam, video_cap in video_caps.items():
                    thread = Worker(cap_cam, cap_cam, video_cap, output_directory,
                                    verbose=self.verbose, prettify=self.prettify, display=display)
                    thread.start()
                    thread_list.append(thread)

                for thread in thread_list:
                    thread.join()

                metrics = dict()
                for thread in thread_list:
                    metrics['energy_htmp'] = thread.cumulative_energy_frame
                    self.save_output(metrics, task.name, thread.camera)