TisaneLampServer.psm1

#Region '.\Private\Compile-LanguageNightlyBuild.ps1' 0
function Compile-LanguageNightlyBuild{
    param($languageCode)
    $sqlCPUUsage = (Get-Counter '\Process(sqlservr)\% Processor Time').CounterSamples.CookedValue
    if ($sqlCPUUsage -gt 30) { # over 30% CPU usage => possibly a zombie SQL process. Restart LaMP, clean up the cache
      Stop-Service "Tisane LaMP *LaMP*"
      Start-Service "Tisane LaMP *LaMP*"
      Invoke-Sqlcmd -Query "USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE"
    }
    C:\Tisane\tisaneCompiler.exe "$languageCode"
    if ($LastExitCode -ne 0) {
      # it crashed. Restart LaMP, then try again
      Stop-Service "Tisane LaMP *LaMP*"
      Start-Service "Tisane LaMP *LaMP*"
      Invoke-Sqlcmd -Query "USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE"
      C:\Tisane\tisaneCompiler.exe "$languageCode"
    }
    
      $compressAndUpload = {
        param($languageCode)
        $languageCode = $languageCode.Replace('-','_')
        $zipFullFilename = "C:\Tisane\tisaneDB$languageCode.zip"
        If (Test-Path $zipFullFilename){
          Remove-Item $zipFullFilename
        }
        Compress-Archive -Path "C:\Tisane\outdb\$languageCode-*" -DestinationPath $zipFullFilename
        Compress-Archive -Path "C:\Tisane\outdb\family" -Update -DestinationPath $zipFullFilename
        Compress-Archive -Path "C:\Tisane\outdb\pragma" -Update -DestinationPath $zipFullFilename
        Compress-Archive -Path "C:\Tisane\outdb\role" -Update -DestinationPath $zipFullFilename
        #$ftpTarget = "ftp://internal%40tisane.ai:Tisanelabs4now4321@ftp.tisane.ai/nightly_tisane_$languageCode.zip"
        # $webclient = New-Object -TypeName System.Net.WebClient
        # $uri = New-Object -TypeName System.Uri -ArgumentList $ftpTarget
        # $webclient.UploadFile($uri, $zipFullFilename)
    
      }
      #Start-Job -ScriptBlock $compressAndUpload -ArgumentList $languageCode
    }
#EndRegion '.\Private\Compile-LanguageNightlyBuild.ps1' 36
#Region '.\Private\Compile-SpellChecking.ps1' 0
function Compile-SpellChecking {
If (Test-Path "C:\Tisane\TisaneLaMP.log"){
    Remove-Item "C:\Tisane\TisaneLaMP.log"
}


"Compiling"
# from the heaviest to the lightest
CompileLanguage -languageCode ps-AF
CompileLanguage -languageCode ar
CompileLanguage -languageCode de
CompileLanguage -languageCode tr
CompileLanguage -languageCode vi
CompileLanguage -languageCode es
CompileLanguage -languageCode fa
CompileLanguage -languageCode ru
CompileLanguage -languageCode fi
CompileLanguage -languageCode da
CompileLanguage -languageCode ur
CompileLanguage -languageCode hi
CompileLanguage -languageCode id
CompileLanguage -languageCode it
CompileLanguage -languageCode ko
CompileLanguage -languageCode ms
CompileLanguage -languageCode nl
CompileLanguage -languageCode no
CompileLanguage -languageCode pl
CompileLanguage -languageCode pt
CompileLanguage -languageCode fr
CompileLanguage -languageCode sv
CompileLanguage -languageCode ta
CompileLanguage -languageCode he
CompileLanguage -languageCode en

}
#EndRegion '.\Private\Compile-SpellChecking.ps1' 35
#Region '.\Private\CompileLanguage.ps1' 0
function CompileLanguage{
    param($languageCode)
    C:\Tisane\tisaneCompiler.exe "$languageCode" spell
    } 
#EndRegion '.\Private\CompileLanguage.ps1' 4
#Region '.\Public\Bulk-Normalize.ps1' 0
## =============================================================================
##
## This script's purpose is to set features from Wiktionary. MUST BE RUN ON THE LAMP SERVER
##
## =============================================================================
function Bulk-Normalize{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $true, HelpMessage="Language code: ")][String] $language,
     [Parameter(Mandatory = $true, HelpMessage="Filter: ")][String] $filter,
     [Parameter(Mandatory = $false, HelpMessage="Non-MWE mode: ")][boolean] $nonMWE
   )
   

# . ".\normalizationLib.ps1"

$config_path = $path + "Tisane.TestConsole.exe.config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)
Add-Type -AssemblyName System.Configuration
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"}).GetField("s_current", "NonPublic, Static").SetValue($null, $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
  
[Reflection.Assembly]::LoadFrom($path + "Tisane.Runtime.dll")

# $authenticationBody = '["' + $user + '", "' + $password + '"]'
# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
$global:productionHost = 'https://lampws.tisane.ai:443'
# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $languageJSON = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET
# $languageNamesToCodes = @{}
# $languageID = 0
# $languageJSON | foreach {
# if ($_.ISOCode -eq $language) {
# $languageID = $_.id
# $languageName = $_.englishName
# $commaPos = $languageName.IndexOf(',')
# if ($commaPos -gt 0) {
# $languageName = $languageName.Substring(0, $commaPos)
# }
# $languageNamesToCodes.Add($languageName, $_.ISOCode)
# }
# }

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
Login-Lamp
# $whatever = Invoke-WebRequest -Uri "$productionHost/setLanguage?language=$languageID" -Method POST -Headers $global:authorizationToken -Body ' '
Set-LampLanguage -languageId $languageId
if ($nonMWE) {
  $mweSQL = ''
} else {
  $mweSQL = "AND MainLemma LIKE '% %'"
}

$sql = "USE tisane; SELECT Id, MainLemma FROM Lexemes l WHERE LanguageId = $languageID AND (ISNULL(l.LastUpdatedByBatch,'') <> 'bulkNormalize.ps1') AND InflectingSegment IS NULL $mweSQL AND ($filter)"
$lexemes = Invoke-Sqlcmd -Query $sql

$lexemes | ForEach-Object {
  $mainLemma = $_.MainLemma
  $lexemeId = $_.Id
  if ($nonMWE) {
    $updated = GetNormalizedWikidataLemma -language $language -entry $mainLemma
    if ($updated) {
      $updateSQL = "MainLemma = N'$updated'"
    } else {
      $updateSQL = ""
    }
  } else {
    $updateSQL = GetSegmentSQL -language $language -entry $mainLemma
  }
  if ($updateSQL) {
   Write-Host "[$lexemeId] $mainLemma UPDATE: $updateSQL" -ForegroundColor Green
   $sql = "USE tisane; UPDATE Lexemes SET $updateSQL, LastUpdatedByBatch = 'bulkNormalize.ps1', LastBatchUpdate = GETUTCDATE() WHERE Id = $lexemeId; DELETE dbo.Features WHERE ConnectionType = 1 AND EntityId = $lexemeId"
   #$sql
   Invoke-Sqlcmd -Query $sql
    
    $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme?id=$lexemeId" -Method GET -Headers $global:authorizationToken
    $grammar = @()
    
    if ($updated) {
      $mainLemma = $updated
    }

    $lexeme = @{
      id=$lexemeId
      lemma=$mainLemma
      grammar=$grammar
    }

    $grammar = $response.grammar # existing grammar; cleared before if needed
    #$grammar += @([Feature]::new($featureIndex, $translatedTag, "Grammar"))
    $lexeme.grammar = $grammar
    $lexemeJson = ConvertTo-Json -InputObject $lexeme
    #"Tagging: " + $lexemeJson
    $taggedLemma = Invoke-RestMethod -Uri "$global:productionHost/tagLemma" -Method POST -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))

    $lexeme.grammar = $taggedLemma.grammar
    $lexeme.stem = $taggedLemma.stem
    if ($taggedLemma.style) {
      $lexeme.style = $taggedLemma.style
    }
    $lexeme.requestId = $response.requestId # need for the update request
    $lexemeJson = ConvertTo-Json -InputObject $lexeme
    $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme" -Method PUT -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))
  }
  
}
}
#EndRegion '.\Public\Bulk-Normalize.ps1' 116
#Region '.\Public\Bulk-SameInflectionAs.ps1' 0
## =============================================================================
##
## This script's purpose is to set same inflection as. MUST BE RUN ON THE LAMP SERVER
##
## =============================================================================
function Bulk-SameInflectionAs{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $true, HelpMessage="Language code: ")][String] $language,
     [Parameter(Mandatory = $true, HelpMessage="Filter: ")][String] $filter
   )
   

# . ".\normalizationLib.ps1"

$config_path = $path + "Tisane.TestConsole.exe.config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)
Add-Type -AssemblyName System.Configuration
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"}).GetField("s_current", "NonPublic, Static").SetValue($null, $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
  
[Reflection.Assembly]::LoadFrom($path + "Tisane.Runtime.dll")

# $authenticationBody = '["' + $user + '", "' + $password + '"]'
# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
# $global:productionHost = 'https://lampws.tisane.ai:443'
# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $languageJSON = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET
# $languageNamesToCodes = @{}
# $languageID = 0
# $languageJSON | foreach {
# if ($_.ISOCode -eq $language) {
# $languageID = $_.id
# $languageName = $_.englishName
# $commaPos = $languageName.IndexOf(',')
# if ($commaPos -gt 0) {
# $languageName = $languageName.Substring(0, $commaPos)
# }
# $languageNamesToCodes.Add($languageName, $_.ISOCode)
# }
# }

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
Login-Lamp
# $whatever = Invoke-WebRequest -Uri "$productionHost/setLanguage?language=$languageID" -Method POST -Headers $authorizationToken -Body ' '
Set-LampLanguage -languageId $languageId
$mweSQL = "AND MainLemma LIKE '% %'"

$sql = "USE tisane; SELECT Id, MainLemma FROM Lexemes l WHERE LanguageId = $languageID AND (ISNULL(l.LastUpdatedByBatch,'') NOT LIKE 'bulk%') AND InflectingSegment IS NULL AND SameInflectionsAs IS NULL $mweSQL AND ($filter)"
$lexemes = Invoke-Sqlcmd -Query $sql

