Skip to content

Predictive IntelliSense #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 58 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
bafe2b2
Added RFC Error View
theJasonHelmick Jul 31, 2019
bdd3ee9
update RFC error view
theJasonHelmick Jul 31, 2019
dd58c11
Added shorter reference code
theJasonHelmick Jul 31, 2019
d3ed694
update alternate view
theJasonHelmick Jul 31, 2019
5fd9c69
Added RFC Error View
theJasonHelmick Jul 31, 2019
3dd0560
update RFC error view
theJasonHelmick Jul 31, 2019
a7d6a75
Added shorter reference code
theJasonHelmick Jul 31, 2019
6faa7dc
update alternate view
theJasonHelmick Jul 31, 2019
c454366
updated comment due date on Error-View
theJasonHelmick Aug 7, 2019
fb60588
Update 1-Draft/RFC00XX-Update-Error-View.md
theJasonHelmick Aug 26, 2019
f4edfcd
review update for view name -simpleview
theJasonHelmick Aug 26, 2019
a6329e7
update to view name
theJasonHelmick Aug 26, 2019
0641bb2
fix unresolved merge conflict
theJasonHelmick Sep 3, 2019
8dabf42
Removed incorrect parameter -Oldest
theJasonHelmick Sep 3, 2019
35ed896
errorview-removed unneeded parameters
theJasonHelmick Sep 23, 2019
5cf273d
Errorview update to remove unneeded parameters
theJasonHelmick Sep 23, 2019
07af6d2
Changed view name from Concise to SimpleView
theJasonHelmick Sep 24, 2019
da03165
Added WriteErrorLine clarification
theJasonHelmick Sep 24, 2019
8cdd56a
Added example showing Inner exception
theJasonHelmick Sep 24, 2019
1bc65b1
Merge to my master
theJasonHelmick Sep 24, 2019
6de0c3e
updated normal and detailed view
theJasonHelmick Sep 24, 2019
697327c
added image of new error view
theJasonHelmick Sep 25, 2019
d6f6af4
Added image of errorview and adjusted carets
theJasonHelmick Sep 25, 2019
889cad4
Spelling correction
theJasonHelmick Sep 25, 2019
9439d35
Updated graphic display of error messages
theJasonHelmick Sep 25, 2019
51ec0f2
graphic update
theJasonHelmick Sep 25, 2019
1f272cd
edits to Overview
theJasonHelmick Sep 25, 2019
a58d4e8
update $errorview to enum
theJasonHelmick Sep 26, 2019
800f653
resolved conflict
theJasonHelmick Sep 26, 2019
ea14fcd
spelling corrections
theJasonHelmick Sep 26, 2019
46b2382
update for a new pr
theJasonHelmick Sep 26, 2019
b2f46ca
update to reflect view changes
theJasonHelmick Sep 30, 2019
0cef8c3
updated RFC Resolve-errorrecord definition
theJasonHelmick Oct 8, 2019
ec0b745
Corected typos
theJasonHelmick Oct 8, 2019
493a3a7
Updated RFC with Prefix conditions
theJasonHelmick Oct 8, 2019
8d0498e
update RFC to reflect new cmdlet name
theJasonHelmick Oct 15, 2019
34a3a62
updated RFC with Concise view as default view
theJasonHelmick Oct 21, 2019
3493c6b
Update RFC00XX-Update-Error-View.md
SteveL-MSFT Oct 23, 2019
04559ed
updated image to reflect cuurent code
theJasonHelmick Oct 24, 2019
eaecab0
update to reflect implementation
theJasonHelmick Jan 16, 2020
a97cbfe
update to match implementation - remove carets
theJasonHelmick Jan 16, 2020
0cfab18
update to correct readability flow
theJasonHelmick Jan 16, 2020
07807c7
update messageposition property information
theJasonHelmick Jan 16, 2020
e6cf938
Prep RFC0048 - Updated Error View for merging
joeyaiello Jan 29, 2020
69f695c
Merge branch 'master' of https://github.com/PowerShell/PowerShell-RFC
theJasonHelmick Sep 28, 2020
6c8bcf3
wip:PredIntell
theJasonHelmick Sep 28, 2020
20213c7
Apply suggestions from code review
theJasonHelmick Oct 9, 2020
3994b0b
Apply suggestions from code review
theJasonHelmick Oct 9, 2020
fee045f
Corrections;Clarity on ship plan
theJasonHelmick Oct 9, 2020
872336a
Corrections;added new color params
theJasonHelmick Oct 9, 2020
be78ebd
Corrections
theJasonHelmick Oct 9, 2020
6c6b8df
Added Get-Subsystem
theJasonHelmick Oct 12, 2020
1d36316
Added Get-Subsystem
theJasonHelmick Oct 12, 2020
24ad89b
Corrected API registration
theJasonHelmick Oct 14, 2020
a4df14c
added background highlight example prediction
theJasonHelmick Oct 14, 2020
539898d
Removed Module Owner section
theJasonHelmick Oct 19, 2020
78fb15f
updates from Dongbo pr #1909
theJasonHelmick Oct 29, 2020
2c33c3a
updates from Dongbo pr #1909
theJasonHelmick Oct 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 359 additions & 0 deletions 1-Draft/RFC00XX-PredIctive-IntelliSense.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
---
RFC: RFCXXXX
Author: Jason Helmick
Status: Draft
Area: Shell
Comments Due: 10/31/2020
---

