assignOrthancStudy.ipynb 32 KB

import sys
import os
import SimpleITK
import numpy
import matplotlib.pyplot
import subprocess
import json

import segmentation
import importlib
import datetime

sys.path.append(os.path.join(os.path.expanduser('~'),'software','src','nixSuite','wrapper'))
import nixWrapper
nixWrapper.loadLibrary('labkeyInterface')
import labkeyInterface
import labkeyFileBrowser
import labkeyDatabaseBrowser

nixWrapper.loadLibrary('orthancInterface')
import orthancInterface
import orthancFileBrowser
import orthancDatabaseBrowser

def configFile(server):
    return os.path.join(os.path.expanduser('~'),'.labkey',"{}.json".format(server))
    

def connectDB(server):
    fconfig=configFile(server)
    net=labkeyInterface.labkeyInterface()
    net.init(fconfig)
    net.getCSRF()
    return labkeyDatabaseBrowser.labkeyDB(net)

def connectOrthanc(server):
    fconfig=configFile(server)
    net=orthancInterface.orthancInterface()
    net.init(fconfig)
    return orthancDatabaseBrowser.orthancDB(net)
    
#manipulate segmentations
#rewrite this
#nim=getPatientNIM(pId)

loadLibrary
remoteSourcesURL https://git0.fmf.uni-lj.si/studen/nixSuite/raw/master/remoteResources/resources.json
{'labkeyInterface': {'url': 'https://git0.fmf.uni-lj.si/studen/labkeyInterface/archive/master.zip', 'branch': 'master', 'modules': []}, 'irAEMM': {'url': 'https://git0.fmf.uni-lj.si/studen/iraemm/archive/master.zip', 'branch': 'master', 'modules': ['iraemmBrowser']}, 'SlicerLabkeyExtension': {'url': 'https://git0.fmf.uni-lj.si/studen/SlicerLabkeyExtension/archive/SlicerExtensionIndex.zip', 'branch': 'SlicerExtensionIndex', 'modules': ['labkeyBrowser']}, 'limfomiPET': {'url': 'https://git0.fmf.uni-lj.si/studen/limfomiPET/archive/master.zip', 'branch': 'master', 'modules': ['imageBrowser', 'segmentationBrowser']}, 'parseConfig': {'url': 'https://git0.fmf.uni-lj.si/studen/parseConfig/archive/master.zip', 'branch': 'master', 'modules': []}, 'orthancInterface': {'url': 'https://git0.fmf.uni-lj.si/studen/orthancInterface/archive/master.zip', 'branch': 'master', 'modules': []}, 'dynamicSPECT': {'url': 'https://git0.fmf.uni-lj.si/studen/dynamicSPECT/archive/master.zip', 'branch': 'master', 'modules': ['imageBrowser']}}
{'url': 'https://git0.fmf.uni-lj.si/studen/labkeyInterface/archive/master.zip', 'branch': 'master', 'modules': []}
File  /home/studen/temp/labkeyInterface.zip: True
loadLibrary
remoteSourcesURL https://git0.fmf.uni-lj.si/studen/nixSuite/raw/master/remoteResources/resources.json
{'labkeyInterface': {'url': 'https://git0.fmf.uni-lj.si/studen/labkeyInterface/archive/master.zip', 'branch': 'master', 'modules': []}, 'irAEMM': {'url': 'https://git0.fmf.uni-lj.si/studen/iraemm/archive/master.zip', 'branch': 'master', 'modules': ['iraemmBrowser']}, 'SlicerLabkeyExtension': {'url': 'https://git0.fmf.uni-lj.si/studen/SlicerLabkeyExtension/archive/SlicerExtensionIndex.zip', 'branch': 'SlicerExtensionIndex', 'modules': ['labkeyBrowser']}, 'limfomiPET': {'url': 'https://git0.fmf.uni-lj.si/studen/limfomiPET/archive/master.zip', 'branch': 'master', 'modules': ['imageBrowser', 'segmentationBrowser']}, 'parseConfig': {'url': 'https://git0.fmf.uni-lj.si/studen/parseConfig/archive/master.zip', 'branch': 'master', 'modules': []}, 'orthancInterface': {'url': 'https://git0.fmf.uni-lj.si/studen/orthancInterface/archive/master.zip', 'branch': 'master', 'modules': []}, 'dynamicSPECT': {'url': 'https://git0.fmf.uni-lj.si/studen/dynamicSPECT/archive/master.zip', 'branch': 'master', 'modules': ['imageBrowser']}}
{'url': 'https://git0.fmf.uni-lj.si/studen/orthancInterface/archive/master.zip', 'branch': 'master', 'modules': []}
File  /home/studen/temp/orthancInterface.zip: True
#figure out and set studyId from seriesId
def assignFromSeriesId():
    db=connectDB('merlin')
    orthanc=connectOrthanc('merlin')
    project='/dinamic_spect/Patients'
    dataset='Imaging1'

    ds=db.selectRows(project,'study',dataset,'')
    for r in ds['rows']:
        se=orthanc.getSeriesData(r['nmCorrDataOrthancId'])
        r['studyOrthancId']=se['ParentStudy']
        db.modifyRows('update',project,'study',dataset,[r])