$lexemes | ForEach-Object {
  $mainLemma = $_.MainLemma
  $targetLexemeId = $_.Id
  $lexemeId, $stem = GetVerbSameInflectionAs -languageId $languageID -entry $mainLemma
  if ($lexemeId -gt 0) {
   $updateSQL = "SameInflectionsAs = $lexemeId, Stem = N'$stem'"
   Write-Host "$mainLemma UPDATE: $updateSQL" -ForegroundColor Green
   $sql = "USE tisane; UPDATE Lexemes SET $updateSQL, LastUpdatedByBatch = 'bulkSameInflectionAs.ps1', LastBatchUpdate = GETUTCDATE() WHERE Id = $targetLexemeId; DELETE dbo.Features WHERE ConnectionType = 1 AND EntityId = $lexemeId"
   #$sql
   $res = Invoke-Sqlcmd -Query $sql
  }
  
}

}
#EndRegion '.\Public\Bulk-SameInflectionAs.ps1' 75
#Region '.\Public\Import-FamiliesByWikidataCategory.ps1' 0
## =============================================================================
##
## This script's purpose is to import new entries from Wikidata for all the supported languages
##
## =============================================================================
function Import-FamiliesByWikidataCategory{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $false, HelpMessage="Language: ")][String] $language
   )
   

# SELECT fa.Definition, fa.Id, other.Id OtherId, other.Definition otherDefinition FROM dbo.Families fa INNER JOIN dbo.Families other ON other.WikidataId = fa.WikidataId AND other.Id > fa.Id WHERE fa.WikidataId IS NOT NULL ## duplicates

## 60000 was where it ended

$global:maxEntries = 0

$ttr = New-Object System.Diagnostics.TextWriterTraceListener("C:\Tisane\wikidata.log")
[System.Diagnostics.Trace]::Listeners.Add($ttr)
[System.Diagnostics.Trace]::AutoFlush = $true


## overcome the HTTPS error: https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
# If (-not ("TrustAllCertsPolicy" -as [type])) {
# Add-Type @"
# using System.Net;
# using System.Security.Cryptography.X509Certificates;
# public class TrustAllCertsPolicy : ICertificatePolicy {
# public bool CheckValidationResult(
# ServicePoint srvPoint, X509Certificate certificate,
# WebRequest request, int certificateProblem) {
# return true;
# }
# }
# "@
# }
# [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Login-Lamp
class LexiconEntry {
  [string]$word
  [int]$familyId
  [string]$wikidata
  
  LexiconEntry([string]$word, [int]$familyId, [string]$wikidata) {
    $this.word = $word
    $this.familyId = $familyId
    $this.wikidata = $wikidata
  }
}

class ImportedLanguage {
  [string]$ietf
  [int]$tisaneId
  $entries
  
  AddWord([string]$word, [int]$familyId, [string]$wikidata, [boolean]$proper) {
    if (-not $proper -and -not ($this.ietf -eq 'de')) {
        if (-not $word.ToLower().Equals($word) -and $word.Substring(1).Equals($word.Substring(1).ToLower())) {
          # uncapitalize
          $word = $word.ToLower() 
        }
    }
    $toRemovePos = $word.IndexOf('(')
    if ($toRemovePos -gt 0) {
      $word = $word.Substring(0, $toRemovePos).Trim()
    }
    #Write-Host "Adding $word (family $familyId)"
    $this.entries += @([LexiconEntry]::new($word, $familyId, $wikidata))
    if ($this.entries.length -gt $global:maxEntries) {
      $global:maxEntries = $this.entries.length
      Write-Host "Adding $word (family $familyId)"
    }
    if ($this.entries.length -gt 300) {
      $this.Flush()
      $global:maxEntries = 0
    }
  }
  
  Flush() {
    $languageId = $this.tisaneId
    Write-Progress -Activity "Saving language $languageId"
    try {
      $whatever = Invoke-WebRequest -Uri "$global:productionHost/setLanguage?language=$languageId" -Method POST -Headers $global:authorizationToken -Body ' '
    } catch {
      Write-Host "Error setting language: $_" -ForegroundColor Red
      break
    }
    $this.entries | ForEach-Object {
      #Write-Host "Saving language " + $this.tisaneId + ", family " + $_.familyId + ": " + $_.word
      $id = $_.familyId
      $wrd = $_.word
      $wdid = $_.wikidata
      try {
      Write-Progress -Activity "Saving language $languageId $wrd [$id]"
      $ack = Invoke-RestMethod -Uri "$global:productionHost/importFamilies?lexeme=$wrd&families=$id&behavior=f1&source=wikidata&orgId=$wdid" -Method POST -Headers $global:authorizationToken
      } catch {
        Write-Host "Error saving: $_" -ForegroundColor Red
      }
    }
    $this.entries = @()
    Invoke-Sqlcmd -Query "USE tisane; DELETE edits WHERE username = 'bulkimport'" # prevent log blowout
    Invoke-Sqlcmd -Query "USE tisane; update lexemes SET caninflect = 1 WHERE created > GETUTCDATE() - 0.45 AND caninflect = 0 AND sourcetype = 'wikidata'"
    
    # SELECT bywiki.Definition, l.* FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) INNER JOIN dbo.Families bywiki ON bywiki.WikidataId = l.SourceId WHERE l.Created > GETUTCDATE() - 1 AND l.SourceType = 'wikidata'
  }
  
  ImportedLanguage([string]$ietf,
    [int]$tisaneId) {
    $this.ietf = $ietf
    $this.tisaneId = $tisaneId
    $this.entries = @()
  }
}


$global:productionHost = 'https://lampws.tisane.ai:443'
# #$pPass = ConvertFrom-SecureString $password
# $authenticationBody = '["' + $user + '", "' + $password + '"]'

$languages = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET 
$toImport = @()

$languages | Foreach-Object {
  if ($language) {
    if ($_.ISOCode -eq $language) {
      $toImport += @([ImportedLanguage]::new($_.ISOCode, $_.id))
    }
  } else {
    if ($_.ISOCode -and $_.ISOCode -ne 'en') {
      if ($_.ISOCode -eq 'ps-AF') {
        $toImport += @([ImportedLanguage]::new('ps', $_.id))
      }
      if ($_.ISOCode -eq 'zh-CN') {
        $toImport += @([ImportedLanguage]::new('zh', $_.id))
      }
      if ($_.ISOCode -eq 'zh-TW') {
        $toImport += @([ImportedLanguage]::new('zh-tw', $_.id))
      }
      $toImport += @([ImportedLanguage]::new($_.ISOCode, $_.id))
    }
  }
}


# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls

# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

# remove wrong ones: DELETE l from lexemes l INNER JOIN lexemefamilies lf ON lf.lexemeid = l.id INNER JOIN families fa ON fa.id = lf.familyid AND NOT (fa.WikidataId = l.SourceId) WHERE l.created > GETUTCDATE() - 1.5 AND l.SourceType = 'wikidata'

if ($language) {
  $langId = $toImport[0].tisaneId
  $families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE WikidataId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = f.Id WHERE l.LanguageId = $langId)"
} else {
  $families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE WikidataId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l WHERE l.SourceType = 'wikidata' AND l.SourceId = f.WikidataId)"
}

$i = 0
$updated = 0


$families | Foreach-Object {

  #$_
  
  $familyId = $_.Id
  $wikidataId = $_.WikidataId
  $description = $_.Description
  $proper = $_.IsProperNoun

  $pct = $i / $families.length * 100
  $i += 1
  Write-Progress -Activity "[$familyId] $description max entries: $global:maxEntries" -Status "$pct% complete" -PercentComplete $pct
  #'Sorted: ' + $synonyms
  #'Id=' + $id + ', description=' + $description
  $fnd = @()
  $attempt = 0
  
  $wikidataUrl = "https://www.wikidata.org/w/api.php?action=wbgetentities&ids=$wikidataId&format=json"
  $wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET
  
  $wikidataResponse = $wikidataResponse -replace $wikidataId, 'wikiId'
  $wd = ConvertFrom-Json -InputObject $wikidataResponse
  $labels = $wd.entities.wikiId.labels
  $labels | Get-Member -Type Properties | Foreach-Object {
    $crnt = $_ # [pscustomobject]$_
    $nm = $_.name
    $toImport | ForEach-Object {
      if ($nm -eq $_.ietf) {
        #"Adding " + $labels.$nm.value + " with " + $familyId
        $_.AddWord($labels.$nm.value, $familyId, $wikidataId, $proper)
      }
    }
    #$_.name + ' = ' + $labels.$nm.value
  }
  

}

$toImport | ForEach-Object {
  $_.Flush()
}
}
#EndRegion '.\Public\Import-FamiliesByWikidataCategory.ps1' 212
#Region '.\Public\Import-FamiliesFromWikidataByCategory.ps1' 0
## =============================================================================
##
## This script's purpose is to import new families from Wikidata by hypernym family
##
## =============================================================================
function Import-FamiliesFromWikidataByCategory{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $false, HelpMessage="Wikidata hypernym: ")][int] $family
   )
   

# SELECT fa.Definition, fa.Id, other.Id OtherId, other.Definition otherDefinition FROM dbo.Families fa INNER JOIN dbo.Families other ON other.WikidataId = fa.WikidataId AND other.Id > fa.Id WHERE fa.WikidataId IS NOT NULL ## duplicates

## 60000 was where it ended

$global:maxEntries = 0

$ttr = New-Object System.Diagnostics.TextWriterTraceListener("C:\Tisane\wikidata.log")
[System.Diagnostics.Trace]::Listeners.Add($ttr)
[System.Diagnostics.Trace]::AutoFlush = $true


## overcome the HTTPS error: https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
# If (-not ("TrustAllCertsPolicy" -as [type])) {
# Add-Type @"
# using System.Net;
# using System.Security.Cryptography.X509Certificates;
# public class TrustAllCertsPolicy : ICertificatePolicy {
# public bool CheckValidationResult(
# ServicePoint srvPoint, X509Certificate certificate,
# WebRequest request, int certificateProblem) {
# return true;
# }
# }
# "@
# }
# [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$global:productionHost = 'https://lampws.tisane.ai:443'
# #$pPass = ConvertFrom-SecureString $password
# $authenticationBody = '["' + $user + '", "' + $password + '"]'
Login-Lamp

$languages = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET 
$toImport = @()