# Predictive IntelliSense

Predictive IntelliSense is an addition to the interactive (Shell) experience to assist in command
discovery and accelerate full command execution. The prediction suggestion appears as colored text
following the user’s cursor. This enables new and experienced users of PowerShell to discover, edit,
and execute full commands based on matching predictions from the user’s history or additional
provider.

Additional providers enhance historic predictions by providing domain specific commands and task
completions. Predictive IntelliSense includes an extension model to support the registration of
additional providers.

Predictions may be displayed in either **InlineView** or **ListView** depending on the user’s
preference. Below, predictions are displayed with InlineView.

![image](./media/pred-wlc.png)

Below, predictions are displayed with a dropdown in ListView.

![image](./media/pred-listview.png)

## Motivation

Tab Completion has accelerated the success of both new and experienced PowerShell users. New users
get the benefit of discovery; seeing available cmdlets and parameters as options while interactively
typing. Experienced users receive the benefit of acceleration; typing less while using the **<tab>** key
to quickly complete a command.

The increasing amount of technology translates to an increase in cmdlets and full command
complexity. Predictive IntelliSense is an addition to the concept of Tab Completion; helping the
user discover, build and edit full commands based on the user’s history or additional plugins.

## Release plan

- Proposed 7.1 GA
- Currently in PowerShell 7.1 PReview 7
- Predictive IntelliSense Whole Line Completion
- Historical Predictions
- Extension Framework
- Future PSReadLine previews
- Predictive IntelliSense Whole Line Completion + ListView
- Support for additional providers using extension framework
- Previews begin in October with PSReadLine 2.2.0-beta1

## Goals/Non-Goals

Goals:

- Provide suggestions from PSReadLine history
- The user will be able to enable and disable Predictive IntelliSense
- The user will be able to change between InlineView and ListView
- The user will have keyboard shortcuts to navigate and edit a prediction
- The user will register additional providers when desired
- The user may customize the color of a prediction to support accessibility needs
- The user will be able to search history for similar predictions

Non-goals:

- Due to limit use, PowerShell Session history is not part of the historical suggestion
- VSCode implementation. We agree this is important for a consistent experience and are working to
bring this feature in a future release

## Specification

The proposal is to add Predictive IntelliSense and Extension model to improve the user interactive experience.

### Key Design Considerations Predictive IntelliSense

Predictive IntelliSense displays a best match command completion from command history. The
prediction may change if a better match is found as the user types additional information. The
predicted command may be accepted, edited, or ignored.

![Prediction - Historical](./media/pre-wlc.png)

### Install and Remove Predictive IntelliSense

Predictive IntelliSense is a part of the PSReadLine module. Updating or installing the current beta
release from PSGallery will provide the Predictive IntelliSense feature.

The current release is PSReadLine 2.1.0 Beta 2:

```powershell
Install-Module PSReadLine -RequiredVersion 2.1.0-beta2 -AllowPrerelease
```

It is possible to remove, delete, the PSReadLine module to disable Predictive IntelliSense. This
creates a negative impact to customers as it would remove all features of PSReadLine. For this
reason, Predictive IntelliSense has its own PSReadLine configuration to enable and disable
predictions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph should be under the header at line 99


