Unpacking Software Livestream

Join our monthly Unpacking Software livestream to hear about the latest news, chat and opinion on packaging, software deployment and lifecycle management!

Learn More

Chocolatey Product Spotlight

Join the Chocolatey Team on our regular monthly stream where we put a spotlight on the most recent Chocolatey product releases. You'll have a chance to have your questions answered in a live Ask Me Anything format.

Learn More

Chocolatey Coding Livestream

Join us for the Chocolatey Coding Livestream, where members of our team dive into the heart of open source development by coding live on various Chocolatey projects. Tune in to witness real-time coding, ask questions, and gain insights into the world of package management. Don't miss this opportunity to engage with our team and contribute to the future of Chocolatey!

Learn More

Calling All Chocolatiers! Whipping Up Windows Automation with Chocolatey Central Management

Webinar from
Wednesday, 17 January 2024

We are delighted to announce the release of Chocolatey Central Management v0.12.0, featuring seamless Deployment Plan creation, time-saving duplications, insightful Group Details, an upgraded Dashboard, bug fixes, user interface polishing, and refined documentation. As an added bonus we'll have members of our Solutions Engineering team on-hand to dive into some interesting ways you can leverage the new features available!

Watch On-Demand
Chocolatey Community Coffee Break

Join the Chocolatey Team as we discuss all things Community, what we do, how you can get involved and answer your Chocolatey questions.

Watch The Replays
Chocolatey and Intune Overview

Webinar Replay from
Wednesday, 30 March 2022

At Chocolatey Software we strive for simple, and teaching others. Let us teach you just how simple it could be to keep your 3rd party applications updated across your devices, all with Intune!

Watch On-Demand
Chocolatey For Business. In Azure. In One Click.

Livestream from
Thursday, 9 June 2022

Join James and Josh to show you how you can get the Chocolatey For Business recommended infrastructure and workflow, created, in Azure, in around 20 minutes.

Watch On-Demand
The Future of Chocolatey CLI

Livestream from
Thursday, 04 August 2022

Join Paul and Gary to hear more about the plans for the Chocolatey CLI in the not so distant future. We'll talk about some cool new features, long term asks from Customers and Community and how you can get involved!

Watch On-Demand
Hacktoberfest Tuesdays 2022

Livestreams from
October 2022

For Hacktoberfest, Chocolatey ran a livestream every Tuesday! Re-watch Cory, James, Gary, and Rain as they share knowledge on how to contribute to open-source projects such as Chocolatey CLI.

Watch On-Demand

Downloads:

1,461

Downloads of v 2023.1.1:

163

Last Update:

07 Jan 2023

Package Maintainer(s):

Software Author(s):

  • WPI
  • PeterJohnson
  • Et Al.

Tags:

wpilib frc first robotics admin

WPILib

  • 1
  • 2
  • 3

2023.1.1 | Updated: 07 Jan 2023

Downloads:

1,461

Downloads of v 2023.1.1:

163

Maintainer(s):

Software Author(s):

  • WPI
  • PeterJohnson
  • Et Al.

WPILib 2023.1.1

  • 1
  • 2
  • 3

This Package Contains an Exempted Check

Not All Tests Have Passed


Validation Testing Passed


Verification Testing Exemption:

Application is only intended to work on Windows 10 or newer.

Details

Scan Testing Successful:

No detections found in any package files

Details
Learn More

Deployment Method: Individual Install, Upgrade, & Uninstall

To install WPILib, run the following command from the command line or from PowerShell:

>

To upgrade WPILib, run the following command from the command line or from PowerShell:

>

To uninstall WPILib, run the following command from the command line or from PowerShell:

>

Deployment Method:

NOTE

This applies to both open source and commercial editions of Chocolatey.

1. Enter Your Internal Repository Url

(this should look similar to https://community.chocolatey.org/api/v2/)


2. Setup Your Environment

1. Ensure you are set for organizational deployment

Please see the organizational deployment guide

2. Get the package into your environment

  • Open Source or Commercial:
    • Proxy Repository - Create a proxy nuget repository on Nexus, Artifactory Pro, or a proxy Chocolatey repository on ProGet. Point your upstream to https://community.chocolatey.org/api/v2/. Packages cache on first access automatically. Make sure your choco clients are using your proxy repository as a source and NOT the default community repository. See source command for more information.
    • You can also just download the package and push it to a repository Download

3. Copy Your Script

choco upgrade wpilib -y --source="'INTERNAL REPO URL'" [other options]

See options you can pass to upgrade.

See best practices for scripting.

Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.

If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:


choco upgrade wpilib -y --source="'INTERNAL REPO URL'" 
$exitCode = $LASTEXITCODE

Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
  Exit 0
}