$languages | Foreach-Object {
  if ($language) {
    if ($_.ISOCode -eq $language) {
      $toImport += @([ImportedLanguage]::new($_.ISOCode, $_.id))
    }
  } else {
    if ($_.ISOCode -and $_.ISOCode -ne 'en') {
      if ($_.ISOCode -eq 'ps-AF') {
        $toImport += @([ImportedLanguage]::new('ps', $_.id))
      }
      if ($_.ISOCode -eq 'zh-CN') {
        $toImport += @([ImportedLanguage]::new('zh', $_.id))
      }
      if ($_.ISOCode -eq 'zh-TW') {
        $toImport += @([ImportedLanguage]::new('zh-tw', $_.id))
      }
      $toImport += @([ImportedLanguage]::new($_.ISOCode, $_.id))
    }
  }
}


# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls

# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding



$families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description FROM Families f WHERE f.Id = $family AND f.WikidataId IS NOT NULL"

if (-not($families) -or $families.length -ne 1) {
  Write-Host "No suitable families found for ID: $family" -ForegroundColor Red
  break
}

$i = 0
$updated = 0


$families | ForEach-Object {

  $familyId = $_.Id
  $hypernymWikidataId = $_.WikidataId
  $description = $_.Description
  
  $wikidataUrl = "https://www.wikidata.org/w/api.php?action=query&prop=linkshere&format=json&lhprop=title&lhnamespace=0&lhlimit=500&titles=$hypernymWikidataId"
  $wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET
  # must replace "pages":{"187588" -> "pages":{"this_page"
  $wikidataResponse.query.pages.this_page.linkshere | ForEach-Object {
  
    # 1. Retrieve the page. 2. See if already exists by Wikidata ID and Lexemes in LanguageId 7. 3. Save if new
  
  }




  $pct = $i / $families.length * 100
  $i += 1
  Write-Progress -Activity "[$familyId] $description max entries: $global:maxEntries" -Status "$pct% complete" -PercentComplete $pct
  #'Sorted: ' + $synonyms
  #'Id=' + $id + ', description=' + $description
  $fnd = @()
  $attempt = 0
  
  
  $wikidataResponse = $wikidataResponse -replace $wikidataId, 'wikiId'
  $wd = ConvertFrom-Json -InputObject $wikidataResponse
  $labels = $wd.entities.wikiId.labels
  $descriptions = $wd.entities.wikiId.descriptions
  if ($descriptions -and $descriptions.en.value -eq 'Wikimedia disambiguation page') {
      Invoke-Sqlcmd -Query "USE tisane; UPDATE dbo.Families SET WikidataId = NULL, LastUpdatedByBatch = 'badwikidata_$wikidataId', LastBatchUpdate = GETUTCDATE() WHERE Id = $familyId"
      Write-Host "Removing Wikidata disambiguation page: $wikidataId ($familyId)" -ForegroundColor Yellow
  }
  else {
    $englishLabel = $labels.en.value -replace "'", "''"
    $lexemeIds = Invoke-Sqlcmd -Query "USE tisane; SELECT l.Id FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = $familyId WHERE l.LanguageId = 7 AND l.MainLemma = N'$englishLabel' COLLATE SQL_Latin1_General_CP1_CI_AS"
    if ($familyId -gt 100000 -or $lexemeIds) {
      $labels | Get-Member -Type Properties | Foreach-Object {
        $crnt = $_ # [pscustomobject]$_
        $nm = $_.name
        $toImport | ForEach-Object {
          if ($nm -eq $_.ietf) {
            #"Adding " + $labels.$nm.value + " with " + $familyId
            $_.AddWord($labels.$nm.value, $familyId, $wikidataId, $proper)
          }
        }
        #$_.name + ' = ' + $labels.$nm.value
      }
    } else {
      Invoke-Sqlcmd -Query "USE tisane; UPDATE dbo.Families SET WikidataId = NULL, LastUpdatedByBatch = 'badwikidata_$wikidataId', LastBatchUpdate = GETUTCDATE() WHERE Id = $familyId"
      Write-Host "Incorrect Wikidata: $wikidataId ($familyId)" -ForegroundColor Yellow
    }
  }
  

}

$toImport | ForEach-Object {
  $_.Flush()
}
}
#EndRegion '.\Public\Import-FamiliesFromWikidataByCategory.ps1' 157
#Region '.\Public\Import-FeatureFromWiktionary.ps1' 0
## =============================================================================
##
## This script's purpose is to set features from Wiktionary. MUST BE RUN ON THE LAMP SERVER
##
## =============================================================================
function Import-FeatureFromWiktionary{
[CmdletBinding()]
Param(
# [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
# [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $true, HelpMessage="Language code: ")][String] $language,
     [Parameter(Mandatory = $true, HelpMessage="Path: ")][String] $path,
     [Parameter(Mandatory = $true, HelpMessage="Part of speech: ")][String] $pos,
     [Parameter(Mandatory = $true, HelpMessage="Feature List ID: ")][int] $listId,
     [Parameter(Mandatory = $true, HelpMessage="Wiktionary labels: ")][String[]] $labels,
     [Parameter(Mandatory = $true, HelpMessage="Feature values: ")][String[]] $values, # an array of Tisane feature values
     [Parameter(Mandatory = $true, HelpMessage="Wiktionary category: ")][String] $category,
     [Parameter(Mandatory = $false, HelpMessage="Retag: ")][char] $retag,
     [Parameter(Mandatory = $false, HelpMessage="Allow touched: ")][boolean] $touched,
     [Parameter(Mandatory = $false, HelpMessage="Database: ")][String] $tisaneDb
   )
   
class Feature {
  [string]$index
  [string]$value
  [string]$type
  
  Feature([string]$index,
    [string]$value,
    [string]$type) {
    $this.index = $index
    $this.value = $value
    $this.type = $type
  }
}

if (-not($tisaneDb)) {
  $tisaneDb = 'tisane'
}

$config_path = $path + "Tisane.TestConsole.exe.config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)
Add-Type -AssemblyName System.Configuration
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"}).GetField("s_current", "NonPublic, Static").SetValue($null, $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
  
[Reflection.Assembly]::LoadFrom($path + "Tisane.Runtime.dll")


# $authenticationBody = '["' + $user + '", "' + $password + '"]'
# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
# $global:productionHost = 'https://lampws.tisane.ai:443'
# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)
Login-Lamp
$languageJSON = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET
$languageNamesToCodes = @{}
$languageID = 0
$languageJSON | foreach {
  if ($_.ISOCode -eq $language) {
    $languageID = $_.id
    $languageNamesToCodes.Add($_.englishName, $_.ISOCode)
  }
}

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

$featureIndex = $listId
$featureIndexQueryResult = Invoke-Sqlcmd -Query "USE $tisaneDb; SELECT FeatureIndex FROM FeatureDefinitionLists fdl WHERE fdl.Id = $listId"
if ($featureIndexQueryResult -and $featureIndexQueryResult[0]) {
  $featureIndex = $featureIndexQueryResult[0]
}

$whatever = Invoke-WebRequest -Uri "$global:lampHost/setLanguage?language=$languageID" -Method POST -Headers $global:authorizationToken -Body ' '


$tisanePOSValue = $pos.ToUpper()
switch ($tisanePOSValue) {
  'ADJECTIVE' { $tisanePOSValue = 'ADJ' }
  'ADVERB' { $tisanePOSValue = 'ADV' }
  'PREPOSITION' { $tisanePOSValue = 'PREP' }
  'CONJUNCTION' { $tisanePOSValue = 'CJ' }
  'INTERJECTION' { $tisanePOSValue = 'INTJ' }
}

if ($retag) {
  $retag = [char]::ToLower($retag)
}

$tagsFound = @()

$updated = 0
$articleCount = 0
$existCount = 0

do {
$wikidataUrl = "https://en.wiktionary.org/w/api.php?action=query&generator=categorymembers&format=json&gcmtitle=Category:$category&prop=pageprops&gcmlimit=500&gcmcontinue=$bookmark"
"Loading entries from $wikidataUrl"
$wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET # -UseBasicParsing
$wikidataResponse = $wikidataResponse.Content # -replace '(?<=pages["]:{["])[^"]+', 'results'
$listOfInstances = ConvertFrom-Json -InputObject $wikidataResponse
if ($listOfInstances.continue) {
  $bookmark = $listOfInstances.continue.gcmcontinue
} else {
  $bookmark = $null
}
#"Bookmark: $bookmark"
$listOfInstances.query.pages.PSObject.Properties | foreach {
  if ($_.Value.title) {
    $articleCount += 1
    $originalWord = $_.Value.title
    $pageId = $_.Value.pageid
    $actualWord = $originalWord -replace ' ', '_'
    $wiktionaryParser = New-Object Tisane.Helper.EnglishWiktionaryParser -ArgumentList ($actualWord, $languageNamesToCodes)
    $articleJSON = ($wiktionaryParser.ToJson().Value | Where Key -eq $pos).Value
    if (-not $articleJSON) {
      # $articleJSON = $wiktionaryParser.ToJson().Value
      $indexInLabelArray = -1
    } else {
      $article = ConvertFrom-Json -InputObject $articleJSON.ToString()
      $tag = $article.tag
      $indexInLabelArray = [array]::IndexOf($labels, $tag)
      if ($indexInLabelArray -eq -1 -and $article.interpretations) {
        $article.interpretations | ForEach-Object {
          if ($indexInLabelArray -eq -1 -and $_.case) {
            $tag = $_.case[0]
            $indexInLabelArray = [array]::IndexOf($labels, $tag)
          }
        }
      }
      if ([array]::IndexOf($tagsFound, $tag) -lt 0) {
        $tagsFound += $tag
      }
    }
    if ($indexInLabelArray -gt -1) {
      $translatedTag = $values[$indexInLabelArray]
      $lexemeExistsWithoutCorrectFeatureSQL = "USE $tisaneDb; SELECT l.Id, (SELECT TOP 1 f.FeatureValue FROM dbo.Features f WHERE f.ConnectionType = 1 AND f.EntityID = l.ID AND f.FeatureListID = $listId) CurrentFeatureValue, l.LastUpdatedBy FROM dbo.Lexemes l WHERE l.LanguageID = $languageID AND l.MainLemma = N'$originalWord' AND EXISTS (SELECT TOP 1 1 FROM dbo.LexemeFamilies lf WHERE lf.LexemeID = l.ID AND EXISTS (SELECT TOP 1 1 FROM dbo.Features ff WHERE ff.ConnectionType = 2 AND ff.EntityID = lf.FamilyID AND ff.FeatureListID = 1 AND ff.FeatureValue = '$tisanePOSValue') )"
      
      #$lexemeExistsWithoutCorrectFeatureSQL
      $matchingLexemes = Invoke-Sqlcmd -Query $lexemeExistsWithoutCorrectFeatureSQL
      if ($matchingLexemes) {
        $existCount += 1
        $matchingLexemes | ForEach-Object {
          $lexemeId = $_[0]
          $existingValue = $_[1]
          if ($existingValue -is [DBNull]) {
            $existingValue = $null
          }
          $lastUpdatedBy = $_[2]
          if ($lastUpdatedBy -is [DBNull] -or $lastUpdatedBy -eq 'bulkimport') {
            $lastUpdatedBy = $null
          }
          if ($lastUpdatedBy -and -not ($touched)) {
            Write-Host "Lexeme $originalWord (id $lexemeId) has been touched by a linguist and will not be updated" -ForegroundColor Red
          } else {
            # there is a lexeme we can and are allowed to update
            if ($retag -eq 'c') {
              # delete all features, it will be retagged
              $clearSQL = "USE $tisaneDb; DELETE dbo.Features WHERE ConnectionType = 1 AND EntityId = $lexemeId"
              Invoke-Sqlcmd -Query $clearSQL
              #$clearSQL
              $existingValue = $null
            }
            
            $updated += 1

            $lexemeUpdateSQL = "USE $tisaneDb; UPDATE l SET l.LastBatchUpdate = GETUTCDATE(), l.LastUpdatedByBatch = 'importFeatureFromWiktionary_$category_$pageId' FROM dbo.Lexemes l WHERE l.Id = $lexemeId"
            if (-not $existingValue -or $existingValue -eq $null -or $existingValue -eq '') {
              # there's no existing value
              Write-Host "Updating $originalWord to $listID = $translatedTag ($tag); not set previously" -ForegroundColor Green
             
              #$updateSQL
              
              $insertSQL = "USE $tisaneDb; INSERT INTO dbo.Features (ConnectionType, EntityID, FeatureListID, FeatureValue) SELECT 1, $lexemeId, $listId, '$translatedTag'"
              #$insertSQL
              Invoke-Sqlcmd -Query $insertSQL          
              Invoke-Sqlcmd -Query $lexemeUpdateSQL
              #$lexemeUpdateSQL
            } else {
              if ($existingValue -ne $translatedTag) {
               Write-Host "Updating $originalWord to $listID = $translatedTag ($tag). Existing value: $existingValue" -ForegroundColor Green
               $updateSQL = "USE $tisaneDb; UPDATE f SET f.FeatureValue = '$translatedTag' FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeID = l.ID AND EXISTS (SELECT TOP 1 1 FROM dbo.Features ff WHERE ff.ConnectionType = 2 AND ff.EntityID = lf.FamilyID AND ff.FeatureListID = 1 AND ff.FeatureValue = '$tisanePOSValue') INNER JOIN dbo.Features f ON f.ConnectionType = 1 AND f.EntityID = l.ID AND f.FeatureListID = $listId WHERE l.Id = $lexemeId"

                #$updateSQL
                Invoke-Sqlcmd -Query $updateSQL
                Invoke-Sqlcmd -Query $lexemeUpdateSQL
                #$lexemeUpdateSQL
              }
            }
            
            if ($retag) {              
              #"Updating: " + $lexemeJson
              $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme?id=$lexemeId" -Method GET -Headers $global:authorizationToken
              $grammar = @()
              $lexeme = @{
                id=$lexemeId
                lemma=$originalWord
                stem=$originalWord
                grammar=$grammar
              }

              $grammar = $response.grammar # existing grammar; cleared before if needed
              #$grammar += @([Feature]::new($featureIndex, $translatedTag, "Grammar"))
              $lexeme.grammar = $grammar
              $lexemeJson = ConvertTo-Json -InputObject $lexeme
              #"Tagging: " + $lexemeJson
              $taggedLemma = Invoke-RestMethod -Uri "$global:productionHost/tagLemma" -Method POST -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))
              #$taggedLemma
              $lexeme.grammar = $taggedLemma.grammar
              $lexeme.stem = $taggedLemma.stem
              if ($taggedLemma.style) {
                $lexeme.style = $taggedLemma.style
              }
              $lexeme.requestId = $response.requestId # need for the update request
              $lexemeJson = ConvertTo-Json -InputObject $lexeme
              $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme" -Method PUT -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))
              #$response
            }
          }
        }
      } else {
        Write-Host "Lexeme $originalWord does not exist" -ForegroundColor Red
      }
    } else {
      Write-Host "No valid mapped tag for $originalWord (original tag: $tag, lexeme $lexemeId)" -ForegroundColor Red
    }
  } # otherwise, it's likely less important
}
} while ($bookmark)