def sortStudies(orthanc,xs,f):
    xm={}
    for x in xs:
        sd=f(orthanc.getStudyData(x))
        try:
            xm[sd].append(x)
        except KeyError:
            xm[sd]=[x]
    return xm

#extractors as 3rd arguments to sortStudies;
#they operate on sdata as returned by orthancDatabaseBrowser

def getStudyDate(sdata):
    return sdata['MainDicomTags']['StudyDate']

def getBirthYear(sdata):
    return sdata['PatientMainDicomTags']['PatientBirthDate'][0:4]

#implementation of sortStudies by studyDate
def studyMap(orthanc):
    xs=orthanc.getList('studies')
    return sortStudies(orthanc,xs,getStudyDate)
    
    
        
        
def assignFromDate():
    db=connectDB('labkey-ukc')
    orthanc=connectOrthanc('labkey-ukc')
    project='dynamicSPECT/cardiacSPECT'
    dataset='Imaging1'
    oStudies=studyMap(orthanc)
    ds=db.selectRows(project,'study',dataset,'')
    for r in ds['rows']:
        sid=r['studyOrthancId']
        patientId=r['patientCode']
        if sid:
            print(f'{patientId} ID:{sid}')
            continue
        sdate=r['imagingDate']
        studies=oStudies[sdate]
        if len(studies)==1:
            r['studyOrthancId']=studies[0]
            ds=db.modifyRows('update',project,'study',dataset,[r])
            continue
        xm=sortStudies(orthanc,studies,getBirthYear)
        bdate=patientId[2:]
        #filter on bdate
        xmPrime=xm[bdate]
        #unique solution
        if len(xmPrime)==1:
            r['studyOrthancId']=xmPrime[0]
            ds=db.modifyRows('update',project,'study',dataset,[r])
            continue
        print(xm)
            
        
assignFromDate()    
def isCT(orthanc,sedata):
    #base criteria - is CT and SeriesDescription contains AC
    mtags=sedata['MainDicomTags']
    if not mtags['Modality']=='CT':
        return False
    try:
        if not mtags['SeriesDescription'].find('AC')==0:
            return False
    except KeyError:
        pass
    #backup - more than a single instance
    n=len(sedata['Instances'])
    if n==1:
        return False
    return True

def isMasterNM(orthanc,sedata):
    mtags=sedata['MainDicomTags']
    if not mtags['Modality']=='NM':
        return False
    n=len(sedata['Instances'])
    if not n==1:
        return False
    idata=orthanc.getData('instances',sedata['Instances'][0])
    imtags=idata['MainDicomTags']
    iframes=int(imtags['NumberOfFrames'])
    if iframes<500:
        return False
    #print(idata)
    return True
    