Exit $exitCode

- name: Install wpilib
  win_chocolatey:
    name: wpilib
    version: '2023.1.1'
    source: INTERNAL REPO URL
    state: present

See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.


chocolatey_package 'wpilib' do
  action    :install
  source   'INTERNAL REPO URL'
  version  '2023.1.1'
end

See docs at https://docs.chef.io/resource_chocolatey_package.html.


cChocoPackageInstaller wpilib
{
    Name     = "wpilib"
    Version  = "2023.1.1"
    Source   = "INTERNAL REPO URL"
}

Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.


package { 'wpilib':
  ensure   => '2023.1.1',
  provider => 'chocolatey',
  source   => 'INTERNAL REPO URL',
}

Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.


4. If applicable - Chocolatey configuration/installation

See infrastructure management matrix for Chocolatey configuration elements and examples.

Package Approved

This package was approved as a trusted package on 08 Jan 2023.

Description

The WPILib software required by FIRST Robotics for the FRC competition.

Package Parameters

  • /InstallScope:Scope - Whether to install for all users or current user. Default is allUsers. (allUsers/currentUser)
  • /VSCodeZipPath:Path - Whether to use an existing zip or to download it. Default is download. (download/PATH_TO_ZIP)
    >NOTE: The path should not have any "quotation marks" around it.
  • /AllowUserInteraction:boolean - Lets the user intereact with the installer before execution. Default is false. (true/false)
    >NOTE: AllowUserInteraction is really only for debugging or for custom control over install options.

To pass parameters, use --params "''" (e.g. choco install packageID [other options] --params="'/ITEM:value /ITEM2:value2 /FLAG_BOOLEAN'").
To have choco remember parameters on upgrade, be sure to set choco feature enable -n=useRememberedArgumentsForUpgrades.


tools\chocolateyinstall.ps1
$ErrorActionPreference = 'Stop'; # stop on all errors

$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"

$url         = 'https://github.com/wpilibsuite/allwpilib/releases/download/v2023.1.1/WPILib_Windows-2023.1.1.iso'
$fileName    = 'WPILibInstaller.exe'
$isoChecksum = '5094459bbe2bbe91fa6e21b85d424435bf6ceacea24dae0b441fa4694f941015'