"Tags encountered:" 
$tagsFound

"Updated: $updated, number of articles: $articleCount, $existCount lexeme(s) exist"

}
#EndRegion '.\Public\Import-FeatureFromWiktionary.ps1' 241
#Region '.\Public\Import-FeatureFromWiktionaryDeclension.ps1' 0
## =============================================================================
##
## This script's purpose is to set features based on declension tables in the Wiktionary. MUST BE RUN ON THE LAMP SERVER
##
## It is done by comparison of a set of regexes applied on the lemma to a form identified by the specified label.
## If there's a match, then the feature value is assigned.
##
## EXAMPLE: PS C:\Tisane> .\importFeatureFromWiktionaryDeclension.ps1 -user bulkimport -password xxxxxx -path C:\Tisane\Test
## Console\ -language tr -pos Noun -category Turkish_nouns -label dative -listId 35 -replaceRegexes "(?<=[^ıiuüaoue])[ıiuü]
## (?=[^ıiuüaoue]$)","p$","ç$","t$","k$","k$" -replaceWith "","b","c","d","g","ÄŸ" -values "10","01","02","03","04","05"
## =============================================================================
function Import-FeatureFromWiktionaryDeclension{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $true, HelpMessage="Language code: ")][String] $language,
     [Parameter(Mandatory = $true, HelpMessage="Path: ")][String] $path,
     [Parameter(Mandatory = $true, HelpMessage="Part of speech: ")][String] $pos,
     [Parameter(Mandatory = $true, HelpMessage="Wiktionary category: ")][String] $category, 
     [Parameter(Mandatory = $true, HelpMessage="Wiktionary grammar feature: ")][String] $label, # the grammar label to look for in the declension table
     [Parameter(Mandatory = $true, HelpMessage="Target Feature List ID: ")][int] $listId, # the feature to set
     [Parameter(Mandatory = $true, HelpMessage="Regexes to replace: ")][String[]] $replaceRegexes,
     [Parameter(Mandatory = $true, HelpMessage="Replace with values: ")][AllowEmptyString()][String[]] $replaceWith,
     [Parameter(Mandatory = $true, HelpMessage="Feature values: ")][String[]] $values, # an array of Tisane feature values
     [Parameter(Mandatory = $false, HelpMessage="Retag: ")][char] $retag,
     [Parameter(Mandatory = $false, HelpMessage="Allow touched: ")][boolean] $touched,
     [Parameter(Mandatory = $false, HelpMessage="Database: ")][String] $dbase
   )
   
class Feature {
  [string]$index
  [string]$value
  [string]$type
  
  Feature([string]$index,
    [string]$value,
    [string]$type) {
    $this.index = $index
    $this.value = $value
    $this.type = $type
  }
}

if (-not($dbase)) {
  $dbase = 'tisane'
}

$config_path = $path + "Tisane.TestConsole.exe.config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)
Add-Type -AssemblyName System.Configuration
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"}).GetField("s_current", "NonPublic, Static").SetValue($null, $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
  
[Reflection.Assembly]::LoadFrom($path + "Tisane.Runtime.dll")


# $authenticationBody = '["' + $user + '", "' + $password + '"]'
# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
# $global:productionHost = 'https://lampws.tisane.ai:443'
# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $languageJSON = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET
# $languageNamesToCodes = @{}
# $languageID = 0
# $languageJSON | foreach {
# if ($_.ISOCode -eq $language) {
# $languageID = $_.id
# $languageNamesToCodes.Add($_.englishName, $_.ISOCode)
# }
# }

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
Login-Lamp
$featureIndex = $listId
$featureIndexQueryResult = Invoke-Sqlcmd -Query "USE $dbase; SELECT FeatureIndex FROM FeatureDefinitionLists fdl WHERE fdl.Id = $listId"
if ($featureIndexQueryResult -and $featureIndexQueryResult[0]) {
  $featureIndex = $featureIndexQueryResult[0]
}

$whatever = Invoke-WebRequest -Uri "$global:lampHost/setLanguage?language=$languageID" -Method POST -Headers $global:authorizationToken -Body ' '


$tisanePOSValue = $pos.ToUpper()
switch ($tisanePOSValue) {
  'ADJECTIVE' { $tisanePOSValue = 'ADJ' }
  'ADVERB' { $tisanePOSValue = 'ADV' }
  'PREPOSITION' { $tisanePOSValue = 'PREP' }
  'CONJUNCTION' { $tisanePOSValue = 'CJ' }
  'INTERJECTION' { $tisanePOSValue = 'INTJ' }
}

if ($retag) {
  $retag = [char]::ToLower($retag)
}

$updated = 0
$articleCount = 0
$existCount = 0