### Enabling and Disabling Predictions

By default, the feature Predictive IntelliSense is disabled. The impact of enabling this feature by
default may cause new and existing users to become confused at the shell prompt. The feature is
enabled and disabled with a PSReadLine command Set-PSReadLineOption that is executed at the shell
prompt or in the user’s Profile.

Predictive IntelliSense currently supports four arguments for a prediction source;

* None - This option disables Predictive IntelliSense
* History - This option uses only the PSReadLine history for predictions
* Plugin – This option uses only registered plugin modules for predictions
* HistoryAndPlugin – This option uses both for predictions

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this in separate comment but will add here as well. It would be better to separate out Prediction from Source so that we can use History completion in Most Recently Used order rather than a predictive algorithm.

Prediction Method Examples:

  • None
  • AI Version 1
  • Experimental new AI
  • Cloud AI using Azure or AWS AI (maybe not but at least possible to add)

I guess source can be singular or additive so an array:

  • History
  • Menu
  • Plugin

Is the plugin able to register itself to be accepted into the configuration list? I may want to try 3-4 different sources but end up with 1-2 as my defaults. Maybe have the 3rd-4th for specialized work on remote environments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider using Frecency algorithm rather than most recently used: PowerShell/PSReadLine#1808

Copy link
Contributor Author

@theJasonHelmick theJasonHelmick Oct 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daxian-dbw Thoughts on using frecency algorithm versus Most Recent? I find myself expecting frequency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Frecency algorithm mentioned by @SteveL-MSFT takes into account both frequency and how recent the history is.

To enable Predictive IntelliSense, enter the following command in the shell or in the users Profile:

```powershell
Set-PSReadLineOption -PredictionSource History
```

To disable Predictive IntelliSense, enter the following command in the shell or in the users Profile:

```powershell
Set-PSReadLineOption -PredictionSource None
```

### Changing the Prediction View

Predictions are displayed in one of two view depending on the user preference. The default view is InlineView.

* InlineView – This is the default view and displays the prediction inline with the user’s typing.
This view is similar to other shells Fish and ZSH.
* ListView – ListView provides a dropdown list of predictions below the line the user is typing.
Users may quickly scan the list, highlight and select the desired prediction.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be an option for InlineView alongside a secondary view. Inline and List complement each other. Inline can show the suggested completion with List showing multiple options at once.

Additional Views to consider are

These additional views make me think Inline should be separate On/Off with additional views as a separate configuration with None only affecting what's in its list and not Inline setting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dragonwolf83 Thank you! We are open to considering additional views as we progress. I agree that InlineView and ListView can be complimentary - currently when using ListView, as you highlight selections, they are displayed fully on the same line as your cursor, similar to InlineView. Appreciate your thoughts and feedback as we move forward.

Users may change the view at the command line, or in the user’s PowerShell profile.

```powershell
Set-PSReadLineOption -PredictionViewStyle InlineView
```

### Change the Prediction Color for Accessibility

By default, Predictions appear on the same line the user is typing in a different customizable
color. To support Accessibility needs, the prediction color is settable in the shell or users
Profile.

![pi-color](./media/pi-color.png)
![pi-color](./media/pi-color2.png)

```powershell
Set-PSReadLineOption -Colors @{ Prediction = '#8A0303'}
Set-PSReadLineOption -Colors @{ Prediction = '#2F7004'}
```