$pp = Get-PackageParameters
$ahkParameters = ""
$ahkParameters += if ($pp.InstallScope) { "`"$($pp.InstallScope)`"" }
$ahkParameters += if ($pp.VSCodeZipPath) { " $($pp.VSCodeZipPath)" }
$ahkParameters += if ($pp.AllowUserInteraction) { " $($pp.AllowUserInteraction)" }

$packageArgs = @{
  packageName    = $env:ChocolateyPackageName
  softwareName   = 'WPILib*'
  fileType       = 'EXE'
  checksumType   = 'sha256'
  Url            = $url
  file           = $fileName
  checksum       = $isoChecksum
  silentArgs     = '' #none
}

if (!(Get-OSArchitectureWidth -Compare 64) -or !($env:OS_NAME -eq "Windows 10" -or $env:OS_NAME -eq "Windows 11")) {
  throw "WPILib requires Windows 10 64-bit version or newer. Aborting installation."
}

$ahkExe = "AutoHotKey" # This is a reference to the global AHK exe
$ahkFile = Join-Path $toolsDir "WPILibInstall.ahk"
Write-Debug "Running: $ahkExe `"$ahkFile`"$ahkParameters"
$ahkProc = Start-Process -FilePath $ahkExe -ArgumentList "`"$ahkFile`" $ahkParameters" -Verb RunAs -PassThru

$ahkId = $ahkProc.Id
Write-Debug "$ahkExe start time:`t$($ahkProc.StartTime.ToShortTimeString())"
Write-Debug "Process ID:`t$ahkId"

Install-ChocolateyIsoPackage @packageArgs #https://docs.chocolatey.org/en-us/guides/create/mount-an-iso-in-chocolatey-package
tools\chocolateyuninstall.ps1
#Debug lines can be printed by passing the flag -Debug
$ErrorActionPreference = 'Stop'; # stop on all errors
Write-Host "Beginning uninstall process of WPILib..."

# Variables that will need changed
$year = '2023'

# Generated/Constant Variables
$systemDriveLetter = (Get-WmiObject Win32_OperatingSystem).getPropertyValue("SystemDrive")
$publicUserHome = $systemDriveLetter + "\Users\Public"
$wpiFolder = "$publicUserHome\wpilib"
$userStartMenuFolder = "$HOME\AppData\Roaming\Microsoft\Windows\Start Menu\Programs"
$systemStartMenuFolder = "$systemDriveLetter\ProgramData\Microsoft\Windows\Start Menu\Programs"
$startMenuLinks = @(
  "$year WPILib Tools",
  "$year WPILib Documentation.lnk",
  "$year WPILib VS Code.lnk"
)
$possibleLinkDirectories = @(
  "$HOME\Desktop",
  "$publicUserHome\Desktop",
  "$HOME\OneDrive\Desktop"
)
$linkNames = @(
  "$year WPILib VS Code.lnk",
  "$year WPILib Documentation.lnk",
  "$year WPILib Tools"
)

##### Delete WPILib folder #####
# Check if the inside wpilib folder exists, attempt to delete it, check if was successful
Write-Host "`nRemoving the WPILib folder..."
if (Test-Path -Path "$wpiFolder\$year") {
  Remove-Item "$wpiFolder\$year" -ErrorAction SilentlyContinue -Force -Recurse
  
  if (!(Test-Path -Path "$wpiFolder\$year")) {
    Write-Host "`tRemoved wpilib folder at `"$wpiFolder\$year`"" -ForegroundColor Green
  } else {
    Write-Host "`tAn error occured while trying to delete the wpilib folder at `"$wpiFolder\$year`"" -ForegroundColor Red
  }
} else {
  Write-Host "`tIt appears that the wpilib folder expected at `"$wpiFolder\$year`" does not exists. This could be a good indicator that wpilib (for this year) is not/no longer installed, however the uninstall process will continue to ensure that all elements of wpilib are gone`n" -ForegroundColor Yellow
}

# Delete the outside wpilib folder if it exists and is now empty
if(Test-Path $wpiFolder){
  if ((Get-ChildItem $wpiFolder -force | Select-Object -First 1 | Measure-Object).Count -eq 0) {
    Remove-Item $wpiFolder -ErrorAction SilentlyContinue -Force -Recurse

    if (!(Test-Path -Path $wpiFolder)) {
      Write-Host "`tRemoved the main wpilib folder at `"$wpiFolder`" because it was empty" -ForegroundColor Green
    } else {
      Write-Host "`tAn error occured while trying to delete the main wpilib folder at `"$wpiFolder`"" -ForegroundColor Red
    }
  }
} else {
  Write-Host "`tIt appears that the main wpilib folder at `"$wpiFolder`" does not exists. This could be a good indicator that wpilib is not/no longer installed, however the uninstall process will continue to ensure that all elements of wpilib are gone" -ForegroundColor Yellow
}

##### Delete Desktop Shortcuts ##### 
# Both public and current user desktop. It differes upon whether you select current user or all users when installing. 
# It might be infered that if one link is found the others will be next to it, but that's a dangerous game. Plus what if the links are in multiple places?
Write-Host "`nDeleteing Desktop Shortcuts..."
$LinksFound = ""
foreach ($directory in $possibleLinkDirectories) {
  Write-Host "`tSearching `"$directory`" for links to delete:"
  foreach ($link in $linkNames) {
    # Check for link file, if its there attempt to delete it, recheck if its there.
    if (Test-Path ("{0}\{1}" -f $directory, $link)) {
      $LinksFound = $TRUE
      Remove-Item ("{0}\{1}" -f $directory, $link) -ErrorAction SilentlyContinue -Force -Recurse

      if (!(Test-Path ("{0}\{1}" -f $directory, $link))) {
        Write-Host "`t`tFound and deleted `"$link`" in `"$directory`"" -ForegroundColor Green
      } else {
        Write-Host "`t`tAttempted Deleting `"$link`" in `"$directory`" but could not delete" -ForegroundColor Red
      }
    } else {
      Write-Host "`t`tLooked for `"$link`" in `"$directory`" but found nothing" -ForegroundColor Yellow
    }
  }
}
if (!$LinksFound) {
  Write-Host "`tUnable to find links to be deleted automatically. You will have to manually delete them if you have them in a place other than your desktop." -ForegroundColor Yellow
}