do {
$wikidataUrl = "https://en.wiktionary.org/w/api.php?action=query&generator=categorymembers&format=json&gcmtitle=Category:$category&prop=pageprops&gcmlimit=500&gcmcontinue=$bookmark"
"Loading entries from $wikidataUrl"
$wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET # -UseBasicParsing
$wikidataResponse = $wikidataResponse.Content # -replace '(?<=pages["]:{["])[^"]+', 'results'
$listOfInstances = ConvertFrom-Json -InputObject $wikidataResponse
if ($listOfInstances.continue) {
  $bookmark = $listOfInstances.continue.gcmcontinue
} else {
  $bookmark = $null
}
#"Bookmark: $bookmark"
$listOfInstances.query.pages.PSObject.Properties | foreach {
  if ($_.Value.title) {
    $articleCount += 1
    $originalWord = $_.Value.title
    $pageId = $_.Value.pageid
    $actualWord = $originalWord -replace ' ', '_'
    #$actualWord
    $wiktionaryParser = New-Object Tisane.Helper.EnglishWiktionaryParser -ArgumentList ($actualWord, $languageNamesToCodes)
    $articleJSON = ($wiktionaryParser.ToJson().Value | Where Key -eq $pos).Value
    $indexInLabelArray = -1
    $translatedTag = ''
    if ($articleJSON) {
      $article = ConvertFrom-Json -InputObject $articleJSON.ToString()
      $declensionTable = $article.inflection
      if ($declensionTable) {
        $declensionTable | ForEach-Object {
          $formText = $_.text
          $_.categories | ForEach-Object {
            if ($indexInLabelArray -eq -1 -and $_ -eq $label) { # that's the form!!!
              For ($i = 0; $indexInLabelArray -eq -1 -and $i -lt $replaceRegexes.length; $i++) {
                $rx = $replaceRegexes[$i]
                if ($originalWord -match $rx) {
                  # the original word matches the regex...
                  $rw = $replaceWith[$i]
                  $modifiedLemma = $originalWord -replace $rx, $rw
                  $modifiedLemmaWildcard = $modifiedLemma + '*'
                  if ($formText -like $modifiedLemmaWildcard) {
                    # ... and the modified lemma is found in the actual form
                    $indexInLabelArray = $i
                    $translatedTag = $values[$indexInLabelArray]
                    Write-Host "Entry $originalWord -> $modifiedLemma : $rx -> $rw detected => $listId = $translatedTag" -ForegroundColor Green
                   $indexInLabelArray = $i
                  }
                }
              }
            }
          }
        }
      }
    }
    if ($indexInLabelArray -gt -1) {
      $lexemeExistsWithoutCorrectFeatureSQL = "USE $dbase; SELECT l.Id, (SELECT TOP 1 f.FeatureValue FROM dbo.Features f WHERE f.ConnectionType = 1 AND f.EntityID = l.ID AND f.FeatureListID = $listId) CurrentFeatureValue, l.LastUpdatedBy FROM dbo.Lexemes l WHERE l.LanguageID = $languageID AND l.MainLemma = N'$originalWord' AND EXISTS (SELECT TOP 1 1 FROM dbo.LexemeFamilies lf WHERE lf.LexemeID = l.ID AND EXISTS (SELECT TOP 1 1 FROM dbo.Features ff WHERE ff.ConnectionType = 2 AND ff.EntityID = lf.FamilyID AND ff.FeatureListID = 1 AND ff.FeatureValue = '$tisanePOSValue') )"
      
      #$lexemeExistsWithoutCorrectFeatureSQL
      $matchingLexemes = Invoke-Sqlcmd -Query $lexemeExistsWithoutCorrectFeatureSQL
      if ($matchingLexemes) {
        $existCount += 1
        $matchingLexemes | ForEach-Object {
          $lexemeId = $_[0]
          $existingValue = $_[1]
          if ($existingValue -is [DBNull]) {
            $existingValue = $null
          }
          $lastUpdatedBy = $_[2]
          if ($lastUpdatedBy -is [DBNull] -or $lastUpdatedBy -eq 'bulkimport') {
            $lastUpdatedBy = $null
          }
          if ($lastUpdatedBy -and -not ($touched)) {
            Write-Host "Lexeme $originalWord (id $lexemeId) has been touched by a linguist and will not be updated" -ForegroundColor Red
          } else {
            # there is a lexeme we can and are allowed to update
            if ($retag -eq 'c') {
              # delete all features, it will be retagged
              $clearSQL = "USE $dbase; DELETE dbo.Features WHERE ConnectionType = 1 AND EntityId = $lexemeId"
              Invoke-Sqlcmd -Query $clearSQL
              #$clearSQL
              $existingValue = $null
            }
            
            $updated += 1

            $lexemeUpdateSQL = "USE $dbase; UPDATE l SET l.LastBatchUpdate = GETUTCDATE(), l.LastUpdatedByBatch = 'importFeatureFromWiktionaryDeclension_$category_$pageId' FROM dbo.Lexemes l WHERE l.Id = $lexemeId"
            if (-not $existingValue -or $existingValue -eq $null -or $existingValue -eq '') {
              # there's no existing value
              Write-Host "Updating $originalWord to $listID = $translatedTag; not set previously" -ForegroundColor Green
             
              #$updateSQL
              
              $insertSQL = "USE $dbase; INSERT INTO dbo.Features (ConnectionType, EntityID, FeatureListID, FeatureValue) SELECT 1, $lexemeId, $listId, '$translatedTag'"
              #$insertSQL
              Invoke-Sqlcmd -Query $insertSQL          
              Invoke-Sqlcmd -Query $lexemeUpdateSQL
              #$lexemeUpdateSQL
            } else {
              if ($existingValue -ne $translatedTag) {
               Write-Host "Updating $originalWord to $listID = $translatedTag. Existing value: $existingValue" -ForegroundColor Green
               $updateSQL = "USE $dbase; UPDATE f SET f.FeatureValue = '$translatedTag' FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeID = l.ID AND EXISTS (SELECT TOP 1 1 FROM dbo.Features ff WHERE ff.ConnectionType = 2 AND ff.EntityID = lf.FamilyID AND ff.FeatureListID = 1 AND ff.FeatureValue = '$tisanePOSValue') INNER JOIN dbo.Features f ON f.ConnectionType = 1 AND f.EntityID = l.ID AND f.FeatureListID = $listId WHERE l.Id = $lexemeId"

                #$updateSQL
                Invoke-Sqlcmd -Query $updateSQL
                Invoke-Sqlcmd -Query $lexemeUpdateSQL
                #$lexemeUpdateSQL
              }
            }
            
            if ($retag) {              
              #"Updating: " + $lexemeJson
              $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme?id=$lexemeId" -Method GET -Headers $global:authorizationToken
              $grammar = @()
              $lexeme = @{
                id=$lexemeId
                lemma=$originalWord
                stem=$originalWord
                grammar=$grammar
              }

              $grammar = $response.grammar # existing grammar; cleared before if needed
              #$grammar += @([Feature]::new($featureIndex, $translatedTag, "Grammar"))
              $lexeme.grammar = $grammar
              $lexemeJson = ConvertTo-Json -InputObject $lexeme
              #"Tagging: " + $lexemeJson
              $taggedLemma = Invoke-RestMethod -Uri "$global:productionHost/tagLemma" -Method POST -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))
              #$taggedLemma
              $lexeme.grammar = $taggedLemma.grammar
              $lexeme.stem = $taggedLemma.stem
              if ($taggedLemma.style) {
                $lexeme.style = $taggedLemma.style
              }
              $lexeme.requestId = $response.requestId # need for the update request
              $lexemeJson = ConvertTo-Json -InputObject $lexeme
              $response = Invoke-RestMethod -Uri "$global:productionHost/lexeme" -Method PUT -Headers $global:authorizationToken -Body ([System.Text.Encoding]::UTF8.GetBytes($lexemeJson))
              #$response
            }
          }
        }
      } else {
        Write-Host "Lexeme $originalWord does not exist" -ForegroundColor Red
      }
    }
  } # otherwise, it's likely less important
}
} while ($bookmark)

"Updated: $updated, number of articles: $articleCount, $existCount lexeme(s) exist"
}
#EndRegion '.\Public\Import-FeatureFromWiktionaryDeclension.ps1' 253
#Region '.\Public\Import-Wikidata.ps1' 0
## =============================================================================
##
## This script's purpose is to import new entries from Wikidata for all the supported languages
##
## =============================================================================
function Import-Wikidata{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $false, HelpMessage="Language: ")][String] $language,
     [Parameter(Mandatory = $false, HelpMessage="Changes: ")][boolean] $changes
   )
   

# SELECT fa.Definition, fa.Id, other.Id OtherId, other.Definition otherDefinition FROM dbo.Families fa INNER JOIN dbo.Families other ON other.WikidataId = fa.WikidataId AND other.Id > fa.Id WHERE fa.WikidataId IS NOT NULL ## duplicates

## 60000 was where it ended

$global:maxEntries = 0

$ttr = New-Object System.Diagnostics.TextWriterTraceListener("C:\Tisane\wikidata.log")
[System.Diagnostics.Trace]::Listeners.Add($ttr)
[System.Diagnostics.Trace]::AutoFlush = $true

# . ".\normalizationLib.ps1"

## overcome the HTTPS error: https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
# If (-not ("TrustAllCertsPolicy" -as [type])) {
# Add-Type @"
# using System.Net;
# using System.Security.Cryptography.X509Certificates;
# public class TrustAllCertsPolicy : ICertificatePolicy {
# public bool CheckValidationResult(
# ServicePoint srvPoint, X509Certificate certificate,
# WebRequest request, int certificateProblem) {
# return true;
# }
# }
# "@
# }
# [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Login-Lamp
$global:productionHost = 'https://lampws.tisane.ai:443'
class LexiconEntry {
  [string]$word
  [int]$familyId
  [string]$wikidata
  #[string]$mweSQL
  
  LexiconEntry([string]$word, [int]$familyId, [string]$wikidata) {
    $this.word = $word
    $this.familyId = $familyId
    $this.wikidata = $wikidata
    #$this.mweSQL = ''
  }
}

class ImportedLanguage {
  [string]$ietf
  [int]$tisaneId
  $entries
  
  AddWord([string]$word, [int]$familyId, [string]$wikidata, [boolean]$proper) {
    try {
      #Write-Host "AddWord $word"
      if (-not $proper -and -not ($this.ietf -eq 'de')) {
          if (-not $word.ToLower().Equals($word) -and $word.Substring(1).Equals($word.Substring(1).ToLower())) {
            # uncapitalize
            $word = $word.ToLower()
          }
      }
      $languageCode = $this.ietf
      $toRemovePos = $word.IndexOf('(')
      if ($toRemovePos -gt 0) {
        $word = $word.Substring(0, $toRemovePos).Trim()
      }
      #Write-Host "Before GetNormalizedWikidataLemma $word"
      $word = GetNormalizedWikidataLemma -language $this.ietf -entry $word
      #Write-Host "After GetNormalizedWikidataLemma $word"
      $newLexeme = @([LexiconEntry]::new($word, $familyId, $wikidata))
      if ($word.Trim() -like '* *') {
        $mweSegments = GetSegmentSQL -language $this.ietf -entry $word.Trim()
        if ($mweSegments) {
          $newLexeme | Add-Member -MemberType NoteProperty -Force -Name 'mweSQL' -Value $mweSegments
          #$newLexeme.mweSQL = $mweSegments
        }
      }
      #Write-Host "Adding $word (family $familyId)"
      $this.entries += $newLexeme
      if ($this.entries.length -gt $global:maxEntries) {
        $global:maxEntries = $this.entries.length
        Write-Host "Adding ($languageCode) $word (family $familyId)"
      }
    } catch {
      Write-Host "Error saving: $_" -ForegroundColor Red
    }    
    if ($this.entries.length -gt 300) {
      $this.Flush()
      $global:maxEntries = 0
    }
  }
  