def isCorrDataNM(orthanc,sedata):
    mtags=sedata['MainDicomTags']
    if not mtags['Modality']=='NM':
        return False
    n=len(sedata['Instances'])
    if n==1:
        return False
    #idata=orthanc.getData('instances',sedata['Instances'][0])
    #imtags=idata['MainDicomTags']
    itype=orthanc.getDicomField(sedata['Instances'][0],'0028-0051')
    if itype.find('SCAT')==-1:
        return False
    #print(itype)
    return True
            

def getSeries():
    db=connectDB('labkey-ukc')
    orthanc=connectOrthanc('labkey-ukc')
    project='dynamicSPECT/cardiacSPECT'
    dataset='Imaging1'
    ds=db.selectRows(project,'study',dataset,'')
    for r in ds['rows']:
        if r['nmMasterOrthancId']:
            continue
        series=orthanc.getStudyData(r['studyOrthancId'])['Series']
        for s in series:
            sedata=orthanc.getSeriesData(s)
            mtags=sedata['MainDicomTags']
            #print('{} {}'.format(mtags['Modality'],mtags['SeriesDescription']))
            if isCT(orthanc,sedata):
                r['ctOrthancId']=s
                continue
            if isMasterNM(orthanc,sedata):
                r['nmMasterOrthancId']=s
                continue
            if isCorrDataNM(orthanc,sedata):
                r['nmCorrDataOrthancId']=s
                continue
            
            #print(sedata)
        #break
        ds=db.modifyRows('update',project,'study',dataset,[r])
        #break
getSeries() 
    
User: andrej studen CSRF: 7350f9dcc87c17afddc8c65618089763
User: andrej studen CSRF: 7ddb2a798e2815d2cc6344b560e9a8e1
User: andrej studen CSRF: 523db9b5e52a7a6c294b36d8e86b81d4
#get imagingDate from studyOrthancId
def getImagingDate():
    db=connectDB('labkey-ukc')
    orthanc=connectOrthanc('labkey-ukc')
    project='/dynamicSPECT/cardiacSPECT'
    dataset='Imaging1'
    ds=db.selectRows(project,'study',dataset,'')
    rows=ds['rows']
    for r in rows:
        sid=r['studyOrthancId']
        patientId=r['PatientId']
        if not sid:
            print(f'No study id for {patientId}')
            continue
        sd=orthanc.getStudyData(r['studyOrthancId'])
        r['imagingDate']=sd['MainDicomTags']['StudyDate']
        db.modifyRows('update',project,'study',dataset,[r])
        
def setStudyDate():
    db=connectDB('labkey-ukc')
    orthanc=connectOrthanc('labkey-ukc')
    project='/dynamicSPECT/cardiacSPECT'
    dataset='Imaging1'
    ds=db.selectRows(project,'study',dataset,[])
    rows=ds['rows']
    for r in rows:
        dt=datetime.datetime.strptime(r['imagingDate'],'%Y%m%d')
        r['studyDate']=dt.strftime('%Y/%m/%d')
        db.modifyRows('update',project,'study',dataset,[r])
        
setStudyDate()
User: andrej studen CSRF: eda92fe6acfc645dcc20e64451de2bcc
User: andrej studen CSRF: ccdd6bfe993c84237648879c32922324
User: andrej studen CSRF: 1eefebcb86155da277327e320c6d855e
User: andrej studen CSRF: 97ac1e100819769b7852e9a7dd3290fd
User: andrej studen CSRF: ed40684a2b8537c23fc358ed4d900a47
User: andrej studen CSRF: 34ad147b1b7dd2dd3e61e67158a34afb
User: andrej studen CSRF: 5f51b6f277e43102b44c97658b8a11c8
User: andrej studen CSRF: 8b66c1e79af33886680486734ab0b10b
User: andrej studen CSRF: 0c4c51e3f4b05f46f5fe68b35a1d6e21
User: andrej studen CSRF: 73f023fe6494ee80f446212df52f6702
User: andrej studen CSRF: 479c20de89dc3d47e250677aab54db53
User: andrej studen CSRF: 375be6798203b87d56a61eafdcc2fdc4
User: andrej studen CSRF: 13553704c3885f2667711e1bb5bd8100
User: andrej studen CSRF: 84442ae1e529d6e74d730fe96342a64f
#set patientCode
db=connectDB('labkey-ukc')
project='/dynamicSPECT/cardiacSPECT'
dataset='Imaging1'
ds=db.selectRows(project,'study',dataset,'')
rows=ds['rows']
for r in rows:
    r['patientCode']=r['PatientId']
    db.modifyRows('update',project,'study',dataset,[r])