Multiple types of color code values are supported in PSReadLine. For more information see
Set-PSReadLineOption in
[PSReadLine](https://docs.microsoft.com/en-us/powershell/module/PSReadline/Set-PSReadlineOption?view=powershell-7)

Examples of different color code values:

```powershell
# Use a ConsoleColor enum
Set-PSReadLineOption -Colors @{ Prediction = 'DarkRed'}
Set-PSReadLineOption -Colors @{ Prediction = [ConsoleColor]::DarkRed}

# 24 bit color escape sequence
Set-PSReadLineOption -Colors @{ Prediction = "$([char]0x1b)[38;5;100m"}

# RGB value
Set-PSReadLineOption -Colors @{ Prediction = "#8181f7"}
```

### Key Bindings for Predictions

Key bindings control cursor movement and additional features within the prediction. To support users
running Predictive IntelliSense on multiple platforms, key bindings are user-settable in the Shell
and user’s PowerShell profile.

Example of setting a key binding in the shell or user’s profile:

```powershell
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
```

List of suggested key bindings defined in **SamplePSReadLineProfile.ps1**

Key Binding | PSReadLine Function | Description
------------- | ------------------- | -----------
Up Arrow | HistorySearchBackward | Move backward through history
Down Arrow | HistorySearchForward | Move forward through history
F7 | Profile Code | Opens Out-GridView with full history
F1 | Profile Code | Opens the Help window for the current command or parameter
Ctrl-b | Profile Code | Add command to history
Ctrl-q | TabCompleteNext | Windows style Tab for Emacs mode
Ctrl-Q | TabCompletePrevious | Windows style Tab for Emacs mode
Ctrl-c | Copy | Clipboard interaction for Emacs mode
Ctrl-v | Paste | Clipboard interaction for Emacs mode
Ctrl-d,Ctrl-c | CaptureScreen | Captures screen for pasting to email or blog
Alt-d | ShellKillWord | Token based movement bound to Emacs word movement
Alt-Backspace | ShellBackwardKillWord | “
Alt-b | ShellBackwardWord | “
Alt-f | ShellForwardWord | “
Alt-B | SelectShellBackwardWord| “
Alt-F | SelectShellForwardWord | “
“ or ‘ | Profile Code | Insert Smart quotes
( or { or [ | Profile Code | Insert matching braces
Backspace | Profile Code | Delete previous character
Alt-w | Profile Code | Save current line in history – don’t execute
Ctrl-V | Profile Code | Paste clipboard as a Here string
Alt-( | Profile Code | Insert parenthesis around selection or entire line
Alt-‘ | Profile Code | Toggle quotes on argument under cursor
Alt-% | Profile Code | Replace aliases with resolved commands

### Search prediction history based on cursor location

The prediction history from PSReadLine is searchable when the user begins typing into the shell.
Users may search the entire prediction history for commands matching under the current cursor
position. Users may search prediction history based on 'Verb', 'Noun' and 'Parameter' of a cmdlet
using the up/down arrow keys.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this section related to the predictive intellisense feature? It sounds like the history searching capability, which exists for a long time now.

Copy link
Contributor Author

@theJasonHelmick theJasonHelmick Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daxian-dbw I removed reference to prediction from the text to reduce confusion. User's may not have experience searching history in this manner especially with predictive text being shown, so felt it should be described in the RFC. If this still seems redundant and unnessiary to the existing feature in PSReadLine, I can remove the section.


* Searching history from cmdlet verb.
![Verb](./media/pi-arrow-verb.gif)

* Searching histroy from cmdlet noun.
![noun](./media/pi-arrow-noun.gif)

* Searching history from parameter.
![Param](./media/pi-arrow-param.gif)

### Edit predictions before accepting the prediction

Users may navigate prediction tokens to make changes to parameters, arguments, and additional
pipeline commands. The prediction model will update the displayed prediction from the closest
matches in PSReadLine history or added provider.

In the example below, a user navigates the prediction, pausing to change the -Property argument and
receiving an updated prediction.

![arg change](./media/pi-fb.gif)

## Prediction Extension Model

Additional providers enhance historic predictions by providing domain specific commands and task
completions. Predictive IntelliSense includes an extension model to support the registration of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's getting rather confusing where this "Predictive Intellisense" feature is implemented in. For example, is the extension model provided by PSReadLine? (no, it's provided by PowerShell itself, but requiring the host to consume and render the prediction results). We probably should be more clear about it.

Copy link
Contributor Author

@theJasonHelmick theJasonHelmick Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added clarification here and earlier in RFC to define the extension components in the PowerShell engine versus rendering from PSReadLine.

additional providers.

## Goals/Non-Goals

Goals:

* Provide extension model to support additional providers
* Support the discovery of providers using Get-Subsystem

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider different noun. Subsystem is way too generic and doesn't make sense for discovery. Get-IntellisenseProvider or Get-IntellisenseSystem makes more sense. For easier typing, Get-CompletionProvider would work too.

Also, please prefix this with PS so it is Get-PSIntellisenseProvider

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prediction plugins are using the general PowerShell subsystem model, but that cmdlet should probably be called Get-PSSubsystem, perhaps have a -Type parameter where Prediction is a valid type making it easy to filter? -Type can be added later since we don't support other types currently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but that cmdlet should probably be called Get-PSSubsystem

Agreed that we can revisit the cmdlet name.

a -Type parameter where Prediction is a valid type making it easy to filter?

It already does so: Get-Subsystem -Kind CommandPredictor

Copy link
Contributor Author

@theJasonHelmick theJasonHelmick Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that name should be Get-PSSubsystem, will leave currently in RFC as Get-Subsystem until final decision.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The renaming to Get-PSSubsystem is done.

* Render predictions from providers within performance guidelines 20ms
* Provide Module owners method of registration

Non-goals:

* Register/Unregister-Subsystem cmdlets are not planned because it's targeting binary subsystem
implementations, which should deal with registration/unregistration via APIs.
* Server-side provider privacy is the responsibility of the provider module

## Extension Model Specification

### Predictive Suggestion Contract to Support Addition Providers

Below is an abbreviated code listing of the API contract to support suggestions from additional
providers.

```csharp
/// The class represents a predictive suggestion generated by a predictor.
public sealed class PredictiveSuggestion
{
/// Gets the suggestion.
public string SuggestionText { get; }

/// Gets the tooltip of the suggestion.
public string? ToolTip { get; }

/// Initializes a new instance of the <see cref="PredictiveSuggestion"/> class.
/// <param name="suggestion">The predictive suggestion text.</param>
public PredictiveSuggestion(string suggestion)
: this(suggestion, toolTip: null)
```

### Discovery of Provider Metadata and Registration

Providers are registered automatically when the user installs a provider module. Removal of
registration occurs when the module is removed. Users will need to discover installed providers
along with additional metadata, such as version information to assist users in upgrading and
diagnosing problems.

To list the currently installed providers and their respective metadata:

```powershell
Get-SubSystem
```

### Expected Provider Performance

Additional providers often will communicate with an internet connect service to provide suggestions.
To minimize the appearance of slow responses, we estimate that the maximum roundtrip time of 20ms is
permissible to not negatively impact users.

If the roundtrip time is exceeded, the predictor model will provide historical suggestions, or
suggestions from another provider that completed in the allowed time.

* Default required provider performance = 20ms

The current roundtrip time in PSReadLine using the Tab Completion feature is approximately **2-3ms**. We
believe that this current default roundtrip time for additional providers may still exceed user
expectations. With additional testing and feedback, we may need to reduce the roundtrip time to less
than **20ms**.

### Registration for Module Owners

Predictive IntelliSense is an extensible model offering module authors the opportunity to create their own predictor plugins. Customers using Predictive IntelliSense will benefit from increased coverage of domain specific technologies and other helpful predictors.

Module authors writing new predictors will need to register their predictor with the extension
model. Predictor registration is accomplished with the **OnImport** and **OnRemove** methods
executed on module startup and removal. Additional documentation is available for
[IModuleAssemblyInitializer
(OnImport)](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.imoduleassemblyinitializer?view=powershellsdk-7.0.0)
and
[IModuleAssemblyCleanup (OnRemove)](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.imoduleassemblycleanup?view=powershellsdk-7.0.0).

* Example of registering a predictor using **OnImport**

```csharp
// The initializer to register the predictor implementation at module loading time.

public class PredictorInitializer : IModuleAssemblyInitializer
{
public void OnImport()
{
var predictor = new MyPredictor();
SubsystemManager.RegisterSubsystem<IPredictor,MyPredictor>(predictor);
}
}
```

* Example of unregistering a predictor using **OnRemove**

```csharp
// Clean up the registeration when unloading the module.

public class PredictorCleanup : IModuleAssemblyCleanup
{
public void OnRemove(PSModuleInfo psModuleInfo)
{
SubsystemManager.UnregisterSubsystem<IPredictor>(MyPredictor.Identifier);
}
}
```

In the above example, the predictor implementation is elsewhere in the module code with the type
name **MyPredictor**. An object of **MyPredictor** is created in **OnImport** and **OnRemove**. To
remove (unregister) your implementation instance, you need the **GUID** id of your implementation.

Binary file added 1-Draft/media/pi-arrow-Noun.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pi-arrow-param.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pi-arrow-verb.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pi-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pi-color2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pi-fb.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pred-listview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 1-Draft/media/pred-wlc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.