Missing dependencies for instrumentations when upgrading to v0.31.0

What version of OpenTelemetry are you using?
I'm updating @opentelemetry/auto-instrumentations-node from 0.27.1 to 0.31.0
What version of Node are you using?
v16.13.1
What did you do?
Dependabot opened a PR to bump @opentelemetry/auto-instrumentations-node from 0.27.1 to 0.31.0, e.g. it only changed the version and updated yarn.lock.
What did you expect to see?
My app is not building when running typescript.
What did you see instead?
Building the app, I'm getting the following errors on types for a few instrumentations. I'd expect them to register their dependencies instead of requiring those to be added to my project package.json.
yarn run v1.22.4
$ tsc
node_modules/@opentelemetry/instrumentation-aws-sdk/build/src/aws-sdk.d.ts:1:27 - error TS2307: Cannot find module 'aws-sdk' or its corresponding type declarations.

1 import type * as AWS from 'aws-sdk';
                            ~~~~~~~~~

node_modules/@opentelemetry/instrumentation-aws-sdk/build/src/types.d.ts:3:27 - error TS2307: Cannot find module 'aws-sdk' or its corresponding type declarations.

3 import type * as AWS from 'aws-sdk';
                            ~~~~~~~~~

node_modules/@opentelemetry/instrumentation-cassandra-driver/build/src/instrumentation.d.ts:4:39 - error TS2307: Cannot find module 'cassandra-driver' or its corresponding type declarations.

4 import type * as CassandraDriver from 'cassandra-driver';
                                        ~~~~~~~~~~~~~~~~~~

node_modules/@opentelemetry/instrumentation-knex/build/src/instrumentation.d.ts:3:28 - error TS2307: Cannot find module 'knex' or its corresponding type declarations.

3 import type * as knex from 'knex';
                             ~~~~~~

node_modules/@opentelemetry/instrumentation-mysql2/build/src/instrumentation.d.ts:2:34 - error TS2307: Cannot find module 'mysql2' or its corresponding type declarations.

2 import type * as mysqlTypes from 'mysql2';
                                   ~~~~~~~~

Additional context
Two current workaround:

If I add these packages to my own package.json, works!
Use skipLibCheck: true in the TS config, works!

{
  "name": "xxxxx",
  "private": true,
  "version": "0.0.0",
  "description": "xxxxx",
  "main": "index.ts",
  "engines": {
    "node": ">=14.16.0"
  },
  "engineStrict": true,
  "scripts": {
    "build": "tsc",
  },
  "keywords": [
    "graphql",
    "api",
    "gateway"
  ],
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.18.6",
    "@babel/preset-env": "^7.18.9",
    "@graphql-codegen/cli": "2.5.0",
    "@graphql-codegen/typescript": "2.4.2",
    "@graphql-codegen/typescript-resolvers": "2.4.3",
    "@openapitools/openapi-generator-cli": "^2.4.26",
    "@types/express": "^4.17.13",
    "@types/ioredis": "^4.28.10",
    "@types/jaeger-client": "^3.18.3",
    "@types/jest": "^27.4.0",
    "@types/lodash": "^4.14.178",
    "@types/node": "^17.0.14",
    "@types/ws": "^8.2.2",
    "@urql/core": "^2.5.0",
    "babel-core": "7.0.0-bridge.0",
    "commander": "^8.3.0",
    "concurrently": "^7.2.2",
    "contentful-management": "^7.53.0",
    "contentful-migration": "^4.7.1",
    "husky": "^7.0.4",
    "imurmurhash": "^0.1.4",
    "nodemon": "^2.0.19",
    "prettier": "^2.6.2",
    "pretty-quick": "^3.1.3",
    "ts-jest": "^27.1.2",
    "typescript": "^4.5.4",
    "urql": "^2.2.0",
    "wait-on": "^6.0.0"
  },
  "dependencies": {
<EMAIL_ADDRESS>"^1.1.1",
<EMAIL_ADDRESS>"^1.0.1",
    "@bmatei/apollo-prometheus-exporter": "^2.1.1",
    "@graphql-tools/graphql-file-loader": "^7.4.0",
    "@graphql-tools/load": "^7.7.0",
    "@graphql-tools/merge": "^8.2.1",
    "@graphql-tools/utils": "^8.6.12",
    "@keyv/redis": "^2.3.9",
    "@lukeed/uuid": "^2.0.0",
    "@opentelemetry/api": "^1.0.4",
    "@opentelemetry/auto-instrumentations-node": "^0.31.0",
    "@opentelemetry/core": "^1.0.0",
    "@opentelemetry/exporter-jaeger": "^1.0.1",
    "@opentelemetry/sdk-trace-base": "^1.0.0",
    "@opentelemetry/sdk-trace-node": "^1.3.0",
    "@sesamecare/model": "22.20220729123435.0",
    "@sesamecare/tracing-tools": "^1.20211227040030.0",
    "apollo-datasource-rest": "^3.6.1",
    "apollo-server-express": "^3.10.0",
    "contentful": "^9.1.28",
    "cookie-parser": "^1.4.6",
    "dataloader": "^2.0.0",
    "dotenv": "^14.3.2",
    "esm": "^3.0.84",
    "express": "^4.17.2",
    "express-prom-bundle": "^6.4.1",
    "fast-sort": "^2.2.0",
    "geo-tz": "^7.0.1",
    "graphql": "^15.8.0",
    "graphql-jit": "^0.7.4",
    "graphql-query-complexity": "^0.11.0",
    "graphql-scalars": "^1.17.0",
    "graphql-tools": "^8.2.12",
    "haversine-js": "^1.0.0",
    "ip": "^1.1.5",
    "jaeger-client": "^3.19.0",
    "jest": "^27.5.0",
    "keyv": "^4.3.3",
    "lodash": "^4.17.21",
    "lodash.get": "^4.4.2",
    "module-alias": "^2.2.2",
    "moment": "^2.29.3",
    "moment-timezone": "^0.5.34",
    "node-fetch": "~2.6.7",
    "prom-client": "^14.0.1",
    "superagent": "^8.0.0",
    "superagent-mock": "^4.0.0",
    "superagent-response-time": "^1.0.3",
    "superagent-use": "^0.1.0",
    "tiny-lru": "^7.0.6",
    "util": "^0.12.4",
    "winston": "^3.5.1"
  },
  "resolutions": {
    "babel-core": "7.0.0-bridge.0",
    "ioredis": "^4"
  },
  "optionalDependencies": {
    "fsevents": "^2.3.2"
  },
}

Right now skip lib check is probably your best workaround. I think the true solution for this is to either use optional peer dependencies (but that requires npm 7+ which is not bundled with node 14) or to remove dependencies on the vendor types in our instrumentation code.


[Bug] CheckComboBox SelectAll not selecting all

Describe the bug
If in the checkComboBox there is too many item, the SelectAll will select only the visible items.
To Reproduce
Steps to reproduce the behavior:
You can find the code  here  : #981
Expected behavior
When checking the selectAll , every items need to be selected
Environment (please complete the following information):

.net: [e.g. 4.8.2]
IDE [e.g. vs2019]
Version [e.g. 3.3.0]

Additional context
On way to solve the pb, is to scale the dropdown to the size of the number of items in it.

I have seen the same issue. When there's a lot of items, scaling to number of items is not really an option.

Yes ! But for now I need it to work so I scale it big !

I have seen this too. It seems that until the items are visible on the drop down, the select all button will not grab everything. So If you open the dropdown and scroll all the way down before hitting the "All" button, then it will select all items.
P.S. I have also seen it where if you set items as selected by default, their tags won't show them as selected until you open/close the dropdown.

closed in 7519c7e


Python CDK: Async Support

@garnaat – this is the minimal async work we just completed, right?  Or is this additional work?

This should be completed now.


Fix the environment passed to subprocess calls when Flintrock is packaged with PyInstaller

Fixes #158.

@gnsiva - Can you let me know if this package fixes the issues you reported in #158?
Flintrock-0.8.0.dev0-standalone-Linux-x86_64.zip

The fix works, thanks very much! I'm glad you found such a clean fix, the stuff that came up on the PyInstaller bug report looked really awkward :+1:

OK, I tweaked this PR slightly per my comment earlier. We may see slightly different behavior once the build runs on Travis CI, since the test package I posted here was built on a local Ubuntu VM.
Once we release Flintrock 0.8.0, @gnsiva let me know if you still see this issue and we can revisit it. For now I think it's been addressed.

The issue is fixed for me in the Flintrock 0.8.0 release as well


Follow-up helm refactoring

This is a follow-up ticket for keptn's helm refactoring started in #6042.
Tasks that still need to be done:

[x] change all places where custom helpers are now used and replace them with helpers from the keptn common chart
[x] where possible, introduce new helpers in the common chart to reduce code duplication between the 3 helm chart that keptn releases
[ ] include helm and jmeter service in the main keptn chart with a condition on .Values.continuousDelivery.enabled~, then update the CLI install/upgrade commands accordingly~
[x] think about how upgrade through the keptn CLI can work with the --reuse-values flag since the structure in the keptn values file changed (doesn't need to be done since this installation option is not there anymore)
[x] https://github.com/keptn/keptn.github.io/issues/1267

The last open point was discussed, and won't be done since helm/jmeter service will move out of the installer chart.


fix SCE ignore_index with label_smoothing

ugly

I still want to make it prettier, but thanks for the fix!


plugin

Hi there, i tried to update the site just and it came up with a message that the beta version has ended and we need to upgrade the RC version? it also says that the plugins may not yet be compatable, could you advise if yours is please before i upgrade.
Many Thanks
Ian

Now that October is in RC, a lot of plugins have moved to RC as well. I recommend you to backup your website and download and install a fresh copy of October from the website. Read this for more info >> http://octobercms.com/beta#fresh-install


Review all component names

The component names being used for the titles of the component pages were taken from the docs collaboration spreadsheet
We need to review these to make sure we are using the right names

The content team has been reviewing the names as we've done component documentation reviews for our pieces. We've got 5 to go (7 if you could Promotional card and Scrollable card). Right now we're just doing it as we do each component. If we keep to that practice, we estimate we'll be done by December 22.
We have a work meeting tomorrow. If it helps the engineering team, we could do a pass on the remaining names and sort those out. Would you like us to do that @aaronhans and @wrendo ?

@m-sullivan7 Please do. I think we trust the content team on this :)

We'll tackle it tomorrow. Would you like us to do Promotional card and Scrollable card reviewed? Yesterday it was up in the air if they'd be in the January launch components.

Actually, yes. I just realized it's already in our component matrix sheet so it'll be in the DS under "In research", or possibly Alpha. Will let you know later about the progress stage.

The content team has reviewed all the components and considered their names. We've updated the component documentation and the spreadsheet with the new names with our recommendations.
We had some minor questions around the promotional card and related scrollable card gallery (our new, preferred term for that component), but these names will probably hold. Perhaps part of moving from research to alpha is making a decision on the name?
Who should get this issue next for internal review? The content team would be happy to discuss our names if people are not a fan of one. 😉

Were many of the component names changed in the spreadsheet last couple of days?
I used the names from the spreadsheet to create the set of components in the left nav here https://designsystem.webstandards.ca.gov/ds-components/

This week we made these changes to names:

Per page feedback became page feedback
Branding/site logo became department header
Scrollable card became scrollable card gallery

@aaronhans quick note: I'm soliciting input on the overall Component page content we worked on from other engineers. In the first set I got back there were some suggestions to the component names. If we have time before we need to lock names in, we may want to briefly discuss any feedback on names once it's all in. I asked for thoughts by Thursday.

No problem, thanks for carefully considering the names

The content designers changed three more names:

Department header is now site header
Department footer is now site footer
Button grid is now link grid

I've asked the content designers to confirm there will be no more name changes and let them know that tomorrow is the cutoff for name changes so we can get engineering going.

The content team has decided on our final names. They are all in the Component Audit Matrix. Thanks for your patience!
OK to close the ticket @aaronhans and @wrendo or is there anything left on your end to do?

The names look great to me. Ok to close by me. Will defer to @aaronhans for his opinion.

Based on some activity https://github.com/cagov/design-system/issues/248, I think Aaron has what he needs. I'm going to go ahead and close it.


Ensure consistency for non-optional array types

Just like [JSONDecodable] and [Enum] types, [JSONCompatible] should return an empty array instead of throwing.

looks good to me


Add numberOfLines prop to Scrollable tab heading

Scrollable tab heading devided into 2 lines. Is it possible to prevent this behavior? I didn't find the way to add numberOfLines prop to Text in heading.
"native-base": "^2.7.2",

If it is Scrollable Tab, then the Text appears in single line

If you want Tab heading Text in single line, then use Scrollable Tab
If you want Tab heading in two lines, then use default Tab

@SupriyaKalghatgi
How can I use numberOfLines for Tabs (4 tab for 2 lines) ?
Can you support to me ! I had try to numberOfLines FlatList but status textStyle and tabStyle is not right,
it's active when i settup them difference.

Scrollable

They are also  Scrollable Tab and shows two line on android but ios shows one line..


[release-2.8] build dynamically linked binaries with promu

[ ] I added CHANGELOG entry for this change.
[ ] Change is not relevant to the end user.

Changes

Verification

/lgtm

/retest-required


add register overload for variadic PathComponent

In one of my apps, I'm wanting to mount several GraphQL resolvers for different API consumers, and to implement some path-based API versioning (like /graphql/macosapp-05-2022 and /graphql/dashboard), but the current register(...) function doesn't allow passing through variadic path components.  Because you can't have default arguments for variadic parameters in Swift, I couldn't just changed the type to PathComponent..., so I added an overload.
The diff is noisier than it should be, because I ran swift-format on it, and it broken things up a little. I didn't touch the first function at all, it's just re-formatted.
If you'd prefer me to undo the formatting changes, I'm happy to do that, just let me know.
Or, if you don't think this is a change you want in the main library, or have a better alternative on how to implement it, I'm all ears.

Thanks for the PR.
I would like to understand why you would want to have the versioning/grouping at the end instead of e.g. /dashboard/graphql and /macosapp-05-2022/graphql. This could already be achieved with app.grouped("dashboard").register(...).
The official GraphQL documentation uses /graphqlat the end as well and I would like to keep this aligned with that.
If this doesn't meet your requirements I would prefer to keep reformats and functional changes as much as possible separated from each other. So I would like to ask you to undo that reformatting for this PR, please.


add_comment doesn't work anymore

Octokit.add_comment doesn't work anymore. The Github API for commenting on an issue doesn't work either

That call requires authentication. Calling Octokit.add_comment or using the api directly (via something like curl) without authenticating will give you a 404. See this gist for an example.

Wohoo, that works for me. Thanks.


Viewport Fit issue on ios 10

Hi Ionic Team,
I'm getting the issue for ios 10 device version
viewport argument key "viewport-fit" not recognized and ignored.
As app is perfectly running on ios 11

I am also getting this same issue in ios 10.
viewport argument key "viewport-fit" not recognized and ignored.
as app is working fine in ios 11.x

+1

Also getting the same issue on iOS 9.3.2. Got it working on another device though. I didn't note the version

For IOS 10.3+ it worked fine for me, I'm thinking that the problem is the SHADOW-DOM that IOS 10.2- does not understand.


[Feature Request] Brace expansion for creating files/folders

Basically the ability to use curly brace to create multiple files/folders like in shell
user/user.{controller,schema,route}.ts

I would love to have this feature as well.
I'll try to implement it and make a PR when I'm done.

Hi @etrnal70, I implemented this feature but as mentioned in the PR, I am not 100% sure if this is going to work.
May I ask you to test my implementation in your setup?
If you are using packer.nvim,
  use({
    "pysan3/neo-tree.nvim",
    branch = "add-brace-expansion",
    requires = {
      "nvim-lua/plenary.nvim",
      "nvim-tree/nvim-web-devicons", -- not strictly required, but recommended
      "MunifTanjim/nui.nvim",
    },
    config = function()
      ... -- Your configuration
    end,
  })

And it should work out of the box.
Thanks in advance :)

Ccol ! I'll give it a shot today


SOLR-17482: Change long form of -r to --recursive

Deprecate --recurse
https://issues.apache.org/jira/browse/SOLR-17482
Description
See JIRA
Solution
See JIRA
Tests
Please describe the tests you've developed or run to confirm this patch implements the feature or solves the problem.
Checklist
Please review the following and check all that apply:

[ ] I have reviewed the guidelines for How to Contribute and my code conforms to the standards described there to the best of my ability.
[ ] I have created a Jira issue and added the issue ID to my pull request title.
[ ] I have given Solr maintainers access to contribute to my PR branch. (optional but recommended, not available for branches on forks living under an organisation)
[ ] I have developed this patch against the main branch.
[ ] I have run ./gradlew check.
[ ] I have added tests for my changes.
[ ] I have added documentation for the Reference Guide

@malliaridis this is ready for review!

@epugh please note that --recurse may need adaptation for branch_9x. There are more references than in main.


fix: DiagnosticableMixin

Now the version after 1.20 is not available. The temporary solution is to modify the source code and change "DiagnosticableMixin" to "DiagnosticableTreeMixin" so that both the new version and the old version are available. I don’t know if this modification is correct, I hope to update the version as soon as possible (some people say it can be changed to "Diagnosticable", but this only solves the problem of the new version of the SDK, the old version of the SDK is not compatible)

hi @Realank , can you please release the latest version on https://pub.dev/packages/flutter_datetime_picker ?


b3sum: digest checksum for multiple files

I have a project with a requirement to output a hash for each file and an overall hash of the whole set of files at the end. This could be achieved with b3sum file1 file2 file3 > filesums; b3sum filesums but a built-in option would be nice too.
I started work on this in https://github.com/daviessm/BLAKE3/commit/d6be56658ec8c0f3075bb3254bc248026aa38a60 but as a Rust newbie I don't know if I'm going down the right path with this.

Why not use tar? Or am I missing something? Do different implementations of tar have implementation diffs that cause tarballs to be slightly different even if they were generated from the same dir?

For my original use-case it's to prove that files have not been modified during a transfer between systems. Adding them to an archive obviously does change the files; as such we need to generate the checksums in the original file structure.

Adding them to an archive obviously does change the files; as such we need to generate the checksums in the original file structure

I see now. Thank you for clarifying.

Just in case it interests anyone landing here, to get a checksum over a range of files individual checksums you can use find and pair it with sort to ensure order is consistent across systems. awk just extracts the digest value from the final output.
find ./target-folder -type f -exec b3sum file1 another/file {} + \
  | LC_ALL=C sort \
  | b3sum \
  | awk '{ print $1 }'

This will recursively search for all files in the relative path ./target-folder and append them to the -exec command b3sum (which has two static filepaths already added from other locations if you need that). The rest of the functionality is described well in this article that I referenced, especially useful with the LC_ALL=C for sort.

I had a similar requirement but only needed the final hash.
Wrote paq using the Blake3 crate.

Just in case it interests anyone landing here, to get a checksum over a range of files individual checksums you can use find and pair it with sort to ensure a deterministic list of checksums to pass to the 2nd b3sum as input from stdin (1st b3sum call is provided with N filepaths).
find ./target-folder -type f -exec b3sum {} + | sort | b3sum --no-names

That will recursively search for all files in the relative path ./target-folder and append them to the -exec command b3sum
The + after {} is to ensure all file paths are provided to a single b3sum call, instead of multiple calls to b3sum for each indivdual file path returned by find.
Original version (more verbose)

Very practical usage, thank you! But is there a similar command on Windows? @polarathene

But is there a similar command on Windows?

I don't use Windows, but you can probably find a similar command to do the same:

Get all file names/paths recursively from a location.
Run b3sum on each one
Sort the output
b3sum the sorted output

You could maybe try with WSL? Or that paq tool linked above should accomplish roughly the same? (just try download and run the windows x64 release file)

Just in case it interests anyone landing here, to get a checksum over a range of files individual checksums you can use find and pair it with sort to ensure a deterministic list of checksums to pass to the 2nd b3sum as input from stdin (1st b3sum call is provided with N filepaths).
find ./target-folder -type f -exec b3sum {} + | sort | b3sum --no-names

That will recursively search for all files in the relative path ./target-folder and append them to the -exec command b3sum
The + after {} is to ensure all file paths are provided to a single b3sum call, instead of multiple calls to b3sum for each indivdual file path returned by find.
Original version (more verbose)

From the future here, to the next future.
The double space requirement between checksum and file got me here. I have blake3 checksums from TeraCopy and the files transfered from Windows to Linux over the internet. In this case I used SyncThing, no rsync, no robocopy and no Samba/Windows share.
It is inconvenient to be in between 2 tools that just dont work with the same data, and then some glue has to be constructed, because.

what
command
output

mydir
find mydir -type f -exec b3sum {} + > mydir.b3
3de3577a7c26681bdae91dbd9b8dcfebaef16fd2b3b82d3369b230feadf51961  mydir/myfile.txt

./mydir
find ./mydir -type f -exec b3sum {} + > mydir.b3
3de3577a7c26681bdae91dbd9b8dcfebaef16fd2b3b82d3369b230feadf51961  ./mydir/myfile.txt

From pwsh and Windows generated .blake3 etc (TeraCopy) on
Unexpected input:

3de3577a7c26681bdae91dbd9b8dcfebaef16fd2b3b82d3369b230feadf51961 *myfile.txt

"\x20\x2A" aka  * aka space followed by star.

3de3577a7c26681bdae91dbd9b8dcfebaef16fd2b3b82d3369b230feadf51961 *mydir\myfile.txt

"\x20\x2A" as above, with wrong (\) directory separator.

On Windows a filesystem name entry containing * or / \ should not be legal.

Be mindful of \\.\c:\very-long-long-path (>MAX_PATH), \\machine\share
On Windows Powershell (powershell.exe) uses System.Text.ASCIIEncoding, whereas
On Microsoft Powershell (pwsh.exe) uses System.Text.UTF8Encoding+UTF8EncodingSealed

The "it just works".
Theres a PSPath of Microsoft.PowerShell.Core\FileSystem::/home/username/mydir/myfile of (Get-Item $HOME).PSPath

