from __future__ import print_function

import numpy as np
import scipy as sp
from healpy import query_disc
from numba import jit

from picca import constants
from picca.utils import print

# npb = number of parallel bins (to avoid collision with numpy np)
npb = None
ntb = None
ntm= None
npm= None
rp_max = None
rp_min = None
z_cut_max = None
z_cut_min = None
rt_max = None
angmax = None
nside = None

counter = None
ndata = None
ndata2 = None

zref = None
alpha= None
alpha2= None
alpha_abs= None
lambda_abs = None
lambda_abs2 = None

data = None
data2 = None

cosmo=None

rej = None
lock = None
x_correlation = None
ang_correlation = None
remove_same_half_plate_close_pairs = False

def fill_neighs(pix):
    for ipix in pix:
        for d1 in data[ipix]:
            npix = query_disc(nside,[d1.xcart,d1.ycart,d1.zcart],angmax,inclusive = True)
            npix = [p for p in npix if p in data]
            neighs = [d for p in npix for d in data[p] if d1.thid != d.thid]
            ang = d1^neighs
            w = ang<angmax
            neighs = np.array(neighs)[w]
            d1.dneighs = [d for d in neighs if d1.ra > d.ra and (d.z[-1]+d1.z[-1])/2.>=z_cut_min and (d.z[-1]+d1.z[-1])/2.<z_cut_max ]

def fill_neighs_x_correlation(pix):
    for ipix in pix:
        for d1 in data[ipix]:
            npix = query_disc(nside,[d1.xcart,d1.ycart,d1.zcart],angmax,inclusive = True)
            npix = [p for p in npix if p in data2]
            neighs = [d for p in npix for d in data2[p] if d1.thid != d.thid]
            ang = d1^neighs
            w = (ang<angmax)
            neighs = np.array(neighs)[w]
            d1.dneighs = [d for d in neighs if (d.z[-1]+d1.z[-1])/2.>=z_cut_min and (d.z[-1]+d1.z[-1])/2.<z_cut_max ]

def cf(pix):
    xi = np.zeros(npb*ntb)
    we = np.zeros(npb*ntb)
    rp = np.zeros(npb*ntb)
    rt = np.zeros(npb*ntb)
    z = np.zeros(npb*ntb)
    nb = np.zeros(npb*ntb,dtype=sp.int64)

    for ipix in pix:
        for d1 in data[ipix]:
            print("\rcomputing xi: {}%".format(round(counter.value*100./ndata,2)),end="")
            with lock:
                counter.value += 1
            for d2 in d1.dneighs:
                ang = d1^d2
                same_half_plate = (d1.plate == d2.plate) and\
                        ( (d1.fid<=500 and d2.fid<=500) or (d1.fid>500 and d2.fid>500) )
                if ang_correlation:
                    cw,cd,crp,crt,cz,cnb = fast_cf(d1.z,10.**d1.ll,10.**d1.ll,d1.we,d1.de,
                        d2.z,10.**d2.ll,10.**d2.ll,d2.we,d2.de,ang,same_half_plate)
                else:
                    cw,cd,crp,crt,cz,cnb = fast_cf(d1.z,d1.r_comov,d1.rdm_comov,d1.we,d1.de,
                        d2.z,d2.r_comov,d2.rdm_comov,d2.we,d2.de,ang,same_half_plate)

                xi[:len(cd)]+=cd
                we[:len(cw)]+=cw
                rp[:len(crp)]+=crp
                rt[:len(crp)]+=crt
                z[:len(crp)]+=cz
                nb[:len(cnb)]+=cnb.astype(int)
            setattr(d1,"neighs",None)

    w = we>0
    xi[w]/=we[w]
    rp[w]/=we[w]
    rt[w]/=we[w]
    z[w]/=we[w]
    return we,xi,rp,rt,z,nb
@jit
def fast_cf(z1,r1,rdm1,w1,d1, z2,r2,rdm2,w2,d2, ang,same_half_plate):
    wd1 = d1*w1
    wd2 = d2*w2
    if ang_correlation:
        rp = r1/r2[:,None]
        if not x_correlation:
            rp[(rp<1.)] = 1./rp[(rp<1.)]
        rt = ang*np.ones_like(rp)
    else:
        rp = (r1-r2[:,None])*sp.cos(ang/2)
        if not x_correlation :
            rp = abs(rp)
        rt = (rdm1+rdm2[:,None])*sp.sin(ang/2)
    wd12 = wd1*wd2[:,None]
    w12 = w1*w2[:,None]
    z = (z1+z2[:,None])/2

    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)

    rp = rp[w]
    rt = rt[w]
    z  = z[w]
    wd12 = wd12[w]
    w12 = w12[w]
    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    bins = bt + ntb*bp

    if remove_same_half_plate_close_pairs and same_half_plate:
        w = abs(rp)<(rp_max-rp_min)/npb
        wd12[w] = 0.
        w12[w] = 0.

    cd = np.bincount(bins,weights=wd12)
    cw = np.bincount(bins,weights=w12)
    crp = np.bincount(bins,weights=rp*w12)
    crt = np.bincount(bins,weights=rt*w12)
    cz = np.bincount(bins,weights=z*w12)
    cnb = np.bincount(bins,weights=(w12>0.))

    return cw,cd,crp,crt,cz,cnb

def dmat(pix):

    dm = np.zeros(npb*ntb*ntm*npm)
    wdm = np.zeros(npb*ntb)
    rpeff = np.zeros(ntm*npm)
    rteff = np.zeros(ntm*npm)
    zeff = np.zeros(ntm*npm)
    weff = np.zeros(ntm*npm)

    npairs = 0
    npairs_used = 0
    for p in pix:
        for d1 in data[p]:
            print("\rcomputing xi: {}%".format(round(counter.value*100./ndata,3)),end="")
            with lock:
                counter.value += 1
            order1 = d1.order
            r1 = d1.r_comov
            rdm1 = d1.rdm_comov
            w1 = d1.we
            l1 = d1.ll
            z1 = d1.z
            r = sp.random.rand(len(d1.dneighs))
            w=r>rej
            npairs += len(d1.dneighs)
            npairs_used += w.sum()
            for d2 in np.array(d1.dneighs)[w]:
                same_half_plate = (d1.plate == d2.plate) and\
                        ( (d1.fid<=500 and d2.fid<=500) or (d1.fid>500 and d2.fid>500) )
                order2 = d2.order
                ang = d1^d2
                r2 = d2.r_comov
                rdm2 = d2.rdm_comov
                w2 = d2.we
                l2 = d2.ll
                z2 = d2.z
                fill_dmat(l1,l2,r1,r2,rdm1,rdm2,z1,z2,w1,w2,ang,wdm,dm,rpeff,rteff,zeff,weff,same_half_plate,order1,order2)
            setattr(d1,"neighs",None)

    return wdm,dm.reshape(npb*ntb,npm*ntm),rpeff,rteff,zeff,weff,npairs,npairs_used
