├── .Rbuildignore ├── .appveyor.yml ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── CITATION.cff ├── DESCRIPTION ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── SGP-class.R ├── abcSGP.R ├── analyzeSGP.R ├── as.splineMatrix.R ├── baselineSGP.R ├── bubblePlot.R ├── bubblePlot_Styles.R ├── capwords.R ├── checkConfig.R ├── checkKnotsBoundaries.R ├── checkSGP.R ├── checksplineMatrix.R ├── combineSGP.R ├── convertScaleScore.R ├── convertTime.R ├── courseProgressionSGP.R ├── createKnotsBoundaries.R ├── createLongCutscores.R ├── createSuperCohortData.R ├── createUniqueLongData.R ├── csemScoreSimulator.R ├── ddcast.R ├── detectSGPCores.R ├── doRNG.R ├── equateSGP.R ├── getAchievementLevel.R ├── getCohortDataInfo.R ├── getErrorReports.R ├── getFirstAndLastInGroup.R ├── getHighNeedStatus.R ├── getJSON.R ├── getKey.R ├── getKnotsBoundaries.R ├── getMaxOrderForProgression.R ├── getMyLabel.R ├── getNewCutscores.R ├── getPanelData.R ├── getPanelDataVnames.R ├── getPercentileTableNames.R ├── getPreferredSGP.R ├── getSGPBaselineConfig.R ├── getSGPColor.R ├── getSGPConfig.R ├── getSGPSRSBaselineConfig.R ├── getSGPtNames.R ├── getStateAbbreviation.R ├── getTableNameYear.R ├── getTargetAchievementLevels.R ├── getTargetInitialStatus.R ├── getTargetName.R ├── getTargetSGP.R ├── getTargetSGPContentArea.R ├── getTargetSGPLevel.R ├── getTargetScaleScore.R ├── getTargetScaleScoreTableNames.R ├── getTimeShiftIndex.R ├── getVersion.R ├── getYearsContentAreasGrades.R ├── getsplineMatrices.R ├── gofPrint.R ├── gofSGP.R ├── growthAchievementPlot.R ├── is.SGP.R ├── is.splineMatrix.R ├── linkagePlot.R ├── mergeSGP.R ├── mergeScaleScoreTarget.R ├── messageSGP.R ├── outputSGP.R ├── piecewiseTransform.R ├── prepareSGP.R ├── prettyDate.R ├── rliCutscoreCreation.R ├── rliSGP.R ├── setNamesSGP.R ├── splineMatrix-class.R ├── sqliteSGP.R ├── startParallel.R ├── stopParallel.R ├── stratifiedRandomSampleSGP.R ├── studentGrowthPercentiles.R ├── studentGrowthPlot.R ├── studentGrowthPlot_Styles.R ├── studentGrowthProjections.R ├── summarizeSGP.R ├── summarizeSGP_Utilities.R ├── testSGP.R ├── timetakenSGP.R ├── transformScaleScore.R ├── unfoldstudentGrowthPlots.R ├── uniquesplineMatrix.R ├── updateSGP.R ├── visualizeSGP.R ├── yearIncrement.R └── zzz.R ├── README.md ├── _pkgdown.yml ├── data ├── SGPstateData.rda └── datalist ├── docs ├── CNAME ├── articles │ ├── SGP.html │ ├── SGP_Data_Analysis.html │ ├── SGP_Data_Analysis_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ ├── SGP_Data_Preparation.html │ ├── SGP_Data_Preparation_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── crosstalk-1.1.0.1 │ │ │ ├── css │ │ │ │ └── crosstalk.css │ │ │ └── js │ │ │ │ ├── crosstalk.js │ │ │ │ ├── crosstalk.js.map │ │ │ │ ├── crosstalk.min.js │ │ │ │ └── crosstalk.min.js.map │ │ ├── crosstalk-1.1.1 │ │ │ ├── css │ │ │ │ └── crosstalk.css │ │ │ └── js │ │ │ │ ├── crosstalk.js │ │ │ │ ├── crosstalk.js.map │ │ │ │ ├── crosstalk.min.js │ │ │ │ └── crosstalk.min.js.map │ │ ├── crosstalk-1.2.0 │ │ │ ├── css │ │ │ │ └── crosstalk.min.css │ │ │ ├── js │ │ │ │ ├── crosstalk.js │ │ │ │ ├── crosstalk.js.map │ │ │ │ ├── crosstalk.min.js │ │ │ │ └── crosstalk.min.js.map │ │ │ └── scss │ │ │ │ └── crosstalk.scss │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── htmlwidgets-1.5.1 │ │ │ └── htmlwidgets.js │ │ ├── htmlwidgets-1.5.3 │ │ │ └── htmlwidgets.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ ├── htmlwidgets-1.6.2 │ │ │ └── htmlwidgets.js │ │ ├── jquery-1.11.3 │ │ │ ├── jquery-AUTHORS.txt │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ │ ├── jquery-3.5.1 │ │ │ ├── jquery-AUTHORS.txt │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ │ ├── plotly-binding-4.10.0 │ │ │ └── plotly.js │ │ ├── plotly-binding-4.10.1 │ │ │ └── plotly.js │ │ ├── plotly-binding-4.10.2 │ │ │ └── plotly.js │ │ ├── plotly-binding-4.9.2.1 │ │ │ └── plotly.js │ │ ├── plotly-binding-4.9.3 │ │ │ └── plotly.js │ │ ├── plotly-htmlwidgets-css-1.52.2 │ │ │ └── plotly-htmlwidgets.css │ │ ├── plotly-htmlwidgets-css-1.57.1 │ │ │ └── plotly-htmlwidgets.css │ │ ├── plotly-htmlwidgets-css-2.11.1 │ │ │ └── plotly-htmlwidgets.css │ │ ├── plotly-htmlwidgets-css-2.5.1 │ │ │ └── plotly-htmlwidgets.css │ │ ├── plotly-main-1.52.2 │ │ │ └── plotly-latest.min.js │ │ ├── plotly-main-1.57.1 │ │ │ └── plotly-latest.min.js │ │ ├── plotly-main-2.11.1 │ │ │ └── plotly-latest.min.js │ │ ├── plotly-main-2.5.1 │ │ │ └── plotly-latest.min.js │ │ └── typedarray-0.1 │ │ │ └── typedarray.min.js │ ├── SGP_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ ├── index.html │ └── releases │ │ ├── SGP-1.4-0.0.html │ │ ├── SGP-1.4-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.5-0.0.html │ │ ├── SGP-1.5-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.6-0.0.html │ │ ├── SGP-1.6-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.7-0.0.html │ │ ├── SGP-1.7-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.8-0.0.html │ │ ├── SGP-1.8-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.9-0.0.html │ │ ├── SGP-1.9-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-1.9-5.0.html │ │ ├── SGP-1.9-5.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.13 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.14 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── SGP-2.0-0.0.html │ │ ├── SGP-2.0-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ │ ├── anchor-sections-hash.css │ │ │ ├── anchor-sections-icon.css │ │ │ ├── anchor-sections-symbol.css │ │ │ ├── anchor-sections.css │ │ │ └── anchor-sections.js │ │ ├── header-attrs-2.22 │ │ │ └── header-attrs.js │ │ └── header-attrs-2.25 │ │ │ └── header-attrs.js │ │ ├── SGP-2.1-0.0.html │ │ └── SGP-2.1-0.0_files │ │ ├── anchor-sections-1.1.0 │ │ ├── anchor-sections-hash.css │ │ ├── anchor-sections-icon.css │ │ ├── anchor-sections-symbol.css │ │ ├── anchor-sections.css │ │ └── anchor-sections.js │ │ ├── header-attrs-2.22 │ │ └── header-attrs.js │ │ └── header-attrs-2.25 │ │ └── header-attrs.js ├── authors.html ├── img │ ├── REPO_CARD_image.png │ ├── favicon.png │ ├── link.svg │ ├── logo.png │ ├── logo.svg │ ├── logo_grey.png │ ├── logo_white.png │ └── tocBullet.svg ├── index.html ├── jquery.sticky-kit.min.js ├── link.svg ├── news │ └── index.html ├── packagePages.css ├── pkgdown.css ├── pkgdown.js └── reference │ ├── SGP-class.html │ ├── SGP-package.html │ ├── SGPstateData.html │ ├── abcSGP.html │ ├── analyzeSGP.html │ ├── baselineSGP.html │ ├── bubblePlot.html │ ├── bubblePlot_Styles.html │ ├── capwords.html │ ├── combineSGP.html │ ├── courseProgressionSGP.html │ ├── createKnotsBoundaries.html │ ├── getStateAbbreviation.html │ ├── gofPrint.html │ ├── gofSGP.html │ ├── growthAchievementPlot.html │ ├── index.html │ ├── outputSGP.html │ ├── prepareSGP.html │ ├── rliSGP.html │ ├── setNamesSGP.html │ ├── splineMatrix-class.html │ ├── studentGrowthPercentiles.html │ ├── studentGrowthPlot.html │ ├── studentGrowthPlot_Styles.html │ ├── studentGrowthProjections.html │ ├── summarizeSGP.html │ ├── testSGP.html │ ├── updateSGP.html │ └── visualizeSGP.html ├── inst ├── CITATION ├── NEWS └── doc │ ├── SGP.R │ ├── SGP.Rmd │ ├── SGP.html │ ├── SGP_Data_Analysis.R │ ├── SGP_Data_Analysis.Rmd │ ├── SGP_Data_Analysis.html │ ├── SGP_Data_Preparation.R │ ├── SGP_Data_Preparation.Rmd │ └── SGP_Data_Preparation.html ├── man ├── SGP-class.Rd ├── SGP-package.Rd ├── SGPstateData.Rd ├── abcSGP.Rd ├── analyzeSGP.Rd ├── baselineSGP.Rd ├── bubblePlot.Rd ├── bubblePlot_Styles.Rd ├── capwords.Rd ├── combineSGP.Rd ├── courseProgressionSGP.Rd ├── createKnotsBoundaries.Rd ├── createSuperCohortData.Rd ├── getStateAbbreviation.Rd ├── gofPrint.Rd ├── gofSGP.Rd ├── growthAchievementPlot.Rd ├── outputSGP.Rd ├── prepareSGP.Rd ├── rliSGP.Rd ├── setNamesSGP.Rd ├── splineMatrix-class.Rd ├── studentGrowthPercentiles.Rd ├── studentGrowthPlot.Rd ├── studentGrowthPlot_Styles.Rd ├── studentGrowthProjections.Rd ├── summarizeSGP.Rd ├── testSGP.Rd ├── updateSGP.Rd └── visualizeSGP.Rd └── vignettes ├── SGP.Rmd ├── SGP_Data_Analysis.Rmd ├── SGP_Data_Preparation.Rmd └── releases ├── SGP-1.4-0.0.Rmd ├── SGP-1.5-0.0.Rmd ├── SGP-1.6-0.0.Rmd ├── SGP-1.7-0.0.Rmd ├── SGP-1.8-0.0.Rmd ├── SGP-1.9-0.0.Rmd ├── SGP-1.9-5.0.Rmd ├── SGP-2.0-0.0.Rmd └── SGP-2.1-0.0.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^docs$ 2 | ^README\.md$ 3 | ^LICENSE.md 4 | ^\.appveyor\.yml$ 5 | ^vignettes/releases$ 6 | ^\.github$ 7 | ^CITATION\.cff$ 8 | ^_pkgdown\.yml$ 9 | ^\.git$ 10 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | 18 | build_script: 19 | - travis-tool.sh install_deps 20 | 21 | test_script: 22 | - travis-tool.sh run_tests 23 | 24 | on_failure: 25 | - 7z a failure.zip *.Rcheck\* 26 | - appveyor PushArtifact failure.zip 27 | 28 | artifacts: 29 | - path: '*.Rcheck\**\*.log' 30 | name: Logs 31 | 32 | - path: '*.Rcheck\**\*.out' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.fail' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.Rout' 39 | name: Logs 40 | 41 | - path: '\*_*.tar.gz' 42 | name: Bits 43 | 44 | - path: '\*_*.zip' 45 | name: Bits 46 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main, master] 4 | pull_request: 5 | branches: [main, master] 6 | 7 | name: R-CMD-check 8 | 9 | jobs: 10 | R-CMD-check: 11 | runs-on: ${{ matrix.config.os }} 12 | 13 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | config: 19 | - {os: macos-latest, r: 'release'} 20 | - {os: windows-latest, r: 'release'} 21 | - {os: ubuntu-latest, r: 'devel'} 22 | - {os: ubuntu-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'oldrel-1'} 24 | 25 | env: 26 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 27 | R_KEEP_PKG_SOURCE: yes 28 | 29 | steps: 30 | - name: Install Homebrew 31 | if: runner.os == 'macOS' 32 | run: | 33 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 34 | 35 | - name: Install XQUARTZ dependencies on MacOS 36 | if: runner.os == 'macOS' 37 | run: | 38 | brew install --cask xquartz 39 | 40 | - uses: actions/checkout@v3 41 | 42 | - uses: r-lib/actions/setup-pandoc@v2 43 | 44 | - uses: r-lib/actions/setup-r@v2 45 | with: 46 | r-version: ${{ matrix.config.r }} 47 | http-user-agent: ${{ matrix.config.http-user-agent }} 48 | use-public-rspm: true 49 | 50 | # Cache R packages to speed up builds 51 | - name: Cache R packages 52 | uses: actions/cache@v3 53 | with: 54 | path: ~/.cache/R 55 | key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('**/DESCRIPTION') }} 56 | restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }} 57 | 58 | - uses: r-lib/actions/setup-r-dependencies@v2 59 | with: 60 | extra-packages: any::rcmdcheck 61 | needs: check 62 | 63 | - uses: r-lib/actions/check-r-package@v2 64 | with: 65 | upload-snapshots: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data/.DS_Store 2 | R/.Rhistory 3 | R/.DS_Store 4 | .DS_Store 5 | SGP.wiki 6 | .vscode 7 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.1.0 2 | message: "If you use the SGP Package, please cite it using these metadata." 3 | authors: 4 | - family-names: "Betebenner" 5 | given-names: "Damian" 6 | orcid: "https://orcid.org/0000-0003-0476-5599" 7 | - family-names: "VanIwaarden" 8 | given-names: "Adam" 9 | - family-names: "Domingue" 10 | given-names: "Ben" 11 | - family-names: "Shang" 12 | given-names: "Yi" 13 | title: "SGP: Student Growth Percentiles & Percentile Growth Trajectories" 14 | version: 2.2-1.9998 15 | doi: 10.5281/zenodo.10037891 16 | date-released: 2025-6-19 17 | url: "https://sgp.io" 18 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | export(abcSGP) 2 | export(analyzeSGP) 3 | export(as.splineMatrix) 4 | export(baselineSGP) 5 | export(bubblePlot) 6 | export(bubblePlot_Styles) 7 | export(capwords) 8 | export(combineSGP) 9 | export(courseProgressionSGP) 10 | export(createKnotsBoundaries) 11 | export(getStateAbbreviation) 12 | export(gofPrint) 13 | export(gofSGP) 14 | export(growthAchievementPlot) 15 | export(is.splineMatrix) 16 | export(is.SGP) 17 | export(outputSGP) 18 | export(prepareSGP) 19 | export(rliSGP) 20 | export(setNamesSGP) 21 | export(studentGrowthPercentiles) 22 | export(studentGrowthPlot) 23 | export(studentGrowthPlot_Styles) 24 | export(studentGrowthProjections) 25 | export(summarizeSGP) 26 | export(testSGP) 27 | export(updateSGP) 28 | export(visualizeSGP) 29 | exportClasses(SGP) 30 | exportClasses(splineMatrix) 31 | import(data.table) 32 | import(datasets) 33 | import(grid) 34 | import(methods) 35 | importFrom(Cairo,Cairo,CairoSVG) 36 | importFrom(callr,r_bg) 37 | importFrom(collapse, add_stub, add_vars, collapv, ffirst, fmean, fmedian, fnrow, fsd, ftransform, ftransformv, fvar, get_vars, join, na_omit, pivot, .quantile, replace_outliers, roworderv, rm_stub) 38 | importFrom(colorspace,rainbow_hcl,diverge_hcl) 39 | importFrom(crayon,bold,cyan,green,magenta,red,yellow) 40 | importFrom(curl,curl_fetch_memory,new_handle) 41 | importFrom(digest,digest) 42 | importFrom(doParallel,registerDoParallel) 43 | importFrom(equate,freqtab,equate) 44 | importFrom(foreach,'%dopar%',foreach,registerDoSEQ,getDoParName,setDoPar) 45 | importFrom(graphics,par,plot,text) 46 | importFrom(grDevices,colorRampPalette,col2rgb,dev.off,extendrange,hsv,pdf,rgb,rgb2hsv) 47 | importFrom(gridBase,gridFIG) 48 | importFrom(gtools,mixedsort) 49 | importFrom(iterators,iter) 50 | importFrom(jsonlite,toJSON) 51 | importFrom(matrixStats,weightedMedian) 52 | importFrom(parallel,clusterApplyLB,clusterEvalQ,clusterExport,detectCores,makeCluster,makePSOCKcluster,mclapply,parLapplyLB,parLapply,stopCluster) 53 | importFrom(quantreg,rq) 54 | importFrom(randomNames,randomNames) 55 | importFrom(rngtools,getRNG,setRNG,RNGseed,RNGseq,RNGtype,showRNG) 56 | importFrom(RSQLite,dbGetQuery,dbWriteTable,dbConnect,dbDisconnect,dbListFields,dbSendQuery,dbListResults,dbClearResult,SQLite) 57 | importFrom(sn,rsn) 58 | importFrom(splines,bs) 59 | importFrom(svglite,svglite) 60 | importFrom(stats,approx,approxfun,lm,median,na.omit,ppoints,predict,quantile,reshape,rnorm,runif,sd,spline,splinefun,stepfun,var,weighted.mean,cor) 61 | importFrom(toOrdinal,toOrdinal) 62 | importFrom(utils,compareVersion,Rprof,head,object.size,packageVersion,read.table,recover,tail,type.convert,unzip,write.table,zip) 63 | -------------------------------------------------------------------------------- /R/SGP-class.R: -------------------------------------------------------------------------------- 1 | setClassUnion("list.null", c("list","NULL")) 2 | 3 | setOldClass(c('data.frame')) 4 | setOldClass(c('data.table', 'data.frame')) 5 | setClass("SGP", representation(Data="data.table", Data_Supplementary="list.null", Names="list.null", SGP="list.null", Summary="list.null", Version="list.null")) 6 | 7 | .Valid.SGP <- function(object) { 8 | out <- NULL 9 | 10 | ## RUN A SET OF CHECKS ON THE SPECIFIED VARIABLES TO ENSURE THAT THE 11 | ## SCORES ARE WITHIN ACCEPTABLE LIMITS AND THE VARIABLES HAVE THE 12 | ## PROPER VARIABLE TYPE 13 | 14 | if (is.null(out)) out <- TRUE 15 | return(out) 16 | 17 | } 18 | setValidity("SGP", .Valid.SGP) 19 | -------------------------------------------------------------------------------- /R/capwords.R: -------------------------------------------------------------------------------- 1 | `capwords` <- 2 | function( 3 | x, 4 | special.words = c("ELA", "I", "II", "III", "IV", "CCSD", "CUSD", "CUD", "USD", "PSD", "UD", "ESD", "DCYF", "EMH", "HS", "MS", "ES", "SES", "IEP", "ELL", "MAD", "PARCC", "SBAC", "SD", "SWD", "US", "SGP", "SIMEX", "SS", "SAT", "PSAT", "WIDA", "ACCESS", "WIDA-ACCESS") 5 | ) { 6 | if (is.null(x)) return(NULL) 7 | if (is.na(x)) return(NA) 8 | if (identical(x, " ")) return(" ") 9 | 10 | # Basic cleaning: replace underscores, periods, and extra spaces 11 | x <- gsub("[_.]", " ", x) 12 | x <- gsub("\\s+", " ", trimws(x)) # Trim and reduce multiple spaces 13 | 14 | # Helper function to capitalize while respecting special words and numbers 15 | capitalize_words <- function(word) { 16 | # Handle special words 17 | if (word %in% special.words) { 18 | return(word) 19 | } else if (grepl("^[0-9]+(\\.[0-9]+)?$", word)) { # Check for numbers 20 | return(word) 21 | } else { 22 | # Capitalize the first letter only 23 | return(paste0(toupper(substring(word, 1, 1)), tolower(substring(word, 2)))) 24 | } 25 | } 26 | 27 | # Split words and process each, handling punctuation (hyphens, apostrophes) 28 | words <- unlist(strsplit(x, "(?=[\\s'-])|(?<=[\\s'-])", perl = TRUE)) 29 | result <- sapply(words, capitalize_words) 30 | 31 | # Combine processed words and fix spacing around punctuation 32 | s.new <- paste(result, collapse = "") 33 | s.new <- gsub("\\s+([)-])", "\\1", gsub("([(])\\s+", "\\1", s.new)) 34 | 35 | return(s.new) 36 | } ### END capwords -------------------------------------------------------------------------------- /R/checksplineMatrix.R: -------------------------------------------------------------------------------- 1 | `checksplineMatrix` <- 2 | function(list.of.splineMatrix, 3 | sgp_object=NULL, 4 | state=NULL, 5 | content_area=NULL, 6 | year=NULL) { 7 | 8 | if (is.splineMatrix(list.of.splineMatrix)) { 9 | list.of.splineMatrix <- list(list.of.splineMatrix) 10 | } 11 | for (i in names(list.of.splineMatrix)) { 12 | if (!grepl("SIMEX", i)) { 13 | if (!grepl("BASELINE", i) || is.null(state) || is.null(SGP::SGPstateData[[state]][['Baseline_splineMatrix']])) { 14 | splineMatrix.tf <- sapply(list.of.splineMatrix[[i]], validObject, test=TRUE)==TRUE 15 | if (!all(splineMatrix.tf)) { 16 | content_area <- unlist(strsplit(i, "[.]"))[1]; year <- unlist(strsplit(i, "[.]"))[2] 17 | for (j in names(list.of.splineMatrix[[i]])[!splineMatrix.tf]) { 18 | message(paste("\tNOTE: Updating Coefficient Matrix", i, j, "to new splineMatrix class.")) 19 | list.of.splineMatrix[[i]][[j]] <- 20 | as.splineMatrix(matrix_argument=list.of.splineMatrix[[i]][[j]], matrix_argument_name=j, content_area=content_area, year=year, sgp_object=sgp_object) 21 | } 22 | } 23 | list.of.splineMatrix[[i]] <- uniquesplineMatrix(list.of.splineMatrix[[i]]) 24 | } else { 25 | list.of.splineMatrix[[i]] <- SGP::SGPstateData[[state]][['Baseline_splineMatrix']][['Coefficient_Matrices']][[i]] 26 | } 27 | } else { 28 | for (grd_ord in names(list.of.splineMatrix[[i]])) { 29 | for (lambda in grep("lambda", names(list.of.splineMatrix[[i]][[grd_ord]]), value=TRUE)) { 30 | splineMatrix.tf <- sapply(list.of.splineMatrix[[i]][[grd_ord]][[lambda]], validObject, test=TRUE)==TRUE 31 | if (!all(splineMatrix.tf)) { 32 | content_area <- unlist(strsplit(i, "[.]"))[1]; year <- unlist(strsplit(i, "[.]"))[2] 33 | for (j in names(list.of.splineMatrix[[i]][[grd_ord]][[lambda]])[!splineMatrix.tf]) { 34 | message(paste("\tNOTE: Updating Coefficient Matrix", i, grd_ord, lambda, j, "to new splineMatrix class.")) 35 | list.of.splineMatrix[[i]][[grd_ord]][[lambda]][[j]] <- 36 | as.splineMatrix(matrix_argument=list.of.splineMatrix[[i]][[grd_ord]][[lambda]][[j]], matrix_argument_name=j, content_area=content_area, year=year, sgp_object=sgp_object) 37 | } 38 | } 39 | list.of.splineMatrix[[i]][[grd_ord]][[lambda]] <- uniquesplineMatrix(list.of.splineMatrix[[i]][[grd_ord]][[lambda]]) 40 | } 41 | } 42 | } 43 | } 44 | return(list.of.splineMatrix) 45 | } ### END checksplineMatrix 46 | -------------------------------------------------------------------------------- /R/convertScaleScore.R: -------------------------------------------------------------------------------- 1 | `convertScaleScore` <- 2 | function(tmp.data.for.equate, 3 | tmp.year.for.equate, 4 | equate.list, 5 | conversion.type, 6 | equating.method, 7 | state) { 8 | 9 | SCALE_SCORE <- TEMP_SCALE_SCORE_EQUATED <- GRADE <- CONTENT_AREA <- YEAR <- NULL 10 | 11 | ### Define variables 12 | 13 | tmp.unique.years <- unique(tmp.data.for.equate[['YEAR']]) 14 | 15 | if (conversion.type=="NEW_TO_OLD") { 16 | tmp.years.for.equate <- sort(tmp.unique.years[tmp.unique.years >= tmp.year.for.equate]) 17 | } else { 18 | tmp.years.for.equate <- sort(tmp.unique.years[tmp.unique.years < tmp.year.for.equate]) 19 | } 20 | if (paste("SCALE_SCORE_EQUATED", equating.method, conversion.type, sep="_") %in% names(tmp.data.for.equate)) tmp.data.for.equate[,paste("SCALE_SCORE_EQUATED", equating.method, conversion.type, sep="_"):=NULL] 21 | 22 | if (!is.null(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][["Equated_Content_Areas_and_Grades"]])) { 23 | equating.content_areas.grades <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][["Equated_Content_Areas_and_Grades"]] 24 | } else { 25 | equating.content_areas.grades <- lapply(equate.list, names) 26 | names(equating.content_areas.grades) <- sapply(strsplit(names(equating.content_areas.grades), '[.]'), '[', 1) 27 | for (tmp.iter in seq_along(equating.content_areas.grades)) { 28 | equating.content_areas.grades[[tmp.iter]] <- gsub("GRADE_", "", equating.content_areas.grades[[tmp.iter]]) 29 | } 30 | } 31 | 32 | 33 | ### Create scale.score.concordance lookup 34 | 35 | for (content_area.iter in names(equating.content_areas.grades)) { 36 | for (grade.iter in equating.content_areas.grades[[content_area.iter]]) { 37 | tmp.data.for.equate[YEAR %in% tmp.years.for.equate & CONTENT_AREA==content_area.iter & GRADE==grade.iter, 38 | TEMP_SCALE_SCORE_EQUATED:=equate.list[[paste(content_area.iter, tmp.year.for.equate, sep=".")]][[paste("GRADE", grade.iter, sep="_")]][[toupper(equating.method)]][[conversion.type]][['interpolated_function']](SCALE_SCORE)] 39 | } 40 | } 41 | 42 | tmp.data.for.equate[!YEAR %in% tmp.years.for.equate, TEMP_SCALE_SCORE_EQUATED:=SCALE_SCORE] 43 | tmp.data.for.equate[is.na(TEMP_SCALE_SCORE_EQUATED) & !is.na(SCALE_SCORE), TEMP_SCALE_SCORE_EQUATED:=SCALE_SCORE] 44 | setnames(tmp.data.for.equate, "TEMP_SCALE_SCORE_EQUATED", paste("SCALE_SCORE_EQUATED", toupper(equating.method), conversion.type, sep="_")) 45 | 46 | return(tmp.data.for.equate) 47 | } ### END convertScaleScore function 48 | -------------------------------------------------------------------------------- /R/convertTime.R: -------------------------------------------------------------------------------- 1 | `convertTime` <- 2 | function(tmp.time) { 3 | tmp <- tail(c(0, 0, 0, as.numeric(unlist(strsplit(tmp.time, ":")))), 4) 4 | tmp.label <- c("Day", "Hour", "Minute", "Second") 5 | tmp.label[which(tmp!=1)] <- paste0(tmp.label, "s")[which(tmp!=1)] 6 | return(paste(paste(tmp[tmp!=0], tmp.label[tmp!=0]), collapse=", ")) 7 | } ### END convertTime 8 | -------------------------------------------------------------------------------- /R/createKnotsBoundaries.R: -------------------------------------------------------------------------------- 1 | `createKnotsBoundaries` <- 2 | function(tmp.data, 3 | knot.cut.percentiles=c(0.2,0.4,0.6,0.8)) { 4 | 5 | CONTENT_AREA <- GRADE <- VALID_CASE <- NULL 6 | 7 | tmp.grade.list <- tmp.list <- list() 8 | 9 | setkeyv(tmp.data, c("VALID_CASE", "CONTENT_AREA", "GRADE")) 10 | 11 | for (my.list.label in unique(tmp.data["VALID_CASE"], by="CONTENT_AREA")[["CONTENT_AREA"]]) { 12 | tmp.grade.list[[my.list.label]] <- sort(unique(tmp.data[SJ("VALID_CASE", my.list.label)], by="GRADE")[["GRADE"]]) 13 | for (j in seq_along(tmp.grade.list[[my.list.label]])) { 14 | tmp.list[[my.list.label]][[3*j-2]] <- 15 | round(quantile(tmp.data[list("VALID_CASE", my.list.label, tmp.grade.list[[my.list.label]][j])][["SCALE_SCORE"]], 16 | probs=knot.cut.percentiles, na.rm=TRUE, names=FALSE), digits=3) 17 | tmp.list[[my.list.label]][[3*j-1]] <- 18 | round(extendrange(tmp.data[list("VALID_CASE", my.list.label, tmp.grade.list[[my.list.label]][j])][["SCALE_SCORE"]], f=0.1), digits=3) 19 | tmp.list[[my.list.label]][[3*j]] <- 20 | round(extendrange(tmp.data[list("VALID_CASE", my.list.label, tmp.grade.list[[my.list.label]][j])][["SCALE_SCORE"]], f=0.0), digits=3) 21 | } 22 | setattr(tmp.list[[my.list.label]], "names", paste0(rep(c("knots_", "boundaries_", "loss.hoss_"), length(tmp.grade.list[[my.list.label]])), 23 | rep(tmp.grade.list[[my.list.label]], each=3))) 24 | } 25 | 26 | return(tmp.list) 27 | } ## END createKnotsBoundaries 28 | -------------------------------------------------------------------------------- /R/createSuperCohortData.R: -------------------------------------------------------------------------------- 1 | `createSuperCohortData` <- 2 | function( 3 | base_data, 4 | sgp.config, 5 | supercohort_base_years, ## Subset of years of supplied_base data to use for super-cohort construction 6 | indicate_cohort=FALSE 7 | ) { 8 | 9 | YEAR <- CONTENT_AREA <- GRADE <- YEAR_NEW <- COHORT <- ID <- NULL 10 | 11 | ### Parameters 12 | data.years <- sort(unique(base_data$YEAR)) 13 | tmp.cohort.list <- list() 14 | 15 | ### Test parameters 16 | if (!missing(supercohort_base_years) && !all(supercohort_base_years %in% data.years)) stop("Note: supercohort_base_years supplied not all in years provided in base_data.") 17 | 18 | ### Use supercohort_base_years to filter data if it is provided. 19 | if (!missing(supercohort_base_years)) base_data <- base_data[YEAR %in% supercohort_base_years] 20 | 21 | ### Loop over configurations 22 | for (sgp.config.iter in sgp.config) { 23 | tmp.list <- list() 24 | for (data.years.iter in 1:(length(data.years) - sum(sgp.config.iter[['sgp.grade.sequences.lags']]))) { 25 | grade_year_content_area_map <- data.table( 26 | CONTENT_AREA = sgp.config.iter[['sgp.content.areas']], 27 | YEAR = data.years[c(data.years.iter, data.years.iter + (cumsum(sgp.config.iter[['sgp.grade.sequences.lags']])))], 28 | GRADE = sgp.config.iter[['sgp.grade.sequences']], 29 | YEAR_NEW = tail(data.years, length(sgp.config.iter[['sgp.content.areas']]))) 30 | 31 | tmp.list[[data.years.iter]] <- base_data[grade_year_content_area_map, on=list(CONTENT_AREA, YEAR, GRADE)][,YEAR:=YEAR_NEW][,YEAR_NEW:=NULL] 32 | 33 | if (indicate_cohort) { 34 | tmp.list[[data.years.iter]][,COHORT:=paste(unlist(grade_year_content_area_map[,1:3]), collapse="_")] 35 | } 36 | 37 | tmp.dt <- rbindlist(tmp.list) 38 | setkey(tmp.dt, YEAR, GRADE, ID) 39 | tmp.dt <- tmp.dt[unique(tmp.dt[, .(YEAR, GRADE, ID)]), mult="last"] ### Remove duplicates created by collapsing data into YEAR_NEW taking LAST (most recent) case 40 | } 41 | 42 | tmp.cohort.list[[paste(sgp.config.iter[['sgp.content.areas']][1], paste(sgp.config.iter[['sgp.grade.sequences']], collapse=""), sep="_")]] <- tmp.dt 43 | } 44 | return(rbindlist(tmp.cohort.list)) 45 | } ### END createSuperCohortData 46 | -------------------------------------------------------------------------------- /R/csemScoreSimulator.R: -------------------------------------------------------------------------------- 1 | csemScoreSimulator <- 2 | function( 3 | scale_scores, 4 | grade, 5 | content_area, 6 | year, 7 | state, 8 | variable=NULL, 9 | distribution=NULL, 10 | round.digits=NULL) { 11 | 12 | GRADE <- CONTENT_AREA <- YEAR <- SIM <- V1 <- NULL 13 | 14 | get.my.knots.boundaries <- function(content_area, year) { 15 | tmp.knots.boundaries.names <- grep(content_area, names(SGP::SGPstateData[[state]][["Achievement"]][["Knots_Boundaries"]]), value=TRUE) 16 | tmp.knots.boundaries <- tmp.knots.boundaries.names[grep(paste0("^", content_area, "$"), sapply(strsplit(tmp.knots.boundaries.names, "[.]"), '[', 1L))] 17 | if (length(tmp.knots.boundaries)==1L) { 18 | return(content_area) 19 | } else { 20 | tmp.knots.boundaries.years <- sapply(strsplit(tmp.knots.boundaries, "[.]"), '[', 2L) 21 | tmp.index <- sum(year >= tmp.knots.boundaries.years, na.rm=TRUE) 22 | return(paste(c(content_area, sort(tmp.knots.boundaries.years)[tmp.index]), collapse=".")) 23 | } 24 | } 25 | 26 | ### Define relevant variables 27 | 28 | if (is.null(round.digits)) round.digits <- 1L 29 | if (is.null(distribution)) distribution <- "Normal" 30 | if (!is.null(state)) { 31 | min.max <- SGP::SGPstateData[[state]][["Achievement"]][["Knots_Boundaries"]][[get.my.knots.boundaries(content_area, year)]][[paste0("loss.hoss_", grade)]] 32 | } else { 33 | min.max <- range(scale_scores, na.rm=TRUE) 34 | } 35 | Interpolation_Function <- function(scale_score, variance, round.digits) return(splinefun(scale_score, variance/sqrt(round.digits), method="natural")) 36 | 37 | ### Create scale score dependent CSEMs 38 | 39 | if (is.null(variable) && !is.null(state)) { 40 | if ("YEAR" %in% names(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["CSEM"]])) { 41 | Interpolation_Data <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["CSEM"]][GRADE==grade & CONTENT_AREA==content_area & YEAR==year] 42 | } else { 43 | Interpolation_Data <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["CSEM"]][GRADE==grade & CONTENT_AREA==content_area] 44 | } 45 | tmp.omega <- Interpolation_Function(Interpolation_Data[['SCALE_SCORE']], Interpolation_Data[['SCALE_SCORE_CSEM']], round.digits)(scale_scores) 46 | } 47 | if (!is.null(variable)) { 48 | tmp.dt <- setkey(unique(data.table(V1=scale_scores, V2=variable), by="V1"), V1) 49 | tmp.omega <- Interpolation_Function(tmp.dt[['V1']], tmp.dt[['V2']], round.digits)(scale_scores) 50 | } 51 | if (distribution=="Skew-Normal") { 52 | tmp.scores <- data.table(SIM=round(rsn(length(scale_scores), xi=scale_scores, omega=tmp.omega, 53 | alpha=tan((pi/2)*((min.max[1]+min.max[2]) - 2*scale_scores)/(min.max[2]-min.max[1]))), digits=round.digits)) 54 | } else { 55 | tmp.scores <- data.table(SIM=round(rnorm(length(scale_scores), scale_scores, tmp.omega), digits=round.digits)) 56 | } 57 | 58 | tmp.scores[SIM < min.max[1L] | SIM > min.max[2L], SIM:=fifelse(SIM < min.max[1L], min.max[1L], min.max[2L])] 59 | return(tmp.scores[['SIM']]) 60 | } ### END csemScoreSimulator 61 | -------------------------------------------------------------------------------- /R/ddcast.R: -------------------------------------------------------------------------------- 1 | `ddcast` <- 2 | function(tmp.dt, ...) { 3 | if (dim(tmp.dt)[1L]==0L) { 4 | return(data.table(NULL)) 5 | } else { 6 | dcast(tmp.dt, ...) 7 | } 8 | } ### END ddcast Function 9 | -------------------------------------------------------------------------------- /R/detectSGPCores.R: -------------------------------------------------------------------------------- 1 | `detectSGPCores` <- 2 | function(logical=TRUE) { 3 | return(min(detectCores(logical=logical), 50L)) 4 | } ### END detectSGPCores Function 5 | -------------------------------------------------------------------------------- /R/getCohortDataInfo.R: -------------------------------------------------------------------------------- 1 | `getCohortDataInfo` <- 2 | function(sgp.data, 3 | par.sgp.config) { 4 | 5 | for (sgp.iter in seq(length(par.sgp.config))) { 6 | tmp.grades.names <- paste("GRADE", tail(par.sgp.config[[sgp.iter]][['sgp.panel.years']], 2), tail(par.sgp.config[[sgp.iter]][['sgp.content.areas']], 2), sep=".") 7 | tmp.scale_scores.names <- paste("SCALE_SCORE", tail(par.sgp.config[[sgp.iter]][['sgp.panel.years']], 2), tail(par.sgp.config[[sgp.iter]][['sgp.content.areas']], 2), sep=".") 8 | tmp.data <- getPanelData(sgp.data, "sgp.percentiles", par.sgp.config[[sgp.iter]]) 9 | if (all(c(tmp.grades.names, tmp.scale_scores.names) %in% names(tmp.data))) { 10 | par.sgp.config[[sgp.iter]][['number_of_1_prior_cases']] <- dim(na.omit(tmp.data[,c("ID", tmp.grades.names, tmp.scale_scores.names), with=FALSE]))[1] 11 | } else { 12 | par.sgp.config[[sgp.iter]][['number_of_1_prior_cases']] <- 0 13 | } 14 | } 15 | return(par.sgp.config) 16 | } ### END getCohortDataInfo 17 | -------------------------------------------------------------------------------- /R/getErrorReports.R: -------------------------------------------------------------------------------- 1 | `getErrorReports` <- 2 | function(tmp, 3 | tmp.tf, 4 | par.sgp.config) { 5 | 6 | tmp.errors <- tmp[tmp.tf] 7 | tmp.config <- par.sgp.config[tmp.tf] 8 | tmp.error.report <- list() 9 | for (i in 1:length(tmp.errors)) tmp.error.report[[i]] <- list(Error=tmp.errors[[i]], Analysis=tmp.config[[i]]) 10 | return(tmp.error.report) 11 | 12 | } ### END getErrorReports 13 | -------------------------------------------------------------------------------- /R/getFirstAndLastInGroup.R: -------------------------------------------------------------------------------- 1 | `getFirstAndLastInGroup` <- 2 | function(DT) { 3 | VALID_CASE <- YEAR <- CONTENT_AREA <- FIRST_OBSERVATION <- LAST_OBSERVATION <- ID <- GRADE <- YEAR_WITHIN <- NULL 4 | setkey(DT, VALID_CASE, CONTENT_AREA, YEAR, GRADE, ID, YEAR_WITHIN) 5 | setkey(DT, VALID_CASE, CONTENT_AREA, YEAR, GRADE, ID) 6 | DT[DT[unique(DT["VALID_CASE"], by=key(DT)),,mult="first", which=TRUE], FIRST_OBSERVATION:=1L] 7 | DT[DT[unique(DT["VALID_CASE"], by=key(DT)),,mult="last", which=TRUE], LAST_OBSERVATION:=1L] 8 | return(DT) 9 | } ### END getFirstAndLastInGroup 10 | -------------------------------------------------------------------------------- /R/getHighNeedStatus.R: -------------------------------------------------------------------------------- 1 | `getHighNeedStatus` <- 2 | function(sgp_object) { 3 | 4 | ID <- CONTENT_AREA <- YEAR_INT <- PRIOR_GRADE <- GRADE <- SCALE_SCORE <- PRIOR_SCALE_SCORE <- HIGH_NEED_STATUS <- VALID_CASE <- SCHOOL_NUMBER <- YEAR <- NULL 5 | 6 | # my.quantile.function producing HIGH_NEED_STATUS variable 7 | 8 | my.quantile.function <- function(x, invalid_cases, quantiles=c(0.25, 0.75)) { 9 | high.needs.status.labels <- c(paste0("High Needs Status: Prior Achievement Below ", 100*quantiles[1], "th Percentile"), 10 | NA, paste0("High Needs Status: Prior Achievement Above ", 100*quantiles[2], "th Percentiles")) 11 | if (invalid_cases) { 12 | return(rep(NA_character_, length(x))) 13 | } 14 | if (all(is.na(x))) { 15 | return(rep(NA_character_, length(x))) 16 | } else { 17 | if (any(diff(quantile(x, probs=c(0, quantiles, 1), na.rm=TRUE))==0)) { 18 | return(rep(NA_character_, length(x))) 19 | } else { 20 | return(high.needs.status.labels[cut(x, quantile(x, probs=c(0, quantiles, 1), na.rm=TRUE), include.lowest=TRUE, labels=FALSE)]) 21 | } 22 | } 23 | } ### END my.quantile.function 24 | 25 | 26 | slot.data <- copy(sgp_object@Data) 27 | slot.data[,YEAR_INT:=as.integer(factor(YEAR))] 28 | setkeyv(slot.data, c("ID", "CONTENT_AREA", "YEAR_INT", "VALID_CASE")) 29 | slot.data[,c("PRIOR_SCALE_SCORE", "PRIOR_GRADE"):=slot.data[SJ(ID, CONTENT_AREA, YEAR_INT-1L), mult="last"][,list(SCALE_SCORE, GRADE)]] 30 | setkeyv(slot.data, c("VALID_CASE", "CONTENT_AREA", "YEAR_INT", "SCHOOL_NUMBER", "PRIOR_GRADE", "ID")) 31 | slot.data[,HIGH_NEED_STATUS:=slot.data[,my.quantile.function(PRIOR_SCALE_SCORE, !VALID_CASE[1]=="VALID_CASE"), 32 | keyby=list(VALID_CASE, CONTENT_AREA, YEAR_INT, SCHOOL_NUMBER, PRIOR_GRADE)][['V1']]] 33 | slot.data[,HIGH_NEED_STATUS:=as.factor(HIGH_NEED_STATUS)] 34 | slot.data[,c("PRIOR_SCALE_SCORE", "PRIOR_GRADE", "YEAR_INT"):=NULL] 35 | setkey(slot.data, VALID_CASE, CONTENT_AREA, YEAR, ID) 36 | sgp_object@Data <- slot.data 37 | if (!is.null(sgp_object@Names) && !"HIGH_NEED_STATUS" %in% sgp_object@Names[['names.sgp']]) { 38 | sgp_object@Names <- rbind(sgp_object@Names, c("HIGH_NEED_STATUS", "HIGH_NEED_STATUS", "demographic", "High need status flag", TRUE)) 39 | } 40 | messageSGP("\tNOTE: Added variable HIGH_NEED_STATUS to @Data.") 41 | return(sgp_object) 42 | } ### END getHighNeedStatus 43 | -------------------------------------------------------------------------------- /R/getKey.R: -------------------------------------------------------------------------------- 1 | `getKey` <- 2 | function(sgp_object) { 3 | if (is.SGP(sgp_object)) { 4 | if ("YEAR_WITHIN" %in% names(sgp_object@Data)) return(c("VALID_CASE", "CONTENT_AREA", "YEAR", "GRADE", "ID", "YEAR_WITHIN")) else return(c("VALID_CASE", "CONTENT_AREA", "YEAR", "GRADE", "ID")) 5 | } 6 | if (is.data.table(sgp_object)) { 7 | if ("YEAR_WITHIN" %in% names(sgp_object)) return(c("VALID_CASE", "CONTENT_AREA", "YEAR", "GRADE", "ID", "YEAR_WITHIN")) else return(c("VALID_CASE", "CONTENT_AREA", "YEAR", "GRADE", "ID")) 8 | } 9 | } ### END getKey 10 | -------------------------------------------------------------------------------- /R/getMaxOrderForProgression.R: -------------------------------------------------------------------------------- 1 | `getMaxOrderForProgression` <- 2 | function(year, 3 | content_area, 4 | state, 5 | sgp.projections.equated) { 6 | 7 | if (is.null(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Scale_Change"]][[content_area]])) { 8 | return(SGP::SGPstateData[[state]][["SGP_Configuration"]][["max.order.for.projection"]]) ## Returns NULL if it doesn't exist 9 | } else { 10 | if (is.null(sgp.projections.equated)) { 11 | tmp <- as.numeric(tail(unlist(strsplit(as.character(year), "_")), 1)) - 12 | as.numeric(tail(unlist(strsplit(as.character(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Scale_Change"]][[content_area]]), "_")), 1)) 13 | if (tmp < 0) return(SGP::SGPstateData[[state]][["SGP_Configuration"]][["max.order.for.projection"]]) 14 | if (tmp > 0) return(min(c(as.numeric(tmp), SGP::SGPstateData[[state]][["SGP_Configuration"]][["max.order.for.projection"]]))) 15 | if (tmp==0 && 16 | !identical(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][["Baseline_Projections_in_Transition_Year"]], TRUE)) { 17 | message(paste0("\tNOTE: Based upon state scale changes in ", year, ". student growth projections are not possible. No student growth projections will be generated")) 18 | } 19 | } else { 20 | return(SGP::SGPstateData[[state]][["SGP_Configuration"]][["max.order.for.projection"]]) ## Returns NULL if it doesn't exist 21 | } 22 | } 23 | } ### getMaxOrderForProgression 24 | -------------------------------------------------------------------------------- /R/getMyLabel.R: -------------------------------------------------------------------------------- 1 | `getMyLabel` <- 2 | function(state, 3 | content_area, 4 | year, 5 | label="Cutscores") { 6 | 7 | tmp.cutscore.years <- unlist(lapply(sapply(strsplit(grep(content_area, names(SGP::SGPstateData[[state]][["Achievement"]][[label]]), value=TRUE), "[.]"), tail, -1), paste, collapse=".")) 8 | tmp.cutscore.years[tmp.cutscore.years==""] <- NA 9 | if (any(!is.na(tmp.cutscore.years))) { 10 | if (year %in% tmp.cutscore.years) { 11 | return(paste(content_area, year, sep=".")) 12 | } else { 13 | if (year==sort(c(year, tmp.cutscore.years))[1]) { 14 | return(content_area) 15 | } else { 16 | return(paste(content_area, sort(tmp.cutscore.years)[which(year==sort(c(year, tmp.cutscore.years)))-1], sep=".")) 17 | } 18 | } 19 | } else { 20 | return(content_area) 21 | } 22 | } ## END getMyLabel Function 23 | -------------------------------------------------------------------------------- /R/getNewCutscores.R: -------------------------------------------------------------------------------- 1 | `getNewCutscores` <- 2 | function(content_area, 3 | content_area_label, 4 | year, 5 | grade, 6 | state, 7 | Cutscores) { 8 | 9 | 10 | ### Utility function 11 | 12 | get.cutscore.year <- function(year, cutscore.years) { 13 | if (year %in% cutscore.years) return(year) 14 | if (year==sort(c(year, cutscore.years))[1]) return(as.character(NA)) 15 | return(sort(cutscore.years)[which(year==sort(c(year, cutscore.years)))-1]) 16 | } 17 | 18 | 19 | ### Define variables 20 | 21 | if (!is.na(tmp.index <- match(content_area, names(SGP::SGPstateData[[state]][["Student_Report_Information"]][["Content_Areas_Domains"]])))) { 22 | content_area_domain <- SGP::SGPstateData[[state]][["Student_Report_Information"]][["Content_Areas_Domains"]][[tmp.index]] 23 | } else { 24 | content_area_domain <- content_area 25 | } 26 | 27 | cutscore.year <- get.cutscore.year(year, unique(Cutscores[[content_area_domain]][content_area][['YEAR']])) 28 | 29 | if (year %in% SGP::SGPstateData[[state]][["Student_Report_Information"]][["Transformed_Achievement_Level_Cutscores"]][[content_area]]) { 30 | tmp.cutscore.label <- "CUTSCORES_TRANSFORMED" 31 | } else { 32 | tmp.cutscore.label <- "CUTSCORES" 33 | } 34 | 35 | 36 | ### Return result 37 | 38 | if (is.na(content_area) | is.na(grade)) { 39 | return(NULL) 40 | } else { 41 | return(sort(Cutscores[[content_area_domain]][list(content_area_label, cutscore.year, grade)][[tmp.cutscore.label]])) 42 | } 43 | } ### END getNewCutscores function 44 | -------------------------------------------------------------------------------- /R/getSGPColor.R: -------------------------------------------------------------------------------- 1 | `getSGPColor` <- 2 | function( 3 | sgp, 4 | type) { 5 | 6 | if (toupper(type)=="PRESENTATION") { 7 | return(colorRampPalette(c("red","yellow3","springgreen","royalblue"))(99)[sgp]) 8 | } 9 | if (toupper(type)=="PRINT") { 10 | return(colorRampPalette(c("red","yellow3","springgreen","royalblue"))(99)[sgp]) 11 | } 12 | } ### END getSGPColor function 13 | -------------------------------------------------------------------------------- /R/getSGPtNames.R: -------------------------------------------------------------------------------- 1 | `getSGPtNames` <- 2 | function(sgp.iter, 3 | SGPt=NULL, 4 | type) { 5 | 6 | if (is.null(SGPt)) { 7 | return(NULL) 8 | } 9 | 10 | if (type %in% c("sgp.percentiles", "sgp.percentiles.equated", "sgp.percentiles.baseline")) { 11 | tmp.list <- as.list(paste(c("TIME", "TIME_LAG"), tail(sgp.iter[["sgp.panel.years"]], 1), tail(sgp.iter[["sgp.content.areas"]], 1), sep=".")) 12 | names(tmp.list) <- c("TIME", "TIME_LAG") 13 | return(tmp.list) 14 | } 15 | 16 | if (type=="sgp.projections") { 17 | return(paste("DATE", tail(sgp.iter[["sgp.projection.panel.years"]], 1), tail(sgp.iter[["sgp.projection.content.areas"]], 1), sep=".")) 18 | } 19 | 20 | if (type=="sgp.projections.baseline") { 21 | return(paste("DATE", tail(sgp.iter[["sgp.projection.baseline.panel.years"]], 1), tail(sgp.iter[["sgp.projection.baseline.content.areas"]], 1), sep=".")) 22 | } 23 | 24 | if (type %in% c("sgp.projections.lagged", "sgp.projections.lagged.baseline")) { 25 | return(paste("DATE", tail(sgp.iter[["sgp.panel.years"]], 1), tail(sgp.iter[["sgp.content.areas"]], 1), sep=".")) 26 | } 27 | } ## END getSGPtNames 28 | -------------------------------------------------------------------------------- /R/getTableNameYear.R: -------------------------------------------------------------------------------- 1 | `getTableNameYear` <- 2 | function(year) { 3 | if (is.numeric(type.convert(unlist(strsplit(year, "[.]"))[3], as.is=TRUE))) { 4 | return(paste(unlist(strsplit(year, "[.]"))[2:3], collapse=".")) 5 | } else { 6 | return(unlist(strsplit(year, "[.]"))[2]) 7 | } 8 | } ### END getTableNameYear 9 | -------------------------------------------------------------------------------- /R/getTargetAchievementLevels.R: -------------------------------------------------------------------------------- 1 | `getTargetAchievementLevels` <- 2 | function(state, 3 | status.type="CATCH_UP_KEEP_UP") { 4 | 5 | tmp.list <- list() 6 | 7 | if (status.type=="CATCH_UP_KEEP_UP") { 8 | if (!is.null(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]])) { 9 | tmp.index <- grep("Achievement_Levels", names(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]])) 10 | levels.that.are.proficient <- 11 | sort(unlist(sapply(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][tmp.index], function(x) x[['Labels']]))[ 12 | unlist(sapply(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][tmp.index], function(x) x[['Proficient']]))=="Proficient"]) 13 | levels.that.are.not.proficient <- 14 | sort(unlist(sapply(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][tmp.index], function(x) x[['Labels']]))[ 15 | unlist(sapply(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][tmp.index], function(x) x[['Proficient']]))=="Not Proficient"]) 16 | } else { 17 | levels.that.are.proficient <- SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Labels"]][ 18 | which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient")] 19 | levels.that.are.not.proficient <- SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Labels"]][ 20 | which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Not Proficient")] 21 | } 22 | return(list(NO=as.character(levels.that.are.not.proficient), YES=as.character(levels.that.are.proficient))) 23 | } 24 | 25 | if (status.type=="MOVE_UP_STAY_UP") { 26 | if (!is.null(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]])) { 27 | levels.that.are.advanced <- levels.that.are.not.advanced <- list() 28 | for (i in grep("Achievement_Levels", names(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]]), value=TRUE)) { 29 | levels.that.are.advanced[[i]] <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][[i]][['Labels']][ 30 | tail(which(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][[i]][["Proficient"]]=="Proficient"), -1)] 31 | levels.that.are.not.advanced[[i]] <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][[i]][['Labels']][ 32 | c(which(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][[i]][["Proficient"]]=="Not Proficient"), 33 | head(which(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][[i]][["Proficient"]]=="Proficient"), 1))] 34 | } 35 | } else { 36 | levels.that.are.advanced <- SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Labels"]][ 37 | tail(which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient"), -1)] 38 | levels.that.are.not.advanced <- SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Labels"]][ 39 | c(which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Not Proficient"), 40 | head(which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient"), 1))] 41 | } 42 | return(list(NO=as.character(unlist(levels.that.are.not.advanced)), YES=as.character(unlist(levels.that.are.advanced)))) 43 | } 44 | } ### END getTargetAchievementLevels 45 | -------------------------------------------------------------------------------- /R/getTargetName.R: -------------------------------------------------------------------------------- 1 | `getTargetName` <- 2 | function(state, 3 | target.type="sgp.projections.lagged", 4 | target.level="CATCH_UP_KEEP_UP", 5 | target.years=NULL, 6 | target.label="SGP_TARGET", 7 | projection.unit.label="YEAR", 8 | projection_group.iter=NULL) { 9 | 10 | if (target.level=="CATCH_UP_KEEP_UP") target.level <- NULL 11 | if (target.type %in% c("sgp.projections", "sgp.projections.baseline")) target.period <- "CURRENT" else target.period <- NULL 12 | if (target.type %in% c("sgp.projections.baseline", "sgp.projections.lagged.baseline")) sgp.type <- "BASELINE" else sgp.type <- NULL 13 | if (is.null(target.years) && !is.null(projection_group.iter) && projection_group.iter %in% names(SGP::SGPstateData[[state]][['SGP_Configuration']][['grade.projection.sequence']])) { 14 | tmp.target.years <- SGP::SGPstateData[[state]][['SGP_Configuration']][['max.forward.projection.sequence']][[projection_group.iter]] 15 | if (!is.null(tmp.target.years)) target.years <- tmp.target.years 16 | } 17 | 18 | return(paste(c(target.label, sgp.type, target.level, target.years, projection.unit.label, target.period), collapse="_")) 19 | } ### END getTargetName 20 | -------------------------------------------------------------------------------- /R/getTargetSGPContentArea.R: -------------------------------------------------------------------------------- 1 | `getTargetSGPContentArea` <- 2 | function(grade, 3 | content_area, 4 | state, 5 | max.sgp.target.years.forward, 6 | my.sgp.target.content_area) { 7 | 8 | if (is.null(SGP::SGPstateData[[state]][["SGP_Configuration"]][["content_area.projection.sequence"]][[content_area]])) { 9 | return(content_area) 10 | } else { 11 | tmp.content_areas.by.grade <- paste(SGP::SGPstateData[[state]][["SGP_Configuration"]][["content_area.projection.sequence"]][[content_area]], 12 | SGP::SGPstateData[[state]][["SGP_Configuration"]][["grade.projection.sequence"]][[content_area]], sep=".") 13 | tmp.index <- match(paste(content_area, grade, sep="."), tmp.content_areas.by.grade) 14 | if (is.na(tmp.index)) { 15 | message(paste0("\tNOTE: '", content_area, "', GRADE '", grade, "' combination is not in current @Data. Will return ", content_area, " for '", my.sgp.target.content_area, "'.")) 16 | return(content_area) 17 | } else { 18 | return(SGP::SGPstateData[[state]][["SGP_Configuration"]][["content_area.projection.sequence"]][[content_area]][ 19 | min(tmp.index+max.sgp.target.years.forward, length(SGP::SGPstateData[[state]][["SGP_Configuration"]][["grade.projection.sequence"]][[content_area]]))]) 20 | } 21 | } 22 | } ### END getTargetSGPContentArea 23 | -------------------------------------------------------------------------------- /R/getTargetSGPLevel.R: -------------------------------------------------------------------------------- 1 | `getTargetSGPLevel` <- 2 | function(state, 3 | state.iter=NULL, 4 | target.level){ 5 | 6 | if (!is.null(SGP::SGPstateData[[state]][['Achievement']][['Cutscore_Information']])) { 7 | tmp.state.level <- which(sapply(lapply(SGP::SGPstateData[[state]][["Achievement"]][["Cutscore_Information"]][['State_Levels']], '[[', 1), function(x) state.iter %in% x)) 8 | if (target.level=="CATCH_UP_KEEP_UP") { 9 | level.to.get <- which.max(SGP::SGPstateData[[state]][["Achievement"]][["Cutscore_Information"]][['State_Levels']][[tmp.state.level]][['Levels']]=="Proficient")-1 10 | } 11 | if (target.level=="MOVE_UP_STAY_UP") { 12 | if (length(which(SGP::SGPstateData[[state]][["Achievement"]][["Cutscore_Information"]][['State_Levels']][[tmp.state.level]][['Levels']]=="Proficient")) <= 1) { 13 | message(paste0("\tNOTE: MOVE_UP_STAY_UP Targets cannot be calculated because no achievement levels above PROFICIENT exist in ", state, "/", state.iter, ".")) 14 | level.to.get <- NULL 15 | } else { 16 | level.to.get <- which.max(SGP::SGPstateData[[state]][["Achievement"]][["Cutscore_Information"]][['State_Levels']][[tmp.state.level]][['Levels']]=="Proficient") 17 | } 18 | } 19 | } else { 20 | if (target.level=="CATCH_UP_KEEP_UP") level.to.get <- which.max(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient")-1 21 | if (target.level=="MOVE_UP_STAY_UP") { 22 | if (length(which(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient")) <= 1) { 23 | stop(paste0("\tNOTE: MOVE_UP_STAY_UP Targets cannot be calculated because no achievement levels above PROFICIENT exist in ", state, ".")) 24 | } else { 25 | level.to.get <- which.max(SGP::SGPstateData[[state]][["Achievement"]][["Levels"]][["Proficient"]]=="Proficient") 26 | } 27 | } 28 | } 29 | return(level.to.get) 30 | } ### END getTargetSGPLevel 31 | -------------------------------------------------------------------------------- /R/getTargetScaleScoreTableNames.R: -------------------------------------------------------------------------------- 1 | `getTargetScaleScoreTableNames` <- 2 | function( 3 | table_names, 4 | years) { 5 | if (is.null(years)) { 6 | return(grep("TARGET_SCALE_SCORES", table_names, value=TRUE)) 7 | } else { 8 | return(grep(paste(years, collapse="|"), grep("TARGET_SCALE_SCORES", table_names, value=TRUE), value=TRUE)) 9 | } 10 | } ### END getTargetScaleScoreTableNames 11 | -------------------------------------------------------------------------------- /R/getTimeShiftIndex.R: -------------------------------------------------------------------------------- 1 | getTimeShiftIndex <- 2 | function(my.time.data, 3 | my.matrix, 4 | time.shift=365, 5 | time.buffer=30) { 6 | (-20:20)[which.max(sapply(-20:20, function(x) my.matrix@Version[['Matrix_Information']][['SGPt']][['MAX_TIME']]+time.buffer+time.shift*x - my.time.data) > 0)] 7 | } ### END getTimeShiftIndex 8 | -------------------------------------------------------------------------------- /R/getVersion.R: -------------------------------------------------------------------------------- 1 | `getVersion` <- 2 | function(data=NULL) { 3 | if (is.SGP(data) && .hasSlot(data, "Version")) { 4 | existing <- data@Version 5 | return( 6 | Filter(Negate(is.null), 7 | list( 8 | SGP_Package_Version = 9 | c(existing[["SGP_Package_Version"]], as.character(packageVersion("SGP"))), 10 | Date_Prepared = 11 | c(existing[["Date_Prepared"]], prettyDate()), 12 | session_platform = if ("session_platform" %in% names(existing)) { 13 | existing[["session_platform"]] 14 | } else NULL, 15 | attached_pkgs = if ("attached_pkgs" %in% names(existing)) { 16 | existing[["attached_pkgs"]] 17 | } else NULL, 18 | namespace_pkgs = if ("namespace_pkgs" %in% names(existing)) { 19 | existing[["namespace_pkgs"]] 20 | } else NULL 21 | )) 22 | ) 23 | } else { 24 | return( 25 | list( 26 | SGP_Package_Version = as.character(packageVersion("SGP")), 27 | Date_Prepared = prettyDate() 28 | ) 29 | ) 30 | } 31 | } ### END getVersion function 32 | -------------------------------------------------------------------------------- /R/getYearsContentAreasGrades.R: -------------------------------------------------------------------------------- 1 | `getYearsContentAreasGrades` <- 2 | function(state, 3 | years, 4 | content_areas=NULL, 5 | content_areas_domains=NULL, 6 | earliest_year_reported=NULL) { 7 | 8 | CONTENT_AREA <- NULL 9 | 10 | tmp.list <- list() 11 | if (is.null(content_areas)) tmp.content_areas <- content_areas_domains else tmp.content_areas <- content_areas 12 | for (i in intersect(names(SGP::SGPstateData[[state]][["Student_Report_Information"]][["Grades_Reported"]]), tmp.content_areas)) { 13 | if (!is.null(content_areas_domains) && !is.null(SGP::SGPstateData[[state]][["Student_Report_Information"]][['Content_Areas_Domains']])) { 14 | tmp.dt <- data.table(GRADE=as.character(unique(unlist(SGP::SGPstateData[[state]][["Student_Report_Information"]][["Grades_Reported"]][ 15 | grep(i, SGP::SGPstateData[[state]][["Student_Report_Information"]][['Content_Areas_Domains']])])))) 16 | } else { 17 | tmp.dt <- data.table(GRADE=as.character(SGP::SGPstateData[[state]][["Student_Report_Information"]][["Grades_Reported"]][[i]])) 18 | } 19 | 20 | if (!is.null(earliest_year_reported[[i]])) { 21 | tmp.years.diff <- as.numeric(tail(unlist(strsplit(tail(sort(years), 1L), "_")), 1L))-as.numeric(tail(unlist(strsplit(earliest_year_reported[[i]], "_")), 1L)) 22 | tmp.dt <- CJ(tmp.dt$GRADE, intersect(yearIncrement(tail(sort(years), 1L), c(-seq(tmp.years.diff), 0)), years)) 23 | } else { 24 | tmp.dt <- CJ(tmp.dt$GRADE, years) 25 | } 26 | 27 | setnames(tmp.dt, c("GRADE", "YEAR")) 28 | tmp.list[[i]] <- data.table(CONTENT_AREA=i, tmp.dt) 29 | } 30 | tmp.dt <- rbindlist(tmp.list, fill=TRUE) 31 | setkeyv(tmp.dt, c("CONTENT_AREA", "GRADE", "YEAR")) 32 | return(na.omit(tmp.dt, cols="CONTENT_AREA")) 33 | } ## END getYearsContentAreasGrades 34 | -------------------------------------------------------------------------------- /R/is.SGP.R: -------------------------------------------------------------------------------- 1 | `is.SGP` <- 2 | function(x) { 3 | inherits(x, "SGP") 4 | } 5 | -------------------------------------------------------------------------------- /R/is.splineMatrix.R: -------------------------------------------------------------------------------- 1 | `is.splineMatrix` <- 2 | function(x) { 3 | inherits(x, "splineMatrix") 4 | } 5 | -------------------------------------------------------------------------------- /R/mergeSGP.R: -------------------------------------------------------------------------------- 1 | `mergeSGP` <- 2 | function(list_1, 3 | list_2) { 4 | 5 | ### Merge lists 6 | 7 | if (is.null(names(list_1))) return(list_2) 8 | if (!is.null(names(list_2))) { 9 | for (j in c("Coefficient_Matrices", "Cutscores", "Goodness_of_Fit", "Knots_Boundaries", "Linkages", "SGPercentiles", "SGProjections", "Simulated_SGPs", "Error_Reports")) { 10 | list_1[[j]] <- c(list_1[[j]], list_2[[j]])[!duplicated(names(c(list_1[[j]], list_2[[j]])))] 11 | } 12 | 13 | ### SGPercentiles, SGProjections, Simulated_SGPs 14 | 15 | for (j in c("SGPercentiles", "SGProjections", "Simulated_SGPs")) { 16 | if (all(names(list_2[[j]]) %in% names(list_1[[j]]))) { 17 | for (k in names(list_2[[j]])) { # merging list_2 in with list_1, so use it here 18 | if (!identical(list_1[[j]][[k]], list_2[[j]][[k]])) { # keeps it from copying first set of results 19 | list_1[[j]][[k]] <- rbindlist(list(list_1[[j]][[k]], list_2[[j]][[k]]), fill=TRUE) 20 | } 21 | } 22 | } 23 | } 24 | 25 | ### Goodness_of_Fit, Knots_Boundaries 26 | 27 | for (j in c("Goodness_of_Fit", "Knots_Boundaries")) { 28 | for (k in names(list_2[[j]])) { 29 | if (!identical(list_1[[j]][[k]], list_2[[j]][[k]])) { 30 | names.list <- c(unique(names(list_1[[j]][[k]])), unique(names(list_2[[j]][[k]]))) # Get list of (unique) names first. 31 | list_1[[j]][[k]] <- c(list_1[[j]][[k]], list_2[[j]][[k]][!names(list_2[[j]][[k]]) %in% names(list_1[[j]][[k]])]) #new.elements 32 | if (any(duplicated(names.list))) { 33 | dups <- names.list[which(duplicated(names.list))] 34 | for (l in seq(dups)) { 35 | if (!identical(list_1[[j]][[k]][[dups[l]]], list_2[[j]][[k]][[dups[l]]])) { # could be same matrices, different @Version (???) 36 | x <- length(list_1[[j]][[k]])+1 37 | list_1[[j]][[k]][[x]] <- list_2[[j]][[k]][[dups[l]]] 38 | names(list_1[[j]][[k]]) <- c(names(list_1[[j]][[k]])[-x], dups[l]) 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } # j in c("Goodness_of_Fit", "Knots_Boundaries") 45 | 46 | ### Coefficient_Matrices 47 | 48 | j <- "Coefficient_Matrices" 49 | for (k in names(list_2[[j]])) { 50 | if (!grepl("SIMEX", k)) { 51 | if (!identical(list_1[[j]][[k]], list_2[[j]][[k]])) { 52 | list_1[[j]][[k]] <- uniquesplineMatrix(c(list_1[[j]][[k]], list_2[[j]][[k]])) 53 | } 54 | } else { 55 | for (grd_ord in names(list_2[[j]][[k]])) { 56 | for (lambda in grep("lambda", names(list_2[[j]][[k]][[grd_ord]]), value=TRUE)) { 57 | if (!identical(list_1[[j]][[k]][[grd_ord]][[lambda]], list_2[[j]][[k]][[grd_ord]][[lambda]])) { 58 | list_1[[j]][[k]][[grd_ord]][[lambda]] <- uniquesplineMatrix(c(list_1[[j]][[k]][[grd_ord]][[lambda]], list_2[[j]][[k]][[grd_ord]][[lambda]])) 59 | } 60 | } 61 | for (rst in grep("ranked_simex_table", names(list_2[[j]][[k]][[grd_ord]]), value=TRUE)) { 62 | # if (!is.null(list_1[[j]][[k]][[grd_ord]][[rst]]))stop("FmeN@$$") 63 | if (!identical(list_1[[j]][[k]][[grd_ord]][[rst]], list_2[[j]][[k]][[grd_ord]][[rst]])) { 64 | list_1[[j]][[k]][[grd_ord]][[rst]] <- c(list_1[[j]][[k]][[grd_ord]][[rst]], list_2[[j]][[k]][[grd_ord]][[rst]]) 65 | } 66 | } 67 | # for (rst in grep("ranked_simex_table|n_records", names(list_2[[j]][[k]][[grd_ord]]), value=TRUE)) { 68 | # if (!identical(list_1[[j]][[k]][[grd_ord]][[rst]], list_2[[j]][[k]][[grd_ord]][[rst]])) { 69 | # list_1[[j]][[k]][[grd_ord]][[rst]] <- c(list_1[[j]][[k]][[grd_ord]][[rst]], list_2[[j]][[k]][[grd_ord]][[rst]]) 70 | # } 71 | # } 72 | } 73 | } 74 | } # j <- "Coefficient_Matrices" 75 | } 76 | list_1[which(names(list_1) != "Panel_Data")] 77 | } ### END mergeSGP 78 | -------------------------------------------------------------------------------- /R/messageSGP.R: -------------------------------------------------------------------------------- 1 | `messageSGP` <- 2 | function(tmp.message, 3 | domain=NULL, 4 | appendLF=TRUE) { 5 | 6 | PrintLogMessage <- function(tmp.message, domain=NULL) { 7 | # print log message to file 8 | dir.create("Logs", showWarnings = FALSE) 9 | logfile <- paste0("Logs/SGP-", packageVersion("SGP"), "_", Sys.Date(), ".txt") 10 | 11 | if (is.call(tmp.message)) { 12 | tmp.message2 <- c(paste0("\n\n\t", as.character(tmp.message)[1L], "(\n\t\t"), paste(names(tmp.message)[-1L], as.character(tmp.message)[-1L], sep=" = ", collapse="\n\t\t"), ")\n\n") 13 | cat(tmp.message2, file = logfile, append=appendLF) 14 | } else cat(tmp.message, "\n", file=logfile, sep="", append=appendLF) 15 | } 16 | 17 | if (!is.call(tmp.message)) { 18 | base::message(tmp.message) 19 | } 20 | PrintLogMessage(tmp.message) 21 | invisible() 22 | } 23 | -------------------------------------------------------------------------------- /R/piecewiseTransform.R: -------------------------------------------------------------------------------- 1 | `piecewiseTransform` <- 2 | function(scale_score, 3 | state, 4 | content_area, 5 | year, 6 | grade, 7 | output.digits=1, 8 | sgp.projections.equated=NULL, 9 | new.cutscores=NULL, 10 | equating.method="equipercentile", 11 | vertical_scale_for_projections=NULL) { 12 | 13 | if (all(is.na(scale_score))) return(scale_score) 14 | if (is.null(vertical_scale_for_projections)) vertical_scale_for_projections <- TRUE 15 | 16 | ### Test to deal with assessment transition scenario 17 | 18 | if (!is.null(SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]])) { 19 | equate.year <- SGP::SGPstateData[[state]][["Assessment_Program_Information"]][["Assessment_Transition"]][["Year"]] 20 | if (is.null(equate.year)) equate.year <- 0 21 | if (year < equate.year) { 22 | tmp.test <- "Transformed_Achievement_Level_Cutscores" 23 | } else { 24 | if (!is.null(new.cutscores) && length(new.cutscores) > 0) { 25 | tmp.test <- "NOT_NULL" 26 | } else { 27 | tmp.test <- NULL 28 | } 29 | } 30 | } else { 31 | tmp.test <- NULL 32 | } 33 | 34 | 35 | if (is.null(sgp.projections.equated) | !is.null(tmp.test)) { 36 | if (((year %in% SGP::SGPstateData[[state]][["Student_Report_Information"]][["Transformed_Achievement_Level_Cutscores"]][[content_area]] | !vertical_scale_for_projections) && 37 | grade %in% unlist(lapply(strsplit(names(SGP::SGPstateData[[state]][["Achievement"]][["Knots_Boundaries"]][[getMyLabel(state, content_area, year, "Knots_Boundaries")]]), "_"), '[', 2))) || !is.null(tmp.test)) { 38 | 39 | my.knots_boundaries.label <- getMyLabel(state, content_area, year, "Knots_Boundaries") 40 | tmp.loss.hoss <- SGP::SGPstateData[[state]][["Achievement"]][["Knots_Boundaries"]][[my.knots_boundaries.label]][[paste0("loss.hoss_", grade)]] 41 | scale_score[scale_score < tmp.loss.hoss[1]] <- tmp.loss.hoss[1]; scale_score[scale_score > tmp.loss.hoss[2]] <- tmp.loss.hoss[2] 42 | my.cutscores.label <- getMyLabel(state, content_area, year) 43 | old.cutscores <- c(tmp.loss.hoss[1], SGP::SGPstateData[[state]][["Achievement"]][["Cutscores"]][[my.cutscores.label]][[paste0("GRADE_", grade)]], 44 | tmp.loss.hoss[2]) 45 | if (is.null(new.cutscores)) new.cutscores <- seq(0, by=100, length.out=length(old.cutscores)) 46 | tmp.index <- findInterval(scale_score, old.cutscores, rightmost.closed=TRUE) 47 | tmp.diff <- diff(new.cutscores)/diff(old.cutscores) 48 | round(new.cutscores[tmp.index] + (scale_score - old.cutscores[tmp.index]) * (diff(new.cutscores)/diff(old.cutscores))[tmp.index], digits=output.digits) 49 | } else { 50 | as.numeric(scale_score) 51 | } 52 | } else { 53 | if (!is.na(content_area) & !is.na(grade)) { 54 | sgp.projections.equated[['Linkages']][[paste(content_area, sgp.projections.equated[['Year']], sep=".")]][[paste("GRADE", grade, sep="_")]][[toupper(equating.method)]][['OLD_TO_NEW']][['interpolated_function']](scale_score) 55 | } else { 56 | as.numeric(scale_score) 57 | } 58 | } 59 | } ## END piecewiseTransform Function 60 | -------------------------------------------------------------------------------- /R/prettyDate.R: -------------------------------------------------------------------------------- 1 | `prettyDate` <- 2 | function() { 3 | format(Sys.time(), "%A %B %d %H:%M:%S %Y") 4 | } 5 | -------------------------------------------------------------------------------- /R/setNamesSGP.R: -------------------------------------------------------------------------------- 1 | `setNamesSGP` <- 2 | function( 3 | data, 4 | state=NULL) { 5 | 6 | ### Get state (if possible) 7 | if (is.null(state)) { 8 | tmp.name <- toupper(gsub("_", " ", deparse(substitute(data)))) 9 | state <- getStateAbbreviation(tmp.name, "prepareSGP") 10 | } 11 | 12 | variable.name.lookup <- SGP::SGPstateData[[state]][["Variable_Name_Lookup"]] 13 | if (is.null(variable.name.lookup)) stop("Variable name lookup must be in SGPstateData for ", state, " to use setNamesSGP") 14 | names.in.data <- which(variable.name.lookup[["names.provided"]] %in% names(data)) 15 | setnames(data, variable.name.lookup[['names.provided']][names.in.data], variable.name.lookup[['names.sgp']][names.in.data]) 16 | } ### END setNamesSGP 17 | -------------------------------------------------------------------------------- /R/splineMatrix-class.R: -------------------------------------------------------------------------------- 1 | setClassUnion("list.null", c("list","NULL")) 2 | .Valid.splineMatrix <- function(object) { 3 | 4 | errors <- NULL 5 | 6 | tmp.test.null <- 7 | all(!is.null(object@Knots) & 8 | !is.null(object@Boundaries) & 9 | !is.null(object@Content_Areas) & 10 | !is.null(object@Grade_Progression) & 11 | !is.null(object@Time) & 12 | !is.null(object@Time_Lags) & 13 | !is.null(object@Version)) 14 | 15 | tmp.test.length <- length(object@Content_Areas[[1]]) == length(object@Grade_Progression[[1]]) & length(object@Grade_Progression[[1]]) == length(object@Time[[1]]) 16 | 17 | if (!is.null(object@Content_Areas) & !is.null(object@Grade_Progression) & !is.null(object@Time)) { 18 | tmp.test.character <- is.character(object@Content_Areas[[1]]) & is.character(object@Grade_Progression[[1]]) & is.character(object@Time[[1]]) 19 | } 20 | 21 | if (!is.null(object@Time)) { 22 | if (any(object@Time[[1]]=="BASELINE")) { 23 | tmp.test.time <- TRUE 24 | } else { 25 | tmp.test.time <- all(yearIncrement(head(object@Time[[1]], 1), c(0, cumsum(object@Time_Lags[[1]]))) == object@Time[[1]]) 26 | } 27 | } 28 | 29 | if (!is.null(object@Time_Lags)) { 30 | tmp.test.numeric.lags <- is.numeric(object@Time_Lags[[1]]) 31 | } 32 | 33 | if (!tmp.test.null) errors <- c(errors, "\tError in splineMatrix construction: Slots in splineMatrix are not all non-null.") 34 | if (!tmp.test.length) errors <- c(errors, "\tError in splineMatrix construction: Slots @Grade_Progression, @Content_Areas, and @Time are not all the same length.") 35 | if (!tmp.test.character) errors <- c(errors, "\tError in splineMatrix construction: Slots @Grade_Progression, @Content_Areas, and @Time are not all characters.") 36 | if (!tmp.test.time) errors <- c(errors, "\tError in splineMatrix construction: Slots @Time and @Time_Lags are not commensurate with one another.") 37 | if (!tmp.test.numeric.lags) errors <- c(errors, "\tError in splineMatrix construction: Slot @Time_Lags is not numeric.") 38 | 39 | if (is.null(errors)) TRUE else errors 40 | } 41 | setClass("splineMatrix", 42 | contains='matrix', 43 | representation( 44 | Knots='list.null', 45 | Boundaries='list.null', 46 | Content_Areas='list.null', 47 | Grade_Progression='list.null', 48 | Time='list.null', 49 | Time_Lags='list.null', 50 | Version="list.null"), 51 | validity=.Valid.splineMatrix) 52 | setValidity("splineMatrix", .Valid.splineMatrix) 53 | -------------------------------------------------------------------------------- /R/stopParallel.R: -------------------------------------------------------------------------------- 1 | `stopParallel` <- 2 | function(parallel.config, 3 | par.start) { 4 | 5 | if (toupper(parallel.config[['BACKEND']]) == 'FOREACH') { 6 | if (is.na(parallel.config[['TYPE']])) parallel.config[['TYPE']] <- "NA" # Stop checks on NA below. 7 | 8 | # if (parallel.config[['TYPE']]=="doMPI") { 9 | # closeCluster(par.start$doPar.cl) 10 | # return() 11 | # } 12 | 13 | if (parallel.config[['TYPE']]=="doParallel" & par.start$par.type=='SNOW') { 14 | stopCluster(par.start$doPar.cl) 15 | return() 16 | } 17 | 18 | # if (parallel.config[['TYPE']]=="doSNOW") { 19 | # stopCluster(par.start$doPar.cl) 20 | # return() 21 | # } 22 | 23 | # if (parallel.config[['TYPE']]=="doRedis") { 24 | # removeQueue(par.start$jobs) 25 | # return() 26 | # } 27 | } # END FOREACH 28 | 29 | # Nothing required for MULTICORE (or doMC) 30 | # if (toupper(parallel.config[['BACKEND']]) == 'MULTICORE') { 31 | # } 32 | 33 | if (par.start$par.type == 'SNOW') { 34 | if (is.null(parallel.config[['CLUSTER.OBJECT']])) { 35 | stopCluster(par.start$internal.cl) 36 | } 37 | } 38 | } ### END stopParallel Function 39 | -------------------------------------------------------------------------------- /R/stratifiedRandomSampleSGP.R: -------------------------------------------------------------------------------- 1 | `stratifiedRandomSampleSGP` <- 2 | function( 3 | norm_group_data, 4 | strata_variable, 5 | strata_proportions, 6 | sample_size=NULL) { 7 | 8 | CONTENT_AREA <- GRADE <- ID <- VALID_CASE <- YEAR <- NULL ### To prevent R CMD check warnings 9 | 10 | tmp.years <- unique(norm_group_data[['YEAR']]) 11 | sample_data <- norm_group_data[YEAR==tail(tmp.years, 1)] 12 | if (is.null(sample_size)) sample_size=nrow(sample_data) 13 | stopifnot(length(strata_proportions) == uniqueN(norm_group_data[[strata_variable]])) 14 | tmp.replications <- ceiling(max((strata_proportions*sample_size)/table(sample_data[[strata_variable]]))) 15 | setkey(norm_group_data, VALID_CASE, CONTENT_AREA, YEAR, GRADE, ID) 16 | tmp.replicated_norm_group_data <- rbindlist(replicate(tmp.replications, return(norm_group_data), simplify=FALSE))[,ID:=paste(ID, rep(seq.int(tmp.replications), each=nrow(norm_group_data)), sep="_")] 17 | tmp.sample_data <- tmp.replicated_norm_group_data[YEAR==tail(tmp.years, 1)][, .SD[sample(.N, ceiling(sample_size*strata_proportions[[unlist(.BY)]]))], keyby = strata_variable] 18 | return(rbindlist(list(tmp.replicated_norm_group_data[YEAR %in% head(tmp.years, -1) & ID %in% tmp.sample_data[['ID']]], tmp.sample_data), use.names=TRUE)) 19 | } ### END stratifiedRandomSamplSGP 20 | -------------------------------------------------------------------------------- /R/timetakenSGP.R: -------------------------------------------------------------------------------- 1 | timetakenSGP <- 2 | function(started.at) { 3 | 4 | format = function(secs) { 5 | secs.integer = as.integer(secs) 6 | sprintf("%02d:%02d:%02d:%.3f", secs.integer%/%86400L, (secs.integer%/%3600L)%%24L, (secs.integer%/%60L)%%60L, secs%%60L) 7 | } 8 | tt = proc.time() - started.at 9 | format(tt[3L]) 10 | } ### END timetakenSGP function 11 | -------------------------------------------------------------------------------- /R/unfoldstudentGrowthPlots.R: -------------------------------------------------------------------------------- 1 | `unfoldstudentGrowthPlots` <- 2 | function(directory="Visualizations"){ 3 | 4 | tmp.directory <- file.path(directory, "studentGrowthPlots_FLAT") 5 | dir.create(tmp.directory, recursive=TRUE, showWarnings=FALSE) 6 | 7 | ### Get list of zip files 8 | 9 | list.of.zip.files <- list.files(file.path(directory, "studentGrowthPlots"), recursive=TRUE, pattern="zip") 10 | list.of.zip.files <- paste(getwd(), file.path(directory, "studentGrowthPlots"), list.of.zip.files, sep="/") 11 | 12 | ### unzip the files 13 | 14 | setwd(tmp.directory) 15 | 16 | for (i in list.of.zip.files) { 17 | system(paste("unzip -oq", i)) 18 | } 19 | 20 | ### Get new list of individual files 21 | 22 | list.of.directories <- list.files() 23 | list.of.pdf.files <- list.files(recursive=TRUE) 24 | list.of.pdf.files <- paste(getwd(), list.of.pdf.files, sep="/") 25 | list.of.studentGrowthPlots <- list.of.pdf.files[-grep("Catalog", list.of.pdf.files)] 26 | list.of.pdf.catalogs <- grep("Catalog", list.of.pdf.files, value=TRUE) 27 | 28 | ### Create directory for School Catalogs 29 | 30 | dir.create("School_Catalogs", recursive=TRUE, showWarnings=FALSE) 31 | dir.create("studentGrowthPlots", recursive=TRUE, showWarnings=FALSE) 32 | 33 | for (i in list.of.pdf.catalogs) { 34 | file.rename(i, file.path("School_Catalogs", sapply(strsplit(i, "/"), tail, 1))) 35 | } 36 | 37 | for (i in list.of.studentGrowthPlots) { 38 | file.rename(i, file.path("studentGrowthPlots", sapply(strsplit(i, "/"), tail, 1))) 39 | } 40 | 41 | ### Remove empty directories 42 | 43 | for (i in list.of.directories) { 44 | unlink(file.path(getwd(), i), recursive=TRUE) 45 | } 46 | } ### END unfoldstudentGrowthPlots function 47 | -------------------------------------------------------------------------------- /R/uniquesplineMatrix.R: -------------------------------------------------------------------------------- 1 | `uniquesplineMatrix` <- 2 | function(list.of.splineMatrices) { 3 | 4 | ### First identify/remove exact duplicates (not newer/older Versions). Fixes issue of mergeSGP with existing SIMEX Baseline Matrices - 10/8/14 5 | tmp.list.1 <- lapply(list.of.splineMatrices, 6 | function(x) list(Data = x@.Data, Content_Areas=x@Content_Areas, Grade_Progression=x@Grade_Progression, Time=x@Time, Time_Lags=x@Time_Lags, Version=x@Version)) 7 | if (any(duplicated(tmp.list.1))) { 8 | list.of.splineMatrices <- list.of.splineMatrices[!duplicated(tmp.list.1)] 9 | } 10 | 11 | tmp.list.1 <- lapply(list.of.splineMatrices, 12 | function(x) list(Data = x@.Data, Content_Areas=x@Content_Areas, Grade_Progression=x@Grade_Progression, Time=x@Time, Time_Lags=x@Time_Lags)) 13 | tmp.list.2 <- lapply(list.of.splineMatrices, 14 | function(x) list(Data = x@.Data, Content_Areas=x@Content_Areas, Grade_Progression=x@Grade_Progression, Time=x@Time, Time_Lags=x@Time_Lags, Version=x@Version)) 15 | if (any(duplicated(tmp.list.1))) { 16 | list.of.splineMatrices[!duplicated(tmp.list.1[order(as.character(unlist(sapply(tmp.list.2, function(x) x$Version[1]))), decreasing=TRUE)])] 17 | } else { 18 | list.of.splineMatrices 19 | } 20 | } ### END uniquesplineMatrix 21 | -------------------------------------------------------------------------------- /R/yearIncrement.R: -------------------------------------------------------------------------------- 1 | `yearIncrement` <- 2 | function(year, 3 | increment, 4 | lag=0) { 5 | 6 | if (is.null(year)) return(NULL) 7 | 8 | if (identical(year, "BASELINE")) { 9 | return(rep("BASELINE", length(increment))) 10 | } else { 11 | if (grepl("_", year[1L])) { 12 | tmp1 <- sapply(seq_along(increment), function(i) as.numeric(sapply(strsplit(as.character(year), "_"), '[', 2L)) + increment[i] - lag) 13 | paste(floor(tmp1)-1L, tmp1, sep="_") 14 | } else { 15 | as.character(sapply(seq_along(increment), function(i) as.numeric(year) + increment[i] - lag)) 16 | } 17 | } 18 | } ### End yearIncrement 19 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | `.onLoad` <- 2 | function(libname, pkgname) { 3 | available_threads <- data.table::getDTthreads() 4 | data.table::setDTthreads(available_threads) 5 | utils::globalVariables(c(".")) 6 | } 7 | 8 | `.onAttach` <- function(libname, pkgname) { 9 | if (interactive()) { 10 | # Utility function with timeout 11 | get_dev_version <- function(package, timeout = 2) { 12 | url <- paste0("https://raw.githubusercontent.com/CenterForAssessment/", package, "/refs/heads/master/DESCRIPTION") 13 | tryCatch({ 14 | # Use curl with timeout 15 | response <- curl::curl_fetch_memory(url, handle = curl::new_handle(timeout = timeout)) 16 | if (response$status_code == 200) { 17 | lines <- strsplit(rawToChar(response$content), "\n")[[1]] 18 | version_line <- grep("^Version:", lines, value = TRUE) 19 | if (length(version_line) > 0) { 20 | return(cyan("v", strsplit(version_line, ": ")[[1]][2], sep="")) 21 | } 22 | } 23 | return(red("Not Available")) 24 | }, error = function(e) { 25 | return(red("Not Available")) 26 | }, warning = function(w) { 27 | return(red("Not Available")) 28 | }) 29 | } 30 | 31 | # Extract version information with timeout 32 | installed.version <- utils::packageDescription("SGP")[['Version']] 33 | cran.version <- tryCatch({ 34 | # Add timeout to CRAN check 35 | curl::curl_fetch_memory("https://cran.r-project.org/web/packages/SGP/index.html", 36 | handle = curl::new_handle(timeout = 2)) 37 | green("v", pkgsearch::cran_package("SGP")[['Version']], sep="") 38 | }, error = function(e) red("Not Available"), 39 | warning = function(w) red("Not Available")) 40 | dev.version <- get_dev_version("SGP") 41 | 42 | # Define a friendly startup message 43 | message_text <- paste0( 44 | magenta(bold("\uD83C\uDF89 SGP v", installed.version, sep="")), " - ", toOrdinal::toOrdinalDate("2025-6-17"), "\n", 45 | strrep("\u2501", 40), "\n", 46 | bold("\U1F4E6 CRAN: "), cran.version, "\n", 47 | bold("\U1F527 Dev: "), dev.version, "\n", 48 | strrep("\u2501", 40), "\n", 49 | "\U1F4A1 Tip: ", magenta(bold("> help(package=\"SGP\")")), "\n", 50 | "\U1F310 Docs: ", magenta(bold("https://sgp.io")), "\n", 51 | strrep("\u2501", 40), "\n", 52 | "\u2728 Happy SGPing!", "\n") 53 | 54 | # Display the startup message 55 | packageStartupMessage(message_text) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SGP 2 | === 3 | 4 | [](https://doi.org/10.5281/zenodo.6471237) 5 | [](https://github.com/CenterForAssessment/SGP/actions) 6 | [](https://cran.r-project.org/package=SGP) 7 | [](https://github.com/CenterForAssessment/SGP) 8 | [](https://github.com/metacran/cranlogs.app) 9 | [](https://github.com/CenterForAssessment/SGP/blob/master/LICENSE.md) 10 | 11 | 12 | # Overview 13 | 14 | The SGP Package is open source software built for the [**R** software environment](https://www.r-project.org/). The classes, functions and data within the SGP package are used to calculate student growth percentiles and percentile growth projections/trajectories using large scale, longitudinal assessment data. Quantile regression is used to estimate the conditional density associated with each student's achievement history. Percentile growth projections/trajectories are calculated using the derived coefficient matrices and show the percentile growth needed to reach future achievement targets. 15 | 16 | 17 | # Installation 18 | 19 | ## From [CRAN](https://CRAN.R-project.org/package=SGP) 20 | 21 | To install the latest stable release of SGP from [CRAN](https://CRAN.R-project.org/package=SGP) 22 | 23 | ```R 24 | > install.packages("SGP") 25 | ``` 26 | 27 | ## From [Github](https://github.com/CenterForAssessment/SGP/) 28 | 29 | To install the development release of SGP from [GitHub](https://github.com/CenterForAssessment/SGP/): 30 | 31 | ```R 32 | > devtools::install_github("CenterForAssessment/SGP") 33 | ``` 34 | 35 | 36 | # Resources 37 | 38 | * [SGP GitHub Pages](https://sgp.io) 39 | * [CRAN Repo](https://CRAN.R-project.org/package=SGP) 40 | * [Norm- and Criterion-Referenced Student Growth](https://github.com/CenterForAssessment/SGP_Resources/blob/master/articles/Betebenner_EMIP_2009.pdf) 41 | 42 | 43 | # Contributors 44 | 45 | The SGP Package is crafted with :heart: by: 46 | 47 | * [Damian Betebenner](https://github.com/dbetebenner) 48 | * [Adam R. Van Iwaarden](https://github.com/adamvi) 49 | * [Ben Domingue](https://github.com/ben-domingue) 50 | * [Yi Shang](https://github.com/shangyi) 51 | 52 | We love feedback and are happy to answer questions. 53 | 54 | 55 | # References 56 | 57 | Betebenner, D. W., VanIwaarden, A., Domingue, B., and Shang, Y. (2025). SGP: Student Growth Percentiles & Percentile Growth Trajectories. 58 | 59 | R Core Team (2025). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. URL 60 | https://www.R-project.org/. 61 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | template: 2 | package: centerPackageTemplate 3 | default_assets: false 4 | 5 | 6 | home: 7 | strip_header: true 8 | links: 9 | - text: Other Center stuff 10 | href: https://centerforassessment.github.io/ 11 | 12 | 13 | navbar: 14 | title: ~ 15 | type: default 16 | left: 17 | - text: Getting Started 18 | href: articles/SGP.html 19 | - text: Vignettes 20 | menu: 21 | - text: "SGP Data Preparation" 22 | href: articles/SGP_Data_Preparation.html 23 | - text: "SGP Data Analysis" 24 | href: articles/SGP_Data_Analysis.html 25 | - text: Reference 26 | href: reference/index.html 27 | - text: News 28 | menu: 29 | - text: "Release notes" 30 | - text: "SGP 2.1-0.0" 31 | href: articles/releases/SGP-2.1-0.0.html 32 | - text: "SGP 2.0-0.0" 33 | href: articles/releases/SGP-2.0-0.0.html 34 | - text: "SGP 1.9-5.0" 35 | href: articles/releases/SGP-1.9-5.0.html 36 | - text: "SGP 1.9-0.0" 37 | href: articles/releases/SGP-1.9-0.0.html 38 | - text: "SGP 1.8-0.0" 39 | href: articles/releases/SGP-1.8-0.0.html 40 | - text: "SGP 1.7-0.0" 41 | href: articles/releases/SGP-1.7-0.0.html 42 | - text: "SGP 1.6-0.0" 43 | href: articles/releases/SGP-1.6-0.0.html 44 | - text: "SGP 1.5-0.0" 45 | href: articles/releases/SGP-1.5-0.0.html 46 | - text: "SGP 1.4-0.0" 47 | href: articles/releases/SGP-1.4-0.0.html 48 | - text: "------------------" 49 | - text: "Change log" 50 | href: news/index.html 51 | right: 52 | - icon: 'fab fa-github' 53 | href: https://github.com/centerforassessment/SGP 54 | - icon: 'fab fa-twitter' 55 | href: https://twitter.com/intent/tweet?url=https%3A%2F%2Fsgp.io&via=NCIEA1&text=SGP%3A%20Student%20Growth%20Percentiles%20%26%20Percentile%20Growth%20Trajectories&hashtags=rstats%2CSGP 56 | 57 | 58 | reference: 59 | - title: Low level SGP functions 60 | desc: These functions are responsible for all student growth percentile and student growth projection calculation. 61 | contents: 62 | - studentGrowthPercentiles 63 | - studentGrowthProjections 64 | - title: High level SGP functions 65 | desc: These functions simplify operation SGP calculations as wrappers for low level functions. 66 | contents: 67 | - abcSGP 68 | - analyzeSGP 69 | - baselineSGP 70 | - combineSGP 71 | - outputSGP 72 | - prepareSGP 73 | - rliSGP 74 | - summarizeSGP 75 | - testSGP 76 | - updateSGP 77 | - visualizeSGP 78 | - title: SGP utility functions 79 | desc: These functions are used in various ways as part SGP analyses. 80 | contents: 81 | - bubblePlot 82 | - bubblePlot_Styles 83 | - courseProgressionSGP 84 | - createKnotsBoundaries 85 | - capwords 86 | - getStateAbbreviation 87 | - gofSGP 88 | - growthAchievementPlot 89 | - is.splineMatrix 90 | - is.SGP 91 | - studentGrowthPlot 92 | - studentGrowthPlot_Styles 93 | - title: SGP meta-data for state/organization level analyses 94 | desc: This internal data set contains meta-data and configurations used as part of state/organization level analyses. 95 | contents: 96 | - SGPstateData 97 | -------------------------------------------------------------------------------- /data/SGPstateData.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/data/SGPstateData.rda -------------------------------------------------------------------------------- /data/datalist: -------------------------------------------------------------------------------- 1 | SGPstateData 2 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | sgp.io 2 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Analysis_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/crosstalk-1.1.0.1/css/crosstalk.css: -------------------------------------------------------------------------------- 1 | /* Adjust margins outwards, so column contents line up with the edges of the 2 | parent of container-fluid. */ 3 | .container-fluid.crosstalk-bscols { 4 | margin-left: -30px; 5 | margin-right: -30px; 6 | white-space: normal; 7 | } 8 | 9 | /* But don't adjust the margins outwards if we're directly under the body, 10 | i.e. we were the top-level of something at the console. */ 11 | body > .container-fluid.crosstalk-bscols { 12 | margin-left: auto; 13 | margin-right: auto; 14 | } 15 | 16 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 17 | display: inline-block; 18 | padding-right: 12px; 19 | vertical-align: top; 20 | } 21 | 22 | @media only screen and (max-width:480px) { 23 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 24 | display: block; 25 | padding-right: inherit; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/crosstalk-1.1.1/css/crosstalk.css: -------------------------------------------------------------------------------- 1 | /* Adjust margins outwards, so column contents line up with the edges of the 2 | parent of container-fluid. */ 3 | .container-fluid.crosstalk-bscols { 4 | margin-left: -30px; 5 | margin-right: -30px; 6 | white-space: normal; 7 | } 8 | 9 | /* But don't adjust the margins outwards if we're directly under the body, 10 | i.e. we were the top-level of something at the console. */ 11 | body > .container-fluid.crosstalk-bscols { 12 | margin-left: auto; 13 | margin-right: auto; 14 | } 15 | 16 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 17 | display: inline-block; 18 | padding-right: 12px; 19 | vertical-align: top; 20 | } 21 | 22 | @media only screen and (max-width:480px) { 23 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 24 | display: block; 25 | padding-right: inherit; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/crosstalk-1.2.0/css/crosstalk.min.css: -------------------------------------------------------------------------------- 1 | .container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} 2 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/crosstalk-1.2.0/scss/crosstalk.scss: -------------------------------------------------------------------------------- 1 | /* Adjust margins outwards, so column contents line up with the edges of the 2 | parent of container-fluid. */ 3 | .container-fluid.crosstalk-bscols { 4 | margin-left: -30px; 5 | margin-right: -30px; 6 | white-space: normal; 7 | } 8 | 9 | /* But don't adjust the margins outwards if we're directly under the body, 10 | i.e. we were the top-level of something at the console. */ 11 | body > .container-fluid.crosstalk-bscols { 12 | margin-left: auto; 13 | margin-right: auto; 14 | } 15 | 16 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 17 | display: inline-block; 18 | padding-right: 12px; 19 | vertical-align: top; 20 | } 21 | 22 | @media only screen and (max-width:480px) { 23 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 24 | display: block; 25 | padding-right: inherit; 26 | } 27 | } 28 | 29 | /* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ 30 | .crosstalk-input { 31 | margin-bottom: 15px; /* a la .form-group */ 32 | .control-label { 33 | margin-bottom: 0; 34 | vertical-align: middle; 35 | } 36 | input[type="checkbox"] { 37 | margin: 4px 0 0; 38 | margin-top: 1px; 39 | line-height: normal; 40 | } 41 | .checkbox { 42 | position: relative; 43 | display: block; 44 | margin-top: 10px; 45 | margin-bottom: 10px; 46 | } 47 | .checkbox > label{ 48 | padding-left: 20px; 49 | margin-bottom: 0; 50 | font-weight: 400; 51 | cursor: pointer; 52 | } 53 | .checkbox input[type="checkbox"], 54 | .checkbox-inline input[type="checkbox"] { 55 | position: absolute; 56 | margin-top: 2px; 57 | margin-left: -20px; 58 | } 59 | .checkbox + .checkbox { 60 | margin-top: -5px; 61 | } 62 | .checkbox-inline { 63 | position: relative; 64 | display: inline-block; 65 | padding-left: 20px; 66 | margin-bottom: 0; 67 | font-weight: 400; 68 | vertical-align: middle; 69 | cursor: pointer; 70 | } 71 | .checkbox-inline + .checkbox-inline { 72 | margin-top: 0; 73 | margin-left: 10px; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/plotly-htmlwidgets-css-1.52.2/plotly-htmlwidgets.css: -------------------------------------------------------------------------------- 1 | /* 2 | just here so that plotly works 3 | correctly with ioslides. 4 | see https://github.com/ropensci/plotly/issues/463 5 | */ 6 | 7 | slide:not(.current) .plotly.html-widget{ 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/plotly-htmlwidgets-css-1.57.1/plotly-htmlwidgets.css: -------------------------------------------------------------------------------- 1 | /* 2 | just here so that plotly works 3 | correctly with ioslides. 4 | see https://github.com/ropensci/plotly/issues/463 5 | */ 6 | 7 | slide:not(.current) .plotly.html-widget{ 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/plotly-htmlwidgets-css-2.11.1/plotly-htmlwidgets.css: -------------------------------------------------------------------------------- 1 | /* 2 | just here so that plotly works 3 | correctly with ioslides. 4 | see https://github.com/ropensci/plotly/issues/463 5 | */ 6 | 7 | slide:not(.current) .plotly.html-widget{ 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /docs/articles/SGP_Data_Preparation_files/plotly-htmlwidgets-css-2.5.1/plotly-htmlwidgets.css: -------------------------------------------------------------------------------- 1 | /* 2 | just here so that plotly works 3 | correctly with ioslides. 4 | see https://github.com/ropensci/plotly/issues/463 5 | */ 6 | 7 | slide:not(.current) .plotly.html-widget{ 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/SGP_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.4-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.5-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.6-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.7-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.8-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-0.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.13/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.14/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-1.9-5.0_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.0-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/anchor-sections-1.1.0/anchor-sections-hash.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section::before {content: '#';font-size: 80%;} 3 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/anchor-sections-1.1.0/anchor-sections-icon.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* From https://icons.getbootstrap.com/icons/link-45deg/ 3 | Licence: https://github.com/twbs/icons/blob/main/LICENSE.md */ 4 | 5 | a.anchor-section:before { 6 | display: inline-block; 7 | content: url("data:image/svg+xml,"); 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/anchor-sections-1.1.0/anchor-sections-symbol.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors content */ 2 | /* Link symbol : https://codepoints.net/U+1F517 3 | with variation selector https://graphemica.com/FE0E */ 4 | a.anchor-section::before{content: '\01F517\00FE0E';font-size: 20px;} 5 | /* deactivate underline for link symbol */ 6 | a.anchor-section:hover {text-decoration: none;} 7 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/anchor-sections-1.1.0/anchor-sections.css: -------------------------------------------------------------------------------- 1 | /* Styles for section anchors */ 2 | a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} 3 | .hasAnchor:hover a.anchor-section {visibility: visible;} 4 | ul > li > .anchor-section {display: none;} 5 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/anchor-sections-1.1.0/anchor-sections.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | // If section divs is used, we need to put the anchor in the child header 3 | const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") 4 | 5 | headers.forEach(function (x) { 6 | // Add to the header node 7 | if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') 8 | // Remove from the section or div created by Pandoc 9 | x.parentElement.classList.remove('hasAnchor') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/header-attrs-2.22/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/releases/SGP-2.1-0.0_files/header-attrs-2.25/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/img/REPO_CARD_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/docs/img/REPO_CARD_image.png -------------------------------------------------------------------------------- /docs/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/docs/img/favicon.png -------------------------------------------------------------------------------- /docs/img/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /docs/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/docs/img/logo.png -------------------------------------------------------------------------------- /docs/img/logo_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/docs/img/logo_grey.png -------------------------------------------------------------------------------- /docs/img/logo_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CenterForAssessment/SGP/aab195e7a06c11778837a3db1b683923d5c01174/docs/img/logo_white.png -------------------------------------------------------------------------------- /docs/img/tocBullet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /docs/jquery.sticky-kit.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 3 | */ 4 | (function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); 5 | if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, 6 | u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),e