User: andrej studen CSRF: ef76bf934ffbf0af9fc0547fc7871983
User: andrej studen CSRF: 816ac23d327ba77af1abb18b9c0ba3e1
User: andrej studen CSRF: 1be64b3e1b0d3ed0b6853d56ac70e6a5
User: andrej studen CSRF: d5b958584db13089e2731feb37334487
User: andrej studen CSRF: 9ecdad5e798ef004b999fce6727c4e0f
User: andrej studen CSRF: 19850f8c5b0c4217d483bea59a6fe743
User: andrej studen CSRF: 3ecb54e610afb5605c92a7fa19fb3326
User: andrej studen CSRF: 602968a1373dac5c14d55af8dd1c475b
User: andrej studen CSRF: 16eb98eddbaa6b58f4a5d733a270c013
User: andrej studen CSRF: 207b55bf76fcd1a88fb316cd832d88a4
User: andrej studen CSRF: ecf8895ef0da5c1f092a6ec3a64f7d9c
User: andrej studen CSRF: 94735fb33035a678e5836a38f7cdcdb6
User: andrej studen CSRF: 9cbec531e64fed313135398a92341495
User: andrej studen CSRF: 2387d8b279dfa87b4a1d6cadf1db7d3f
#copy files from one orthanc instance to another
db=connectDB('merlin')
orthanc=connectOrthanc('merlin')
project='/dinamic_spect/Patients'
dataset='Imaging1'

ds=db.selectRows(project,'study',dataset,'')
src=configFile('merlin')
target=configFile('kclj')
path=['software','src','orthancInterface','scripts','moveDicom.sh']
path.insert(0,os.path.expanduser('~'))
script=os.path.join(*path)
for r in ds['rows']:
    subprocess.run([script,src,target,r['studyOrthancId']])
    
User: andrej studen CSRF: 4f341fbc6f8b6681df54039307becbd7
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  9.8M    0  9.8M    0     0  1017k      0 --:--:--  0:00:09 --:--:-- 2100k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Downloaded study 992c0733-b219b554-7ffbb1eb-e29d0606-63a62c51 to /home/studen/temp/Study.zip
100  9.9M  100 23131  100  9.8M   3353  1468k  0:00:06  0:00:06 --:--:-- 1524k
AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored AlreadyStored
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 9262k    0 9262k    0     0   369k      0 --:--:--  0:00:25 --:--:-- 1015k
Downloaded study 8de576d0-e88601c2-5317457b-47705c87-60c15eee to /home/studen/temp/Study.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 9283k  100 21233  100 9262k   3544  1546k  0:00:05  0:00:05 --:--:-- 1745k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 11.7M    0 11.7M    0     0   346k      0 --:--:--  0:00:34 --:--:-- 37959
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Downloaded study 137d9e53-0e77d03e-55f56fbf-55358d85-f473d2c5 to /home/studen/temp/Study.zip
100 11.7M  100 33199  100 11.7M   4014  1455k  0:00:08  0:00:08 --:--:-- 1347k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 12.9M    0 12.9M    0     0   359k      0 --:--:--  0:00:36 --:--:-- 2426k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Downloaded study 3dd2760f-412cbfba-192c1d12-3832dc3c-321651a5 to /home/studen/temp/Study.zip
100 12.9M  100 35515  100 12.9M   3549  1326k  0:00:10  0:00:10 --:--:--  307k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 12.1M    0 12.1M    0     0   539k      0 --:--:--  0:00:22 --:--:--  123k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Downloaded study 07cb4e32-30da5d01-75d7067f-f393540f-432489e1 to /home/studen/temp/Study.zip
100 12.1M  100 34743  100 12.1M   4214  1503k  0:00:08  0:00:08 --:--:--  939k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 11.7M    0 11.7M    0     0   857k      0 --:--:--  0:00:14 --:--:--  964k
Downloaded study 80bb7c25-6e4d4890-f6f3c46e-f0a7bdfd-2be580d2 to /home/studen/temp/Study.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 11.7M  100 33199  100 11.7M   4160  1508k  0:00:07  0:00:07 --:--:-- 1091k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 12.4M    0 12.4M    0     0   659k      0 --:--:--  0:00:19 --:--:-- 2216k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Downloaded study 1a759996-7bdd0109-c5e8f833-c6857dfe-84eaed66 to /home/studen/temp/Study.zip
100 12.4M    0     0  100 12.4M      0  1671k  0:00:07  0:00:07 --:--:-- 1762kSuccess Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success Success
100 12.5M  100 35515  100 12.4M   4102  1474k  0:00:08  0:00:08 --:--:--  910k
#copy dataset from one instance to another
src=connectDB('merlin')
target=connectDB('kclj')
srcProject='dinamic_spect/Patients'
targetProject='dynamicSPECT/cardiacSPECT'
schema='study'
dataset='Imaging1'