  Flush() {
    $languageId = $this.tisaneId
    $entryCount = $this.entries.length
    Write-Progress -Activity "Saving language $languageId - $entryCount entries"
    try {
      $whatever = Invoke-WebRequest -Uri "$global:productionHost/setLanguage?language=$languageId" -Method POST -Headers $global:authorizationToken -Body ' ' -UseBasicParsing
    } catch {
      Write-Host "Error setting language: $_" -ForegroundColor Red
      break
    }
    $this.entries | ForEach-Object {
      #Write-Host "Saving language " + $this.tisaneId + ", family " + $_.familyId + ": " + $_.word
      $id = $_.familyId
      $wrd = $_.word
      $wdid = $_.wikidata
      try {
      #TODO: integrate segmentation cues
      Write-Progress -Activity "Saving language $languageId $wrd [$id]"
      $ack = Invoke-RestMethod -Uri "$global:productionHost/importFamilies?lexeme=$wrd&families=$id&behavior=f1&source=wikidata&orgId=$wdid" -Method POST -Headers $global:authorizationToken
      } catch {
        Write-Host "Error saving: $_" -ForegroundColor Red
      }
    }
    $this.entries = @()
    Invoke-Sqlcmd -Query "USE tisane; DELETE edits WHERE username = 'bulkimport'" # prevent log blowout
    Invoke-Sqlcmd -Query "USE tisane; update lexemes SET caninflect = 1 WHERE created > GETUTCDATE() - 0.45 AND caninflect = 0 AND sourcetype = 'wikidata'"
    
    # SELECT bywiki.Definition, l.* FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) INNER JOIN dbo.Families bywiki ON bywiki.WikidataId = l.SourceId WHERE l.Created > GETUTCDATE() - 1 AND l.SourceType = 'wikidata'
    # UPDATE lf SET lf.FamilyId = bywiki.Id, lf.LastUpdatedBy = 'vadim_sql_wiki_fix', lf.LastUpdate = GETUTCDATE() FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) INNER JOIN dbo.Families bywiki ON bywiki.WikidataId = l.SourceId AND NOT EXISTS (SELECT TOP 1 1 FROM dbo.LexemeFamilies bywikilf WHERE bywikilf.FamilyId = bywiki.Id AND bywikilf.LexemeId = l.Id) WHERE l.Created > GETUTCDATE() - 25 AND l.SourceType = 'wikidata';

    # DELETE l FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) WHERE l.Created > GETUTCDATE() - 30 AND l.SourceType = 'wikidata';

  }
  
  ImportedLanguage([string]$ietf,
    [int]$tisaneId) {
    $this.ietf = $ietf
    $this.tisaneId = $tisaneId
    $this.entries = @()
  }
}



#$pPass = ConvertFrom-SecureString $password
# $authenticationBody = '["' + $user + '", "' + $password + '"]'

$languages = Invoke-RestMethod -Uri "$global:productionHost/languages" -Method GET 
$toImport = @()

$languages | Foreach-Object {
  if (-not($language) -or $_.ISOCode -eq $language) {
    if ($_.ISOCode -and $_.ISOCode -ne 'en') {
      if ($_.ISOCode -eq 'no') {
        $toImport += @([ImportedLanguage]::new('nn', $_.id))
      }
      if ($_.ISOCode -eq 'pt') {
        $toImport += @([ImportedLanguage]::new('pt-br', $_.id))
      }
      if ($_.ISOCode -eq 'ps-AF') {
        $toImport += @([ImportedLanguage]::new('ps', $_.id))
      }
      if ($_.ISOCode -eq 'zh-TW') {
        $toImport += @([ImportedLanguage]::new('zh-hk', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-tw', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-hant', $_.id))
      }
      if ($_.ISOCode -eq 'zh-CN') {
        $toImport += @([ImportedLanguage]::new('zh', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-cn', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-sg', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-hans', $_.id))
      }
      if ($_.ISOCode -eq 'yue') {
        $toImport += @([ImportedLanguage]::new('yue', $_.id))
        $toImport += @([ImportedLanguage]::new('zh-yue', $_.id))
      }
      $toImport += @([ImportedLanguage]::new($_.ISOCode, $_.id))
    }
  }
}


# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls

# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

# remove wrong ones: DELETE l from lexemes l INNER JOIN lexemefamilies lf ON lf.lexemeid = l.id INNER JOIN families fa ON fa.id = lf.familyid AND NOT (fa.WikidataId = l.SourceId) WHERE l.created > GETUTCDATE() - 1.5 AND l.SourceType = 'wikidata'

$addOnSql = ""
if ($changes) {
    Invoke-Sqlcmd -Query "USE tisane; UPDATE lf SET lf.FamilyId = bywiki.Id, lf.LastUpdatedBy = 'sql_wikidata_fix', lf.LastUpdate = GETUTCDATE() FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) INNER JOIN dbo.Families bywiki ON bywiki.WikidataId = l.SourceId AND NOT EXISTS (SELECT TOP 1 1 FROM dbo.LexemeFamilies bywikilf WHERE bywikilf.FamilyId = bywiki.Id AND bywikilf.LexemeId = l.Id) WHERE l.Created > GETUTCDATE() - 25 AND l.SourceType = 'wikidata'; DELETE l FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id INNER JOIN dbo.Families fa ON fa.Id = lf.FamilyId AND (fa.WikidataId <> l.SourceId OR fa.WikidataId IS NULL) WHERE l.Created > GETUTCDATE() - 30 AND l.SourceType = 'wikidata'"

  $addOnSql = " AND (f.LastUpdate > GETUTCDATE() - 20 OR f.Created > GETUTCDATE() - 20)"
}

if ($language) {
  $langId = $toImport[0].tisaneId
  $sql = "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE LEN(WikidataId) > 1 AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = f.Id WHERE l.LanguageId = $langId ) $addOnSql"
  $families = Invoke-Sqlcmd -Query $sql
} else {
  #$families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE WikidataId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l WHERE l.SourceType = 'wikidata' AND l.SourceId = f.WikidataId)"
  $families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE LEN(WikidataId) > 1 $addOnSql"
}

$i = 0
$updated = 0


$families | Foreach-Object {

  #$_
  
  $familyId = $_.Id
  $wikidataId = $_.WikidataId
  $description = $_.Description
  $proper = $_.IsProperNoun

  $pct = $i / $families.length * 100
  $i += 1
  Write-Progress -Activity "[$familyId] $description max entries: $global:maxEntries" -Status "$pct% complete" -PercentComplete $pct
  #'Sorted: ' + $synonyms
  #'Id=' + $id + ', description=' + $description
  $fnd = @()
  $attempt = 0
  
  $wikidataUrl = "https://www.wikidata.org/w/api.php?action=wbgetentities&ids=$wikidataId&format=json"
  $wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET # -UseBasicParsing
  
  $wikidataResponse = $wikidataResponse -replace $wikidataId, "wikiId"
  $wd = ConvertFrom-Json -InputObject $wikidataResponse
  $labels = $wd.entities.wikiId.labels
  $descriptions = $wd.entities.wikiId.descriptions
  if ($descriptions -and $descriptions.en.value -eq 'Wikimedia disambiguation page1') {
      Invoke-Sqlcmd -Query "USE tisane; UPDATE dbo.Families SET WikidataId = NULL, LastUpdatedByBatch = 'badwikidata_$wikidataId', LastBatchUpdate = GETUTCDATE() WHERE Id = $familyId"
      Write-Host "Removing Wikidata disambiguation page: $wikidataId ($familyId)" -ForegroundColor Yellow
  }
  else {
    $filledLanguages = Invoke-Sqlcmd -Query "USE tisane; SELECT l.ISOCode FROM dbo.LexemeFamilies lf INNER JOIN dbo.Lexemes lx ON lx.Id = lf.LexemeId INNER JOIN dbo.Languages l ON l.Id = lx.LanguageId AND lx.SourceType = 'wikidata' WHERE lf.FamilyId = $familyId"
    $englishLabel = $labels.en.value -replace "'", "''"
    $lexemeIds = 1 #Invoke-Sqlcmd -Query "USE tisane; SELECT l.Id FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = $familyId WHERE l.LanguageId = 7 AND l.MainLemma = N'$englishLabel' COLLATE SQL_Latin1_General_CP1_CI_AS"
    if ($labels -and ($familyId -gt 100000 -or $lexemeIds)) {
      $labels | Get-Member -Type Properties | Foreach-Object {
        $crnt = $_ # [pscustomobject]$_
        $nm = $_.name
        $wikidataEntry = $labels.$nm.value
        $alreadyExists = $false
        $filledLanguages | ForEach-Object {
          if ($nm -eq $_.ISOCode) {
            if (-not($language) -or $language -eq $_.ISOCode) {
              $currentLanguageName = $_.englishName
              #"$wikidataEntry already exists in $currentLanguageName"
            }
            $alreadyExists = $true
          }
        }
        if (-not $alreadyExists) {
          $toImport | ForEach-Object {
            if ($nm -eq $_.ietf -and $labels.$nm.value -notlike '*,*' -and $labels.$nm.value -notlike '*/*') {
            
              #"Adding $wikidataEntry with $familyId"
              $_.AddWord($wikidataEntry, $familyId, $wikidataId, $proper)
            }
          }
        }
        #$_.name + ' = ' + $labels.$nm.value
      }
    } else {
      #Invoke-Sqlcmd -Query "USE tisane; UPDATE dbo.Families SET WikidataId = NULL, LastUpdatedByBatch = 'badwikidata_$wikidataId', LastBatchUpdate = GETUTCDATE() WHERE Id = $familyId"
      Write-Host "Incorrect Wikidata: $wikidataId ($familyId)?" -ForegroundColor Yellow
    }
  }
  

}

$toImport | ForEach-Object {
  $_.Flush()
}

# remove duplicated names
Invoke-Sqlcmd -Query "USE tisane; DELETE l FROM Lexemes l
INNER JOIN LexemeFamilies lf ON lf.LexemeId = l.Id
AND EXISTS (SELECT TOP 1 1 FROM LexemeFamilies elf INNER JOIN Lexemes el ON el.Id = elf.LexemeId AND el.LanguageId = 7 AND el.MainLemma = l.MainLemma WHERE elf.FamilyId = lf.FamilyId)
INNER JOIN Families f ON f.Id = lf.FamilyId AND f.IsProperNoun = 1 AND f.Definition LIKE '%name%'
WHERE l.Created > GETUTCDATE() - 0.1 AND l.SourceType = 'wikidata'"

}
#EndRegion '.\Public\Import-Wikidata.ps1' 296
#Region '.\Public\Import-WikidataDomain.ps1' 0
## =============================================================================
##
## This script's purpose is to import new entries from Wikidata based on a category in Wikipedia
##
## =============================================================================
function Import-WikidataDomain{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $false, HelpMessage="Domain ID: ")][int] $domain,
     [Parameter(Mandatory = $false, HelpMessage="Filter Hypernym Wikidata: ")][String] $instanceOf,
     [Parameter(Mandatory = $true, HelpMessage="Filter Hypernym ID: ")][int] $hypernym,
     [Parameter(Mandatory = $true, HelpMessage="Domain Wikidata: ")][String] $category,
     [Parameter(Mandatory = $false, HelpMessage="Remove: ")][String] $remove,
     [Parameter(Mandatory = $false, HelpMessage="Start Family ID: ")][int] $startFamily
     
   )
   