##### Remove Start Menu Shortcuts #####
Write-Host "`nRemoving Start Menu Shortcuts..."
$foundStartMenu = ""
# Check for and delete start menu shortcuts in the user's start menu folder
Write-Host "`tSearching `"$userStartMenuFolder`" for links to delete:"
foreach ($item in $startMenuLinks) {
  if (Test-Path -Path "$userStartMenuFolder\$item") {
    Remove-Item "$userStartMenuFolder\$item" -ErrorAction SilentlyContinue -Force -Recurse
    $foundStartMenu = $TRUE
    
    if (!(Test-Path -Path "$userStartMenuFolder\$item")) {
      Write-Host "`t`tRemoved start menu item at `"$userStartMenuFolder\$item`"" -ForegroundColor Green
    } else {
      Write-Host "`t`tAn error occured while trying to delete the start menu item at `"$userStartMenuFolder\$item`"" -ForegroundColor Red
    }
  } else {
    Write-Host "`t`tLooked for `"$item`" in `"$userStartMenuFolder`" but found nothing" -ForegroundColor Yellow
  }
}
# Check for and delete start menu shortcuts in the system's start menu folder
Write-Host "`tSearching `"$systemStartMenuFolder`" for links to delete:"
foreach ($item in $startMenuLinks) {
  if (Test-Path -Path "$systemStartMenuFolder\$item") {
    Remove-Item "$systemStartMenuFolder\$item" -ErrorAction SilentlyContinue -Force -Recurse
    $foundStartMenu = $TRUE
    
    if (!(Test-Path -Path "$systemStartMenuFolder\$item")) {
      Write-Host "`t`tRemoved start menu item at `"$systemStartMenuFolder\$item`"" -ForegroundColor Green
    } else {
      Write-Host "`t`tAn error occured while trying to delete the start menu item at `"$systemStartMenuFolder\$item`"" -ForegroundColor Red
    } 
  } else {
    Write-Host "`t`tLooked for `"$item`" in `"$userStartMenuFolder`" but found nothing" -ForegroundColor Yellow
  }
}
if (!$foundStartMenu) {
  Write-Host "`tThere is no Start Menu folder to delete. It was either already removed or the wpilib installer was run without admin privlages" -ForegroundColor Yellow
}

Write-Host "`nFinished uninstalling WPILib!" -ForegroundColor Green
tools\WPILibInstall.ahk
#SingleInstance, Force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
CoordMode, Mouse, Client
CoordMode, Pixel, Client

;;;;; Options ;;;;;
installScope := "allUsers" ; Default value for whether to install for "allUsers" or "currentUser"
VSCodeZipPath := "download" ; Default Zip Name of "download" will cause a download instead of using a cached zip
allowUserInteraction := "false" ; Default is to not allow user interaction

;;;;; Contstants ;;;;;
INSTALLER_TITLE := "WPILib Installer"
ZIP_SELECTOR_TITLE := "Select VS Code Installer ZIP"
BUTTON_COLOR := "0xF5F5F5"

;;;;; Parameters ;;;;;
; MsgBox % "Starting with " . A_Args[0] . " parameters: " . A_Args[1] . " " A_Args[2] . " " A_Args[3] . "."

; Parameter for Install Scope
if(A_Args[1] != "" and (A_Args[1] = "allUsers" or A_Args[1] = "currentUser")) {
    installScope := A_Args[1]
}

; Parameter for whether to download zip or use given or default local zip
if(A_Args[2] != "") {
    VSCodeZipPath := A_Args[2]
}

; Parameter for user interaction
if(A_Args[3] = "true") {
    allowUserInteraction := "true"
}

;;;;; Operations ;;;;;
WinWait, %INSTALLER_TITLE%
WinActivate, %INSTALLER_TITLE%
WinSet, AlwaysOnTop , On, %INSTALLER_TITLE% ; Prevent Windows on top
WinSet, Style, -0xc00000, %INSTALLER_TITLE% ; Prevent moving/resizing
Sleep, 2000