def copyDatasetDesign(src,srcProject,target,targetProject,schema,dataset):
    minProperties=['name','label','rangeURI','lookupSchema',
                       'lookupContainer','lookupQuery']
    dsgn=target.getQueryDesign(targetProject,'study',dataset)
    if 'exception' in dsgn:
        print('Missing {} {}'.format(schema,dataset))
        #impossible to create list copy them by hand
        if schema=='lists':
            print('create lists by list archive export')
            return
        design=src.getQueryDesign(srcProject,schema,dataset)

        fields=[]
        for f in design['fields']:
            #skip Key
            if f['name']=='Key':
                continue
            #use subselection
            q={p:f[p] for p in minProperties}
            fields.append(q)

        print(target.addQuery(targetProject,schema,dataset,fields))
        print('Created {}'.format(dataset))

def internalField(v):
    if v.find('_')==0:
        return True
    if v=='lsid':
        return True
    return False
        
def copyDatasetData(src,srcProject,target,targetProject,schema,dataset):
    ds=src.selectRows(srcProject,schema,dataset,[])
    fVar=['PatientId','SequenceNum']
    skipVar=['lsid']
    for r in ds['rows']:
        qfilter=[{'variable':x,'value':'{}'.format(r[x]),'oper':'eq'} for x in fVar]
        ds1=target.selectRows(targetProject,schema,dataset,qfilter)
        if len(ds1['rows'])>0:
            outRow=ds1['rows'][0]
            mode='update'
        else:
            mode='insert'
            outRow={}
        for x in r:
            if internalField(x):
                #print('{}/Skip'.format(x))
                continue
            #print('{}/Use'.format(x))
            outRow[x]=r[x]
        target.modifyRows(mode,targetProject,schema,dataset,[outRow])
        #break
#copyDatasetDesign(src,srcProject,target,targetProject,schema,dataset)
copyDatasetData(src,srcProject,target,targetProject,schema,dataset)
User: andrej studen CSRF: ad0e9a315e6fac8a19f892af1e550d39
User: andrej studen CSRF: e89f9c751f9ca44877fceac804e4909f
User: andrej studen CSRF: f7b3b5f0ddf5198e98a29b7ba31072bd
User: andrej studen CSRF: d34f232a12afc576f9d0477842f9d099
User: andrej studen CSRF: 16deee5f2eb2c59edb604416b8a71bab
User: andrej studen CSRF: fab98bb2b2fc0bb9c7c356ed7d468963
User: andrej studen CSRF: 20974f8994412e7c209edb0c100b59bc
User: andrej studen CSRF: 84cff63141f897248071e16692de5338
User: andrej studen CSRF: a80d3d28add7108dd4287c5fbf4b65b8