@jit
def fill_dmat(l1,l2,r1,r2,rdm1,rdm2,z1,z2,w1,w2,ang,wdm,dm,rpeff,rteff,zeff,weff,same_half_plate,order1,order2):

    rp = (r1[:,None]-r2)*sp.cos(ang/2)
    if  not x_correlation:
        rp = abs(rp)
    rt = (rdm1[:,None]+rdm2)*sp.sin(ang/2)
    z = (z1[:,None]+z2)/2.

    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)

    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    bins = bt + ntb*bp
    bins = bins[w]

    m_bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npm).astype(int)
    m_bt = (rt/rt_max*ntm).astype(int)
    m_bins = m_bt + ntm*m_bp
    m_bins = m_bins[w]

    sw1 = w1.sum()
    sw2 = w2.sum()

    ml1 = sp.average(l1,weights=w1)
    ml2 = sp.average(l2,weights=w2)

    dl1 = l1-ml1
    dl2 = l2-ml2

    slw1 = (w1*dl1**2).sum()
    slw2 = (w2*dl2**2).sum()

    n1 = len(l1)
    n2 = len(l2)
    ij = np.arange(n1)[:,None]+n1*np.arange(n2)
    ij = ij[w]

    we = w1[:,None]*w2
    we = we[w]

    if remove_same_half_plate_close_pairs and same_half_plate:
        wsame = abs(rp[w])<(rp_max-rp_min)/npb
        we[wsame] = 0.

    c = np.bincount(m_bins,weights=we*rp[w])
    rpeff[:c.size] += c
    c = np.bincount(m_bins,weights=we*rt[w])
    rteff[:c.size] += c
    c = np.bincount(m_bins,weights=we*z[w])
    zeff[:c.size] += c
    c = np.bincount(m_bins,weights=we)
    weff[:c.size] += c

    c = np.bincount(bins,weights=we)
    wdm[:len(c)] += c
    eta1 = np.zeros(npm*ntm*n1)
    eta2 = np.zeros(npm*ntm*n2)
    eta3 = np.zeros(npm*ntm*n1)
    eta4 = np.zeros(npm*ntm*n2)
    eta5 = np.zeros(npm*ntm)
    eta6 = np.zeros(npm*ntm)
    eta7 = np.zeros(npm*ntm)
    eta8 = np.zeros(npm*ntm)

    c = np.bincount(ij%n1+n1*m_bins,weights=(np.ones(n1)[:,None]*w2)[w]/sw2)
    eta1[:len(c)]+=c
    c = np.bincount((ij-ij%n1)//n1+n2*m_bins,weights = (w1[:,None]*np.ones(n2))[w]/sw1)
    eta2[:len(c)]+=c
    c = np.bincount(m_bins,weights=(w1[:,None]*w2)[w]/sw1/sw2)
    eta5[:len(c)]+=c

    if order2==1:
        c = np.bincount(ij%n1+n1*m_bins,weights=(np.ones(n1)[:,None]*w2*dl2)[w]/slw2)
        eta3[:len(c)]+=c
        c = np.bincount(m_bins,weights=(w1[:,None]*(w2*dl2))[w]/sw1/slw2)
        eta6[:len(c)]+=c
    if order1==1:
        c = np.bincount((ij-ij%n1)//n1+n2*m_bins,weights = ((w1*dl1)[:,None]*np.ones(n2))[w]/slw1)
        eta4[:len(c)]+=c
        c = np.bincount(m_bins,weights=((w1*dl1)[:,None]*w2)[w]/slw1/sw2)
        eta7[:len(c)]+=c
        if order2==1:
            c = np.bincount(m_bins,weights=((w1*dl1)[:,None]*(w2*dl2))[w]/slw1/slw2)
            eta8[:len(c)]+=c

    ubb = np.unique(m_bins)
    for k, (ba,m_ba) in enumerate(zip(bins,m_bins)):
        dm[m_ba+npm*ntm*ba]+=we[k]
        i = ij[k]%n1
        j = (ij[k]-i)//n1
        for bb in ubb:
            dm[bb+npm*ntm*ba] += we[k]*(eta5[bb]+eta6[bb]*dl2[j]+eta7[bb]*dl1[i]+eta8[bb]*dl1[i]*dl2[j])\
             - we[k]*(eta1[i+n1*bb]+eta3[i+n1*bb]*dl2[j]+eta2[j+n2*bb]+eta4[j+n2*bb]*dl1[i])

def metal_dmat(pix,abs_igm1="LYA",abs_igm2="SiIII(1207)"):

    dm = np.zeros(npb*ntb*ntm*npm)
    wdm = np.zeros(npb*ntb)
    rpeff = np.zeros(ntm*npm)
    rteff = np.zeros(ntm*npm)
    zeff = np.zeros(ntm*npm)
    weff = np.zeros(ntm*npm)

    npairs = 0
    npairs_used = 0
    for p in pix:
        for d1 in data[p]:
            print("\rcomputing metal dmat {} {}: {}%".format(abs_igm1,abs_igm2,round(counter.value*100./ndata,3)),end="")
            with lock:
                counter.value += 1

            r = sp.random.rand(len(d1.dneighs))
            w=r>rej
            npairs += len(d1.dneighs)
            npairs_used += w.sum()
            for d2 in np.array(d1.dneighs)[w]:
                r1 = d1.r_comov
                rdm1 = d1.rdm_comov
                z1_abs1 = 10**d1.ll/constants.absorber_IGM[abs_igm1]-1
                r1_abs1 = cosmo.r_comoving(z1_abs1)
                rdm1_abs1 = cosmo.dm(z1_abs1)
                w1 = d1.we

                wzcut = z1_abs1<d1.zqso
                r1 = r1[wzcut]
                rdm1 = rdm1[wzcut]
                w1 = w1[wzcut]
                r1_abs1 = r1_abs1[wzcut]
                rdm1_abs1 = rdm1_abs1[wzcut]
                z1_abs1 = z1_abs1[wzcut]

                same_half_plate = (d1.plate == d2.plate) and\
                        ( (d1.fid<=500 and d2.fid<=500) or (d1.fid>500 and d2.fid>500) )
                ang = d1^d2
                r2 = d2.r_comov
                rdm2 = d2.rdm_comov
                z2_abs2 = 10**d2.ll/constants.absorber_IGM[abs_igm2]-1
                r2_abs2 = cosmo.r_comoving(z2_abs2)
                rdm2_abs2 = cosmo.dm(z2_abs2)
                w2 = d2.we

                wzcut = z2_abs2<d2.zqso
                r2 = r2[wzcut]
                rdm2 = rdm2[wzcut]
                w2 = w2[wzcut]
                r2_abs2 = r2_abs2[wzcut]
                rdm2_abs2 = rdm2_abs2[wzcut]
                z2_abs2 = z2_abs2[wzcut]

                rp = (r1[:,None]-r2)*sp.cos(ang/2)
                if not x_correlation:
                    rp = abs(rp)

                rt = (rdm1[:,None]+rdm2)*sp.sin(ang/2)
                w12 = w1[:,None]*w2

                bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
                bt = (rt/rt_max*ntb).astype(int)

                if remove_same_half_plate_close_pairs and same_half_plate:
                    wp = abs(rp) < (rp_max-rp_min)/npb
                    w12[wp] = 0.

                bA = bt + ntb*bp
                wA = (bp<npb) & (bt<ntb) & (bp >=0)
                c = np.bincount(bA[wA],weights=w12[wA])
                wdm[:len(c)]+=c

                rp_abs1_abs2 = (r1_abs1[:,None]-r2_abs2)*sp.cos(ang/2)

                if not x_correlation:
                    rp_abs1_abs2 = abs(rp_abs1_abs2)

                rt_abs1_abs2 = (rdm1_abs1[:,None]+rdm2_abs2)*sp.sin(ang/2)
                zwe12 = (1+z1_abs1[:,None])**(alpha_abs[abs_igm1]-1)*(1+z2_abs2)**(alpha_abs[abs_igm2]-1)/(1+zref)**(alpha_abs[abs_igm1]+alpha_abs[abs_igm2]-2)

                bp_abs1_abs2 = sp.floor((rp_abs1_abs2-rp_min)/(rp_max-rp_min)*npm).astype(int)
                bt_abs1_abs2 = (rt_abs1_abs2/rt_max*ntm).astype(int)
                bBma = bt_abs1_abs2 + ntm*bp_abs1_abs2
                wBma = (bp_abs1_abs2<npm) & (bt_abs1_abs2<ntm) & (bp_abs1_abs2>=0)
                wAB = wA & wBma
                c = np.bincount(bBma[wAB]+npm*ntm*bA[wAB],weights=w12[wAB]*zwe12[wAB])
                dm[:len(c)]+=c
                c = np.bincount(bBma[wAB],weights=rp_abs1_abs2[wAB]*w12[wAB]*zwe12[wAB])
                rpeff[:len(c)]+=c
                c = np.bincount(bBma[wAB],weights=rt_abs1_abs2[wAB]*w12[wAB]*zwe12[wAB])
                rteff[:len(c)]+=c
                c = np.bincount(bBma[wAB],weights=(z1_abs1[:,None]+z2_abs2)[wAB]/2*w12[wAB]*zwe12[wAB])
                zeff[:len(c)]+=c
                c = np.bincount(bBma[wAB],weights=w12[wAB]*zwe12[wAB])
                weff[:len(c)]+=c

                if ((not x_correlation) and (abs_igm1 != abs_igm2)) or (x_correlation and (lambda_abs == lambda_abs2)):
                    r1 = d1.r_comov
                    rdm1 = d1.rdm_comov
                    w1 = d1.we
                    z1_abs2 = 10**d1.ll/constants.absorber_IGM[abs_igm2]-1
                    r1_abs2 = cosmo.r_comoving(z1_abs2)
                    rdm1_abs2 = cosmo.dm(z1_abs2)

                    wzcut = z1_abs2<d1.zqso
                    r1 = r1[wzcut]
                    rdm1 = rdm1[wzcut]
                    w1 = w1[wzcut]
                    z1_abs2 = z1_abs2[wzcut]
                    r1_abs2 = r1_abs2[wzcut]
                    rdm1_abs2 = rdm1_abs2[wzcut]

                    r2 = d2.r_comov
                    rdm2 = d2.rdm_comov
                    w2 = d2.we
                    z2_abs1 = 10**d2.ll/constants.absorber_IGM[abs_igm1]-1
                    r2_abs1 = cosmo.r_comoving(z2_abs1)
                    rdm2_abs1 = cosmo.dm(z2_abs1)

                    wzcut = z2_abs1<d2.zqso
                    r2 = r2[wzcut]
                    rdm2 = rdm2[wzcut]
                    w2 = w2[wzcut]
                    z2_abs1 = z2_abs1[wzcut]
                    r2_abs1 = r2_abs1[wzcut]
                    rdm2_abs1 = rdm2_abs1[wzcut]

                    rp = (r1[:,None]-r2)*sp.cos(ang/2)
                    if not x_correlation:
                        rp = abs(rp)

                    rt = (rdm1[:,None]+rdm2)*sp.sin(ang/2)
                    w12 = w1[:,None]*w2

                    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
                    bt = (rt/rt_max*ntb).astype(int)
                    if remove_same_half_plate_close_pairs and same_half_plate:
                        wp = abs(rp) < (rp_max-rp_min)/npb
                        w12[wp] = 0.
                    bA = bt + ntb*bp
                    wA = (bp<npb) & (bt<ntb) & (bp >=0)
                    c = np.bincount(bA[wA],weights=w12[wA])
                    wdm[:len(c)]+=c
                    rp_abs2_abs1 = (r1_abs2[:,None]-r2_abs1)*sp.cos(ang/2)
                    if not x_correlation:
                        rp_abs2_abs1 = abs(rp_abs2_abs1)

                    rt_abs2_abs1 = (rdm1_abs2[:,None]+rdm2_abs1)*sp.sin(ang/2)
                    zwe21 = (1+z1_abs2[:,None])**(alpha_abs[abs_igm2]-1)*(1+z2_abs1)**(alpha_abs[abs_igm1]-1)/(1+zref)**(alpha_abs[abs_igm1]+alpha_abs[abs_igm2]-2)

                    bp_abs2_abs1 = sp.floor((rp_abs2_abs1-rp_min)/(rp_max-rp_min)*npm).astype(int)
                    bt_abs2_abs1 = (rt_abs2_abs1/rt_max*ntm).astype(int)
                    bBam = bt_abs2_abs1 + ntm*bp_abs2_abs1
                    wBam = (bp_abs2_abs1<npm) & (bt_abs2_abs1<ntm) & (bp_abs2_abs1>=0)
                    wAB = wA & wBam

                    c = np.bincount(bBam[wAB],weights=rp_abs2_abs1[wAB]*w12[wAB]*zwe21[wAB])
                    rpeff[:len(c)]+=c
                    c = np.bincount(bBam[wAB],weights=rt_abs2_abs1[wAB]*w12[wAB]*zwe21[wAB])
                    rteff[:len(c)]+=c
                    c = np.bincount(bBam[wAB],weights=(z1_abs2[:,None]+z2_abs1)[wAB]/2*w12[wAB]*zwe21[wAB])
                    zeff[:len(c)]+=c
                    c = np.bincount(bBam[wAB],weights=w12[wAB]*zwe21[wAB])
                    weff[:len(c)]+=c

                    c = np.bincount(bBam[wAB]+npm*ntm*bA[wAB],weights=w12[wAB]*zwe21[wAB])
                    dm[:len(c)]+=c
            setattr(d1,"neighs",None)

    return wdm,dm.reshape(npb*ntb,npm*ntm),rpeff,rteff,zeff,weff,npairs,npairs_used

n1d = None
lmin = None
lmax = None
dll = None
def cf1d(pix):
    xi1d = np.zeros(n1d**2)
    we1d = np.zeros(n1d**2)
    nb1d = np.zeros(n1d**2,dtype=sp.int64)

    for d in data[pix]:
        bins = ((d.ll-lmin)/dll+0.5).astype(int)
        bins = bins + n1d*bins[:,None]
        wde = d.we*d.de
        we = d.we
        xi1d[bins] += wde * wde[:,None]
        we1d[bins] += we*we[:,None]
        nb1d[bins] += (we*we[:,None]>0.).astype(int)

    w = we1d>0
    xi1d[w]/=we1d[w]
    return we1d,xi1d,nb1d

def x_forest_cf1d(pix):
    xi1d = np.zeros(n1d**2)
    we1d = np.zeros(n1d**2)
    nb1d = np.zeros(n1d**2,dtype=sp.int64)

    for d1 in data[pix]:
        bins1 = ((d1.ll-lmin)/dll+0.5).astype(int)
        wde1 = d1.we*d1.de
        we1 = d1.we

        d2thingid = [d2.thid for d2 in data2[pix]]
        neighs = data2[pix][np.in1d(d2thingid,[d1.thid])]
        for d2 in neighs:
            bins2 = ((d2.ll-lmin)/dll+0.5).astype(int)
            bins = bins1 + n1d*bins2[:,None]
            wde2 = d2.we*d2.de
            we2 = d2.we
            xi1d[bins] += wde1 * wde2[:,None]
            we1d[bins] += we1*we2[:,None]
            nb1d[bins] += (we1*we2[:,None]>0.).astype(int)

    w = we1d>0
    xi1d[w]/=we1d[w]
    return we1d,xi1d,nb1d

v1d = {}
c1d = {}
max_diagram = None
cfWick = {}

## auto
def wickT(pix):

    T1 = np.zeros((npb*ntb,npb*ntb))
    T2 = np.zeros((npb*ntb,npb*ntb))
    T3 = np.zeros((npb*ntb,npb*ntb))
    T4 = np.zeros((npb*ntb,npb*ntb))
    T5 = np.zeros((npb*ntb,npb*ntb))
    T6 = np.zeros((npb*ntb,npb*ntb))
    wAll = np.zeros(npb*ntb)
    nb = np.zeros(npb*ntb,dtype=sp.int64)
    npairs = 0
    npairs_used = 0

    for ipix in pix:

        r = sp.random.rand(len(data[ipix]))
        w = r>rej
        npairs += len(data[ipix])
        npairs_used += w.sum()
        if w.sum()==0: continue

        for d1 in [ td for ti,td in enumerate(data[ipix]) if w[ti] ]:
            print("\rcomputing xi: {}%".format(round(counter.value*100./ndata/(1.-rej),3)),end="")
            with lock:
                counter.value += 1
            if len(d1.dneighs)==0: continue

            v1 = v1d[d1.fname](d1.ll)
            w1 = d1.we
            c1d_1 = (w1*w1[:,None])*c1d[d1.fname](abs(d1.ll-d1.ll[:,None]))*np.sqrt(v1*v1[:,None])
            r1 = d1.r_comov
            z1 = d1.z

            for i2,d2 in enumerate(d1.dneighs):
                ang12 = d1^d2

                v2 = v1d[d2.fname](d2.ll)
                w2 = d2.we
                c1d_2 = (w2*w2[:,None])*c1d[d2.fname](abs(d2.ll-d2.ll[:,None]))*np.sqrt(v2*v2[:,None])
                r2 = d2.r_comov
                z2 = d2.z

                fill_wickT123(r1,r2,ang12,w1,d2.we,z1,z2,c1d_1,c1d_2,wAll,nb,T1,T2,T3)
                if max_diagram<=3: continue

                ### d3 and d2 have the same 'fname'
                for d3 in d1.dneighs[:i2]:
                    ang13 = d1^d3
                    ang23 = d2^d3

                    v3 = v1d[d3.fname](d3.ll)
                    w3 = d3.we
                    c1d_3 = (w3*w3[:,None])*c1d[d3.fname](abs(d3.ll-d3.ll[:,None]))*np.sqrt(v3*v3[:,None])
                    r3 = d3.r_comov
                    z3 = d3.z

                    fill_wickT45(r1,r2,r3, ang12,ang13,ang23, w1,w2,w3,
                        z1,z2,z3, c1d_1,c1d_2,c1d_3,
                        d1.fname,d2.fname,d3.fname,
                        T4,T5)

                ### TODO: when there is two different catalogs
                ### d3 and d1 have the same 'fname'

    return wAll, nb, npairs, npairs_used, T1, T2, T3, T4, T5, T6
@jit
def fill_wickT123(r1,r2,ang,w1,w2,z1,z2,c1d_1,c1d_2,wAll,nb,T1,T2,T3):

    n1 = len(r1)
    n2 = len(r2)
    i1 = np.arange(n1)
    i2 = np.arange(n2)
    zw1 = ((1+z1)/(1+zref))**(alpha-1)
    zw2 = ((1+z2)/(1+zref))**(alpha2-1)

    bins = i1[:,None]+n1*i2
    rp = (r1[:,None]-r2)*sp.cos(ang/2)
    if not x_correlation:
        rp = abs(rp)
    rt = (r1[:,None]+r2)*sp.sin(ang/2)
    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    ba = bt + ntb*bp
    we = w1[:,None]*w2
    we1 = w1[:,None]*np.ones(w2.size)
    we2 = np.ones(w1.size)[:,None]*w2
    zw = zw1[:,None]*zw2

    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)
    if w.sum()==0: return

    bins = bins[w]
    ba = ba[w]
    we = we[w]
    we1 = we1[w]
    we2 = we2[w]
    zw = zw[w]

    for k1 in range(ba.size):
        p1 = ba[k1]
        i1 = bins[k1]%n1
        j1 = (bins[k1]-i1)//n1
        wAll[p1] += we[k1]
        nb[p1] += 1
        T1[p1,p1] += we[k1]*zw[k1]

        for k2 in range(k1+1,ba.size):
            p2 = ba[k2]
            i2 = bins[k2]%n1
            j2 = (bins[k2]-i2)//n1
            if i1==i2:
                prod = c1d_2[j1,j2]*we1[k1]*zw1[i1]
                T2[p1,p2] += prod
                T2[p2,p1] += prod
            elif j1==j2:
                prod = c1d_1[i1,i2]*we2[k2]*zw2[j1]
                T2[p1,p2] += prod
                T2[p2,p1] += prod
            else:
                prod = c1d_1[i1,i2]*c1d_2[j1,j2]
                T3[p1,p2] += prod
                T3[p2,p1] += prod

    return
@jit
def fill_wickT45(r1,r2,r3, ang12,ang13,ang23, w1,w2,w3, z1,z2,z3, c1d_1,c1d_2,c1d_3, fname1,fname2,fname3, T4,T5):
    """

    """

    ### forest-1 x forest-2
    rp = (r1[:,None]-r2)*sp.cos(ang12/2.)
    if not x_correlation:
        rp = np.absolute(rp)
    rt = (r1[:,None]+r2)*sp.sin(ang12/2.)
    pix1_12 = (np.arange(r1.size)[:,None]*np.ones(r2.size)).astype(int)
    pix2_12 = (np.ones(r1.size)[:,None]*np.arange(r2.size)).astype(int)
    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)
    if w.sum()==0: return
    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    ba12 = bt + ntb*bp
    ba12[~w] = 0
    cf12 = cfWick['{}_{}'.format(fname1,fname2)][ba12]
    cf12[~w] = 0.

    ba12 = ba12[w]
    pix1_12 = pix1_12[w]
    pix2_12 = pix2_12[w]

    ### forest-1 x forest-3
    rp = (r1[:,None]-r3)*sp.cos(ang13/2.)
    if not x_correlation:
        rp = np.absolute(rp)
    rt = (r1[:,None]+r3)*sp.sin(ang13/2.)
    pix1_13 = (np.arange(r1.size)[:,None]*np.ones(r3.size)).astype(int)
    pix3_13 = (np.ones(r1.size)[:,None]*np.arange(r3.size)).astype(int)
    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)
    if w.sum()==0: return
    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    ba13 = bt + ntb*bp
    ba13[~w] = 0
    cf13 = cfWick['{}_{}'.format(fname1,fname3)][ba13]
    cf13[~w] = 0.

    ba13 = ba13[w]
    pix1_13 = pix1_13[w]
    pix3_13 = pix3_13[w]

    ### forest-2 x forest-3
    rp = (r2[:,None]-r3)*sp.cos(ang23/2.)
    if not x_correlation:
        rp = np.absolute(rp)
    rt = (r2[:,None]+r3)*sp.sin(ang23/2.)
    pix2_23 = (np.arange(r2.size)[:,None]*np.ones(r3.size)).astype(int)
    pix3_23 = (np.ones(r2.size)[:,None]*np.arange(r3.size)).astype(int)
    w = (rp<rp_max) & (rt<rt_max) & (rp>=rp_min)
    if w.sum()==0: return
    bp = sp.floor((rp-rp_min)/(rp_max-rp_min)*npb).astype(int)
    bt = (rt/rt_max*ntb).astype(int)
    ba23 = bt + ntb*bp
    ba23[~w] = 0
    cf23 = cfWick['{}_{}'.format(fname2,fname3)][ba23]
    cf23[~w] = 0.

    ba23 = ba23[w]
    pix2_23 = pix2_23[w]
    pix3_23 = pix3_23[w]

    ### Wick T4 and T5
    for k1,p1 in enumerate(ba12):
        tpix1_12 = pix1_12[k1]
        tpix2_12 = pix2_12[k1]

        for k2,p2 in enumerate(ba13):
            tpix1_13 = pix1_13[k2]
            tpix3_13 = pix3_13[k2]

            tcf23 = cf23[tpix2_12,tpix3_13]
            if tpix1_12==tpix1_13:
                wcorr = w1[tpix1_12]*tcf23 ### TODO work on the good formula
                T4[p1,p2] += wcorr
                T4[p2,p1] += wcorr
            else:
                wcorr = c1d_1[tpix1_12,tpix1_13]*tcf23 ### TODO work on the good formula
                T5[p1,p2] += wcorr
                T5[p2,p1] += wcorr

    return