Syntax note: | % { $_ }  is short-hand for | ForEach-Object { $_ }, where $_ is the equivalent of $item in foreach($item in $collection) { }. | is the expected pipe.
$blakefile = "windows.teracopy.blake3"
# Convert, foreach line send to file.
Get-Content $blakefile | % { $_.Replace('\','/').Replace(' *','  ') } | Out-File -Append -File "$blakefile.b3"

# Convert, foreach line  pipe to b3sum.
Get-Content $blakefile | % { $_.Replace('\','/').Replace(' *','  ') } |

# Pipe direct to b3sum, read entire $blakefile using -Raw.
Get-Content $blakefile -Raw | % { $_.Replace('\','/').Replace(' *','  ') } | b3sum --check

# If you want there is Tee-Object, send to file and to b3sum
Get-Content $blakefile -Raw | % { $_.Replace('\','/').Replace(' *','  ') } | Tee-Object -FilePath "$blakefile.b3" | b3sum --check --quiet

In case you need to tinker with checksum files thats not the right location for b3sum to find.
Get-ChildItem -File -Recurse | %{ $.FullName } and the $.FullName property, and I'm sure there is a resolve relative path
Resolve-Path -Path "/home/username/mydir/myfile" -RelativeBasePath "/home/username/" -Relative

# For convenience.
$cwd = "/home/username/"
$fullpath = "/home/username/mydir/myfile"
$remove = $cwd
Resolve-Path -Path "$fullpath" -RelativeBasePath "$remove" -Relative

# ./mydir/myfile

From the future here, to the next future.
The double space requirement between checksum and file got me here.

Sorry could you be ab it more clear on what your comment was about? I can only infer the Windows adaptation?
I mean I understand the path separator difference with Windows:

"\x20\x2A" as above, with wrong (\) directory separator.

On Windows a filesystem name entry containing * or / \ should not be legal.

But the checksums being the same that you provided whilst having different paths was your concern?
I haven't gone back through the prior history of this issue, but IIRC you have a content hash of the file, and a reference to the associated file in the 2nd column.
So I don't see an issue with paths differing while keeping the same digest, could you clarify the specific problem there? Are you trying to use those paths afterwards?
Path separators differing between windows and linux isn't always a concern, at least with Rust I recall it having good support to process / convert both. On Windows you can have WSL2 and access content on Windows or WSL2 from either end where obviously the path separator differs despite filesystem boundaries being crossed.

This is a tangent from recent comments, but I want to point out to folks who might be following along that v1.5.0 of the blake3 Rust crate added the Hasher::update_mmap_rayon method, which is the same as what b3sum does internally. So if you want to use e.g. walkdir to code a directory hash, it's easier than it used to be.


Cast interface events

Solution

Solves #594

Had some oddity with f97aa47, git said I had changes to foundryup/install somehow, but file looked the same and I couldn't discard, so I tried to stop tracking.

Tested on two contracts and works great! 👌 Neither had any ABIEncoderV2 params, as I'm not sure of contracts offhand to test that with though

Thanks for helping get finished up, I was working on but would've taken bit longer. One nit I was going to fix was the 's' should probably be dropped off of format_event_params.


Don't use Netlify / sanity to host photo-grid

Thank you for photo-grid, which looks nice.
Is that possible to not use sanity and netlify to host it?
I tried to use it locally, but I need a Sanity account, even on localhost...

Hi @nicosomb thank you for the interest in Photo Grid. There is no hard requirement of Netlify or any hosting solution for the front-end site. However, there is a hard requirement on Sanity which is the headless-CMS that handles photo assets. This is required to enable a lot of the features Photo Grid offers such as the backend dashboard, image resizing, CDN, metadata extraction among many other things.
Sanity has a generous free tier which offers 100GB of asset hosting. The front-end site can also be hosted totally for free at places like Netlify and Vercel with their free tiers. In theory, you can host a Photo Grid site completely for free if it's a hobby project with normal traffic.
I hope that answers your questions and we currently don't have any plans to move away from Sanity due to feature dependencies listed above.
For future, please use our discussions page for questions or general discussions as we want to keep the Issues section focused on features and bugs.


Reading large doubly jagged arrays iteratively/lazily?

Edit: sorry, some copy&paste error destroyed the intro :wink: now fixed
So basically what we need is to process many branches of doubly jagged arrays in files which do not fit into memory.
Here is an example with a small file, showing the structure of such a branch (with uproot3 which falls back to ObjectArray and uproot4 which gives a nice awkward1 array):
import uproot
import uproot4
from km3net_testdata import data_path
print(uproot.__version__)  # 3.12.0
print(uproot4.__version__)  # 0.0.20

filename = data_path("offline/km3net_offline.root")
f = uproot.open(filename)
f4 = uproot4.open(filename)

f["E/Evt/trks/trks.rec_stages"].array()
# <ObjectArray [[[1, 3, 5, 4], [1, 3, 5], [1, 3], ...

f4["E/Evt/trks/trks.rec_stages"].array()
# <Array [[[1, 3, 5, 4], [1, ... 1], [1], [1]]] type='10 * var * var * int64'>

I uploaded a larger file here: http://<IP_ADDRESS>:8889/doubly_jagged.root for which f["E/Evt/trks/trks.rec_stages"].array() takes extremely long.
So I tried to utilise uproot4.lazy() and played around with uproot4.iterate() but I have not figured out how to read the data iteratively. Here are my naive approaches (based on some
trks = uproot4.lazy({"doubly_jagged.root": "E/Evt/trks"})
trks[0, "trks.rec_stages"]

which yiels:
ValueError: generated array does not conform to expected form:

{
    "class": "ListOffsetArray64",
    "offsets": "i64",
    "content": {
        "class": "ListOffsetArray64",
        "offsets": "i64",
        "content": "int32"
    }
}

but generated:

{
    "class": "ListOffsetArray64",
    "offsets": "i64",
    "content": {
        "class": "ListOffsetArray64",
        "offsets": "i64",
        "content": "int64"
    }
}

(https://github.com/scikit-hep/awkward-1.0/blob/0.2.33/src/libawkward/virtual/ArrayGenerator.cpp#L46)

I am not sure why it confuses between int32 and int64, maybe due to empty arrays? No clue...
ping @zinebaly

Okay, the quick answer to your question is that you can use entry_start and entry_stop parameters to limit which TBaskets are read by an array or arrays call. If you do this in little intervals through a dataset, it could be suboptimal because the TBasket boundaries might not line up with your chosen entry_start/entry_stop ranges and you would end up re-reading the TBasket that covers different entry intervals. (Note that there's TBranch.entry_offsets to find out where a branch's TBasket boundaries are and HasBranches.common_entry_offsets to find out where a set of branches have TBasket boundaries that line up, if at all.)
(Uproot 4 doesn't have a basket_cache like Uproot 3: Uproot 3 had too many different types of caches that required the user to have deep understanding of how ROOT files work in order to use them effectively. Also, iterate solves this problem in a better way than a blind LRU cache.)
A better way to iterate over intervals of entries is TBranch.iterate (for a single TTree) and uproot4.iterate (for a set of files). I think you know about this method and function; the advantage over calling array or arrays on intervals is that iterate knows it's sequential, so it knows to save the TBasket data from one iteration to use it in the next.
 As soon as I saw the issues they were causing, I regretted having introduced! However, they are popular, and the right thing to do is to figure out how to do them well, which will take some experience. While we work out these issues, I always recommend performance-minded users to use array, arrays, or iterate because at least you can control exactly when things get read. It requires more diligence to set the first argument properly (many users read all arrays, even when they plan to use only one or two), which is probably why lazy is so popular, but in ceding the responsibility of choosing what gets read to Uproot+Awkward, Uproot+Awkward will have to get better at not reading arrays prematurely.
As for the lazy Form bug you found, I've fixed it. It's because all AsObjects interpretations in Awkward Array are passed through ak.from_iter and that function has only one integer type and one floating point type (like Python, which is appropriate because ak.from_iter is intended for Python data).
The performance issue with doubly jagged arrays is related: because of TTree serialization, more than one level of jaggedness has to be interpreted AsObjects, and so it needs to go through ak.from_iter (like Uproot 3). I've been setting up the infrastructure to write the AsObjects → Awkward interpretation in Awkward's C++ layer, like a faster version of ak.ArrayBuilder because it knows its type at the outset. (That's the ak.forms.Form object.)
However, that optimization likely won't happen until next year—I'm setting things up to make it possible, but we have to do the uproot4 → uproot, uproot → uproot3 migration first. Also, before porting the read methods of all containers and models from Python to C++, I want them to fully stabilize in Python first. This includes understanding memberwise splitting (issue #38) because it comes up often enough. In assigning the is_memberwise attribute from kStreamedMemberWise, I found out that 100% of the std::map examples in our tests are memberwise—we've never seen a non-memberwise std::map.
Some more things you should know:

If you're going to use lazy anyway, update to the latest Awkward, which has corrections from @nsmith- to avoid circular references between an array and its own cache. This PR #92 fixes some Uproot things related to that: the caches have to be explicitly attached to high-level Arrays because the deeply nested ArrayCache objects now only hold weak references, and fail when those weak references go out of scope.
All of the public API modules, classes, functions, and methods have docstrings now.
I'm going to deploy a version with PR #92 to make sure no one gets into trouble with weak references.

Thanks Jim for the detailed answer! Yes, I understand of course the decision regarding the caches and I think that the uproot4 design is the right choice regarding caching and laziness. In our use-case the TBranch.iterate is the right choice and I also tried that (I forgot to add those examples) but I think I am either using them wrong, or there are some other issues which make it unusable in our case.
Given the file I uploaded (should still be online), the following shows that using TBranch.iterate() (assuming I am using it correctly) is painfully slow, it takes like 30 seconds per iteration although each entry is something like ~200 * ~10 * float64 and only retrieves 3 items (in the file there are 145000).
So in general, I am currently still struggling a way to somehow iteratively process these branches. Both trks.fitinf and trks.rec_stages are needed and both are doubly jagged integer arrays. This branch format is really making me cry but it is what it is. Another problem, which I will post in a future issue that working with these arrays is far from the numpy performance (doing things like arr > 0.5 takes ~2ms for 100 entries, while in numpy/Julia/C it should be more around a few hundred ns), but that's another story.
Here is the example:
import uproot4
f = uproot4.open("doubly_jagged.root")

i = 0
for dir_z in f["E/Evt/trks"].iterate("trks.fitinf"):
    print(i, dir_z)
    i += 1
    if i > 10:
        break

# 0 [{'trks.fitinf': [[0.00296, 0.002, -293, 139, 424, 242, 0.01, ... [], [], [], []]}]
# 1 [{'trks.fitinf': [[0.00899, 0.00561, -188, 69, 14.4, 132, 4.88, ... [], [], [], []]}]
# 2 [{'trks.fitinf': [[0.00701, 0.00372, -38.5, 33, 9.26, 44.7, ... [], [], []]}]

# then it stops...

# This one takes around 2 minutes but gives 10 entries (there are 145000 or so in this file)
f["E/Evt/trks/trks.fitinf"].array()[:10]
# <Array [[[0.00296, 0.002, -293, ... [], []]] type='10 * var * var * float64'>

Just to make sure this does not get lost, should I create a new issue or should we reopen this?
At least the fact that it stops after the third iteration (although there should be 145000) is a bug, which might be related to the extremely slow performance. Even if those are Python loops, I think it should be orders of magnitudes faster.
I ran a line profiler with the following script:
import uproot4

f = uproot4.open("doubly_jagged.root")

for dir_z in f["E/Evt/trks"].iterate("trks.fitinf"):
    print(dir_z)
    # no need to break, it will stop after the third iteration

and here is the output of kernprof -l -v ... but it only revealed that 100% of the time is spent in _ranges_or_baskets_to_arrays and inside that function, 100% is spent on :
Total time: 499.249 s
File: /home/tgal/Dev/uproot4/uproot4/behaviors/TBranch.py
Function: _ranges_or_baskets_to_arrays at line 2972
...
...
  3086<PHONE_NUMBER>40.0 1077132.9     99.9              interpretation_executor.submit(basket_to_array, basket)
...
...

To classify it properly, this isn't a correctness bug: I was able to iterate through the whole file using a ridiculously small step_size (in a Zoom meeting, so my fans were blasting):
for x in tree.iterate("trks.fitinf", step_size=100): print(x)

(The default is tree.num_entries_for("100 MB", "trks.fitinf"), which is 63658. That's 100 MB read from disk, which can translate into a lot of working memory with the current implementation because the current implementation has to construct Python objects, which are known to be memory hogs.)
Data of this type are known to have poor performance for understood reasons, and there's a plan in place to fix it (move the non-vectorized loops to C++). So it wouldn't add much to create an issue; I think there's already some roadmap somewhere saying that I need to do this next year.

The plan to fix it is a major project: I've already encoded the information about Uproot Interpretations into Awkward Forms, but now I've got to translate the Python Interpretation code (not entirely finalized yet!) into a machine in C++ that steps through the TBasket byte stream using the Form as a guide—more likely a streamlined version of it because it will be runtime-interpreted for every entry. Technically, that's a virtual machine in the sense of the JVM or Python VM. (Very specific VMs can be fast, like the NumExpr VM, which is faster than precompiled NumPy. It should be highly specialized for speed, but that requires a thorough understanding of what it needs to do, including memberwise Interpretations.)
Because of your troubles, I was thinking of doing a quick, "foot in the door" implementation that handles only one type: std::vector<std::vector<T>> where T is a numeric type (bools, ints, and floats). That would force me to build the interface between Uproot and Awkward but not the full virtual machine. Since that's a very common type, it would be a good impact-to-effort ratio—helping a lot of people with a relatively small investment.
However, I see that what you actually have are not std::vector<std::vector<T>>, but
trks.fitinf          | std::vector<double>* | AsObjects(AsArray(True, False, AsVector(False, dtype('>f8'))))

That's odd enough that it wouldn't actually have a high impact. It would really just help your case and force me to set up the interface between Uproot and Awkward. I could do it for two very specific types:

std::vector<int32_t>*, which is AsObjects(AsArray(True, False, AsVector(False, dtype('>i4')))) and applies to trks.rec_stages and trks.hit_ids
std::vector<double>*, which is AsObjects(AsArray(True, False, AsVector(False, dtype('>f8')))) and applies to trks.usr, trks.fitinf, and trks.error_matrix.

which wouldn't include any of the strings. The implementation on the Awkward side would check to see if a TBranch has exactly this type and run a canned algorithm to fill it—no virtual machine. (In fact, the code that I write now would have to be removed to create the virtual machine, so I can't invest much time into it.) If you have any other types (like 64-bit integers), let me know now because I'd have to explicitly include them.

Ah, I should have tried much smaller step-sizes. I see indeed, it's working with that setting!

The plan to fix it is a major project: I've already encoded the information about Uproot Interpretations into Awkward Forms, but now I've got to translate the Python Interpretation code (not entirely finalized yet!) into a machine in C++ that steps through the TBasket byte stream using the Form as a guide—more likely a streamlined version of it because it will be runtime-interpreted for every entry. Technically, that's a virtual machine in the sense of the JVM or Python VM.

Absolutely; that sounds like a massive undertaking!
I feel a bit uncomfortable to steal your time -- also given that this code will be obsolete in future -- since you have a lot on the roadmap for uproot4 already (and other things), but it would be certainly quite nice to see what's possible using your above-mentioned approach.
Regarding other types, I could follow your patch and see if I can implement those if needed, but at this very moment these are the only problematic branch types we have.
Anyways, many thanks in advance and If you find it takes too much time, just skip it and we can go with the small-step iteration or figure out some other way. Unfortunately this file format will likely not change in the upcoming years, so I guess we will have a few petabytes of them to process in the future :see_no_evil: ...

Maybe you can try harder to push the file format to change. Having non-splittable double-vectors is probably giving worse performance and compression for classic ROOT analyses as well. Can you convince your collaborators to normalize to using two sets of singly-jagged arrays? See e.g. https://github.com/cms-nanoAOD/cmssw/issues/92#issuecomment-499284307

Well, it will be a hard discussion but I will of course try. It will however not happen before next years and we have already quite a large amount of data stored this way, which is constantly analysed over and over.
But I appreciate your suggestions, I'd definitely go that way and try harder.

These data are already split—the problem is that it's doubly jagged. See PR #96: it was the plan since CHEP (page 26/29) to pass non-vectorizable deserializations to Awkward's C++ layer—this is the first example of that.
I had been hoping that this doubly jagged array of numbers would be generalizable, but it's std::vector<double>*, not std::vector<std::vector<double>>, so it's probably not going to be usable by many. At the moment, the implementation checks for that one type and handles it, but in the long run, it needs to be a translation of the Python (deserialization.py, containers.py, and models/*.py). Since Python is easier to modify and correct, I'd like to get a lot of experience with the Python before lowering it all to C++.


Async adding to product repository

Can someone please give the completed method body for AddProductAsync(product)?
I am trying to build the complete project with Product Repository and Product Controller but stumbling on completing the async method to add a product to the repo.

Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

ID: fa03501b-5e71-4c18-0269-39babbf9d93c
Version Independent ID: b51bc104-a6e2-b21f-8362-45cee22e8c22
Content: Controller action return types in ASP.NET Core Web API
Content Source: aspnetcore/web-api/action-return-types.md
Product: aspnet-core
Technology: aspnetcore-webapi
GitHub Login: @scottaddie
Microsoft Alias: scaddie

@scotaddie thanks very much for the link. It will be highly appreciated when the solution file will made  available for this sample so that it becomes a complete project for training purposes.

@krchome There are two solution files available now: https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/web-api/action-return-types/samples. One solution is for ASP.NET Core 2.0, and the other is for 2.1. I'm currently working on updating the doc and solution for ASP.NET Core 3.0.


Update to 1.20

I really wanna use this mod on 1.20.2 please Update it

Probably it won't be updated anytime soon, the only idea that comes to my mind is finding a kind developer that would make a fork for the new version.


correct subpackage version

A subpackage was added with a default version instead of 0.12.8 as needed.

Joe did the same fix in https://github.com/xetdata/xet-core/pull/231. We can close this


Failed to compile version <IP_ADDRESS>

Describe the issue
When trying to make -j2 I get the following error:
qtum/storageresults.cpp: In member function ‘bool StorageResults::readResult(const h256&, std::vector<TransactionReceiptInfo>&)’:
qtum/storageresults.cpp:121:130: error: ‘NoInformation’ is not a member of ‘dev::eth::TransactionException’
                                        state.itemCount() == 11 ? static_cast<dev::eth::TransactionException>(tris.excepted[j]) : dev::eth::TransactionException::NoInformation

Can you reliably reproduce the issue?
If so, please list the steps to reproduce below:

make clean
./autogen.sh
./configure
make -j2

What version of Qtum are you using?
commit ID: dd9904a5f189064
version: <IP_ADDRESS>
Machine specs:

OS: ubuntu 16.04

#508 try git submodule update


Use in Angular2?

Has anyone tried to use this in Angular2 via dependency injection? Looking for guidance on how to lazy load it...
I am currently initializing the plugin through the Window object, via Window as a provider to NgModule. Unfortunately, this requires it to load on App start and not at time of call.

I've never used Angular, but maybe someone else can help.

@khanhvu161188
Thanks, it works perfectly for me.

Since this seems to be resolved, I'm closing the issue.

Hi,
I would like to integrate pannellum into an angular6 app.
I did:
-cd
-npm i pannellum
This adds pannellum into package.json, but not into angular.json (there is no angular-cli.json now).
With the setup above, the pannellum integration does not work.
import * as pannelllum from pannellum works, but I'm not sure how could I instantiate some pannellum object to work with (viewer)...
Could you help?
Thx,
Regards
Sandor

Hi, I would also know how to use it in angular 8. Can't get it work.

@esanya @alegroSandermann
Implemented into a pano.component.ts like so.....
import * as pannellum from 'pannellum/build/pannellum.js'

@Component({
  selector: 'ng-pano',
  templateUrl: './pano.component.html',
})
export class PanoComponent implements OnInit, OnChanges, OnDestroy {
  private pano

  ngOnInit() {
    this.pano = window.nativeWindow.pannellum.viewer(element, config)
  }

  ngOnChanges(changes) {
    // Couldn't get Pannellum to update the image without destroying, I don't remember why.
    this.pano.destroy()
    this.pano = window.nativeWindow.pannellum.viewer(element, config)
  }

  ngOnDestroy() {
    this.pano.destroy()
  }
}

If I implement this I get the message:
Property 'nativeWindow' does not exist on type 'Window & typeof globalThis'.

If I implement this I get the message:
Property 'nativeWindow' does not exist on type 'Window & typeof globalThis'.

Sorry, nativeWindow should not exist. I've edited it out of my snippet. Have you initiated pannellum in the component? That should exist in your window scope.

I did declare var window: any; after the import. This eliminates the error but it does also not work
And what I have seen, the import import * as pannellum from 'pannellum/build/pannellum.js'; has never been used

I did declare var window: any; after the import. This eliminates the error but it does also not work
And what I have seen, the import import * as pannellum from 'pannellum/build/pannellum.js'; has never been used

What does not work specifically? Please share a snippet.
Right, I've removed that also from the snippet. Are you still seeing that?

This is my component ts file:
`import { Component, OnInit, OnChanges, OnDestroy } from '@angular/core';
declare var window: any;
@Component({
selector: 'app-landingpage',
templateUrl: './landingpage.component.html',
styleUrls: ['./landingpage.component.css']
})
export class LandingpageComponent implements OnInit, OnChanges, OnDestroy {
private pano;
constructor() { }
ngOnInit() {
this.pano = window.pannellum.viewer('panoramaContainer',
{
"type": "equirectangular",
"panorama": "https://pannellum.org/images/alma.jpg"
});
}
ngOnChanges(changes) {
// Couldn't get Pannellum to update the image without destroying, I don't remember why.
this.pano.destroy()
this.pano = window.pannellum.viewer('panoramaContainer',
{
"type": "equirectangular",
"panorama": "https://pannellum.org/images/alma.jpg"
});
}
ngOnDestroy() {
this.pano.destroy()
}
}`
The console says:
ERROR TypeError: Cannot read property 'viewer' of undefined     at LandingpageComponent.ngOnInit (landingpage.component.ts:20)     at checkAndUpdateDirectiveInline (core.js:31910)     at checkAndUpdateNodeInline (core.js:44367)     at checkAndUpdateNode (core.js:44306)     at debugCheckAndUpdateNode (core.js:45328)     at debugCheckDirectivesFn (core.js:45271)     at Object.eval [as updateDirectives] (LandingpageComponent_Host.ngfactory.js? [sm]:1)     at Object.debugUpdateDirectives [as updateDirectives] (core.js:45259)     at checkAndUpdateView (core.js:44271)     at callViewAction (core.js:44637)

Oh, you still have to init pannellum.

in angular-cli.json
add vendor/pannellum/pannellum.js in "scripts"
add vendor/pannellum/pannellum.css in "styles"
in component:
add declare var pannellum: any;
and use like normal

 pannellum.viewer('panoramaContainer', {
      "type": "equirectangular",
      "panorama": photourl,
      "autoLoad": true,
      "compass": true
    });

I have no angular-cli.json, just an angular.json
I added the script and css but get the same error message at the console.

I have no angular-cli.json, just an angular.json
I added the script and css but get the same error message at the console.

From Angular 6 version angular-cli.json has been replaced with angular.json

declare var pannellum: any; is necesary for angular

I'm using angular 17 and I still use the Cli all the time (like to build)? -_(' - ' )_/-
I suggest a reusable component over injection since there is a requirement of some html and it is globally available (The factories is instanced on window already. When the code is imported the javascript makes a single factory object that is stored globally on the window once or at least when you import. It is also kind of important to destroy the instanced viewer later to avoid issue or suffer the dreaded memory. Reusable components with ngAfterViewInit make it easy!).
I mean If you are using type script why not leverage the type script with a type def? Yes sure 'any' will quick and dirty do it for you, so that is an option, but you will get 0 intelligence and 0 type checking. You can define some type interfaces.

First install with

npm i pannellum

Include the CSS one of three ways. I recommend the angular.json way or the first. Try to include it as early as possible if you want to override in components.
angular.json:

"styles": [
              "./node_modules/pannellum/src/css/pannellum.css", //add this line to wherever you set your styles.
              "./node_modules/leaflet/dist/leaflet.css",
              "src/custom-theme.scss",
              "src/styles.scss"
            ],

scss or similar equivalent (pick either the root styles.scss or an appropriate level for you):
@import '~pannellum/src/css/pannellum.css';

Additionally you can include it in the html, but given wanting to integrate it I think its a bad option.
3. import the script. You can similarly do it multiple ways like above. I recommend angular,json since you really only need it to run once. But if you import to get lazy loading as I have done bellow that is fine.
"scripts": [
"./node_modules/pannellum/src/js/libpannellum",
"./node_modules/pannellum/src/js/pannellum"
];

Imports to .ts files:
import 'pannellum/src/js/libpannellum' //this could go in the component as well
import 'pannellum/src/js/pannellum'

additionally you can include it in the html. But given wanting to integrate it I think its a bad option.
4. Then define some type interfaces. here is a rough I did. I don't really want to be responsible for maintaining this and it is a bit roughed for the moment. But if a community would develop a definitely typed that would be great! You can copy and paste it into a file for now. Its really just the imports and some interface definitions for working with the JavaScript in typescript. Most of the comments and interfaces were scraped from the docs anyway,
import 'pannellum/src/js/libpannellum'//as above's option 2
import 'pannellum/src/js/pannellum'//as above's option 2

/** possible Viewer config values for type of viewer */
export type PannellumPanoramaType = 'equirectangular' | 'cube' | 'multires';

/** utility enum for PannellumPanoramaType */
export enum PannellumPanoramaTypeEnum
{
  'equirectangular',
  'cube',
  'multires'
}

/** Calues that may be used for configuration.  */
export type PannellumCrossOrigin = 'anonymous' | 'use-credentials' ;

/** events that you may specify in API
 * load -Fired when a panorama finishes loading.
 * scenechange - Fired when a scene change is initiated. A load event will be fired when the new scene finishes loading. Passes scene ID string to handler.
 * fullscreenchange - Fired when browser fullscreen status changed. Passes status boolean to handler.
 * zoomchange - Fired when scene hfov update. Passes new HFOV value to handler.
 * scenechangefadedone - If a scene transition fade interval is specified, this event is fired when the fading is completed after changing scenes.
 * animatefinished - Fired when any movements / animations finish, i.e. when the renderer stops rendering new frames. Passes final pitch, yaw, and HFOV values to handler.
 * error - Fired when an error occured. The error message string is passed to the event listener.
 * errorcleared - Fired when an error is cleared.
 * mousedown - Fired when the mouse button is pressed. Passes MouseEvent to handler.
 * mouseup - Fired when the mouse button is released. Passes MouseEvent to handler.
 * touchstart - Fired when a touch starts. Passes TouchEvent to handler.
 * touchend - Fired when a touch ends. Passes TouchEvent to handler.
 * messageshown - Fired when a message, e.g., for needing ctrl + scroll to zoom, is shown.
 * messagecleared - Fired when a previously shown message is cleared.
 */
export type PannellumEventType = 'load' | 'scenechange' | 'fullscreenchange' | 'zoomchange' | 'scenechangefadedone' | 'animatefinished' | 'error' | 'errorcleared' | 'mousedown' | 'mouseup' | 'touchstart' | 'touchend';

export type PannellumEquirectangularConfig = PannellumSharedConfig & {
  /** If a string is passed, it sets the URL to the equirectangular panorama image. This is relative to basePath if it is set, else it is relative to the location of pannellum.htm. An absolute URL can also be used. Alternatively, an already loaded image can be passed. */
  panorama: string
  /** Sets the panorama's horizontal angle of view, in degrees. Defaults to 360. This is used if the equirectangular image does not cover a full 360 degrees in the horizontal. */
  haov?: number
  /** Sets the panorama's vertical angle of view, in degrees. Defaults to 180. This is used if the equirectangular image does not cover a full 180 degrees in the vertical. */
  vaov?: number
  /** Sets the vertical offset of the center of the equirectangular image from the horizon, in degrees. Defaults to 0. This is used if vaov is less than 180 and the equirectangular image is not cropped symmetrically. */
  vOffset?: number
  /** If set to true, any embedded Photo Sphere XMP data will be ignored; else, said data will override any existing settings. Defaults to false. */
  ignoreGPanoXMP?: boolean
  /** Currently, only equirectangular dynamic content is supported. The panorama source is considered dynamic when this is set to true. Defaults to false. This should be set to true for video. */
  dynamic?: boolean
  /** Currently, only equirectangular dynamic content is supported. The panorama source is considered dynamic when this is set to true. Defaults to false. This should be set to true for video. */
  dynamicUpdate?: boolean
  /** This specifies the panorama Type. it will need to be equirectangular in this config type, For cube please switch to PannellumCubeMapConfig and for multires please switch to PannellumMultiresConfig*/
  type: 'equirectangular'
}

export type PannellumCubeMapConfig = PannellumSharedConfig & {
  /** This is an array of URLs for the six cube faces in the order front, right, back, left, up, down. These are relative to basePath if it is set, else they are relative to the location of pannellum.htm. Absolute URLs can also be used. Partial cubemap images may be specified by giving null instead of a URL. */
  cubeMap: string[]
  /** This specifies the panorama Type. it will need to be equirectangular in this config type, For equirectangular please switch to PannellumEquirectangularConfig and for multires please switch to PannellumMultiresConfig*/
  type: 'cube'
}

export type PannellumMultiresConfig = PannellumSharedConfig & {
  /** This is the base path of the URLs for the multiresolution tiles. It is relative to the regular basePath option if it is defined, else it is relative to the location of pannellum.htm. An absolute URL can also be used. */
  basePath: string
  /** This is a format string for the location of the multiresolution tiles, relative to multiRes.basePath, which is relative to basePath. Format parameters are %l for the zoom level, %s for the cube face, %x for the x index, and %y for the y index. For each tile, .extension is appended. */
  path: string
  /** This is a format string for the location of the fallback tiles for the CSS 3D transform-based renderer if the WebGL renderer is not supported, relative to multiRes.basePath, which is relative to basePath. The only format parameter is %s, for the cube face. For each face, .extension is appended. */
  fallback: string
  /** Specifies the tiles' file extension. Do not include the '.'. */
  extension: string
  /** This specifies the size in pixels of each image tile. */
  tileResolution: number
  /** This specifies the maximum zoom level. */
  maxLevel: number
  /** This specifies the size in pixels of the full resolution cube faces the image tiles were created from. */
  cubeResolution: number
  /** Specifies the spherical-harmonic-transform-based preview hash. This is rendered instead of the background color before the base set of cube faces are loaded. */
  shtHash?: string
  /** Specifies a equirectangular preview thumbnail to be rendered instead of the background color or SHT hash before the base set of cube faces are loaded. This image can either be specified as a Base64-encoded string or as an object that can be directly uploaded to a WebGL texture, e.g., ImageData, ImageBitmap, HTMLImageElement, HTMLCanvasElement objects. If a Base64-encoded string is used, the image size should be kept small, since it needs to be loaded with the configuration parameters. */
  equirectangularThumbnail?: ImageData | ImageBitmap | HTMLCanvasElement
  /** This specifies the panorama Type. it will need to be equirectangular in this config type, For cube please switch to PannellumCubeMapConfig and for equirectangular please switch to PannellumEquirectangularConfig*/
  type: 'multires'
}

export type PannellumSharedConfig = {
    /** This specifies the panorama type. Can be equirectangular, cubemap, or multires. Defaults to equirectangular */
    type: PannellumPanoramaType
    /** If set, the value is displayed as the panorama's title. If no title is desired, don't set this parameter. */
    title?: string
    /** If set, the value is displayed as the panorama's author. If no author is desired, don't set this parameter. */
    author?: string
    /** If set, the displayed author text is hyperlinked to this URL. If no author URL is desired, don't set this parameter. The author parameter must also be set for this parameter to have an effect. */
    authorURL?: string
    /** Allows user-facing strings to be changed / translated. See defaultConfig.strings definition in pannellum.js for more details. */
    strings?: PannellumStringsDictionary
    /** This specifies a base path to load the images from. */
    basePath?: string
    /** If set to true, device orientation control will be used when the panorama is loaded, if the device supports it. If false, device orientation control needs to be activated by pressing a button. Defaults to false. Note that a secure HTTPS connection is required for device orientation access in most browsers. Additionally, this feature does not work in combination with autoLoad: true in most browsers, since a user interaction is required to prompt for permission. */
    autoLoad?: boolean
    /** Setting this parameter causes the panorama to automatically rotate when loaded. The value specifies the rotation speed in degrees per second. Positive is counter-clockwise, and negative is clockwise. */
    autoRotate?: boolean
    /** Sets the delay, in milliseconds, to start automatically rotating the panorama after user activity ceases. This parameter only has an effect if the autoRotate parameter is set. Before starting rotation, the viewer is panned to the initial pitch. */
    autoRotateInactivityDelay?: number
    /** Sets the delay, in milliseconds, to stop automatically rotating the panorama after it is loaded. This parameter only has an effect if the autoRotate parameter is set. */
    autoRotateStopDelay?: number
    /** If set to true, device orientation control will be used when the panorama is loaded, if the device supports it. If false, device orientation control needs to be activated by pressing a button. Defaults to false. Note that a secure HTTPS connection is required for device orientation access in most browsers. Additionally, this feature does not work in combination with autoLoad: true in most browsers, since a user interaction is required to prompt for permission. */
    orientationOnByDefault?: boolean
    /** If set to false, the zoom controls will not be displayed. Defaults to true. */
    showZoomCtrl?: boolean
    /** If set to false, zooming with keyboard will be disabled. Defaults to true. */
    keyboardZoom?: boolean
    /** If set to false, zooming with mouse wheel will be disabled. Defaults to true. Can also be set to fullscreenonly, in which case it is only enabled when the viewer is fullscreen. Can also be set to ctrl, in which case the ctrl key must be held down to zoom with the mouse wheel (except while the viewer is fullscreen); when the ctrl key is required for mouse wheel zooming, the use of ctrl / shift for zoom control is disabled. */
    mouseZoom?: boolean | 'fullscreenonly'
    /** If set to false, the zoom to click location on double click function will be disabled. Defaults to true. */
    doubleClickZoom?: boolean
    /** If specified, the hotspot can moved using the mouse or by touch. */
    draggable?: boolean
    /** If specified, the hotspot can moved using the mouse or by touch. */
    dragConfirm?: boolean | 'pitch' | 'yaw' | 'both'
    /** Controls the "friction" that slows down the viewer motion after it is dragged and released. Higher values mean the motion stops faster. Should be set (0.0, 1.0]; defaults to 0.15. */
    friction?: number
    /** If set to true, keyboard controls are disabled. Defaults to false. */
    disableKeyboardCtrl?: boolean
    /** If set to false, the fullscreen control will not be displayed. Defaults to true. The fullscreen button will only be displayed if the browser supports the fullscreen API. */
    showFullscreenCtrl?: boolean
    /** If set to false, no controls are displayed. Defaults to true. */
    showControls?: boolean
    /** Adjusts panning speed from touch inputs. Defaults to 1. */
    touchPanSpeedCoeffFactor?: number
    /** Specifies the yaw portion of the hot spot’s location, in degrees. */
    yaw?: number
    /** Sets the panorama’s starting pitch position in degrees. Defaults to 0. */
    pitch?: number
    /** If set to false, one finger can be used to pan viewer. Defaults to false. Can also be set to pitch, yaw, or both. If set to pitch or both, two fingers need to be used to pan vertically (except while the viewer is fullscreen). If set to yaw or both, two fingers need to be used to pan horizontally (except while the viewer is fullscreen). */
    hfov?: number
    /** Sets the minimum yaw the viewer edge can be at, in degrees. Defaults to -180, i.e. no limit. */
    minYaw?: number
    /** Sets the maximum yaw the viewer edge can be at, in degrees. Defaults to 180, i.e. no limit. */
    maxYaw?: number
    /** Sets the minimum / maximum pitch the viewer edge can be at, in degrees. Defaults to undefined, so the viewer center can reach -90 / 90. */
    minPitch?: number
    /** If set to true, prevent displaying out-of-range areas of a partial panorama by constraining the yaw and the field-of-view. Even at the corners and edges of the canvas only areas actually belonging to the image (i.e., within [minYaw, maxYaw] and [minPitch, maxPitch]) are shown, thus setting the backgroundColor option is not needed if this option is set. Defaults to false. */
    maxPitch?: number
    /** Sets the minimum horizontal field of view, in degrees, that the viewer can be set to. Defaults to 50. Unless the multiResMinHfov parameter is set to true, the minHfov parameter is ignored for multires panoramas. */
    minHfov?: number
    /** Sets the maximum horizontal field of view, in degrees, that the viewer can be set to. Defaults to 120. Unless the multiResMinHfov parameter is set to true, the minHfov parameter is ignored for multires panoramas. */
    maxHfov?: number
    /** When set to false, the minHfov parameter is ignored for multires panoramas; an automatically calculated minimum horizontal field of view is used instead. Defaults to false. */
    multiResMinHfov?: boolean
    /** If true, a compass is displayed. Normally defaults to false; defaults to true if heading information is present in Photo Sphere XMP metadata. */
    compass?: boolean
    /** Set the offset, in degrees, of the center of the panorama from North. As this affects the compass, it only has an effect if compass is set to true. */
    northOffset?: number
    /** Specifies a URL for a preview image to display before the panorama is loaded. */
    preview?: string
    /** Specifies the title to be displayed while the load button is displayed. */
    previewTitle?: string
    /** Specifies the author to be displayed while the load button is displayed. */
    previewAuthor?: string
    /** Specifies roll of image horizon, in degrees (for correcting non-leveled panoramas). */
    horizonPitch?: number
    /** Specifies roll of image horizon, in degrees (for correcting non-leveled panoramas). */
    horizonRoll?: number
    /** (API required)This specifies a timing function to be used for animating movements such as when the lookAt method is called. The default timing function is easeInOutQuad. If a custom function is specified, it should take a number [0, 1] as its only argument and return a number [0, 1]. */
    animationTimingFunction?: ((number: number)=>number)
    /** When true, HTML is escaped from configuration strings to help mitigate possible DOM XSS attacks. This is always true when using the standalone viewer since the configuration is provided via the URL; it defaults to false but can be set to true when using the API. */
    escapeHTML?: boolean
    /** When true, target="_blank" is set on most hyperlinks to open them in new tabs. This is always true when using the standalone viewer since said viewer is often used in an <iframe>, where it doesn't make sense to open the link in the same place. Defaults to false. */
    targetBlank?: boolean
    /** This specifies the type of CORS request used and can be set to either anonymous or use-credentials. Defaults to anonymous. */
    crossOrigin?: PannellumCrossOrigin
    /** This specifies a list (note at end) of hot spots that can be links to other scenes, information, or external links. Each array element has the following properties. (originally listed as dictionary but is not) */
    hotSpots?: PannellumHotSpot[]
    /** When true, the mouse pointer's pitch and yaw are logged to the console when the mouse button is clicked. Defaults to false. */
    hotSpotDebug?: boolean
    /** Specifies the fade duration, in milliseconds, when transitioning between scenes. Not defined by default. Only applicable for tours. Only works with WebGL renderer. */
    sceneFadeDuration?: number
    /** Specifies the key numbers that are captured in key events. Defaults to the standard keys that are used by the viewer. */
    capturedKeyNumbers?: number[]
    /** Specifies an array containing RGB values [0, 1] that sets the background color for areas where no image data is available. Defaults to [0, 0, 0] (black). For partial equirectangular panoramas this applies to areas past the edges of the defined rectangle. For multires and cubemap (including fallback) panoramas this applies to areas corresponding to missing tiles or faces. If set to null, the background is not cleared. */
    backgroundColor?: [number, number, number]
    /** If set to true, prevent displaying out-of-range areas of a partial panorama by constraining the yaw and the field-of-view. Even at the corners and edges of the canvas only areas actually belonging to the image (i.e., within [minYaw, maxYaw] and [minPitch, maxPitch]) are shown, thus setting the backgroundColor option is not needed if this option is set. Defaults to false. The minPitch and maxPitch parameters must be defined if this option is enabled. */
    avoidShowingBackground?: boolean
  }

  /** A key value pairing object. See strings on PannellumSharedConfig or PannellumEquirectangularConfig or PannellumCubeMapConfig or PannellumMultiresConfig*/
  export type PannellumStringsDictionary = {
    //** Key value pairing */
    [key: string]: string
  }

  export type PannellumTour = {
    /** sets the default scene */
    default: PannellumDefaultScene
    /** sets the scene key value pairs */
    scenes: PannellumScenes
  }

  export type PannellumDefaultScene = {
    /** required the first scene id */
    firstScene: string
    /** Sets default author. If set, the value is displayed as the panorama's author. If no author is desired, don't set this parameter. */
    author?: string
    /** Sets default Specifies the fade duration, in milliseconds, when transitioning between scenes. Not defined by default. Only applicable for tours. Only works with WebGL renderer. */
    sceneFadeDuration?: number
  }

  /** A multi scene configuration allowing multiple scenes durring init */
  export type PannellumScenes = {
    /** Key value paring for SceneId to scene config */
    [key: string]: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig
  }

  export type PannellumHotSpot = {
    /** Specifies the pitch portion of the hot spot's location, in degrees. */
    pitch: number
    /** Specifies the yaw portion of the hot spot's location, in degrees. */
    yaw: number
    /** Specifies the type of the hot spot. Can be scene for scene links or info for information hot spots. A tour (Scene) configuration file is required for scene hot spots. */
    type: "info" | "scene"
    /** This specifies the text that is displayed when the user hovers over the hot spot. */
    text: string
    /** If specified for an info hot spot, the hot spot links to the specified URL. Not applicable for scene hot spots. */
    URL?: string
    /** Specifies URL's link attributes. If not set, the target attribute is set to _blank, to open link in new tab to avoid opening in viewer frame / page. */
    attributes?: object
    /** Specifies the ID of the scene to link to for scene hot spots. Not applicable for info hot spots. */
    sceneId?: string
    /** Specifies the pitch of the target scene, in degrees. Can also be set to same, which uses the current pitch of the current scene as the initial pitch of the target scene. */
    targetPitch?: number
    /** Specifies the yaw of the target scene, in degrees. Can also be set to same or sameAzimuth. These settings use the current yaw of the current scene as the initial yaw of the target scene; same uses the current yaw directly, while sameAzimuth takes into account the northOffset values of both scenes to maintain the same direction with regard to north. */
    targetYaw?: number
    /** Specifies the HFOV of the target scene, in degrees. Can also be set to same, which uses the current HFOV of the current scene as the initial HFOV of the target scene. */
    targetHfov?: number
    /** Specifies hot spot ID, for use with API's removeHotSpot function. */
    id?: any
    /** If specified, string is used as the CSS class for the hot spot instead of the default CSS classes. */
    cssClass?: string
    /** If createTooltipFunc is specified, this function is used to create the hot spot tooltip DOM instead of the default function. The contents of createTooltipArgs are passed to the function as arguments. */
    createTooltipFunc?: ((createTooltipArgs: object)=> void)
    /** For use with createTooltipFunc. The contents of createTooltipArgs are passed to the createTooltipFunc function as arguments. */
    createTooltipArgs?: object
    /** If clickHandlerFunc is specified, this function is added as an event handler for the hot spot's click, pointerup, and touchend events. The event object and the contents of clickHandlerArgs are passed to the function as arguments. */
    clickHandlerFunc?: ((createArgs: object)=> void)
    /** For use with createTooltipFunc. The event object and the contents of clickHandlerArgs are passed to the createTooltipFunc function as arguments. */
    clickHandlerArgs?: object
    /** If specified, the hotspot can moved using the mouse or by touch. Defaults false */
    draggable?: boolean
    /** If dragHandlerFunc is specified, this function is added as an event handler when dragging of the hotspot starts and ends. The event object and the contents of dragHandlerArgs are passed to the function as arguments. Possible types of the event object are: mousedown, pointerdown, touchend, pointerup, pointerleave, mouseup, and mouseleave. */
    dragHandlerFunc?: ((createArgs: object)=> void)
    /** The event object and the contents of dragHandlerArgs are passed to the function dragHandlerFunc as arguments. */
    dragHandlerArgs?: object
    /** When true, the hot spot is scaled to match changes in the field of view, relative to the initial field of view. Note that this does not account for changes in local image scale that occur due to distortions within the viewport. If set to a number, a fixed scaling is applied relative to the default hot spot size. Defaults to false. */
    scale?: boolean
  }

  export interface PannellumRender{
    /**
     * Initialize renderer.
     * @param haov number Initial horizontal angle of view.
     * @param vaov number Initial vertical angle of view.
     * @param voffset number Initial vertical offset angle.
     * @param callback function Load callback function.
     * @param params Object? Other configuration parameters (horizonPitch, horizonRoll, backgroundColor).
     * @param image  (Image | Array | Object) Input image; format varies based on imageType. For equirectangular, this is an image; for cubemap, this is an array of images for the cube faces in the order [+z, +x, -z, -x, +y, -y]; for multires, this is a configuration object.
     * @param imageType The type of the image: equirectangular, cubemap, or multires.
     * @param dynamic Whether or not the image is dynamic (e.g. video).
     */
    init(haov: number, vaov: number, voffset: number, callback: (()=>void), params?: {horizonPitch?: number, horizonRoll?: number, backgroundColor?: [number, number, number]}, image?: HTMLImageElement | any[] | Object,  imageType?: string, dynamic?: boolean): void
    /** Retrieve renderer’s canvas.
     * @returns Canvas element.
    */
    getCanvas(): HTMLCanvasElement
    /** Check if images are loading.
     * @returns true if image is loading
    */
    isLoading(): boolean
    /**
     * Render new view of panorama.
     * @param pitch number Pitch to render at (in radians).
     * @param yaw number Yaw to render at (in radians).
     * @param hfov number Horizontal field of view to render with (in radians).
     * @param params Object? Extra configuration parameters.
     * @param params.roll number? Camera roll (in radians).
     * @param params.returnImage boolean? Return rendered image?
     * @returns void of nothing or a Image if set to return
     */
    render(pitch: number, yaw: number, hfov: number, params?: { roll?: number, returnImage?: boolean }): void | HTMLImageElement
    /**
     * Set renderer horizon pitch and roll.
     * @param horizonPitch
     * @param horizonRoll
     */
    setPose(horizonPitch: number, horizonRoll: number): void
    /**
     * Resize renderer (call after resizing container).
     */
    resize(): void
    /**
     * Destroy renderer.
     */
    destroy(): void
  }

  export interface PannellumViewer {
    /**
     * Check if images are loading.
     * @returns true when loading or false
     */
    isLoading(): boolean
    /**
     * Check if a panorama is loaded.
     * @returns Returns boolean true if a panorama is loaded, else false
     */
    isLoaded(): boolean
    /**
     * Returns the pitch of the center of the view.
     * @returns Returns number Pitch in degrees
     */
    getPitch(): number
    /**
     * Sets the pitch of the center of the view.
     * @param set number Pitch in degrees
     * @param animated (boolean | number) Animation duration in milliseconds or false for no animation (optional, default 1000)
     * @param callback function? Function to call when animation finishes
     * @param callbackArgs object? Arguments to pass to callback function
     * @returns Viewer this
     */
    setPitch(pitch: number, animated: boolean | number, callback?: ((callbackArgs: object)=>void), callbackArgs?: object): PannellumViewer
    /**
     * Returns the minimum and maximum allowed pitches (in degrees).
     * @returns Array<number> [minimum pitch, maximum pitch]
     */
    getPitchBounds(): [min: number, max: number]
    /**
     * Set the minimum and maximum allowed pitches (in degrees).
     * @param bounds [minimum pitch, maximum pitch]
     * @returns Viewer this
     */
    setPitchBounds(bounds: [min: number, max: number]): PannellumViewer
    /**
     * Returns the yaw of the center of the view.
     * @returns number Yaw in degrees
     */
    getYaw(): number
    /**
     * Sets the yaw of the center of the view.
     * @param animated (boolean | number) Animation duration in milliseconds or false for no animation (optional, default 1000)
     * @param callback function? Function to call when animation finishes
     * @param callbackArgs object? Arguments to pass to callback function
     * @returns Viewer this
     */
    setYaw(yaw: number, animated: boolean | number, callback?: ((callbackArgs: object)=>void), callbackArgs?: object): PannellumViewer
    /**
     * Returns the minimum and maximum allowed pitches (in degrees).
     * @returns Array<number> [yaw pitch, maximum yaw]
     */
    getYawBounds(): [min: number, max: number]
    /**
     * Set the minimum and maximum allowed yaws (in degrees [-180, 180]).
     * @param bounds
     * @returns Viewer this
     */
    setYawBounds(bounds: [min: number, max: number]): PannellumViewer
    /**
     * Returns the horizontal field of view.
     * @returns number Horizontal field of view in degrees
     */
    getHfov(): number
    /**
     * Sets the horizontal field of view.
     * @param set number Horizontal field of view in degrees
     * @param animated (boolean | number) Animation duration in milliseconds or false for no animation (optional, default 1000)
     * @param callback function? Function to call when animation finishes
     * @param callbackArgs object? Arguments to pass to callback function
     * @returns Viewer this
     */
    setHfov(hfov: number, animated: boolean | number, callback?: ((callbackArgs: object)=>void), callbackArgs?: object): PannellumViewer
    /**
     * Returns the minimum and maximum allowed horizontal fields of view (in degrees).
     * @returns Array<number> [minimum hfov, maximum hfov]
     */
    getHfovBounds(): [min: number, max: number]
    /**
     * Set the minimum and maximum allowed horizontal fields of view (in degrees).
     * @param bounds Array<number> [minimum hfov, maximum hfov]
     * @returns Viewer this
     */
    setHfovBounds(bounds: [min: number, max: number]): PannellumViewer
    /**
     * Set a new view. Any parameters not specified remain the same.
     * @param pitch number? Target pitch
     * @param yaw number? Target yaw
     * @param hfov number? Target hfov
     * @param animated (boolean | number) Animation duration in milliseconds or false for no animation (optional, default 1000)
     * @param callback function? Function to call when animation finishes
     * @param callbackArgs object? Arguments to pass to callback function
     * @returns Returns Viewer this
     */
    lookAt(pitch : number, yaw: number, hfov: number, animated: number | boolean, callback?: ((callbackArgs: object)=>void), callbackArgs?: object): PannellumViewer
    /**
     * Returns the panorama’s north offset.
     * @returns Returns number North offset in degrees
     */
    getNorthOffset(): number
    /**
     * Sets the panorama’s north offset.
     * @param heading number North offset in degrees
     * @returns Returns Viewer this
     */
    setNorthOffset(heading: number): PannellumViewer
    /**
     * Returns the panorama’s horizon roll.
     * @returns Returns number Horizon roll in degrees
     */
    getHorizonRoll(): number
    /**
     * Sets the panorama’s horizon roll.
     * @param roll number Horizon roll in degrees [-90, 90]
     * @returns Returns Viewer this
     */
    setHorizonRoll(roll : number): PannellumViewer
    /**
     * Returns the panorama’s horizon pitch.
     * @returns Returns number Horizon pitch in degrees
     */
    getHorizonPitch(): number
    /**
     * Sets the panorama’s horizon pitch.
     * @param pitch number Horizon pitch in degrees [-90, 90]
     * @returns Returns Viewer this
     */
    setHorizonPitch(pitch: number): PannellumViewer
    /**
     * Start auto rotation. Before starting rotation, the viewer is panned to pitch.
     * @param speed number? Auto rotation speed / direction. If not specified, previous value is used.
     * @param pitch number? The pitch to rotate at. If not specified, inital pitch is used.
     * @returns Returns Viewer this
     */
    startAutoRotate(speed?: number, pitch?: number): PannellumViewer
    /**
     * Stop auto rotation.
     * @returns Returns Viewer this
     */
    stopAutoRotate(): PannellumViewer
    /**
     * Stops all movement.
     */
    stopMovement(): void
    /**
     * Returns the panorama renderer.
     * @returns Renderer
     */
    getRenderer(): PannellumRender
    /**
     * Sets update flag for dynamic content.
     * @param force boolean Whether or not viewer should update even when still
     * @returns Viewer this
     */
    setUpdate(force: boolean): PannellumViewer
    /**
     * Calculate panorama pitch and yaw from location of mouse event.
     * @param event MouseEvent Document mouse down event.
     * @returns Array<number> [pitch, yaw]
     */
    mouseEventToCoords(event: MouseEvent):[pitch : number, yaw: number]
    /**
     * Change scene being viewed.
     * @param sceneId string Identifier of scene to switch to.
     * @param pitch number? Pitch to use with new scene
     * @param yaw number? Yaw to use with new scene
     * @param hfov number? HFOV to use with new scene
     * @returns Viewer this
     */
    loadScene(sceneId: string, pitch?: number, yaw?: number, hfov?: number): PannellumViewer
    /**
     * Get ID of current scene.
     * @returns string ID of current scene
     */
    getScene(): string
    /**
     * Add a new scene.
     * @param sceneId string The ID of the new scene
     * @param config string The configuration of the new scene
     * @returns Viewer this
     */
    addScene(sceneId: string, config: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig): PannellumViewer
    /**
     * Remove a scene.
     * @param sceneId string The ID of the scene
     * @returns Returns boolean False if the scene is the current scene or if the scene doesn’t exists, else true
     */
    removeScene(sceneId: string): boolean
    /**
     * Toggle fullscreen.
     * @returns Viewer this
     */
    toggleFullscreen(): PannellumViewer
    /**
     * Get configuration of current scene.
     * @returns Object Configuration of current scene
     */
    getConfig():  PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig | PannellumTour
    /**
     * Get viewer’s container element.
     * @returns HTMLElement Container div element
     */
    getContainer(): HTMLElement
    /**
     * Add a new hot spot.
     * @param hs Object The configuration for the hot spot
     * @param sceneId
     * @returns Viewer this
     */
    addHotSpot(hs: PannellumHotSpot, sceneId?: string): PannellumViewer
    /**
     * Remove a hot spot.
     * @param hotSpotId string The ID of the hot spot
     * @param sceneId string? Removes hot spot from specified scene if provided, else from current scene
     * @returns boolean True if deletion is successful, else false
     */
    removeHotSpot(hotSpotId: string, sceneId?: string): boolean
    /**
     * This method should be called if the viewer’s container is resized.
     */
    resize(): void
    /**
     * Check if device orientation control is supported.
     * @returns boolean True if supported, else false
     */
    isOrientationSupported(): boolean
    /**
     * Stop using device orientation.
     */
    stopOrientation(): void
    /**
     * Start using device orientation (does nothing if not supported).
     */
    startOrientation(): void
    /**
     * Check if device orientation control is currently activated.
     * @returns boolean True if active, else false
     */
    isOrientationActive(): boolean
    /**
     * Subscribe listener to specified event.
     * @param type string Type of event to subscribe to.
     * @param callback Function Listener function to subscribe to event.
     * @returns Viewer this
     */
    on(type: PannellumEventType, callback: ((event: Event)=>void)): PannellumRender
    /**
     * Subscribe listener to specified event.
     * @param type string Type of event to subscribe to.
     * @param callback Function Listener function to subscribe to event.
     * @returns Viewer this
     */
    off(type?: PannellumEventType, callback?: ((event: Event)=>void)): PannellumViewer
    /** destroys object for clean up */
    destroy(): void
  }

  /**
   * Extended global with extended window
   */
  declare global {
    /**
     * Extended window with pannellum access added via interface
     */
    interface Window {
      /**
       * Pannellum accessor interface extention from window as a defined PannellumFactories interface
       */
      pannellum: PannellumFactories
    }
  }

  /**
    * Export of Pannellum accessor interface extention from window as a defined PannellumFactories interface
    */
  export interface Window {
    pannellum: PannellumFactories
  }

  /**
   * A interface to access the Pennellum factory functions
   */
  export interface PannellumFactories {
    /**
     * Creates a new panorama viewer.
     * @param container (HTMLElement | string) The container (div) element for the viewer, or its ID.
     * @param config Object Inital configuration for viewer. See PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig | PannellumTour for more
     * @returns new viewer instance accessable via the PannellumViewer interface
     */
    viewer(container: string | HTMLElement, config: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig | PannellumTour): PannellumViewer;
    /**
     * Creates a new panorama renderer.
     * @param container HTMLElement The container element for the renderer.
     * @returns new viewer instance accessable via the PannellumRender interface
     */
    Renderer(container: HTMLElement): PannellumRender
  }

Add it to the component. Here I'm giving an example of a rough reusable component. It's a rough init of my first component, It simply is for a simple single .jpg equirectangular. Feel free to remix it! Maybe kill it for a Tour version or Keep it and make another Tour version (idk), but it should be a good start point for the remix!
a. Component:

import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core';
import { PannellumCubeMapConfig, PannellumEquirectangularConfig, PannellumHotSpot, PannellumMultiresConfig, PannellumPanoramaType, PannellumPanoramaTypeEnum, PannellumViewer  } from '../pannellum/pannellum';

@Component({
  selector: 'pannellum-panorama',
  templateUrl: './pannellum-panorama.component.html',
  styleUrls: ['./pannellum-panorama.component.scss']
})
export class PannellumComponent implements AfterViewInit, OnDestroy {
  @Input()
  PanoramaId: string = "panorama"
  @Input()
  PanoramaSrc: string | null = null;
  @Input()
  PanoramaType: PannellumPanoramaType = "equirectangular"
  @Input()
  Options: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig | null = null;
  @Input()
  HotSpots: PannellumHotSpot[] | null = null;

  private pannellumViewer: PannellumViewer | null = null

  private ensureArray(array: any[] | null | undefined): any[]
  {
    return array ?? [];
  }

  private initPanorama(): void {
    //Creating the viewer as per docs. I would recommend a function for this. note the options are set in another component as an input.
    //Note the viewer will not auto update, If you want to up date the viewers settings you would need to call destroy from api and then recall this function from an exposed function or a setter function as input or use provided API. For the purposes here I think that might complicate the how to and this is not a library just a how to, so I will leave more advanced features up to you. For instance you could provide support for PannellumTour types provided in the types above.
    this.pannellumViewer = globalThis.window.pannellum.viewer(this.PanoramaId, {
      ...this.Options,
      type: this.PanoramaType,
      panorama: this.PanoramaSrc,
      //fixes a bug with lib where the array not being set in config breaks api
      hotSpots: [...this.ensureArray(this.Options?.hotSpots), ...this.ensureArray(this.HotSpots)]
    } as PannellumEquirectangularConfig)
  }

  constructor() { }

  //Make sure to wait for component to be initialized. Not sure why the other guy need to destroy, but I'm not having that issue. Just make sure it is after View init. If you may not have the html generated as of yet
  ngAfterViewInit(): void {
    this.initPanorama();
   }

  //Make sure to clean up on component destruction and a good example of the API use after initialized or NgInit's. This is actually important!
  this.initPanorama().
  ngOnDestroy(): void {
    if(this.pannellumViewer != null)
    {
      this.pannellumViewer.destroy();
    }
  }
}

b. scss (simply to get you started) you can remix this too (or you could just inline style it.)!:
.panorama-container {
  width: 1000px;
  height: 1000px;
}

.panorama-frame {
  border: 2px solid black;
  height: 100%;
}

#panorama {
  height: 100%;
}

c. HTML Template:
 <div class="panorama-container">
    <div class="panorama-frame">
      <div id="{{PanoramaId}}"></div>
    </div>
</div>

REUSE REUSE! Component usage in other Template HTML on other components
Component:

@Component({
  selector: 'app-root',
  standalone: false,
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'MountainTracker';

//you should get intellisense help  since you defined the types when working in an appropriate IDE! YAY!
  public tempate: PannellumSharedConfig = {
    compass: true,
    type: 'equirectangular',
    autoRotate: true
  }
}

HTML template one line add:
<!--options can be set as per the docs in the .components.ts and you can change the source to locally hosted files etc-->
<pannellum-panorama [PanoramaSrc]="'https://pannellum.org/images/alma.jpg'" [Options]="Options"></pannellum-panorama>

After that I'm sure you have everything you need to get started with the docs and refine what I have here.


dns/ddclient updates nsupdate.info provider despite cache and cmd confirming no update needed

Important notices
Before you add a new report, we ask you kindly to acknowledge the following:

[x] I have read the contributing guide lines at https://github.com/opnsense/plugins/blob/master/CONTRIBUTING.md
[x] I have searched the existing issues, open and closed, and I'm convinced that mine is new.
[x] The title contains the plugin to which this issue belongs

Describe the bug
On newest OPNsense 23.7.6 os-ddclient 1.16 and ddclient-devel 3.10.0_7 seem to trigger a dyndns2 address update against ipv4.nsupdate.info every update interval even if its own cache is confirming that the address last transmitted is unchanged from the address just checked. This results in ddclient triggering nochg ("no change") reports from the dynamic DNS service and - depending on its abuse policy - potentially blocking itself from sending future updates.
I recently upgraded OPNsense from 21.1 to 23.7.6, I do not know anymore which versions of os-ddclient and ddclient-devel I was using on that version. They did not exhibit this current behavior but I can't comment on when exactly this was introduced.
This issue template suggest to try opnsense-revert, for both opnsense-revert -r 22.1 os-ddclient and opnsense-revert -r 22.1 ddclient-devel I received [...] *.sig: Not Found failed.
To Reproduce
This config (screenshots from Edit account menu and General settings menu) generates a /usr/local/etc/ddclient.conf file like so:
syslog=yes                  # log update msgs to syslog
pid=/var/run/ddclient.pid   # record PID in file.
ssl=yes

use=cmd, cmd="/usr/local/opnsense/scripts/ddclient/checkip -t 1 -s nsupdate.info-ipv4 --timeout 10", \
protocol=dyndns2, \
server=ipv4.nsupdate.info, \
login=fully.qualified.domain.name, \
password=12P4aSw0rD \
fully.qualified.domain.name

Where password= is a rather simple 10-character string with only characters [a-zA-Z0-9] generated by nsupdate.info themselves, so no fancy password characters. Manually executing cmd= returns the same IP address that's already set and known at nsupdate.info.
Per OPNsense forum topic 35897 by a helpful poster from September (where OP's issue turned out to be a password with special characters that prevented ddclient from ever seeing the last line in its config file) I've gone ahead and followed their steps for debugging:

Stop service at "Services: Dynamic DNS: Settings"
Confirm that /var/run/ddclient.pid doesn't exist anymore
Remove cache file /var/tmp/ddclient.cache
Run ddclient -daemon=0 -debug -verbose -noquiet

This forces an update attempt since ddclient detects no cache file, see full output at pastebin.com/raw/bJ66Yy8e. It receives a nochg reply and creates a cache file /var/tmp/ddclient.cache like so:
## ddclient-3.10.0
## last updated at Fri Oct 20 00:05:28 2023<PHONE_NUMBER>)
atime=1697753128,backupmx=0,custom=0,host=fully.qualified.domain.name,ipv4=<IP_ADDRESS>,mtime=1697753128,mx=,script=/nic/update,static=0,status=good,status-ipv4=good,status-ipv6=noconnect,warned-min-error-interval=0,warned-min-interval=0,wildcard=0,wtime=0 fully.qualified.domain.name

What seems a bit odd is that in OPNsense web GUI I'm never seeing any content in Current IP nor Updated columns; I'm moderately sure that these fields were always populated with correct info prior to me recently upgrading from 21.1 to 23.7.6:

On consecutive attempts ddclient sees and uses the cache file as seen by the fact that verbose debug output contains this additional section:
=== cache ====
cache{fully.qualified.domain.name}{atime}      :<PHONE_NUMBER>
cache{fully.qualified.domain.name}{backupmx}   : 0
cache{fully.qualified.domain.name}{custom}     : 0
cache{fully.qualified.domain.name}{host}       : fully.qualified.domain.name
cache{fully.qualified.domain.name}{ipv4}       : <IP_ADDRESS>
cache{fully.qualified.domain.name}{mtime}      :<PHONE_NUMBER>
cache{fully.qualified.domain.name}{mx}         :
cache{fully.qualified.domain.name}{script}     : /nic/update
cache{fully.qualified.domain.name}{static}     : 0
cache{fully.qualified.domain.name}{status}     : good
cache{fully.qualified.domain.name}{status-ipv4} : good
cache{fully.qualified.domain.name}{status-ipv6} : noconnect
cache{fully.qualified.domain.name}{warned-min-error-interval} : 0
cache{fully.qualified.domain.name}{warned-min-interval} : 0
cache{fully.qualified.domain.name}{wildcard}   : 0
cache{fully.qualified.domain.name}{wtime}      : 30

The rest remains unchanged: ddclient attempts an update despite its cache and its own cmd= confirming that no update is needed, it receives a correct nochg response and goes one step closer to getting itself blocked from nsupdate.info for spamming unnecessary updates.
Expected behavior
A ddclient DynDNS address update only when local cache file content and cmd= execution result differ.
Screenshots

Accounts menu
Edit account menu
General settings menu

Relevant log files

Full ddclient debug output, no cache exists
Full ddclient debug output when a local cache file exists

Additional context
N/a
Environment

OPNsense 23.7.6
os-ddclient 1.16
ddclient-devel 3.10.0_7
AMD GX-412TC 2nd gen G-series system-on-chip [PDF]
Intel I211-AT 1 GbE ethernet controller

Hi,
This being the "ddclient" backend with dyndns2... have you tried the "native" backend if that works as expected? ddclient will have new releases soon but it was already found that some oddities may take a long time to fix or are not fixable at all on their side -- at least that was the view of the former maintainer who briefly caused the project to be end of life.
We've added the native Python backend for this reason and people have contributed a few nice things that ddclient cannot possibly do being perl and a "lightweight" daemon.
I would recommend recreating the account after changing the backend because the settings for both backends might slightly differ causing issues when run with the other backend unmodified.
Cheers,
Franco

@Contik yay :)


please do a release to make packaging simpler

I added a v0.2.0 tag to current master, which is fine for packaging LXD 3.4. I also added a matching v0.2.0 to the CanonicalLtd/dqlite repository, which is fine as well for LXD 3.4.