# $authenticationBody = '["' + $user + '", "' + $password + '"]'
# [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
# $global:productionHost = 'https://lampws.tisane.ai:443'
# $productionAuthentication = Invoke-WebRequest -Uri "$global:productionHost/authenticate" -Method POST -Body $authenticationBody -UseBasicParsing
# $inJson = ConvertFrom-Json -InputObject $productionAuthentication.Content
# $global:authorizationToken = @{}
# $global:authorizationToken.Add('Authorization', $inJson.token)

# $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
Login-Lamp
if (-not($category)) {
  $sql = "USE tisane; SELECT Id, WikidataId FROM Families f WHERE Id = $domain"
  $family = Invoke-Sqlcmd -Query $sql
  $category = $family[1]
}
if (-not($instanceOf)) {
  $sql = "USE tisane; SELECT Id, WikidataId FROM Families f WHERE Id = $hypernym"
  $family = Invoke-Sqlcmd -Query $sql
  $instanceOf = $family[1]
}

$sql = "USE tisane; SELECT FeatureValue FROM Features f WHERE ConnectionType = 2 AND EntityId = $hypernym AND FeatureListId = 22"
$f22Value = Invoke-Sqlcmd -Query $sql
$isPerson = 0
if ($f22Value -eq 'PERS' -or $f22Value[0] -eq 'PERS') {
  $isPerson = 1
}

if (-not $startFamily) {
  $startFamily = 125000
}
if ($startFamily -lt $hypernym) {
  $startFamily = $hypernym
}
if ($startFamily -lt $domain) {
  $startFamily = $domain
}