from typing import List

class Solution:

    def deleteAndEarn(self, nums: List[int]) -> int:
        calculation = [n for n in range(0, max(nums)+1)]
        arr_size = len(calculation)
        for i in range(0,arr_size):
            calculation[i] = 0

        for n in nums:
            calculation[n] += n

        arr_size = len(calculation)
        for idx in range(2, arr_size):
            calculation[idx] = max(calculation[idx] + calculation[idx-2], calculation[idx-1])

        return calculation[arr_size-1]


#!/usr/bin/env python3

"""
sklearn_pack.py: Do Model training with large sparse matrix with sklearn
"""

__author__ = "Yanshi Luo"
__license__ = "GPL"
__email__ = "yluo82@wisc.edu"

import pandas as pd

def random_forest(finalX_train, finalY_train, finalX_test, n_parallel=1, write_csv=False, write_filename='rf_pref.csv'):
    from sklearn.ensemble import RandomForestClassifier

    clf = RandomForestClassifier(n_estimators=10, n_jobs=n_parallel)
    clf = clf.fit(finalX_train, finalY_train)
    finalY_pred = clf.predict(finalX_test)
    finalY_pred_DF = pd.DataFrame(finalY_pred)

    if write_csv:
        finalY_pred_DF.to_csv(write_filename, index=False)

    return finalY_pred_DF

def decision_tree(finalX_train, finalY_train, finalX_test, dot=False):
    from sklearn import tree

    clf = tree.DecisionTreeClassifier()
    clf = clf.fit(finalX_train, finalY_train)
    if dot:
        tree.export_graphviz(clf, out_file='sklearn_tree.dot')

    finalY_pred = clf.predict(finalX_test)

    return pd.DataFrame(finalY_pred)

def neural_network(finalX_train, finalY_train, finalX_test):
    from sklearn.neural_network import MLPClassifier

    clf = MLPClassifier(solver='adam', alpha=1e-5, random_state=1)
    clf = clf.fit(finalX_train, finalY_train)
    finalY_pred = clf.predict(finalX_test)
    return pd.DataFrame(finalY_pred)


#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Author: HuHao <huhao1@cmcm.com>
Date: '2018/7/21'
Info:

"""
import os,traceback,time,socket,multiprocessing
from threading import Thread

def countdown(n):
	while n>0:
		print('T-minus',n)
		n -=1
		time.sleep(2)

def start():
	# 创建一个线程，target 为目标函数，args 为入参，默认是 集合类型
	t = Thread(target=countdown,args=(3,),name='child-01')
	# 启动线程
	t.start()

	# 监控线程生命状态
	while True:
		if t.is_alive():
			print('Still running')
			time.sleep(1)
		else:
			print('Completed')
			break

class CountdownTask:
	def __init__(self):
		self._running = True

	def terminate(self):
		self._running = False

	def awake(self):
		self._running = True

	def run(self,n):
		while n >0:
			if self._running:
				print('T-minus',n)
				n -=1
			time.sleep(2)

def test_join():
	# 创建线程实现类
	c = CountdownTask()
	# 创建线程实例
	t = Thread(target=c.run,args=(3,))
	# 启动线程
	t.start()
	# 暂停线程，并休眠 3s
	c.terminate()
	print('terminate for 3 seconds ...')
	time.sleep(3)
	# 唤醒线程
	c.awake()
	# 阻塞主进程
	t.join() # 暂停当前主线程，等待 t 结束，在继续向下执行，相当于 阻塞功能
	print('over')

class IOTask:
	def terminate(self):
		self._running = False

	def run(self,sock):
		sock.settimeout(5)
		while self._running:
			try:
				# IO 现场监护人那个阻塞过程，如果 sock 断开，线程将永久被阻塞，此时需要使用 超时循环操作线程
				data = sock.recv(8192)
				break
			except socket.timeout:
				continue

# 继承方式创建线程实例
class CountdownThread(Thread):
	def __init__(self,n):
		super().__init__()
		self.n = n

	def run(self):
		while self.n>0:
			print('T-minus',self.n)
			self.n -=1
			time.sleep(2)

def start_thread():
	c = CountdownThread(3)
	c.start()
	c.join() # 阻塞

# 通过multiprocessing 模块创建多线程
def start_thread2():
	c = CountdownTask()
	p = multiprocessing.Process(target=c.run,args=(3,))
	p.start()
	p.join()

if __name__=="__main__":
	try:
		# start()
		# test_join()
		# start_thread()
		start_thread2()
		pass
	except:
		traceback.print_exc()
	finally:
		os._exit(0)


import socket
import sys

HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 8000        # The port used by the server
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect((HOST, PORT))

url = input("enter url in desired format\neg. GET site1/filename.extension\n\n")
#get url in desired format
# extension = url[-3:]
split_url = url.split('/')
filename = split_url[1]
extension = split_url[1].split(".")
extension = extension[1]
# print(extension)
# print (filename)
url2 ="GET /"+url[4:]+" HTTP/1.1"

mysock.send(url2.encode())
data = mysock.recv(1024)
header,content = data.split(b'\n\n',1)
# print(header.decode())
check = str(header.decode())
if "NOT" in check:
    # print("this file does not exist")
    mysock.close()
    sys.exit("This file does not exist !!!")

with open(filename, "wb") as F:
    while content:
        F.write(content)
        content = mysock.recv(1024)
    F.close()
    print(filename+" has been downloaded on your system!")
    # print(data.decode(),end='')
mysock.close()


import sys
from layers import WEIGHT_DECAY_KEY
sys.path.append('/gan_segmentation/models/discriminators')
import largeFOV, smallFOV, stanford_background_dataset_discriminator
sys.path.append('/gan_segmentation/models/generators')
import fcn32, unet, deeplab_v3
import tensorflow as tf
import numpy as np
from utils import compute_accuracy
import pdb

class GAN_trainer:

    def __init__(self, x, y, num_classes, generator = 'fcn32', discriminator = 'smallFOV', optimizer = 'adagrad', is_train = 1):

        self.x = x
        self.y = y
        self.num_classes = num_classes
        self.generator = generator
        self.discriminator = discriminator
        self.optimizer = optimizer
        self.loss_bce_weight = tf.placeholder(tf.float32)
        self.pkeep = tf.placeholder(tf.float32)
        self.lr_g = tf.placeholder(tf.float32)
        self.lr_d = tf.placeholder(tf.float32)
        self.weight_decay = tf.placeholder(tf.float32)
        if is_train == 1:
            self.is_train = tf.constant(True)
        else:
            self.is_train = tf.constant(False)

    def make_dis_input(self, G_logits, image, label):

        variant = "scaling" # basic, product or scaling
        tau = tf.constant(0.9, dtype=tf.float32)

        # 0. down-sample labels and image
        logits_shape = tf.shape(G_logits)
        downsampling_shape = [logits_shape[1], logits_shape[2]]
        label = tf.image.resize_images(label, size = downsampling_shape)
        label = tf.cast(label, dtype=tf.int32)
        image = tf.image.resize_images(image, size = downsampling_shape)

        # 1. one hot representation of labels
        G_probs = tf.nn.softmax(G_logits, name='softmax_tensor')
        batch = tf.cast(tf.shape(label)[0], dtype=tf.int32)
        height = tf.cast(tf.shape(label)[1], dtype=tf.int32)
        width = tf.cast(tf.shape(label)[2], dtype=tf.int32)
        one_hot_flat_y = tf.one_hot(tf.reshape(label, [-1, ]), self.num_classes, axis=1)
        one_hot_y = tf.reshape(one_hot_flat_y,[batch, height, width, self.num_classes])

        if variant == "basic":

            # define operations between generator and discriminator - version "basic"

            self.c_prime = self.num_classes
            fake_disciminator_input = G_probs
            real_disciminator_input = one_hot_y
            return real_disciminator_input, fake_disciminator_input

        elif variant == "product":

            # define operations between generator and discriminator - version "product"

            self.c_prime = self.num_classes*3

            # 2. Slice r,g,b components
            blue = tf.slice(image, [0,0,0,0], [1, height, width, 1])
            green = tf.slice(image, [0, 0, 0, 1], [1, height, width, 1])
            red = tf.slice(image, [0, 0, 0, 2], [1, height, width, 1])

            # 3. Generate fake discriminator input
            product_b = G_probs * blue
            product_g = G_probs * green
            product_r = G_probs * red
            fake_disciminator_input = tf.concat([product_b, product_g, product_r], axis=3)

            # 4. Generate also real discriminator input
            product_b = one_hot_y * blue
            product_g = one_hot_y * green
            product_r = one_hot_y * red
            real_disciminator_input = tf.concat([product_b, product_g, product_r], axis=3)

            return real_disciminator_input, fake_disciminator_input

        elif variant == "scaling":

            # define operations between generator and discriminator - version "scaling"

            self.c_prime = self.num_classes

            fake_disciminator_input = G_probs

            #2. replace labels

            yil = tf.reduce_sum(tf.where(tf.greater(one_hot_y, 0.),
                                         tf.maximum(G_probs, tau),
                                         tf.zeros_like(one_hot_y)), axis = 3)
            sil = tf.reduce_sum(tf.where(tf.equal(one_hot_y, tf.constant(1, dtype=tf.float32)),
                                         G_probs,
                                         tf.zeros_like(one_hot_y)), axis=3)

            yil = tf.expand_dims(yil, axis=3)
            sil = tf.expand_dims(sil, axis=3)
            yil = tf.concat([yil]*self.num_classes, axis=3)
            sil = tf.concat([sil]*self.num_classes, axis=3)

            real_disciminator_input = tf.where(tf.equal(one_hot_y, 1.),
                                               yil,
                                               G_probs*((1-yil)/(1-sil)))

            return real_disciminator_input, fake_disciminator_input

    def get_loss_discriminator(self, real_D_logits, fake_D_logits):

        # Define logits batch_size, height, width
        in_shape = tf.shape(fake_D_logits)
        batch_size = tf.cast(in_shape[0], dtype=tf.int32)
        height = tf.cast(in_shape[1], dtype=tf.int32)
        width = tf.cast(in_shape[2], dtype=tf.int32)

        # Reshape logits by num of classes
        fake_D_logits_by_num_classes = tf.reshape(fake_D_logits, [-1, 2])
        real_D_logits_by_num_classes = tf.reshape(real_D_logits, [-1, 2])

        # Define real/fake labels
        label_real = tf.cast(tf.fill([batch_size*height*width], 1.0), dtype=tf.int32)
        label_fake = tf.cast(tf.fill([batch_size*height*width], 0.0), dtype=tf.int32)

        # Compute loss
        loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=real_D_logits_by_num_classes,
                                                                              labels=label_real,
                                                                              name="bce_1"))
        loss += tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=fake_D_logits_by_num_classes,
                                                                              labels=label_fake,
                                                                              name="bce_2"))
        # Add l2 cost
        costs = [tf.nn.l2_loss(var) for var in tf.get_collection(WEIGHT_DECAY_KEY, scope="model/discriminator")]
        l2_loss = tf.multiply(self.weight_decay, tf.add_n(costs))
        total_loss = loss + l2_loss

        return total_loss

    def get_loss_generator(self, labels, G_logits, fake_D_logits):

        # Find valid indices
        logits_by_num_classes = tf.reshape(G_logits, [-1, self.num_classes])
        preds = tf.argmax(G_logits, axis=3, output_type=tf.int32)
        preds_flat = tf.reshape(preds, [-1, ])
        labels_flat = tf.reshape(labels, [-1, ])
        valid_indices = tf.multiply(tf.to_int32(labels_flat <= self.num_classes - 1), tf.to_int32(labels_flat > -1))

        # Prepare segmentation model logits and labels
        valid_logits = tf.dynamic_partition(logits_by_num_classes, valid_indices, num_partitions=2)[1]
        valid_labels = tf.dynamic_partition(labels_flat, valid_indices, num_partitions=2)[1]
        valid_preds = tf.dynamic_partition(preds_flat, valid_indices, num_partitions=2)[1]

        in_shape = tf.shape(fake_D_logits)
        batch_size = tf.cast(in_shape[0], dtype=tf.int32)
        height = tf.cast(in_shape[1], dtype=tf.int32)
        width = tf.cast(in_shape[2], dtype=tf.int32)

        fake_D_logits_by_num_classes = tf.reshape(fake_D_logits, [-1, 2])
        label_real = tf.cast(tf.fill([batch_size*height*width], 1.0), dtype=tf.int32)

        l_mce = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=valid_logits,
                                                               labels=valid_labels,
                                                               name="g_mce"))
        l_bce = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=fake_D_logits_by_num_classes,
                                                                              labels=label_real,
                                                                              name="l_bce"))
        loss = l_mce + self.loss_bce_weight * l_bce

        # Add l2 loss
        costs = [tf.nn.l2_loss(var) for var in tf.get_collection(WEIGHT_DECAY_KEY, scope="model/generator")]
        l2_loss = tf.multiply(self.weight_decay, tf.add_n(costs))
        total_loss = loss + l2_loss

        return total_loss, valid_logits, valid_labels, valid_preds

    def train_op(self):

        image = self.x
        labels = self.y

        # Define generator
        if self.generator == 'fcn32':
            #G_logits = fcn32.fcn32(image, self.pkeep, self.num_classes)
            G_unscaled, G_logits = fcn32.fcn32(image, self.pkeep, self.num_classes)
        elif self.generator == 'fcn32_DCGAN':
            G_logits = fcn32_DCGAN.fcn32(image, self.pkeep, self.num_classes)
        elif self.generator == 'unet':
            G_logits = unet.unet(image, self.pkeep, self.num_classes, channels=3, num_layers=5)
        elif self.generator == 'deeplab_v3':
            G_logits = deeplab_v3.deeplab_net(image, self.num_classes, is_train=self.is_train, pkeep=self.pkeep)
        else:
            print('error! specified generator is not valid')
            sys.exit(1)

        # Define discriminators input
        #labels, real_disciminator_input, fake_disciminator_input = self.make_dis_input(G_logits, image, labels)
        real_disciminator_input, fake_disciminator_input = self.make_dis_input(G_unscaled, image, labels)

        # Define 2 discriminators: fake and real
        if self.discriminator == 'smallFOV':
            print('Building discriminator smallFOV')
            with tf.variable_scope('discriminator'):
                real_D_logits = smallFOV.smallFOV(real_disciminator_input, c_prime=self.c_prime)
            with tf.variable_scope('discriminator', reuse=True):
                fake_D_logits = smallFOV.smallFOV(fake_disciminator_input, c_prime=self.c_prime)
        elif self.discriminator == 'smallFOV_DCGAN':
            print('Building discriminator smallFOV_DCGAN')
            with tf.variable_scope('discriminator'):
                real_D_logits = smallFOV_DCGAN.smallFOV(real_disciminator_input, c_prime=self.c_prime)
            with tf.variable_scope('discriminator', reuse=True):
                fake_D_logits = smallFOV_DCGAN.smallFOV(fake_disciminator_input, c_prime=self.c_prime)
        elif self.discriminator == 'largeFOV':
            print('Building discriminator largeFOV')
            with tf.variable_scope('discriminator'):
                real_D_logits = largeFOV.largeFOV(real_disciminator_input, c_prime=self.c_prime)
            with tf.variable_scope('discriminator', reuse=True):
                fake_D_logits = largeFOV.largeFOV(fake_disciminator_input, c_prime=self.c_prime)
        elif self.discriminator == 'largeFOV_DCGAN':
            print('Building discriminator largeFOV_DCGAN')
            with tf.variable_scope('discriminator'):
                real_D_logits = largeFOV_DCGAN.largeFOV(real_disciminator_input, c_prime=self.c_prime)
            with tf.variable_scope('discriminator', reuse=True):
                fake_D_logits = largeFOV_DCGAN.largeFOV(fake_disciminator_input, c_prime=self.c_prime)
        elif self.discriminator == 'sbd':
            print('Building discriminator SBD')
            with tf.variable_scope('discriminator'):
                real_D_logits = stanford_background_dataset_discriminator.stanford_bd_model(image,
                                                                                real_disciminator_input,
                                                                                c_prime=self.c_prime)
            with tf.variable_scope('discriminator', reuse=True):
                fake_D_logits = stanford_background_dataset_discriminator.stanford_bd_model(image,
                                                                                fake_disciminator_input,
                                                                                c_prime=self.c_prime)
        else:
            print('error! specified discriminator is not valid')
            sys.exit(1)

        # Define losses
        D_loss = self.get_loss_discriminator(real_D_logits, fake_D_logits)
        G_loss, valid_logits, valid_labels, valid_preds = self.get_loss_generator(labels, G_logits, fake_D_logits)

        # Improved wasserstein gan penalty
        #epsilon = tf.random_uniform([], 0.0, 1.0)
        #x_hat = real_disciminator_input * epsilon + (1 - epsilon) * fake_disciminator_input
        #with tf.variable_scope('discriminator', reuse=True):
        #    d_hat = largeFOV.largeFOV(x_hat, c_prime=self.c_prime)
        #gradients = tf.gradients(d_hat, x_hat)[0]
        #slopes = tf.sqrt(tf.reduce_sum(tf.square(gradients), reduction_indices=[1]))
        #gradient_penalty = 10 * tf.reduce_mean((slopes - 1.0) ** 2)
        #D_loss += gradient_penalty

        # Define segmentation accuracy
        pixel_acc, mean_iou_acc, mean_per_class_acc = compute_accuracy(valid_preds, valid_labels, self.num_classes, 'accuracy')

        # Define optimizers
        if self.optimizer == 'adagrad':
            D_optimizer = tf.train.AdagradOptimizer(learning_rate=self.lr_d)
            G_optimizer = tf.train.AdagradOptimizer(learning_rate=self.lr_g)
        elif self.optimizer == 'sgd':
            D_optimizer = tf.train.GradientDescentOptimizer(learning_rate=self.lr_d)
            G_optimizer = tf.train.GradientDescentOptimizer(learning_rate=self.lr_g)
        elif self.optimizer == 'adam':
            D_optimizer = tf.train.AdamOptimizer(learning_rate=self.lr_d, epsilon=1e-05)
            G_optimizer = tf.train.AdamOptimizer(learning_rate=self.lr_g, epsilon=1e-05)

        D_grads = D_optimizer.compute_gradients(D_loss, var_list= tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='model/discriminator'))
        G_grads = G_optimizer.compute_gradients(G_loss, var_list= tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='model/generator'))
        D_train_step = D_optimizer.apply_gradients(D_grads)
        G_train_step = G_optimizer.apply_gradients(G_grads)

        return G_train_step, D_train_step, G_loss, D_loss, pixel_acc, mean_iou_acc, mean_per_class_acc


# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/3/26 1:57 下午
# @Author : wangHua
# @File : ProductAddConsumer.py
# @Software: PyCharm

from app.consumers import BaseConsumer
from utils import Logger, Http
from app.proxies import get_proxy_engine
from app.exceptions import NotFoundException, CrawlErrorException
from app.enums import RedisListKeyEnum
from app.entities import ProductJobEntity, ProductAddJobEntity
from app.crawlers import ProductAddCrawler
import common

class ProductAddConsumer(BaseConsumer):
    """
    添加新的asin时，插入对应的任务，该消费者会判断某个站点中的产品是否存在，如果存在，则添加对应站点的asin数据，并产生新的任务
    """
    # ignore = True     # 忽略该消费者
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8'
                  ',application/signed-exchange;v=b3;q=0.9',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/89.0.4389.82 Safari/537.36',
        'accept-encoding': 'gzip, deflate, br',
        'accept-language': 'zh-CN,zh;q=0.9',
        'cache-control': 'max-age=0',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-site': 'none',
        'sec-fetch-user': '?1',
        'upgrade-insecure-requests': '1',
    }

    def __init__(self):
        self.http = None
        self.proxy_engine = None
        BaseConsumer.__init__(self)

    def set_job_key(self) -> str:
        return RedisListKeyEnum.product_add_crawl_job

    def run_job(self):
        Logger().info('product_consumer start')
        self.http = Http()
        self.proxy_engine = get_proxy_engine()
        self.http.set_headers(self.headers)
        while True:
            job_dict = self.get_job_obj()
            if job_dict:
                job_entity = ProductAddJobEntity.instance(job_dict)
                try:
                    if self.proxy_engine:
                        # product 反扒比较苛刻，这边用了随机IP的代理
                        self.http.set_proxy(self.proxy_engine.get_proxy())
                    crawler = ProductAddCrawler(job_entity, self.http)
                    if crawler.productItem:
                        job_dict['product_item_id'] = crawler.productItem.id
                        new_job = ProductJobEntity.instance(job_dict)
                        self.set_job_by_key(RedisListKeyEnum.product_crawl_job, new_job)
                except CrawlErrorException:
                    # 爬虫失败异常，http 连续失败次数+1
                    self.set_error_job(job_entity)
                except NotFoundException:
                    # 页面不存在，不做处理
                    pass
                common.sleep_random()


import cv2
import time

def cam(i):

	bs = cv2.createBackgroundSubtractorKNN(detectShadows = True)
	camera = cv2.VideoCapture(i)

	while True:
		ret, frame = camera.read()
		fgmask = bs.apply(frame)
		# img = frame
		th = cv2.threshold(fgmask.copy(), 244, 255, cv2.THRESH_BINARY)[1]
		th = cv2.erode(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)), iterations = 2)
		dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8,3)), iterations = 2)
		image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
		for c in contours:
			if cv2.contourArea(c) > 1000:
				(x,y,w,h) = cv2.boundingRect(c)
				# cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 255, 0), 2)
				cv2.imwrite('./img/shutter/{}.jpg'.format(time.strftime('%Y%m%d%H%M%S')), frame)

		cv2.imshow("detection", frame)
		k = cv2.waitKey(30) & 0xff
		if k == 27:
			break

	camera.release()
	cv2.destroyAllWindows()
if __name__ == '__main__':
	cam(0)


import sys
from collections import deque

input = sys.stdin.readline

M, N, H = map(int, input().rstrip().split())
box = [[list(map(int, input().rstrip().split())) for _ in range(N)] for _ in range(H)]
visited = [[[False for _ in range(M)] for _ in range(N)] for _ in range(H)]
tomato = []
check = 0

for h in range(H):
    for n in range(N):
        for m in range(M):
            if box[h][n][m] == 1:
                tomato.append((h, n, m, 0))
                visited[h][n][m] = True
            elif box[h][n][m] == 0:
                check += 1

queue = deque(tomato)
dz = [-1, 1, 0, 0, 0, 0]
dy = [0, 0, -1, 1, 0, 0]
dx = [0, 0, 0, 0, -1, 1]
due = 0

while queue:
    z, y, x, cnt = queue.popleft()
    due = max(due, cnt)
    for d in range(6):
        nz, ny, nx = z+dz[d], y+dy[d], x+dx[d]
        if 0 <= nz <= H-1 and 0 <= ny <= N-1 and 0 <= nx <= M-1:
            if box[nz][ny][nx] == 0 and not visited[nz][ny][nx]:
                queue.append((nz, ny, nx, cnt+1))
                visited[nz][ny][nx] = True
                check-=1

print(due) if check == 0 else print(-1)


from fhcrc_pathology.OneFieldPerReport import OneFieldPerReport
import global_strings as gb

class DCIS_NuclearGrade(OneFieldPerReport):
    ''' find the invasive nuclear pleomorphism in the templated pathology report '''
    __version__ = 'DCIS_NuclearGrade1.0'
    def __init__(self):
        super(DCIS_NuclearGrade, self).__init__()
        self.field_name = 'DCIS_NuclearGrade'
        self.regex = r'Nuclear grade of DCIS:[\s]+([A-Za-z]+)'
        self.confidence = .65
        self.match_style = 'first'
        self.table = gb.PATHOLOGY_TABLE
        self.value_type = 'match'
        self.good_section = r'SUMMARY CANCER|DIAGNOSIS'


from requests_html import HTMLSession

s = HTMLSession()

location = input("Enter Location: ")
url = f'https://www.eldersweather.com.au/climate-history/vic/{location}'

r = s.get(url, headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'})

month = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "Annual"]
rainHigh = []
rainLow = []

for i in range(len(month)):
    rainHigh.append(r.html.find(f'div.column.{month[i].lower()}')[14].text)
    rainLow.append(r.html.find(f'div.column.{month[i].lower()}')[15].text)
    print(month[i], "Rain High:", rainHigh[i], ",", month[i], "Rain Low:", rainLow[i])


import logging
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import BbcNewsItem
from readability import Document
import html2text
from datetime import datetime
from goose3 import Goose

class BbcSpider(CrawlSpider):
    name = 'bbc'
    start_urls = ['https://www.bbc.com/']

    rules = [
        Rule(LinkExtractor(allow='https://www.bbc.com/news'),
             callback='parse_news', follow=True)
    ]

    def parse_news(self, response):
        '''
        DESCRIPTION:
        -----------
        * This function is the callback for parsing URL content response,

        PARAMETERS:
        ----------
            1. the response to be parsed
        '''

        if response.status == 200:
            url = response.url
            logging.info(' BBC News URL :  ' + url)
            item = BbcNewsItem()
            item['url'] = url
            item['headline'] = response.xpath('//title/text()').extract_first()
            item['authors'] = response.xpath("//meta[@property='article:author']/@content").extract()

            article_text = self.get_article_text(response=response)
            item['text'] = article_text

            publish_datetime = self.get_publish_datetime(response=response)
            item['publish_datetime'] = publish_datetime
            item['crawling_datetime'] = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.000Z")

            logging.info(' BBC News Item ' + str(item))

            return item

    def get_article_text(self, response):
        '''
               DESCRIPTION:
               -----------
               * This function cleanse the page of superfluous content such as advertising and HTML

               PARAMETERS:
               ----------
                   1. response
        '''
        doc = Document(response.text)
        article_html = Document(doc.content()).summary()
        h = html2text.HTML2Text()
        h.ignore_links = True
        article_text = h.handle(article_html)
        article_text = article_text.replace('\r', ' ').replace('\n', ' ').strip()
        return article_text

    def get_publish_datetime(self, response):
        '''
               DESCRIPTION:
               -----------
               * This function is used for extract publish date time

              PARAMETERS:
               ----------
                   1. response
        '''
        publish_datetime = response.css('span > time::attr(datetime)').get()
        return publish_datetime


# %%
from enum import Enum
from typing import List, AnyStr, Callable, Sequence, Union
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from transformers.pipelines.base import Pipeline
import tweepy as tw
import plotly.express as px
import os
import json
from transformers import (AutoModelForSequenceClassification, AutoTokenizer, pipeline)
import torch
from icecream import ic
import numpy as np
import pandas as pd
import textwrap

import ipywidgets as widgets
from ipywidgets import interact, interact_manual
import IPython.display
from IPython.display import display, clear_output

import plotly.graph_objects as go

import datetime

import dash
from dash import dcc
from dash import html
import plotly
from dash.dependencies import Input, Output, State, ALL, ALLSMALLER, MATCH, DashDependency

# %%
# help(go.Stream)
# %%
# %%
api_key = os.environ['TWITTER_API_KEY']
api_secret = os.environ['TWITTER_API_KEY_SECRET']
access_token = os.environ['TWITTER_ACCESS_TOKEN']
access_token_secret = os.environ['TWITTER_ACCESS_TOKEN_SECRET']
model_name = 'nlptown/bert-base-multilingual-uncased-sentiment'
# %%
#  API Setup
# auth = tw.OAuthHandler(api_key, api_secret)
# auth.set_access_token(access_token, access_token_secret)
# api = tw.API(auth, wait_on_rate_limit=True)
# hashtag = "#VenomReleasesInMumbai"
# query = tw.Cursor(api.search_tweets, q=hashtag).items()
# tweets = [{'Tweet': tweet.text, 'Timestamp': tweet.created_at} for tweet in query]
# df = pd.DataFrame.from_dict(tweets)
# df.head()

# %%
print('Loading pipeline...')
classifier = pipeline('sentiment-analysis', model=model_name)
print('Pipeline load completed.')

# tokenizer = AutoTokenizer.from_pretrained(model_name)
# model = AutoModelForSequenceClassification.from_pretrained(model_name)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

# %%

def classify_sentiment(tweets: Union[AnyStr, Sequence[AnyStr]], classifier: Pipeline) -> Sequence[int]:

    return list(
        pd.DataFrame.from_dict(classifier(tweets))['label']
        .apply(lambda x: x.split()[0])
        .astype(int)
        .values
    )

print(classify_sentiment(["This is worse", "This is fun"], classifier))

# %%

'''
def get_sentiment_score(tweet_text: AnyStr, model, tokenizer):
    classification_result = model(tokenizer.encode(tweet_text, return_tensors='pt'))
    return int(torch.argmax(classification_result.logits)) + 1

class SentimentAnalyzer():
    def get_scores(tweet: AnyStr, func: Callable[[AnyStr, Union[Pipeline, (AutoModelForSequenceClassification, AutoTokenizer)]], int]) -> List[int]:
        return func(tweet)

class PlotType(Enum):
    Current = 1
    Cumulative = 2

class PeriodType(Enum):
    Current = 1
    Day = 2
    Week = 3
    ByWeek = 4
    Month = 5
    Quarter = 6
    HalfYear = 7
    Year = 8
    BiYear = 9
    ThreeYear = 10
    FiveYear = 11

class Plotter:
    def plot_sentiments(plot_type: PlotType, period_type: PeriodType):
        pass

class LayoutGenerator:
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

    def get_layout(self):
        LayoutGenerator.app.layout = html.Div(
            html.Div([
                html.H4('Live Twitter Sentiment analysis'),
                html.Div(id='live-update-tweet'),
                dcc.Graph(id='live-update-graph')
            ])
        )

    @app.callback(Output('live-update-tweet', 'children'))
    def update_tweet(tweets):
        style = {'padding': '5px', 'fontSize': '16px'}
        return html.Span(tweets, style=style)
'''

app = dash.Dash(__name__, external_stylesheets=external_stylesheets,
                suppress_callback_exceptions=True,prevent_initial_callbacks=True,
                meta_tags=[{'name': 'viewport',
                            'content': 'width=device-width, initial-scale=1.0'}])

app.layout = html.Div(
    html.Div([
        html.H4('Live Twitter Sentiment analysis'),
        html.Div(id='live-update-tweet'),
        # dcc.Graph(id='live-update-graph'),
        html.Div(id='1', style={'display': 'none'}, children=None)
    ])
)

@app.callback(Output('live-update-tweet', 'children'), Input('1', 'children'), prevent_initial_call=True)
def update_tweet(tweets):
    print("update_tweet called")
    style = {'padding': '5px', 'fontSize': '16px'}
    return html.Span(tweets, style=style)

class Listener(tw.Stream):
    def __init__(self, consumer_key, consumer_secret, access_token, access_token_secret, *, chunk_size=512, daemon=False, max_retries=10, proxy=None, verify=True):
        super().__init__(consumer_key, consumer_secret, access_token, access_token_secret, chunk_size=chunk_size, daemon=daemon, max_retries=max_retries, proxy=proxy, verify=verify)

        self.df_cols = ["text", "created_at"]
        self.tweets_df = pd.DataFrame(columns=[*self.df_cols, "score"])

    def on_data(self, raw_data):
        data = json.loads(raw_data)
        data = [data.get(field) for field in self.df_cols]
        temp_df = pd.DataFrame(data=data).T
        temp_df.columns = self.df_cols
        tweets = list(temp_df['text'].apply(lambda x: str(x)[:512]).values)
        temp_df["score"] = classify_sentiment(tweets, classifier)
        # app.callback(Output('live-update-tweet', 'children'))(update_tweet)
        # update_tweet("<br>".join(tweets))
        self.tweets_df = self.tweets_df.append(temp_df, ignore_index=True)

        del temp_df
        return super().on_data(raw_data)

    def on_status(self, status):
        return super().on_status(status)

    def on_request_error(self, status_code):
        if status_code == 420:
            return False
        return super().on_request_error(status_code)

    def on_connection_error(self):
        self.disconnect()

    def start(self, keywords):
        return super().filter(track=keywords)

# %%
listener = Listener(api_key, api_secret, access_token, access_token_secret)
print("Startting server")
_ = app.run_server(debug=True)
print("Streaming tweets")
_ = listener.start(['Python'])
# %%


import socket
import threading

IP = socket.gethostbyname(socket.gethostname())
PORT = 56011
ADDR = (IP, PORT)
SIZE = 4096
FORMAT = "utf-8"
DISCONNECT_MSG = "!DISCONNECT"

def handle_client(conn, addr):
    print("[New Connection] {} Connected.".format(addr))

    connected = True
    while connected:
        msg = conn.recv(SIZE).decode(FORMAT)
        if msg == DISCONNECT_MSG:
            connected = False
        print("[addr] {} connected.".format(addr))
        print("[msg] {} connected.".format(msg))
        conn.send(msg.encode(FORMAT))

    conn.close()

def main():
    print("[STARTING] Server is starting...")
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(ADDR)
    server.listen(2)
    print("[LISTENING] Server is listening on port {} Connected".format(PORT))

    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn, addr))
        thread.start()

if __name__ == "__main__":
    main()


import io
import os

# Imports the Google Cloud client library
from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

credential_path = "C:/Users/nickj/OneDrive/Documents/Capstone/voice.json"
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credential_path

# Instantiates a client
client = speech.SpeechClient()

# The name of the audio file to transcribe
file_name = "C:/Users/nickj/OneDrive/Documents/Soundrecordings/milk.m4a"

# Loads the audio into memory
with io.open(file_name, 'rb') as audio_file:
    content = audio_file.read()
    audio = types.RecognitionAudio(content=content)

config = types.RecognitionConfig(
    encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
    sample_rate_hertz=16000,
    language_code='en-US')

# Detects speech in the audio file
response = client.recognize(config, audio)

print(len(response.results))
for result in response.results:
    print('Transcript: {}'.format(result.alternatives[0].transcript))


#/////////////////  Use this pattern to gererate a GUI to manipulate a struct.

import progSpec
import codeDogParser
from progSpec import cdlog, cdErr

classesToProcess=[]
classesEncoded={}
currentClassName=''
currentModelSpec=None

# Code accmulator strings:
newWidgetFields=''
widgetInitFuncCode=''
widgetFromVarsCode=''
varsFromWidgetCode=''
clearWidgetCode=''

def findModelRef(classes, structTypeName):
    modelRef = progSpec.findSpecOf(classes, structTypeName, 'model')
    if modelRef==None:
        cdErr('To build a list GUI for list of "'+structTypeName+'" a model is needed but is not found.')
    return modelRef

def getFieldSpec(fldCat, field):
    parameters={}
    if fldCat=='mode': fldCat='enum'
    elif fldCat=='double': fldCat='float'

    if fldCat=='enum':
        parameters=field['typeSpec']['enumList']
    elif fldCat=='RANGE':
        parameters={1, 10}

    typeSpec=field['typeSpec']
    if progSpec.isAContainer(typeSpec):
        innerFieldType=typeSpec['fieldType']
        datastructID = progSpec.getDatastructID(typeSpec)
        return [datastructID, innerFieldType]
    else:
        if fldCat=='struct':
            fldCat='struct' #field['typeSpec']['fieldType'][0]
        return [fldCat, parameters]

def deCamelCase(identifier):
    outStr=''
    chPos=0
    for ch in identifier:
        if chPos==0: outStr += ch.upper()
        else:
            if ch.isupper() and ch.isalpha():
                outStr += ' '+ch.lower()
            elif ch=='_':
                outStr += ' '
            else: outStr += ch
        chPos+=1
    return outStr

def changeDataFieldType(classes, structTypeName, typeSpec):
    retFieldType = ""
    if structTypeName[:4] == "Time": retFieldType = 'timeValue'; newFieldOwner = 'me'
    elif structTypeName[:3] == "Int": retFieldType = 'int'; newFieldOwner = 'me'
    else: print("ERROR: UNKNOWN WIDGET DATA TYPE CONVERSION: ", structTypeName)
    if retFieldType != "": typeSpec['fieldType'][0] = retFieldType;typeSpec['owner'] = newFieldOwner
    return retFieldType

def addNewStructToProcess(guiStructName, structTypeName, structOrList, widgetStyle):
    global classesEncoded
    if guiStructName == 'timeValue_Dialog_GUI': return
    if not(guiStructName in classesEncoded)and not(structTypeName=='DateValue' or structTypeName=='Agreement' or structTypeName=='timeOfDay' or structTypeName=='DateTime' or structTypeName=='matterTerm' or structTypeName=='MedItemData' or structTypeName=='MedData'):
        classesEncoded[guiStructName]=1
        classesToProcess.append([structTypeName, structOrList, widgetStyle, guiStructName])

def getButtonHandlingCode(classes, buttonLabel, fieldName):
    global newWidgetFields
    global widgetInitFuncCode
    # Add a button to widget and put it in box
    buttonsWidgetName = buttonLabel+'Button'
    widgetInitFuncCode   += '        their GUI_button: '+buttonsWidgetName+' <- makeButtonWidget("'+buttonLabel+'")\n'
    # make its onclick trigger
    # g_signal_connect(G_OBJECT(EnterButton), "clicked", G_CALLBACK(EntryPad_Dialog__EnterBtnCB), Data.get());
    widgetInitFuncCode   += '        GUI.setBtnCallback2('+buttonsWidgetName+', "clicked", '+ buttonsWidgetName +'_CB, Data, _data.'+fieldName+'())\n'
    widgetInitFuncCode   += '        addToContainer(box, '+buttonsWidgetName+')\n'
    # onClick() should call this.callback()
    #   GTK: void EntryPad_Dialog__EnterBtnCB(GtkWidget* wid, EntryPad* EPad){EPad->enter_btn();}

def getListWidgetMgrCode(classes, listManagerStructName, rowTypeName, fieldName, classOptionsTags):
    # New listWidgetMgr code generator
    # Find the model
    rowWidgetName = rowTypeName + 'Widget'
    listWidgetStyle = progSpec.fetchTagValue([classOptionsTags], fieldName+'.style.widgetStyle')
    if listWidgetStyle == None: listWidgetStyle = 'simpleList'
    modelRef = progSpec.findSpecOf(classes[0], rowWidgetName, 'struct')
    if modelRef == None:
        print("modelRef: ", modelRef, rowTypeName)
        addNewStructToProcess(rowWidgetName, rowTypeName, 'struct', 'rowWidget')
    filename = './preDynamicTypes/' + listWidgetStyle + '.dog'
    classSpec = progSpec.stringFromFile(filename)
    classSpec = classSpec.replace('<ROW_TYPE>', rowTypeName)
    classSpec = classSpec.replace('<LIST_CLASS_NAME>', listManagerStructName)
    #print '==========================================================\n'+classSpec
    codeDogParser.AddToObjectFromText(classes[0], classes[1], classSpec, rowWidgetName)

def getWidgetHandlingCode(classes, fldCat, fieldName, field, structTypeName, dialogStyle, classPrimaryGuiItem, classOptionsTags, indent):
    # _Dialog_GUI is editable widget
    global newWidgetFields
    global widgetInitFuncCode
    global widgetFromVarsCode
    global varsFromWidgetCode
    global clearWidgetCode

    label               = deCamelCase(fieldName)
    [fieldSpec, params] = getFieldSpec(fldCat, field)
    typeName            = fieldSpec+'Widget'
    CasedFieldName      = fieldName[0].upper() + fieldName[1:]
    widgetName          = CasedFieldName + 'Widget'
    typeSpec            = field['typeSpec']
    innerFieldType      = typeSpec['fieldType']
    fieldType           = innerFieldType[0]
    widgetBoxName       = widgetName
    localWidgetVarName  = widgetName
    makeTypeNameCall    = ''

    if fieldType=='timeValue':
        typeName              = 'dateWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      =  'Allocate('+widgetName+');\n' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += '        ' + widgetName+ '.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        _data.' + fieldName + ' <- ' + widgetName + '.getValue()\n'
        clearWidgetCode      += '        ' + widgetName+ '.clear()\n'
    elif fieldType=='Agreement':
        typeName              = 'AgreeWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+fieldName+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += ''
        varsFromWidgetCode   += ''
    elif fieldType=='DateValue':
        typeName              = 'DateWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initCrnt("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += ''
        varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        '+widgetName+'.clear()\n'
    elif fieldType=='timeOfDay':
        typeName              = 'TimeWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initCrnt("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += ''
        varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        '+widgetName+'.clear()\n'
    elif fieldType=='DateTime':
        typeName              = 'DateTimeWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initCrnt("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += ''
        varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        '+widgetName+'.clear()\n'
    elif fieldType=='FoodData':
        typeName              = 'FoodDataWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'", _data.'+fieldName+')\n'
        #widgetFromVarsCode   += '        '+widgetName+'.setValue(var.'+ fieldName +')\n'
        #varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
    elif fieldType=='MedItemData':
        typeName              = 'MedItemDataWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'", _data.'+fieldName+')\n'
        #widgetFromVarsCode   += '        '+widgetName+'.setValue(var.'+ fieldName +')\n'
        #varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
    elif fieldType=='MedData':
        typeName              = 'MedBunchDataWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += 'Allocate(_data.'+fieldName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'", _data.'+fieldName+')\n'
        #widgetFromVarsCode   += '        '+widgetName+'.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        '+widgetName+'.clear()\n'
    elif fieldType=='matterTerm':
        typeName              = 'MatterTermWidget'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'", _data.'+fieldName+')\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += '        '+widgetName+'.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        '+widgetName+'.clear()\n'
    elif fieldSpec=='widget':
        typeName              = fieldType
        localWidgetVarName    = fieldName
        if fieldType=='graphWidget':
            widgetName            = fieldName +'Widget'
            widgetBoxName         = fieldName
            newWidgetFields      += '    their GUI_item' + ': ' + fieldName + '\n'
            makeTypeNameCall      = widgetName+' <- Data.' + fieldName + '\n' + fieldName + '<- '+widgetName+'.init("'+label+'")\n'
        else:
            widgetBoxName         = widgetName +'.box'
            dataType = changeDataFieldType(classes, structTypeName, typeSpec)
            makeTypeNameCall      = 'Allocate('+widgetName+')\n'
            makeTypeNameCall     += '        '+widgetBoxName+' <- '+widgetName+'.initWidget("'+label+'")\n'
            makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
    elif fieldSpec=='struct':
        typeName              = 'GUI_Frame'
        guiStructName         = structTypeName + '_Dialog_GUI'
        guiMgrName            = fieldType + '_GUI_Mgr'
        if progSpec.typeIsPointer(typeSpec): widgetInitFuncCode += '        Allocate(_data.'+fieldName+')\n'
        widgetInitFuncCode   += 'Allocate('+guiMgrName+')\n'
        makeTypeNameCall      = widgetName+' <- '+guiMgrName+'.initWidget(_data.'+fieldName+')\n'
        makeTypeNameCall     += '        ' + guiMgrName + '.parentGuiMgr <- self\n'
        newWidgetFields      += '    our ' + guiStructName + ': '+ guiMgrName+'\n'
        widgetFromVarsCode   += '        ' + guiMgrName+ '.setValue(var.'+fieldName+')\n'
        varsFromWidgetCode   += '        ' + guiMgrName + '.getValue()\n'
        clearWidgetCode      += '        ' + guiMgrName + '.clear()\n'
        makeTypeNameCall     += '        ' + guiMgrName + '.load()\n'
    elif fieldSpec=='enum':
        typeName = 'enumWidget'
        EnumItems=[]
        for enumItem in params: EnumItems.append('"'+deCamelCase(enumItem)+'"')
        optionString          = '[' + ', '.join(EnumItems) + ']'
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+'); ' + widgetBoxName+' <- '+ widgetName+'.initWidget("'+label+'", '+optionString+')\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += '        ' + widgetName+ '.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        _data.' + fieldName + ' <- ' + widgetName + '.getValue()\n'
        clearWidgetCode      += '        ' + widgetName+ '.clear()\n'
    elif fieldSpec=='string':
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+'); ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += '        ' + widgetName+ '.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        _data.' + fieldName + ' <- ' + widgetName + '.getValue()\n'
        clearWidgetCode      += '        ' + widgetName+ '.clear()\n'
    elif fieldSpec=='int':
        widgetBoxName         = widgetName +'.box'
        makeTypeNameCall      = 'Allocate('+widgetName+')\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        if progSpec.typeIsNumRange(innerFieldType):
            range1 = innerFieldType[0]
            range2 = innerFieldType[2]
            makeTypeNameCall += '        '+widgetName+'.minValue <- '+range1+'\n        '+widgetName+'.maxValue <- '+range2+'\n'
        makeTypeNameCall += '        '+widgetBoxName+' <- '+widgetName+'.initWidget("'+label+'")\n'
        widgetFromVarsCode   += '        '+widgetName+'.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        _data.'+fieldName+' <- '+widgetName+'.getValue()\n'
        clearWidgetCode      += '        ' + widgetName+ '.clear()\n'
    elif fieldSpec=='bool':
        widgetBoxName         =  widgetName +'.box'
        makeTypeNameCall      =  'Allocate('+widgetName+'); ' + widgetBoxName + ' <- '+ widgetName+'.initWidget("'+label+'")\n'
        makeTypeNameCall     += '        ' + widgetName + '.parentGuiMgr <- self\n'
        widgetFromVarsCode   += '        ' + widgetName+ '.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        _data.' + fieldName + ' <- ' + widgetName + '.getValue()\n'
        clearWidgetCode      += '        ' + widgetName+ '.clear()\n'
    elif fieldSpec=='list' or fieldSpec=='map': pass
    else: print('pattern_MakeGUI.getWidgetHandlingCode fieldSpec not specified: ', fieldSpec);  exit(2)

    if typeName == 'GUI_Frame': owner='their '
    else: owner='our '
    # If this is a list or map, populate it
    if progSpec.isAContainer(typeSpec):
        makeTypeNameCall      =  widgetName+' <- make'+typeName[0].upper() + typeName[1:]+'("'+label+'")\n'
        fldCatInner           = progSpec.innerTypeCategory(innerFieldType)

        # If it hasn't already been added, make a struct <ItemType>_ListWidgetManager:ListWidgetManager{}
        listManagerStructName = structTypeName+'_ListWidgetManager'
        getListWidgetMgrCode(classes, listManagerStructName, structTypeName, fieldName, classOptionsTags)

        listWidMgrName        = 'LEWM'
        newWidgetFields      += '    me '+listManagerStructName+': '+listWidMgrName+'\n'

        widgetListEditorName  = widgetName+'_Editor'
        localWidgetVarName    = widgetListEditorName
        if progSpec.typeIsPointer(typeSpec): widgetInitFuncCode += 'Allocate(_data.'+fieldName+')\n'
        widgetInitFuncCode   += '        their GUI_YStack: '+widgetListEditorName+' <- '+listWidMgrName+'.initWidget(_data.'+fieldName+', "'+label+'")\n'
        if classPrimaryGuiItem==fieldName: widgetInitFuncCode   += '        addToContainerAndExpand(box, '+widgetListEditorName+')\n'
        else: widgetInitFuncCode   += '        addToContainer(box, '+widgetListEditorName+')\n'
#        widgetFromVarsCode   += '        ' + listWidMgrName + '.setValue(var.'+ fieldName +')\n'
        varsFromWidgetCode   += '        ' + listWidMgrName + '.getValue()\n'
        clearWidgetCode      += '        ' + listWidMgrName + '.clear()\n'
    elif dialogStyle == 'WizardStack':
        newWidgetFields      += '    '+owner+typeName+': '+widgetName+'\n'
        widgetInitFuncCode   += '        '+makeTypeNameCall
        widgetInitFuncCode   += '        addToZStack(wiz.ZStack, '+widgetBoxName+', "'+CasedFieldName+'")\n'
        widgetInitFuncCode   += '        wiz.children.pushLast("'+CasedFieldName+'")\n'
    elif dialogStyle   == 'Z_stack':
        widgetBoxName         =  guiMgrName +'.box'
        newWidgetFields      += '    '+owner+typeName+': '+widgetName+'\n'
        widgetInitFuncCode   += '        '+makeTypeNameCall+'\n'
        widgetInitFuncCode   += '        addToZStack(Zbox, '+widgetBoxName+', "'+CasedFieldName+'")\n'
        widgetInitFuncCode   += '        children.pushLast("'+CasedFieldName+'")\n'
    else: # Not an ArraySpec:
        newWidgetFields      += '    '+owner+typeName+': '+widgetName+'\n'
        widgetInitFuncCode   += '        '+makeTypeNameCall
        if classPrimaryGuiItem==fieldName: widgetInitFuncCode   += '        addToContainerAndExpand(box, '+widgetBoxName+')\n'
        else: widgetInitFuncCode   += '        addToContainerAndExpand(box, '+widgetBoxName+')\n'
    if dialogStyle == 'TabbedStack':
        widgetInitFuncCode+='             '+'setTabLabelText(box, '+ localWidgetVarName+', "'+label+'")\n'

def buildListRowView(classes, className, dialogStyle, newStructName):
    # This makes 4 types of changes to the class:
    #   It adds a widget variable for items in model // newWidgetFields: '    their '+typeName+': '+widgetName
    #   It adds a set Widget from Vars function      // widgetFromVarsCode: Func UpdateWidgetFromVars()
    #   It adds a set Vars from Widget function      // varsFromWidgetCode: Func UpdateVarsFromWidget()
    #   It add an initialize Widgets function.       // widgetInitFuncCode: widgetName+' <- '+makeTypeNameCall+'\n    addToContainer(box, '+widgetName+')\n'

    # dialogStyles: 'Z_stack', 'X_stack', 'Y_stack', 'TabbedStack', 'FlowStack', 'WizardStack', 'Dialog', 'SectionedDialogStack'
    # also, handle non-modal dialogs

    global classesEncoded
    global currentClassName
    global currentModelSpec
    classesEncoded[className]=1
    currentClassName = className

    # reset the string vars that accumulate the code
    global newWidgetFields
    global widgetInitFuncCode
    global widgetFromVarsCode
    global varsFromWidgetCode
    global clearWidgetCode

    newWidgetFields=''
    widgetInitFuncCode=''
    widgetFromVarsCode=''
    varsFromWidgetCode=''
    clearWidgetCode   =''
    funcTextToUpdateViewWidget= ''
    funcTextToUpdateEditWidget= ''
    funcTextToUpdateCrntFromWidget= ''

    # Find the model
    modelRef            = findModelRef(classes[0], className)
    currentModelSpec    = modelRef
    rowHeaderCode       = ''
    rowViewCode         = ''
    for field in modelRef['fields']:
        fieldName       = field['fieldName']
        typeSpec        = field['typeSpec']
        fldCat          = progSpec.fieldsTypeCategory(typeSpec)
        fieldType       = progSpec.fieldTypeKeyword(field['typeSpec']['fieldType'])
        [fieldSpec, params] = getFieldSpec(fldCat, field)
        structTypeName  =''
        if fldCat=='struct': # Add a new class to be processed
            structTypeName =typeSpec['fieldType'][0]
            newGUIStyle    = 'Dialog'
            guiStructName  = structTypeName+'_'+newGUIStyle+'_GUI'
            addNewStructToProcess(guiStructName, structTypeName, 'struct', 'Dialog')

        if progSpec.isAContainer(typeSpec):# Add a new list to be processed
            structTypeName = typeSpec['fieldType'][0]
            guiStructName  = structTypeName+'_ROW_View'
            addNewStructToProcess(guiStructName, structTypeName, 'list', 'Dialog')
        else:
            print("field::", fieldName, fldCat)
            if(fldCat!='struct'):
                rowHeaderCode   += '        their GUI_Label: '+fieldName + '_header <- makeLabelWidget("'+fieldName+'")\n'
                rowHeaderCode   += '        setLabelWidth('+fieldName+'_header, 15)\n'
                rowHeaderCode   += '        addToContainer(headerBox, '+fieldName+'_header)\n'
            if fldCat=='struct':
                funcTextToUpdateViewWidget     += ''
            elif fldCat=='enum' or fldCat=='mode':
                funcTextToUpdateViewWidget     += ''
                #funcTextToUpdateEditWidget     += ''
                funcTextToUpdateCrntFromWidget += ''#  crntRecord.'+fieldName+' <- dialog.' + widgetName + '.getValue()\n'
            elif fldCat=='bool':
                funcTextToUpdateViewWidget     += ''
            elif fldCat=='string':
                #funcTextToUpdateViewWidget     += ''
                #funcTextToUpdateEditWidget     += '    dialog.' + widgetName + '.setValue('+structTypeName+'_ListData[N].'+fieldName+')\n'
                #funcTextToUpdateCrntFromWidget += '    me string: '+widgetName+'Str <- dialog.' + widgetName + '.getValue()\n'
                #funcTextToUpdateCrntFromWidget += '    crntRecord.'+fieldName+' <- '+widgetName+'Str\n'
                rowViewCode                    += '        their GUI_Label: '+fieldName + '_value <- makeLabelWidget2(Data.'+fieldName+')\n'
                rowViewCode                    += '        setLabelWidth('+fieldName+'_value, 15)\n'
                rowViewCode                    += '        addToContainer(box, '+fieldName+'_value)\n'
                rowViewCode                    += '        showWidget('+fieldName+'_value)\n'
            elif fldCat=='int':
                funcTextToUpdateViewWidget     += ''
                #funcTextToUpdateEditWidget     += '    dialog.' + widgetName + '.setValue('+structTypeName+'_ListData[N].'+fieldName+')\n'
                #funcTextToUpdateCrntFromWidget += '    me string: '+widgetName+'Str <- string(dialog.' + widgetName + '.getValue())\n'
                #funcTextToUpdateCrntFromWidget += '    crntRecord.'+fieldName+' <- dataStr\n'
                rowViewCode                    += '        their GUI_Label: '+fieldName + '_value <- makeLabelWidget2(toString(Data.'+fieldName+'))\n'
                rowViewCode                    += '        setLabelWidth('+fieldName+'_value, 15)\n'
                rowViewCode                    += '        addToContainer(box, '+fieldName+'_value)\n'
                rowViewCode                    += '        showWidget('+fieldName+'_value)\n'
            else: print('pattern_MakeGUI.codeListWidgetManagerClassOverride fldCat not specified: ', fldCat);  exit(2)

    CODE =  '''struct '''+newStructName+'''{
    their GUI_Frame:            box
    their GUI_Frame: makeHeaderView() <- {
        their GUI_Frame: headerBox <- makeXStack("")
        '''+rowHeaderCode+'''
        showWidget(headerBox)
        return(headerBox)
    }
    their GUI_Frame: initWidget(their '''+className+''': Data) <- {
        box <- makeXStack("")
        '''+rowViewCode+'''
        showWidget(box)
        return(box)
    }
}
'''
    #print ('==========================================================\n'+CODE)
    codeDogParser.AddToObjectFromText(classes[0], classes[1], CODE, newStructName)

def BuildGuiForStruct(classes, className, dialogStyle, newStructName):
    # This makes 4 types of changes to the class:
    #   It adds a widget variable for items in model // newWidgetFields: '    their '+typeName+': '+widgetName
    #   It adds a set Widget from Vars function      // widgetFromVarsCode: Func setValue()
    #   It adds a set Vars from Widget function      // varsFromWidgetCode: Func getValue()
    #   It add an initialize Widgets function.       // widgetInitFuncCode: widgetName+' <- '+makeTypeNameCall+'\n    addToContainer(box, '+widgetName+')\n'

    # dialogStyles: 'Z_stack', 'X_stack', 'Y_stack', 'TabbedStack', 'FlowStack', 'WizardStack', 'Dialog', 'SectionedDialogStack', 'V_viewable'
    # also, handle non-modal dialogs
    global classesEncoded
    global currentClassName
    global currentModelSpec
    classesEncoded[className]=1
    currentClassName = className

    # reset the string vars that accumulate the code
    global newWidgetFields
    global widgetInitFuncCode
    global widgetFromVarsCode
    global varsFromWidgetCode
    global clearWidgetCode

    newWidgetFields    = ''
    widgetInitFuncCode = ''
    widgetFromVarsCode = ''
    varsFromWidgetCode = ''
    clearWidgetCode    = ''
    containerWidget    = ''
    boxFooterCode      = ''
    scrollerCode       = ''
    onLoadedCode       = ''
    tagCode            = ''
    makeBoxFooter      = False
    makeBackBtn        = False
    makeNextBtn        = False
    makeVScroller      = False

    # Find the model
    modelRef         = findModelRef(classes[0], className)
    currentModelSpec = modelRef
    classPrimaryGuiItem=progSpec.searchATagStore(modelRef['tags'], 'primaryGuiItem')
    if classPrimaryGuiItem != None: # This GUI Item is important visually
        classPrimaryGuiItem = classPrimaryGuiItem[0]
    classOptionsTags=progSpec.searchATagStore(modelRef['tags'], 'classOptions')
    guiStyleTag=progSpec.searchATagStore(modelRef['tags'], 'dialogStyle')
    if guiStyleTag != None: # This GUI Item is important visually
        guiStyleTag = guiStyleTag[0]
        if guiStyleTag == 'WizardStack': dialogStyle = 'WizardStack'
        if guiStyleTag == 'Z_stack':     dialogStyle = 'Z_stack'
        if guiStyleTag == 'WizardChild':
            dialogStyle    = 'WizardChild'
            makeBoxFooter  = True
            makeBackBtn    = True
            makeNextBtn    = True
            clickNextLabel = "Next"
        if guiStyleTag == 'WizardChildLast':
            dialogStyle    = 'WizardChild'
            makeBoxFooter  = True
            makeBackBtn    = True
            makeNextBtn    = True
            clickNextLabel = "Done"
        if guiStyleTag == 'WizardChildFirst':
            dialogStyle    = 'WizardChild'
            makeBoxFooter  = True
            makeNextBtn    = True
            clickNextLabel = "Next"
    classProperties = progSpec.searchATagStore(modelRef['tags'], 'properties')
    if classProperties != None:
        for classProperty in classProperties:
            if classProperty[0] == 'vScroller': makeVScroller = True
    ### Write code for each field
    for field in modelRef['fields']:
        typeSpec     = field['typeSpec']
        fldCat       = progSpec.fieldsTypeCategory(typeSpec)
        fieldName    = field['fieldName']
        labelText    = deCamelCase(fieldName)
        fieldType    = typeSpec['fieldType']
        if fieldName=='settings':
            # add settings
            continue

        structTypeName=''
        if fldCat=='struct': # Add a new class to be processed
            structTypeName =typeSpec['fieldType'][0]
            if (progSpec.doesClassDirectlyImlementThisField(classes, structTypeName, structTypeName+':managedWidget')
                    or structTypeName.endswith('Widget')):
                fldCat = 'widget'
            else:
                newGUIStyle    = 'Dialog'
                guiStructName  = structTypeName+'_'+newGUIStyle+'_GUI'
                addNewStructToProcess(guiStructName, structTypeName, 'struct', 'Dialog')

        if fldCat != 'widget' and progSpec.isAContainer(typeSpec):# Add a new list to be processed
            if not isinstance(fieldType, str): fieldType=fieldType[0]
            structTypeName = fieldType
            guiStructName  = structTypeName+'_ROW_View'
            addNewStructToProcess(guiStructName, structTypeName, 'list', 'Dialog')

        #TODO: make actions for each function
        if fldCat=='func':
            if fieldName[-4:]== '_btn':
                buttonLabel = deCamelCase(fieldName[:-4])
                # Add a button whose click calls this.
                print('ADDING BUTTON FOR:', fieldName)
                getButtonHandlingCode(classes, buttonLabel, fieldName)

        else: # Here is the main case where code to edit this field is written
            getWidgetHandlingCode(classes, fldCat, fieldName, field, structTypeName, dialogStyle, classPrimaryGuiItem, classOptionsTags, '')

    onLoadedCode           = 'onLoaded()\n'
    returnCode             = '        return(box)'
    if dialogStyle   == 'Z_stack':
        newWidgetFields   += '    their GUI_ZStack: Zbox\n'
        newWidgetFields   += '    me List<me string>: children\n'
        newWidgetFields   += '    me int: activeScreenIdx <-1\n'
        newWidgetFields   += '    void: setActiveChild(me int: N) <- {\n'
        newWidgetFields   += '        if (N >= 0 and N < children.size()){'
        newWidgetFields   += '            me string: childName <- children[N]\n'
        #newWidgetFields   += '            print("^^^setZStackActive: ",N)\n'
        newWidgetFields   += '            setZStackActive(Zbox, childName)\n'
        newWidgetFields   += '            activeScreenIdx <- N\n'
        newWidgetFields   += '        }\n'
        newWidgetFields   += '    }\n'
        containerWidget    = 'Zbox <- makeZStack("'+className+'")\n'
        onLoadedCode       = 'setActiveChild(0)\n'
        onLoadedCode      += '        onLoaded()\n'
        returnCode         = '        return(Zbox)\n'
    elif dialogStyle == 'TabbedStack': containerWidget='their GUI_Frame:box <- makeTabbedWidget("makeTabbedWidget")'
    elif dialogStyle == 'WizardStack':
        newWidgetFields    += '    our wizardWidget: wiz\n'
        newWidgetFields    += '    their GUI_Frame: box\n'
        newWidgetFields    += '''    void: clickNext() <-{
            me int: size <- wiz.children.size()
            if (wiz.activeScreenIdx == size-1){
                _data.wizardFinished(wiz.widgetID)
            }
            else if (wiz.activeScreenIdx < size-1){
                wiz.activeScreenIdx <- wiz.activeScreenIdx+1
                wiz.setActiveChild(wiz.activeScreenIdx)
            }
        }\n'''
        newWidgetFields    += '''    void: clickBack() <-{
            me int: size <- wiz.children.size()
            if (wiz.activeScreenIdx > 0){wiz.activeScreenIdx <- wiz.activeScreenIdx-1}
            wiz.setActiveChild(wiz.activeScreenIdx)
        }\n'''
        containerWidget     = 'Allocate(wiz)\n'
        containerWidget    += '        box <- wiz.initWidget("'+currentClassName+'")\n'
        containerWidget    += '        wiz._data <- _data\n'
        containerWidget    += '        wiz.parentGuiMgr <- self\n'
        widgetInitFuncCode += '        wiz.activeScreenIdx <- 0\n'
        widgetInitFuncCode += '        wiz.setActiveChild(wiz.activeScreenIdx)\n'
    elif dialogStyle   == 'X_stack':
        newWidgetFields    += '    their GUI_XStack:box\n'
        containerWidget     ='box <- makeXStack("")'
    elif dialogStyle   == 'rowWidget':
        newWidgetFields    += '    their GUI_XStack: box\n'
        containerWidget     ='box <- makeXStack("")'
    else:
        newWidgetFields    += '    their GUI_Frame:box\n'
        containerWidget     ='box <- makeYStack("")'
    if makeBoxFooter:
        newWidgetFields    += '    their GUI_Frame:  boxFooter\n'
        boxFooterCode      += 'boxFooter       <- makeXStack("")\n'
        if makeBackBtn:
            newWidgetFields    += '    their GUI_button: backBtn\n'
            newWidgetFields    += '    void: clickBack() <-{parentGuiMgr.clickBack()}\n'
            boxFooterCode      += '        backBtn         <- makeButtonWidget("Back")\n'
            boxFooterCode      += '        GUI.setBtnCallback(backBtn, "clicked", clickBack, this)\n'
            boxFooterCode      += '        addToContainer(boxFooter, backBtn)\n'
            tagCode            += ''
        if makeNextBtn:
            newWidgetFields    += '    their GUI_button: nextBtn\n'
            newWidgetFields    += '''    void: clickNext() <-{
                if(isComplete()){
                    save()
                    parentGuiMgr.clickNext()
                }
            }\n'''
            newWidgetFields    += '''    void: setNextBtnActive(me bool: checkState) <-{
                nextBtn.setWidgetActive(checkState)
            }\n'''
            newWidgetFields    += '''    void: onChanged() <- {
                getValue()
                setNextBtnActive(isComplete())
            }\n'''
            boxFooterCode      += '        nextBtn         <- makeButtonWidget("'+clickNextLabel+'")\n'
            boxFooterCode      += '        nextBtn.setWidgetActive(false)\n'
            boxFooterCode      += '        GUI.setBtnCallback(nextBtn, "clicked", clickNext, this)\n'
            boxFooterCode      += '        addToContainer(boxFooter, nextBtn)\n'
            tagCode            += ''
        boxFooterCode      += '        addToContainer(box, boxFooter)\n'
    if makeVScroller:
        scrollerCode  = 'their GUI_VerticalScroller: scroller <- makeVerticalScroller()\n'
        scrollerCode += 'addToContainerAndExpand(scroller, box)\n'
        returnCode    = 'return (scroller)'

    CODE =  '''
struct <CLASSNAME>:inherits=appComponentData{}
struct <NEWSTRUCTNAME>:inherits=appComponentGUI '''+tagCode+'''{
    '''+newWidgetFields+'''
    our <CLASSNAME>: _data
    their GUI_Frame: initWidget(our <CLASSNAME>: Data) <- {
        _data <- Data
        _data.guiMgr <- self
        '''+containerWidget+'''
        '''+widgetInitFuncCode+'''
        '''+boxFooterCode+'''
        '''+scrollerCode+'''
        '''+onLoadedCode+'''
        '''+returnCode+'''
    }
    void: setValue(our <CLASSNAME>: var) <- {
        '''+widgetFromVarsCode+'''
    }
    void: getValue() <- {
        '''+varsFromWidgetCode+'''
    }
    void: clear() <- {
        '''+clearWidgetCode+'''
    }
}\n'''  # TODO: add <VARSFROMWIDGETCODE>

    CODE = CODE.replace('<NEWSTRUCTNAME>', newStructName)
    CODE = CODE.replace('<CLASSNAME>', className)
    #print ('==========================================================\n'+CODE)
    codeDogParser.AddToObjectFromText(classes[0], classes[1], CODE, newStructName)

def apply(classes, tags, topClassName):
    print('APPLY: in Apply\n')
    global classesToProcess
    global classesEncoded
    classesEncoded={}

    # Choose an appropriate app style
    appStyle='default'
    topWhichScreenFieldID = topClassName+'::whichScreen(int)'
    if (progSpec.doesClassDirectlyImlementThisField(classes[0], topClassName, topWhichScreenFieldID)): # if all data fields are classes
        appStyle='Z_stack'
    else: appStyle='TabbedStack'
    guiStructName = topClassName+'_GUI'
    classesEncoded[guiStructName]=1
    classesToProcess=[[topClassName, 'struct', appStyle, guiStructName]]

    # Amend items to each GUI data class
    for classToAmend in classesToProcess:
        [className, widgetType, dialogStyle, newStructName] = classToAmend
        cdlog(1, 'BUILDING '+dialogStyle+' GUI for '+widgetType+' ' + className + ' ('+newStructName+')')
        if widgetType == 'struct':
            BuildGuiForStruct(classes, className, dialogStyle, newStructName)
        #elif widgetType == 'list':
            #buildListRowView(classes, className, dialogStyle, newStructName)

    # Fill createAppArea()
    primaryGUIName = 'primary_GUI_Mgr'

    CODE ='''
struct APP{
    our '''+topClassName+''': primary
    our '''+guiStructName+''': <PRIMARY_GUI>
    me void: createAppArea(me GUI_Frame: frame) <- {
        Allocate(primary)
        Allocate(<PRIMARY_GUI>)
        their GUI_storyBoard: appStoryBoard <- <PRIMARY_GUI>.initWidget(primary)
        initializeAppGui()
        addToContainerAndExpand (frame, appStoryBoard)
    }
}'''

    CODE = CODE.replace('<PRIMARY_GUI>', primaryGUIName)
    #print ('==========================================================\n'+CODE)
    codeDogParser.AddToObjectFromText(classes[0], classes[1], CODE, 'APP')

    return