; Find and click the start button on the right side of the screen
WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
FindAndClick(Width, Height, Width/2, Height/2, BUTTON_COLOR)
Sleep, 1500

; Find and click install for all users or install for this user.
if (installScope = "allUsers") {
    ; All Users
    WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
    FindAndClick(Width, Height*.75, Width/2, Height/2, BUTTON_COLOR)
} else if (installScope = "currentUser") {
    ; Current User
    WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
    FindAndClick(0, Height/2, Width/2, Height*.75, BUTTON_COLOR)
}
Sleep, 1500

; Selecting the options to either download or choose existing
if (VSCodeZipPath = "download") {
    ; Download
    WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
    FindAndClick(0, Height/2, Width/2, Height, BUTTON_COLOR)
} else {
    ; Use Existing Zip
    WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
    FindAndClick(Width/2, Height*.7, Width, Height/2, BUTTON_COLOR)
    Sleep, 300
    WinWait, %ZIP_SELECTOR_TITLE%
    Sleep, 300
    SendInput {Raw}%VSCodeZipPath%
    Send {Enter}
}
Sleep, 1500

if !(ErrorLevel) {
    ; MsgBox % "No AHK errors! - GO!"
    if (allowUserInteraction == "false") {
        ; Click next which will start instalation
        WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
        FindAndClick(Width, Height, Width/2, Height*0.9, BUTTON_COLOR)
        Sleep, 5000

        ; Click Finish
        WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
        FindAndClick(Width, Height, Width/2, Height*0.9, BUTTON_COLOR)
    } else {
        MsgBox % "Ending to allow user interaction."
    }
} else {
    MsgBox % "AHK ERROR!!" 
}

; Finds the specified color in the bounding box created by (X1, Y1), (X2, Y2).
; It will search in the direction of X1->X2 and Y1->Y2 (from the first point, to the second)
; It will continute to search until it finds it.
FindAndClick(X1, Y1, X2, Y2, color) {
    WinActivate, %INSTALLER_TITLE%
    PixelSearch, Xout, Yout, X1, Y1, X2, Y2, color, 0, Fast
    While(ErrorLevel = 1) { ; Wait till its found
        ; WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
        WinActivate, %INSTALLER_TITLE%
        PixelSearch, Xout, Yout, X1, Y1, X2, Y2, color, 0, Fast
        Sleep, 1000
    }
    MouseClick, Left, Xout, Yout, 1, 0
    ; MouseMove, Xout, Yout ; For testing
}

; Function for debugging PixelSearch parameters
TestPixelSearch(){
    Loop {
        Sleep, 500
        WinGetPos, X, Y, Width, Height, %INSTALLER_TITLE%
        PixelSearch, X, Y, Width, Height, Width/2, Height/2, %BUTTON_COLOR%, 0, Fast
        ToolTip, The color is at %X%`,%Y%, X, Y
    }
}
LICENSE.md
Copyright (c) 2009-2023 FIRST
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   * Neither the name of the FIRST nor the
     names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Log in or click on link to see number of positives.

In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).

Chocolatey Pro provides runtime protection from possible malware.

Add to Builder Version Downloads Last Updated Status
WPILib 2022.4.1 282 Monday, March 21, 2022 Approved
WPILib 2022.3.1 98 Saturday, February 12, 2022 Approved
WPILib 2022.2.1 59 Friday, February 11, 2022 Approved
WPILib 2022.1.1 117 Friday, January 14, 2022 Approved
WPILib 2021.3.1 155 Tuesday, October 12, 2021 Approved
WPILib 2021.2.1 126 Tuesday, January 26, 2021 Approved
WPILib 2021.1.2.20210123 100 Tuesday, January 26, 2021 Approved
WPILib 2021.1.2 121 Friday, January 8, 2021 Approved
WPILib 2021.1.1-beta4 99 Wednesday, January 6, 2021 Approved
WPILib 2020.3.2 141 Sunday, January 3, 2021 Approved
Discussion for the WPILib Package

Ground Rules:

  • This discussion is only about WPILib and the WPILib package. If you have feedback for Chocolatey, please contact the Google Group.
  • This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
  • The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
  • Tell us what you love about the package or WPILib, or tell us what needs improvement.
  • Share your experiences with the package, or extra configuration or gotchas that you've found.
  • If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.
comments powered by Disqus