#$wikidataUrl = "https://www.wikidata.org/w/api.php?action=query&prop=linkshere&format=json&lhprop=title&lhnamespace=0&lhlimit=500&titles=$category"
$wikidataUrl = "https://en.wikipedia.org/w/api.php?action=query&generator=categorymembers&format=json&gcmtitle=Category:$category&prop=pageprops&gcmlimit=500"
$wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET # -UseBasicParsing
$wikidataResponse = $wikidataResponse.Content # -replace '(?<=pages["]:{["])[^"]+', 'results'
$listOfInstances = ConvertFrom-Json -InputObject $wikidataResponse
#$listOfInstances.query.pages.results.linkshere | Foreach-Object {
$listOfInstances.query.pages.PSObject.Properties | foreach {
  if ($_.Value.pageprops.wikibase_item) {
    $wikidataId = $_.Value.pageprops.wikibase_item
    $mainLabel = $_.Value.title
    if (-not($mainLabel -like '*Wiki*' -or $mainLabel -like 'List *' -or $mainLabel -like 'Category*' -or $mainLabel -like '* (*' -or $mainLabel -like 'The *')) {
      if ($mainLabel.Contains("(")) {
        $mainLabel = $mainLabel.Substring(0, $mainLabel.IndexOf(' (')).Trim()
      }
      if ($mainLabel.IndexOf($remove) -gt -1) {
        $mainLabel = $mainLabel -replace $remove, ''
        $mainLabel = $mainLabel.Trim()
      }
      Write-Host "[$wikidataId] $mainLabel"
      $sql = "USE tisane; SELECT TOP 1 Id FROM Families f WHERE WikidataId = '$wikidataId' OR EXISTS (SELECT TOP 1 1 FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = f.Id WHERE l.LanguageId = 7 AND l.MainLemma = '$mainLabel')"
      $family = Invoke-Sqlcmd -Query $sql
      if ($family -and $family[0]) {
        $existingFamily = $family[0]
        Write-Host "[$wikidataId] $mainLabel already exists as family $existingFamily, won't add again" -ForegroundColor Red
      } else {
        $englishLabels = @()
        $englishLabels += $mainLabel
        $wikidataUrl = "https://www.wikidata.org/w/api.php?action=wbgetentities&ids=$wikidataId&format=json"
        $wikidataResponse = Invoke-WebRequest -Uri $wikidataUrl -Method GET
        $wikidataResponse = $wikidataResponse -replace $wikidataId, "wikiId"
        $wd = ConvertFrom-Json -InputObject $wikidataResponse
        if ($wd.entities.wikiId.descriptions) {
          $definition = $wd.entities.wikiId.descriptions.en.value
        } else {
          $definition = '???'
        }
        $instanceOfNode = $wd.entities.wikiId.claims.P31
        $subclassOf = $wd.entities.wikiId.claims.P279
        if ($instanceOf -ne 'Q' -and (-not($instanceOfNode) -or -not($instanceOfNode.mainsnak.datavalue.value.id -eq $instanceOf)) -and (-not($subclassOf) -or -not($subclassOf.mainsnak.datavalue.value.id -eq $instanceOf))){ 
          Write-Host "[$wikidataId] $mainLabel ($definition) skipping - not an instance of $instanceOf - $instanceOfNode" -ForegroundColor Red
        } else {
          if ($wd.entities.wikiId.aliases) {
            $wd.entities.wikiId.aliases.en | ForEach-Object {
              if ($_ -and $_.value -and $_.value.Length -gt 0 -and -not($_.value -like 'The *') -and -not($_.value -like '* (*')) {
                $englishLabels += $_.value
              }
            }
          }
          .\newNounFamily -user $user -password $password -lang 0 -hypernym $hypernym -family $startFamily -definition $definition -english $englishLabels -person $isPerson -proper 1 -wikidata $wikidataId -domain $domain
        }
      }
    }
  } # otherwise, it's likely less important
}

}
#EndRegion '.\Public\Import-WikidataDomain.ps1' 115
#Region '.\Public\Set-MWEindex.ps1' 0
## =============================================================================
##
## This script's purpose is to import new entries from Wikidata for all the supported languages
##
## =============================================================================
function Set-MWEindex{
[CmdletBinding()]
Param(
    # [Parameter(Mandatory = $true, valueFromPipeline=$true, HelpMessage="LaMP user: ")][String] $user,
    # [Parameter(Mandatory = $true, HelpMessage="LaMP password: ")][String] $password,
     [Parameter(Mandatory = $false, HelpMessage="Language: ")][String] $language,
     [Parameter(Mandatory = $false, HelpMessage="Changes: ")][boolean] $changes
   )
   

# SELECT fa.Definition, fa.Id, other.Id OtherId, other.Definition otherDefinition FROM dbo.Families fa INNER JOIN dbo.Families other ON other.WikidataId = fa.WikidataId AND other.Id > fa.Id WHERE fa.WikidataId IS NOT NULL ## duplicates

## 60000 was where it ended

$global:maxEntries = 0

$ttr = New-Object System.Diagnostics.TextWriterTraceListener("C:\Tisane\wikidata.log")
[System.Diagnostics.Trace]::Listeners.Add($ttr)
[System.Diagnostics.Trace]::AutoFlush = $true


## overcome the HTTPS error: https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
# If (-not ("TrustAllCertsPolicy" -as [type])) {
# Add-Type @"
# using System.Net;
# using System.Security.Cryptography.X509Certificates;
# public class TrustAllCertsPolicy : ICertificatePolicy {
# public bool CheckValidationResult(
# ServicePoint srvPoint, X509Certificate certificate,
# WebRequest request, int certificateProblem) {
# return true;
# }
# }
# "@
# }
Login-Lamp
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy


if ($language) {
  $langId = $toImport[0].tisaneId
  $sql = "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE LEN(WikidataId) > 1 AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l INNER JOIN dbo.LexemeFamilies lf ON lf.LexemeId = l.Id AND lf.FamilyId = f.Id WHERE l.LanguageId = $langId ) $addOnSql"
  $families = Invoke-Sqlcmd -Query $sql
} else {
  #$families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE WikidataId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Lexemes l WHERE l.SourceType = 'wikidata' AND l.SourceId = f.WikidataId)"
  $families = Invoke-Sqlcmd -Query "USE tisane; SELECT Id, WikidataId, Description, IsProperNoun FROM Families f WHERE LEN(WikidataId) > 1 $addOnSql"
}

}
#EndRegion '.\Public\Set-MWEindex.ps1' 54
#Region '.\Public\Tisane-NightlyBuild.ps1' 0
## =============================================================================
##
## This script's purpose is to compile all production-ready languages
##
## =============================================================================
function Tisane-NightlyBuild{
Add-Type -Assembly "System.Io.Compression.FileSystem"

If (Test-Path "C:\Tisane\TisaneLaMP.log"){
    Remove-Item "C:\Tisane\TisaneLaMP.log"
}



# increase available memory for Japanese, Korean, Turkish, Russian, etc.
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 4096
taskkill /IM TisaneDBViewer.exe /F
taskkill /IM HeidiSQL.exe /F /T
"Compiling"
$sqlCPUUsage = (Get-Counter '\Process(sqlservr)\% Processor Time').CounterSamples.CookedValue
if ($sqlCPUUsage -gt 30) {
  Stop-Service "Tisane LaMP *LaMP*"
  Start-Service "Tisane LaMP *LaMP*"
}
C:\Tisane\tisaneCompiler xling
taskkill /IM HeidiSQL.exe /F /T
#Compile-LanguageNightlyBuild -languageCode ps-AF
Compile-LanguageNightlyBuild -languageCode he
Compile-LanguageNightlyBuild -languageCode vi
Compile-LanguageNightlyBuild -languageCode es
Compile-LanguageNightlyBuild -languageCode yue
Compile-LanguageNightlyBuild -languageCode zh-TW
Compile-LanguageNightlyBuild -languageCode ur
Compile-LanguageNightlyBuild -languageCode hi
Compile-LanguageNightlyBuild -languageCode id
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode fr
Compile-LanguageNightlyBuild -languageCode sv
# Compile-LanguageNightlyBuild -languageCode ta
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode da
Compile-LanguageNightlyBuild -languageCode it
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
taskkill /IM HeidiSQL.exe /F /T
Compile-LanguageNightlyBuild -languageCode ms
Compile-LanguageNightlyBuild -languageCode nl
Compile-LanguageNightlyBuild -languageCode no
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
taskkill /IM HeidiSQL.exe /F /T
Compile-LanguageNightlyBuild -languageCode de
#Compile-LanguageNightlyBuild -languageCode fa
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
taskkill /IM HeidiSQL.exe /F /T
Compile-LanguageNightlyBuild -languageCode ar
#Compile-LanguageNightlyBuild -languageCode uk
#Compile-LanguageNightlyBuild -languageCode bn
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Invoke-Sqlcmd -Query "USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE"
Compile-LanguageNightlyBuild -languageCode th
Compile-LanguageNightlyBuild -languageCode en
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode zh-CN
Compile-LanguageNightlyBuild -languageCode sq
Compile-LanguageNightlyBuild -languageCode af
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Invoke-Sqlcmd -Query "USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE"
Compile-LanguageNightlyBuild -languageCode ru
#Compile-LanguageNightlyBuild -languageCode fi
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Invoke-Sqlcmd -Query "USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE"
taskkill /IM HeidiSQL.exe /F /T
Compile-LanguageNightlyBuild -languageCode ko
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode tr
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode pl
Compile-LanguageNightlyBuild -languageCode pt
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode tl
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
Compile-LanguageNightlyBuild -languageCode ja
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
#Compile-LanguageNightlyBuild -languageCode ro
Compile-LanguageNightlyBuild -languageCode hu
#Compile-LanguageNightlyBuild -languageCode cz
Get-Job | Wait-Job
Get-job | Remove-Job # clean up
taskkill /IM HeidiSQL.exe /F /T
#Compile-LanguageNightlyBuild -languageCode el
#Compile-LanguageNightlyBuild -languageCode bg

$tisaneDbZipPath = "C:\Tisane"
$tisaneDbArchive = "$tisaneDbZipPath\tisane_db.zip"
If (Test-Path $tisaneDbArchive){
    Remove-Item $tisaneDbArchive
}

Get-Job | Wait-Job
Get-job | Remove-Job # clean up

#Compress-Archive -Path C:\Tisane\outdb -DestinationPath $tisaneDbArchive
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
#[System.IO.Compression.ZipFile]::CreateFromDirectory("C:\Tisane\outdb\", "$tisaneDbArchive", $compressionLevel, $false)
$compressionJob = Start-Job -ScriptBlock { 
Add-Type -Assembly "System.Io.Compression.FileSystem"
[System.IO.Compression.ZipFile]::CreateFromDirectory("C:\Tisane\outdb\", "C:\Tisane\tisane_db.zip", [System.IO.Compression.CompressionLevel]::Optimal, $false) }

$ftp = "ftp://internal%40tisane.ai:Tisanelabs4now4321@ftp.tisane.ai/nightlyTisaneDB.zip";

Write-Host -Object "ftp url: $ftp";

$webclient = New-Object -TypeName System.Net.WebClient;
$uri = New-Object -TypeName System.Uri -ArgumentList $ftp;

Write-Host -Object "Uploading $tisaneDbArchive...";

#$webclient.UploadFile($uri, $tisaneDbArchive);

# C:\Tisane\tisaneCompiler.exe tests
# $webclient.UploadFile($uri, "C:\Tisane\tisaneDB.zip");

Write-Host -Object "Copying to permanent location...";
#(new-object Net.WebClient).DownloadString("https://lampws.tisane.ai/freeTisane");
#(new-object Net.WebClient).DownloadString("http://94.237.77.124:8001/freeTisane");
taskkill /IM Tisane.TestConsole.exe /F
taskkill /IM TisaneDBViewer.exe /F
Stop-Service "Tisane LaMP *sandbox*"
Stop-Service "Tisane LaMP *LaMP*"
Stop-Service "SQL Server *MSSQLSERVER*"
dir "C:\Tisane\db" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Copy-Item -Path C:\Tisane\outdb\* -Destination C:\Tisane\db -recurse -force
Start-Service "SQL Server *MSSQLSERVER*"
Start-Service "Tisane LaMP *sandbox*"
Start-Service "Tisane LaMP *LaMP*"

Write-Host -Object "Starting nightly tests...";


[System.GC]::Collect()
#$testbedJob = Start-Job -FilePath C:\LaMP\testbedrun\TisaneNightlyTestsOnly.ps1
#$testbedJob | Wait-Job
#$testbedJob | Remove-Job
C:\LaMP\testbedrun\Testbed.Run.exe standard  tl
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  de
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  vi
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  es
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  hi
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  id
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  fa
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ru
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  en
[System.GC]::Collect()
#C:\LaMP\testbedrun\Testbed.Run.exe standard fi
#[System.GC]::Collect()
#C:\LaMP\testbedrun\Testbed.Run.exe standard yue
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  zh-TW
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  af
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  it
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ko
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ms
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  nl
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  no
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  hu
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  pl
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  pt
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  fr
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ja
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  sv
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  he
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  th
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  zh-CN
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  sq
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ar
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  tr
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ur
[System.GC]::Collect()
C:\LaMP\testbedrun\Testbed.Run.exe standard  ps-AF
[System.GC]::Collect()
Invoke-Sqlcmd -Query "USE tisane; DELETE tr FROM TestResults tr WHERE tr.TestProviderId > 2 AND tr.IsStandard = 0 AND tr.Created < GETUTCDATE() - 1; USE tempdb; DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; DBCC FREESYSTEMCACHE ('ALL'); DBCC FREESESSIONCACHE; DBCC SHRINKDATABASE(tempdb, 10); DBCC shrinkfile ('tempdev'); DBCC shrinkfile ('templog')" # prevent tempdb blowout
#C:\Tisane\tisaneCompiler.exe tl spell
#C:\Tisane\tisaneCompiler.exe hi spell

C:\LaMP\testbedrun\Testbed.Run.exe standard  tl 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  de 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  ru 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  es 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  hi 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  fr 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  ko 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  it 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  af 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  ja 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  hu 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  sq 3
C:\LaMP\testbedrun\Testbed.Run.exe standard  nl 3

C:\LaMP\testbedrun\Testbed.Run.exe standard  tl 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  de 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  ru 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  es 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  hi 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  fr 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  ko 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  it 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  af 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  ja 4
C:\LaMP\testbedrun\Testbed.Run.exe standard  nl 4




$compressionJob | Wait-Job
Get-job | Remove-Job # clean up
}
#EndRegion '.\Public\Tisane-NightlyBuild.ps1' 256
#Region '.\Public\TisaneNightlyTestsOnly.ps1' 0
function Tisane-NightlyTestOnly{
C:\LaMP\testbedrun\Testbed.Run.exe standard  ps-AF
C:\LaMP\testbedrun\Testbed.Run.exe standard  ar
C:\LaMP\testbedrun\Testbed.Run.exe standard  de
C:\LaMP\testbedrun\Testbed.Run.exe standard  tr
C:\LaMP\testbedrun\Testbed.Run.exe standard  vi
C:\LaMP\testbedrun\Testbed.Run.exe standard  es
C:\LaMP\testbedrun\Testbed.Run.exe standard  fa
C:\LaMP\testbedrun\Testbed.Run.exe standard  ru
C:\LaMP\testbedrun\Testbed.Run.exe standard  fi
C:\LaMP\testbedrun\Testbed.Run.exe standard  yue
C:\LaMP\testbedrun\Testbed.Run.exe standard  zh-TW
C:\LaMP\testbedrun\Testbed.Run.exe standard  da
C:\LaMP\testbedrun\Testbed.Run.exe standard  ur
C:\LaMP\testbedrun\Testbed.Run.exe standard  hi
C:\LaMP\testbedrun\Testbed.Run.exe standard  id
C:\LaMP\testbedrun\Testbed.Run.exe standard  it
C:\LaMP\testbedrun\Testbed.Run.exe standard  ko
C:\LaMP\testbedrun\Testbed.Run.exe standard  ms
C:\LaMP\testbedrun\Testbed.Run.exe standard  nl
C:\LaMP\testbedrun\Testbed.Run.exe standard  no
C:\LaMP\testbedrun\Testbed.Run.exe standard  pl
C:\LaMP\testbedrun\Testbed.Run.exe standard  pt
C:\LaMP\testbedrun\Testbed.Run.exe standard  fr
C:\LaMP\testbedrun\Testbed.Run.exe standard  sv
C:\LaMP\testbedrun\Testbed.Run.exe standard  ta
C:\LaMP\testbedrun\Testbed.Run.exe standard  he
C:\LaMP\testbedrun\Testbed.Run.exe standard  ja
C:\LaMP\testbedrun\Testbed.Run.exe standard  th
C:\LaMP\testbedrun\Testbed.Run.exe standard  en
C:\LaMP\testbedrun\Testbed.Run.exe standard  zh-CN
}
#EndRegion '.\Public\TisaneNightlyTestsOnly.ps1' 32