From 1518ca02a701fbca9352bc22670d90fa8580e139 Mon Sep 17 00:00:00 2001 From: osakila Date: Tue, 14 Mar 2023 16:09:15 +0900 Subject: [PATCH] Initial commit Dev/1.0.0 upload result add wait --- .github/workflows/dummy.yaml | 14 + .github/workflows/publish-maven.yaml | 26 + .github/workflows/test.yaml | 37 + .gitignore | 10 + LICENSE | 21 + README.md | 57 + build.gradle.kts | 16 + demos/demo-android/.gitignore | 19 + demos/demo-android/LICENSE | 21 + demos/demo-android/README.ja.md | 20 + demos/demo-android/README.md | 20 + demos/demo-android/app/.gitignore | 1 + demos/demo-android/app/build.gradle | 85 + demos/demo-android/app/proguard-rules.pro | 94 + .../ExampleInstrumentedTest.kt | 24 + .../app/src/main/AndroidManifest.xml | 31 + .../app/src/main/assets/bundle.js | 30778 ++++++++++++++++ .../app/src/main/assets/index.html | 36 + .../demo-android/app/src/main/assets/index.js | 75 + .../app/src/main/assets/rxjs.umd.js | 9007 +++++ .../CameraControlCommandV2Screen.kt | 67 + .../thetaBleClientDemo/CameraStatusScreen.kt | 136 + .../thetaBleClientDemo/MainActivity.kt | 106 + .../thetaBleClientDemo/MainScreen.kt | 94 + .../thetaBleClientDemo/ThetaSdkSampleApp.kt | 13 + .../thetaBleClientDemo/ThetaViewModel.kt | 657 + .../thetaBleClientDemo/ui/theme/Color.kt | 8 + .../thetaBleClientDemo/ui/theme/Shape.kt | 11 + .../thetaBleClientDemo/ui/theme/Theme.kt | 47 + .../thetaBleClientDemo/ui/theme/Type.kt | 28 + .../res/drawable/ic_launcher_background.xml | 170 + .../res/drawable/ic_launcher_foreground.xml | 30 + .../main/res/mipmap-anydpi/ic_launcher.xml | 5 + .../res/mipmap-anydpi/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../app/src/main/res/values/colors.xml | 10 + .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/themes.xml | 7 + .../app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + demos/demo-android/build.gradle | 22 + demos/demo-android/gradle.properties | 23 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + demos/demo-android/gradlew | 185 + demos/demo-android/gradlew.bat | 89 + demos/demo-android/lint.xml | 5 + demos/demo-android/settings.gradle | 16 + demos/demo-ios/.gitignore | 13 + demos/demo-ios/Podfile | 12 + demos/demo-ios/README.ja.md | 33 + demos/demo-ios/README.md | 33 + .../demo-ios.xcodeproj/project.pbxproj | 434 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../demo-ios/Assets.xcassets/Contents.json | 6 + .../demo-ios/CameraControlCommandV2View.swift | 73 + .../demo-ios/demo-ios/CameraStatusView.swift | 114 + demos/demo-ios/demo-ios/ContentView.swift | 134 + .../Preview Assets.xcassets/Contents.json | 6 + demos/demo-ios/demo-ios/ThetaBleApi.swift | 576 + demos/demo-ios/demo-ios/demo_iosApp.swift | 25 + demos/demo-react-native/.bundle/config | 2 + demos/demo-react-native/.eslintrc.js | 16 + demos/demo-react-native/.gitignore | 63 + demos/demo-react-native/.node-version | 1 + demos/demo-react-native/.prettierrc.js | 7 + demos/demo-react-native/.ruby-version | 1 + demos/demo-react-native/.watchmanconfig | 1 + demos/demo-react-native/Gemfile | 6 + demos/demo-react-native/README.md | 34 + .../demo-react-native/__tests__/App-test.tsx | 14 + .../android/app/build.gradle | 170 + .../android/app/debug.keystore | Bin 0 -> 2257 bytes .../android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 13 + .../demoreactnative/ReactNativeFlipper.java | 75 + .../android/app/src/main/AndroidManifest.xml | 24 + .../com/demoreactnative/MainActivity.java | 42 + .../com/demoreactnative/MainApplication.java | 62 + .../res/drawable/rn_edit_text_material.xml | 36 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + .../demoreactnative/ReactNativeFlipper.java | 20 + demos/demo-react-native/android/build.gradle | 23 + .../android/gradle.properties | 44 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + demos/demo-react-native/android/gradlew | 234 + demos/demo-react-native/android/gradlew.bat | 89 + .../demo-react-native/android/settings.gradle | 4 + demos/demo-react-native/app.json | 4 + demos/demo-react-native/babel.config.js | 3 + demos/demo-react-native/index.js | 9 + demos/demo-react-native/ios/.xcode.env | 11 + .../DemoReactNative.xcodeproj/project.pbxproj | 710 + .../xcschemes/DemoReactNative.xcscheme | 88 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../ios/DemoReactNative/AppDelegate.h | 6 + .../ios/DemoReactNative/AppDelegate.mm | 36 + .../AppIcon.appiconset/Contents.json | 53 + .../Images.xcassets/Contents.json | 6 + .../ios/DemoReactNative/Info.plist | 57 + .../DemoReactNative/LaunchScreen.storyboard | 47 + .../ios/DemoReactNative/main.m | 10 + .../DemoReactNativeTests.m | 66 + .../ios/DemoReactNativeTests/Info.plist | 24 + demos/demo-react-native/ios/Podfile | 60 + demos/demo-react-native/ios/Podfile.lock | 648 + demos/demo-react-native/metro.config.js | 17 + demos/demo-react-native/package.json | 45 + demos/demo-react-native/src/App.tsx | 51 + .../src/components/ui/button/button.tsx | 39 + .../src/components/ui/button/index.ts | 1 + .../src/components/ui/button/styles.tsx | 24 + .../src/components/ui/input-number/index.ts | 1 + .../ui/input-number/input-number.tsx | 73 + .../src/components/ui/input-number/styles.tsx | 32 + .../src/components/ui/input-string/index.ts | 1 + .../ui/input-string/input-string.tsx | 64 + .../src/components/ui/input-string/styles.tsx | 31 + .../src/components/ui/item-list/index.ts | 7 + .../item-list/item-list-popup-view/index.ts | 1 + .../item-list-popup-view.tsx | 43 + .../item-list/item-list-popup-view/styles.tsx | 34 + .../ui/item-list/item-list-view/index.ts | 1 + .../item-list-view/item-list-view.tsx | 52 + .../ui/item-list/item-list-view/styles.tsx | 25 + .../ui/item-list/item-selector-view/index.ts | 1 + .../item-selector-view/item-selector-view.tsx | 67 + .../item-list/item-selector-view/styles.tsx | 31 + .../src/components/ui/titled-switch/index.ts | 1 + .../components/ui/titled-switch/styles.tsx | 25 + .../ui/titled-switch/titled-switch.tsx | 54 + .../demo-react-native/src/device-context.tsx | 29 + .../camera-control-command-v2-screen.tsx | 198 + .../screen/camera-control-command-v2/index.ts | 1 + .../camera-control-command-v2/styles.tsx | 42 + .../camera-status-screen.tsx | 305 + .../src/screen/camera-status-screen/index.ts | 1 + .../screen/camera-status-screen/styles.tsx | 18 + .../src/screen/menu-screen/index.ts | 1 + .../src/screen/menu-screen/menu-screen.tsx | 315 + .../src/screen/menu-screen/styles.tsx | 18 + .../src/theta-webapi/get-theta-info-webapi.ts | 29 + .../src/theta-webapi/set-ble-on-webapi.ts | 30 + .../src/theta-webapi/set-ble-uuid-webapi.ts | 33 + demos/demo-react-native/tsconfig.json | 3 + demos/demo-react-native/yarn.lock | 6899 ++++ docs/tutorial-android.ja.md | 232 + docs/tutorial-android.md | 231 + docs/tutorial-ios.ja.md | 231 + docs/tutorial-ios.md | 232 + docs/tutorial-react-native.ja.md | 285 + docs/tutorial-react-native.md | 286 + gradle.properties | 15 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 + gradlew.bat | 89 + kotlin-multiplatform/THETABleClient.podspec | 39 + kotlin-multiplatform/build.gradle.kts | 222 + .../src/androidMain/AndroidManifest.xml | 4 + .../com/ricoh360/thetableclient/Platform.kt | 7 + .../com/ricoh360/thetableclient/Utility.kt | 13 + .../ricoh360/thetableclient/AndroidTest.kt | 12 + .../thetableclient/NativeTestUtility.kt | 3 + .../thetableclient/BleCharacteristic.kt | 154 + .../thetableclient/BleObserveManager.kt | 53 + .../com/ricoh360/thetableclient/BleService.kt | 52 + .../ricoh360/thetableclient/ConvertValue.kt | 61 + .../com/ricoh360/thetableclient/Greeting.kt | 9 + .../com/ricoh360/thetableclient/Platform.kt | 7 + .../com/ricoh360/thetableclient/ThetaBle.kt | 449 + .../com/ricoh360/thetableclient/Utility.kt | 5 + .../thetableclient/ble/BleAdvertisement.kt | 24 + .../thetableclient/ble/BlePeripheral.kt | 82 + .../ricoh360/thetableclient/ble/BleScanner.kt | 77 + .../service/CameraControlCommandV2.kt | 168 + .../service/CameraControlCommands.kt | 104 + .../service/CameraInformation.kt | 195 + .../service/CameraStatusCommand.kt | 386 + .../service/ShootingControlCommand.kt | 129 + .../thetableclient/service/ThetaService.kt | 9 + .../thetableclient/service/data/GpsInfo.kt | 50 + .../thetableclient/service/data/Serializer.kt | 97 + .../service/data/StateGpsInfo.kt | 17 + .../thetableclient/service/data/ThetaInfo.kt | 54 + .../thetableclient/service/data/ThetaState.kt | 110 + .../service/data/ThetaState2.kt | 23 + .../service/data/ble/PluginControl.kt | 59 + .../service/data/ble/PluginList.kt | 39 + .../service/data/ble/PluginOrders.kt | 57 + .../service/data/values/CameraError.kt | 138 + .../service/data/values/CameraPower.kt | 37 + .../service/data/values/CaptureMode.kt | 37 + .../service/data/values/CaptureStatus.kt | 77 + .../service/data/values/ChargingState.kt | 52 + .../data/values/CommandErrorDescription.kt | 69 + .../service/data/values/PluginPowerStatus.kt | 34 + .../service/data/values/SerialNameEnum.kt | 16 + .../service/data/values/ShootingFunction.kt | 44 + .../service/data/values/ThetaModel.kt | 78 + .../transferred/CameraGpsInfo.kt | 20 + .../thetableclient/transferred/CameraInfo.kt | 28 + .../thetableclient/transferred/CameraState.kt | 59 + .../transferred/CameraState2.kt | 22 + .../transferred/CameraStateGpsInfo.kt | 8 + .../com/ricoh360/thetableclient/CommonTest.kt | 12 + .../thetableclient/NativeTestUtility.kt | 3 + .../ricoh360/thetableclient/TestUtility.kt | 24 + .../ricoh360/thetableclient/ThetaBleTest.kt | 242 + .../thetableclient/ThetaDeviceConnectTest.kt | 182 + .../ThetaDeviceDisconnectTest.kt | 120 + .../thetableclient/ThetaDeviceServiceTest.kt | 248 + .../thetableclient/ble/BleAdvertisement.kt | 22 + .../thetableclient/ble/BlePeripheral.kt | 55 + .../ricoh360/thetableclient/ble/BleScanner.kt | 32 + .../cameracontrol/GetPluginListTest.kt | 136 + .../cameracontrol/GetPluginOrdersTest.kt | 134 + .../cameracontrol/SetPluginOrdersTest.kt | 112 + .../cameracontrolv2/GetInfoTest.kt | 189 + .../cameracontrolv2/GetState2Test.kt | 166 + .../cameracontrolv2/GetStateTest.kt | 169 + .../cameracontrolv2/SetStateNotifyTest.kt | 247 + .../camerainfo/GetBluetoothMacAddressTest.kt | 108 + .../camerainfo/GetFirmwareRevisionTest.kt | 108 + .../camerainfo/GetManufacturerNameTest.kt | 108 + .../camerainfo/GetModelNumberTest.kt | 108 + .../camerainfo/GetSerialNumberTest.kt | 108 + .../camerainfo/GetWlanMacAddressTest.kt | 108 + .../camerastatus/GetBatteryLevelTest.kt | 109 + .../camerastatus/GetBatteryStatusTest.kt | 134 + .../camerastatus/GetCameraPowerTest.kt | 133 + .../camerastatus/GetPluginControlTest.kt | 134 + .../camerastatus/SetBatteryLevelNotifyTest.kt | 187 + .../SetBatteryStatusNotifyTest.kt | 220 + .../camerastatus/SetCameraPowerNotifyTest.kt | 221 + .../camerastatus/SetCameraPowerTest.kt | 109 + .../SetCommandErrorDescriptionNotifyTest.kt | 219 + .../SetPluginControlNotifyTest.kt | 222 + .../camerastatus/SetPluginControlTest.kt | 110 + .../thetableclient/camerastatus/ValuesTest.kt | 97 + .../shootingcontrol/GetCaptureModeTest.kt | 147 + .../shootingcontrol/SetCaptureModeTest.kt | 110 + .../shootingcontrol/TakePictureTest.kt | 185 + .../shootingcontrol/ValuesTest.kt | 37 + .../thetableclient/values/CameraErrorTest.kt | 127 + .../values/CaptureStatusTest.kt | 55 + .../values/ChargingStateTest.kt | 38 + .../values/ShootingFunctionTest.kt | 38 + .../thetableclient/values/ThetaModelTest.kt | 41 + .../cameracontrolv2/getInfo/info_unknown.json | 7 + .../cameracontrolv2/getInfo/info_x.json | 9 + .../cameracontrolv2/getState/state.json | 17 + .../cameracontrolv2/getState2/state2.json | 20 + .../src/commonTest/resources/err_test.txt | 1 + .../com/ricoh360/thetableclient/Platform.kt | 9 + .../com/ricoh360/thetableclient/Utility.kt | 5 + .../com/ricoh360/thetableclient/IosTest.kt | 12 + .../thetableclient/NativeTestUtility.kt | 5 + react-native/.editorconfig | 15 + react-native/.eslintrc.json | 31 + react-native/.gitattributes | 3 + react-native/.gitignore | 75 + react-native/.watchmanconfig | 1 + react-native/.yarnrc | 3 + react-native/LICENSE | 20 + react-native/README.md | 52 + react-native/android/build.gradle | 86 + react-native/android/gradle.properties | 5 + .../android/src/main/AndroidManifest.xml | 4 + .../CameraControlCommandV2Service.kt | 196 + .../CameraControlCommandsService.kt | 63 + .../CameraInformationService.kt | 119 + .../CameraStatusCommandService.kt | 319 + .../thetableclientreactnative/Converter.kt | 201 + .../ShootingControlCommandService.kt | 75 + .../ThetaBleClientReactNativeModule.kt | 355 + .../ThetaBleClientReactNativePackage.kt | 16 + react-native/babel.config.js | 3 + react-native/example/.bundle/config | 2 + react-native/example/.node-version | 1 + react-native/example/.ruby-version | 1 + react-native/example/.watchmanconfig | 1 + react-native/example/Gemfile | 6 + react-native/example/android/app/build.gradle | 170 + .../example/android/app/debug.keystore | Bin 0 -> 2257 bytes .../example/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 13 + .../ReactNativeFlipper.java | 75 + .../android/app/src/main/AndroidManifest.xml | 24 + .../MainActivity.java | 41 + .../MainApplication.java | 63 + .../res/drawable/rn_edit_text_material.xml | 36 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + .../ReactNativeFlipper.java | 20 + react-native/example/android/build.gradle | 23 + .../example/android/gradle.properties | 44 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + react-native/example/android/gradlew | 234 + react-native/example/android/gradlew.bat | 89 + react-native/example/android/settings.gradle | 4 + react-native/example/app.json | 4 + react-native/example/babel.config.js | 17 + react-native/example/index.js | 5 + react-native/example/ios/.xcode.env | 11 + react-native/example/ios/File.swift | 6 + react-native/example/ios/Podfile | 60 + react-native/example/ios/Podfile.lock | 652 + ...ClientReactNativeExample-Bridging-Header.h | 3 + .../project.pbxproj | 706 + .../ThetaBleClientReactNativeExample.xcscheme | 88 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AppDelegate.h | 6 + .../AppDelegate.mm | 36 + .../AppIcon.appiconset/Contents.json | 53 + .../Images.xcassets/Contents.json | 6 + .../Info.plist | 57 + .../LaunchScreen.storyboard | 47 + .../ThetaBleClientReactNativeExample/main.m | 10 + .../Info.plist | 24 + .../ThetaClientBleReactNativeExampleTests.m | 66 + react-native/example/metro.config.js | 40 + react-native/example/package.json | 29 + react-native/example/react-native.config.js | 10 + react-native/example/src/App.tsx | 51 + .../src/components/ui/button/button.tsx | 40 + .../example/src/components/ui/button/index.ts | 1 + .../src/components/ui/button/styles.tsx | 24 + .../src/components/ui/input-number/index.ts | 1 + .../ui/input-number/input-number.tsx | 73 + .../src/components/ui/input-number/styles.tsx | 32 + .../src/components/ui/input-string/index.ts | 1 + .../ui/input-string/input-string.tsx | 64 + .../src/components/ui/input-string/styles.tsx | 31 + .../src/components/ui/item-list/index.ts | 7 + .../item-list/item-list-popup-view/index.ts | 1 + .../item-list-popup-view.tsx | 43 + .../item-list/item-list-popup-view/styles.tsx | 34 + .../ui/item-list/item-list-view/index.ts | 1 + .../item-list-view/item-list-view.tsx | 53 + .../ui/item-list/item-list-view/styles.tsx | 25 + .../ui/item-list/item-selector-view/index.ts | 1 + .../item-selector-view/item-selector-view.tsx | 68 + .../item-list/item-selector-view/styles.tsx | 31 + .../src/components/ui/titled-switch/index.ts | 1 + .../components/ui/titled-switch/styles.tsx | 25 + .../ui/titled-switch/titled-switch.tsx | 54 + react-native/example/src/device-context.tsx | 29 + .../camera-control-command-v2-screen.tsx | 196 + .../screen/camera-control-command-v2/index.ts | 1 + .../camera-control-command-v2/styles.tsx | 42 + .../camera-status-screen.tsx | 302 + .../src/screen/camera-status-screen/index.ts | 1 + .../screen/camera-status-screen/styles.tsx | 18 + .../example/src/screen/menu-screen/index.ts | 1 + .../src/screen/menu-screen/menu-screen.tsx | 316 + .../example/src/screen/menu-screen/styles.tsx | 18 + .../src/theta-webapi/get-theta-info-webapi.ts | 29 + .../src/theta-webapi/set-ble-on-webapi.ts | 30 + .../src/theta-webapi/set-ble-uuid-webapi.ts | 31 + react-native/example/yarn.lock | 4376 +++ .../ios/CameraControlCommandV2Service.swift | 196 + .../ios/CameraControlCommandsService.swift | 87 + .../ios/CameraInformationService.swift | 148 + .../ios/CameraStatusCommandService.swift | 336 + .../ios/ShootingControlCommandService.swift | 105 + .../ios/ThetaBleClientConvertEnum.swift | 19 + .../ios/ThetaBleClientConvertObject.swift | 260 + ...hetaBleClientReactNative-Bridging-Header.h | 3 + react-native/ios/ThetaBleClientReactNative.m | 150 + .../ios/ThetaBleClientReactNative.swift | 491 + .../project.pbxproj | 309 + react-native/mkpackage.sh | 23 + react-native/package.json | 164 + react-native/scripts/bootstrap.js | 29 + react-native/src/__mocks__/react-native.ts | 52 + .../camera-control-v2/get-info.test.ts | 74 + .../camera-control-v2/get-state.test.ts | 93 + .../camera-control-v2/get-state2.test.ts | 97 + .../camera-control-v2/state-notify.test.ts | 200 + .../camera-control/plugin-list.test.ts | 55 + .../camera-control/plugin-orders.test.ts | 102 + .../src/__tests__/camera-info.test.tsx | 227 + .../battery-level-notify.test.ts | 192 + .../cameta-status/battery-level.test.ts | 49 + .../battery-status-notify.test.ts | 192 + .../cameta-status/battery-status.test.ts | 50 + .../cameta-status/camera-power-notify.test.ts | 192 + .../cameta-status/camera-power.test.ts | 92 + .../command-error-description-notify.test.ts | 192 + .../plugin-control-notify.test.ts | 195 + .../cameta-status/plugin-control.test.ts | 102 + react-native/src/__tests__/scan.test.tsx | 117 + .../shooting-control/capture-mode.test.tsx | 107 + .../shooting-control/take-picture.test.tsx | 70 + .../__tests__/theta-device-service.test.tsx | 63 + .../src/__tests__/theta-device.test.tsx | 175 + .../__tests__/values/camera-error.test.tsx | 39 + .../__tests__/values/capture-status.test.tsx | 25 + .../__tests__/values/charging-status.test.tsx | 20 + .../values/shooting-function.test.tsx | 20 + react-native/src/index.tsx | 28 + react-native/src/native/index.ts | 1 + react-native/src/native/native-functions.ts | 156 + react-native/src/service/ble/index.ts | 3 + .../src/service/ble/plugin-control.ts | 19 + react-native/src/service/ble/plugin-list.ts | 9 + react-native/src/service/ble/plugin-order.ts | 24 + .../src/service/camera-control-command-v2.ts | 86 + .../src/service/camera-control-commands.ts | 83 + .../src/service/camera-information.ts | 124 + .../src/service/camera-status-command.ts | 238 + react-native/src/service/data/gps-info.ts | 15 + react-native/src/service/data/index.ts | 4 + react-native/src/service/data/theta-info.ts | 21 + react-native/src/service/data/theta-state.ts | 74 + react-native/src/service/data/theta-state2.ts | 20 + react-native/src/service/index.ts | 9 + .../src/service/shooting-control-command.ts | 78 + react-native/src/service/theta-service.ts | 7 + .../src/service/values/ble-service.ts | 34 + .../src/service/values/camera-error.ts | 58 + .../src/service/values/camera-power.ts | 23 + .../src/service/values/capture-mode.ts | 23 + .../src/service/values/capture-status.ts | 27 + .../src/service/values/charging-state.ts | 28 + .../values/command-error-description.ts | 55 + react-native/src/service/values/index.ts | 10 + .../src/service/values/plugin-power-status.ts | 19 + .../src/service/values/shooting-function.ts | 19 + .../src/service/values/theta-model.ts | 26 + react-native/src/theta-ble/index.ts | 1 + react-native/src/theta-ble/theta-ble.ts | 65 + react-native/src/theta-device/index.ts | 2 + react-native/src/theta-device/notify.ts | 51 + react-native/src/theta-device/theta-device.ts | 137 + react-native/src/values/index.ts | 1 + react-native/src/values/timeout.ts | 61 + .../theta-ble-client-react-native.podspec | 37 + react-native/tsconfig.build.json | 5 + react-native/tsconfig.json | 28 + react-native/yarn.lock | 9751 +++++ settings.gradle.kts | 17 + 480 files changed, 93066 insertions(+) create mode 100644 .github/workflows/dummy.yaml create mode 100644 .github/workflows/publish-maven.yaml create mode 100644 .github/workflows/test.yaml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.gradle.kts create mode 100755 demos/demo-android/.gitignore create mode 100644 demos/demo-android/LICENSE create mode 100755 demos/demo-android/README.ja.md create mode 100755 demos/demo-android/README.md create mode 100755 demos/demo-android/app/.gitignore create mode 100755 demos/demo-android/app/build.gradle create mode 100755 demos/demo-android/app/proguard-rules.pro create mode 100755 demos/demo-android/app/src/androidTest/java/com/ricoh360/thetableclient/thetaBleClientDemo/ExampleInstrumentedTest.kt create mode 100755 demos/demo-android/app/src/main/AndroidManifest.xml create mode 100755 demos/demo-android/app/src/main/assets/bundle.js create mode 100755 demos/demo-android/app/src/main/assets/index.html create mode 100755 demos/demo-android/app/src/main/assets/index.js create mode 100755 demos/demo-android/app/src/main/assets/rxjs.umd.js create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraControlCommandV2Screen.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraStatusScreen.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainActivity.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainScreen.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaSdkSampleApp.kt create mode 100644 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaViewModel.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Color.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Shape.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Theme.kt create mode 100755 demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Type.kt create mode 100755 demos/demo-android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100755 demos/demo-android/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100755 demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher.xml create mode 100755 demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml create mode 100755 demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100755 demos/demo-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100755 demos/demo-android/app/src/main/res/values/colors.xml create mode 100755 demos/demo-android/app/src/main/res/values/strings.xml create mode 100755 demos/demo-android/app/src/main/res/values/themes.xml create mode 100755 demos/demo-android/app/src/main/res/xml/backup_rules.xml create mode 100755 demos/demo-android/app/src/main/res/xml/data_extraction_rules.xml create mode 100755 demos/demo-android/build.gradle create mode 100755 demos/demo-android/gradle.properties create mode 100755 demos/demo-android/gradle/wrapper/gradle-wrapper.jar create mode 100755 demos/demo-android/gradle/wrapper/gradle-wrapper.properties create mode 100755 demos/demo-android/gradlew create mode 100755 demos/demo-android/gradlew.bat create mode 100755 demos/demo-android/lint.xml create mode 100755 demos/demo-android/settings.gradle create mode 100644 demos/demo-ios/.gitignore create mode 100644 demos/demo-ios/Podfile create mode 100644 demos/demo-ios/README.ja.md create mode 100644 demos/demo-ios/README.md create mode 100644 demos/demo-ios/demo-ios.xcodeproj/project.pbxproj create mode 100644 demos/demo-ios/demo-ios.xcworkspace/contents.xcworkspacedata create mode 100644 demos/demo-ios/demo-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/demo-ios/demo-ios/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 demos/demo-ios/demo-ios/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 demos/demo-ios/demo-ios/Assets.xcassets/Contents.json create mode 100644 demos/demo-ios/demo-ios/CameraControlCommandV2View.swift create mode 100644 demos/demo-ios/demo-ios/CameraStatusView.swift create mode 100644 demos/demo-ios/demo-ios/ContentView.swift create mode 100644 demos/demo-ios/demo-ios/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 demos/demo-ios/demo-ios/ThetaBleApi.swift create mode 100644 demos/demo-ios/demo-ios/demo_iosApp.swift create mode 100644 demos/demo-react-native/.bundle/config create mode 100644 demos/demo-react-native/.eslintrc.js create mode 100644 demos/demo-react-native/.gitignore create mode 100644 demos/demo-react-native/.node-version create mode 100644 demos/demo-react-native/.prettierrc.js create mode 100644 demos/demo-react-native/.ruby-version create mode 100644 demos/demo-react-native/.watchmanconfig create mode 100644 demos/demo-react-native/Gemfile create mode 100644 demos/demo-react-native/README.md create mode 100644 demos/demo-react-native/__tests__/App-test.tsx create mode 100644 demos/demo-react-native/android/app/build.gradle create mode 100644 demos/demo-react-native/android/app/debug.keystore create mode 100644 demos/demo-react-native/android/app/proguard-rules.pro create mode 100644 demos/demo-react-native/android/app/src/debug/AndroidManifest.xml create mode 100644 demos/demo-react-native/android/app/src/debug/java/com/demoreactnative/ReactNativeFlipper.java create mode 100644 demos/demo-react-native/android/app/src/main/AndroidManifest.xml create mode 100644 demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainActivity.java create mode 100644 demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainApplication.java create mode 100644 demos/demo-react-native/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 demos/demo-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 demos/demo-react-native/android/app/src/main/res/values/strings.xml create mode 100644 demos/demo-react-native/android/app/src/main/res/values/styles.xml create mode 100644 demos/demo-react-native/android/app/src/release/java/com/demoreactnative/ReactNativeFlipper.java create mode 100644 demos/demo-react-native/android/build.gradle create mode 100644 demos/demo-react-native/android/gradle.properties create mode 100644 demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 demos/demo-react-native/android/gradlew create mode 100644 demos/demo-react-native/android/gradlew.bat create mode 100644 demos/demo-react-native/android/settings.gradle create mode 100644 demos/demo-react-native/app.json create mode 100644 demos/demo-react-native/babel.config.js create mode 100644 demos/demo-react-native/index.js create mode 100644 demos/demo-react-native/ios/.xcode.env create mode 100644 demos/demo-react-native/ios/DemoReactNative.xcodeproj/project.pbxproj create mode 100644 demos/demo-react-native/ios/DemoReactNative.xcodeproj/xcshareddata/xcschemes/DemoReactNative.xcscheme create mode 100644 demos/demo-react-native/ios/DemoReactNative.xcworkspace/contents.xcworkspacedata create mode 100644 demos/demo-react-native/ios/DemoReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/demo-react-native/ios/DemoReactNative/AppDelegate.h create mode 100644 demos/demo-react-native/ios/DemoReactNative/AppDelegate.mm create mode 100644 demos/demo-react-native/ios/DemoReactNative/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 demos/demo-react-native/ios/DemoReactNative/Images.xcassets/Contents.json create mode 100644 demos/demo-react-native/ios/DemoReactNative/Info.plist create mode 100644 demos/demo-react-native/ios/DemoReactNative/LaunchScreen.storyboard create mode 100644 demos/demo-react-native/ios/DemoReactNative/main.m create mode 100644 demos/demo-react-native/ios/DemoReactNativeTests/DemoReactNativeTests.m create mode 100644 demos/demo-react-native/ios/DemoReactNativeTests/Info.plist create mode 100644 demos/demo-react-native/ios/Podfile create mode 100644 demos/demo-react-native/ios/Podfile.lock create mode 100644 demos/demo-react-native/metro.config.js create mode 100644 demos/demo-react-native/package.json create mode 100644 demos/demo-react-native/src/App.tsx create mode 100644 demos/demo-react-native/src/components/ui/button/button.tsx create mode 100644 demos/demo-react-native/src/components/ui/button/index.ts create mode 100644 demos/demo-react-native/src/components/ui/button/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/input-number/index.ts create mode 100644 demos/demo-react-native/src/components/ui/input-number/input-number.tsx create mode 100644 demos/demo-react-native/src/components/ui/input-number/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/input-string/index.ts create mode 100644 demos/demo-react-native/src/components/ui/input-string/input-string.tsx create mode 100644 demos/demo-react-native/src/components/ui/input-string/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/index.ts create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/index.ts create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/item-list-popup-view.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-view/index.ts create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-view/item-list-view.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-list-view/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-selector-view/index.ts create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-selector-view/item-selector-view.tsx create mode 100644 demos/demo-react-native/src/components/ui/item-list/item-selector-view/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/titled-switch/index.ts create mode 100644 demos/demo-react-native/src/components/ui/titled-switch/styles.tsx create mode 100644 demos/demo-react-native/src/components/ui/titled-switch/titled-switch.tsx create mode 100644 demos/demo-react-native/src/device-context.tsx create mode 100644 demos/demo-react-native/src/screen/camera-control-command-v2/camera-control-command-v2-screen.tsx create mode 100644 demos/demo-react-native/src/screen/camera-control-command-v2/index.ts create mode 100644 demos/demo-react-native/src/screen/camera-control-command-v2/styles.tsx create mode 100644 demos/demo-react-native/src/screen/camera-status-screen/camera-status-screen.tsx create mode 100644 demos/demo-react-native/src/screen/camera-status-screen/index.ts create mode 100644 demos/demo-react-native/src/screen/camera-status-screen/styles.tsx create mode 100644 demos/demo-react-native/src/screen/menu-screen/index.ts create mode 100644 demos/demo-react-native/src/screen/menu-screen/menu-screen.tsx create mode 100644 demos/demo-react-native/src/screen/menu-screen/styles.tsx create mode 100644 demos/demo-react-native/src/theta-webapi/get-theta-info-webapi.ts create mode 100644 demos/demo-react-native/src/theta-webapi/set-ble-on-webapi.ts create mode 100644 demos/demo-react-native/src/theta-webapi/set-ble-uuid-webapi.ts create mode 100644 demos/demo-react-native/tsconfig.json create mode 100644 demos/demo-react-native/yarn.lock create mode 100644 docs/tutorial-android.ja.md create mode 100644 docs/tutorial-android.md create mode 100644 docs/tutorial-ios.ja.md create mode 100644 docs/tutorial-ios.md create mode 100644 docs/tutorial-react-native.ja.md create mode 100644 docs/tutorial-react-native.md create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 kotlin-multiplatform/THETABleClient.podspec create mode 100644 kotlin-multiplatform/build.gradle.kts create mode 100644 kotlin-multiplatform/src/androidMain/AndroidManifest.xml create mode 100644 kotlin-multiplatform/src/androidMain/kotlin/com/ricoh360/thetableclient/Platform.kt create mode 100644 kotlin-multiplatform/src/androidMain/kotlin/com/ricoh360/thetableclient/Utility.kt create mode 100644 kotlin-multiplatform/src/androidUnitTest/kotlin/com/ricoh360/thetableclient/AndroidTest.kt create mode 100644 kotlin-multiplatform/src/androidUnitTest/kotlin/com/ricoh360/thetableclient/NativeTestUtility.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/BleCharacteristic.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/BleObserveManager.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/BleService.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/ConvertValue.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/Greeting.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/Platform.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/ThetaBle.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/Utility.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/ble/BleAdvertisement.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/ble/BlePeripheral.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/ble/BleScanner.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/CameraControlCommandV2.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/CameraControlCommands.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/CameraInformation.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/CameraStatusCommand.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/ShootingControlCommand.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/ThetaService.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/GpsInfo.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/Serializer.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/StateGpsInfo.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ThetaInfo.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ThetaState.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ThetaState2.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ble/PluginControl.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ble/PluginList.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/ble/PluginOrders.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/CameraError.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/CameraPower.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/CaptureMode.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/CaptureStatus.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/ChargingState.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/CommandErrorDescription.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/PluginPowerStatus.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/SerialNameEnum.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/ShootingFunction.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/service/data/values/ThetaModel.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/transferred/CameraGpsInfo.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/transferred/CameraInfo.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/transferred/CameraState.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/transferred/CameraState2.kt create mode 100644 kotlin-multiplatform/src/commonMain/kotlin/com/ricoh360/thetableclient/transferred/CameraStateGpsInfo.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/CommonTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/NativeTestUtility.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/TestUtility.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ThetaBleTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ThetaDeviceConnectTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ThetaDeviceDisconnectTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ThetaDeviceServiceTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ble/BleAdvertisement.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ble/BlePeripheral.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/ble/BleScanner.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrol/GetPluginListTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrol/GetPluginOrdersTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrol/SetPluginOrdersTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrolv2/GetInfoTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrolv2/GetState2Test.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrolv2/GetStateTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/cameracontrolv2/SetStateNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetBluetoothMacAddressTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetFirmwareRevisionTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetManufacturerNameTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetModelNumberTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetSerialNumberTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerainfo/GetWlanMacAddressTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/GetBatteryLevelTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/GetBatteryStatusTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/GetCameraPowerTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/GetPluginControlTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetBatteryLevelNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetBatteryStatusNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetCameraPowerNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetCameraPowerTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetCommandErrorDescriptionNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetPluginControlNotifyTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/SetPluginControlTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/camerastatus/ValuesTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/shootingcontrol/GetCaptureModeTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/shootingcontrol/SetCaptureModeTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/shootingcontrol/TakePictureTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/shootingcontrol/ValuesTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/values/CameraErrorTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/values/CaptureStatusTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/values/ChargingStateTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/values/ShootingFunctionTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/kotlin/com/ricoh360/thetableclient/values/ThetaModelTest.kt create mode 100644 kotlin-multiplatform/src/commonTest/resources/cameracontrolv2/getInfo/info_unknown.json create mode 100644 kotlin-multiplatform/src/commonTest/resources/cameracontrolv2/getInfo/info_x.json create mode 100644 kotlin-multiplatform/src/commonTest/resources/cameracontrolv2/getState/state.json create mode 100644 kotlin-multiplatform/src/commonTest/resources/cameracontrolv2/getState2/state2.json create mode 100644 kotlin-multiplatform/src/commonTest/resources/err_test.txt create mode 100644 kotlin-multiplatform/src/iosMain/kotlin/com/ricoh360/thetableclient/Platform.kt create mode 100644 kotlin-multiplatform/src/iosMain/kotlin/com/ricoh360/thetableclient/Utility.kt create mode 100644 kotlin-multiplatform/src/iosTest/kotlin/com/ricoh360/thetableclient/IosTest.kt create mode 100644 kotlin-multiplatform/src/iosTest/kotlin/com/ricoh360/thetableclient/NativeTestUtility.kt create mode 100644 react-native/.editorconfig create mode 100644 react-native/.eslintrc.json create mode 100644 react-native/.gitattributes create mode 100644 react-native/.gitignore create mode 100644 react-native/.watchmanconfig create mode 100644 react-native/.yarnrc create mode 100644 react-native/LICENSE create mode 100644 react-native/README.md create mode 100644 react-native/android/build.gradle create mode 100644 react-native/android/gradle.properties create mode 100644 react-native/android/src/main/AndroidManifest.xml create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/CameraControlCommandV2Service.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/CameraControlCommandsService.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/CameraInformationService.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/CameraStatusCommandService.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/Converter.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/ShootingControlCommandService.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/ThetaBleClientReactNativeModule.kt create mode 100644 react-native/android/src/main/java/com/ricoh360/thetableclientreactnative/ThetaBleClientReactNativePackage.kt create mode 100644 react-native/babel.config.js create mode 100644 react-native/example/.bundle/config create mode 100644 react-native/example/.node-version create mode 100644 react-native/example/.ruby-version create mode 100644 react-native/example/.watchmanconfig create mode 100644 react-native/example/Gemfile create mode 100644 react-native/example/android/app/build.gradle create mode 100644 react-native/example/android/app/debug.keystore create mode 100644 react-native/example/android/app/proguard-rules.pro create mode 100644 react-native/example/android/app/src/debug/AndroidManifest.xml create mode 100644 react-native/example/android/app/src/debug/java/com/ricoh360/thetableclientreactnativeexample/ReactNativeFlipper.java create mode 100644 react-native/example/android/app/src/main/AndroidManifest.xml create mode 100644 react-native/example/android/app/src/main/java/com/ricoh360/thetableclientreactnativeexample/MainActivity.java create mode 100644 react-native/example/android/app/src/main/java/com/ricoh360/thetableclientreactnativeexample/MainApplication.java create mode 100644 react-native/example/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 react-native/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 react-native/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 react-native/example/android/app/src/main/res/values/strings.xml create mode 100644 react-native/example/android/app/src/main/res/values/styles.xml create mode 100644 react-native/example/android/app/src/release/java/com/ricoh360/thetableclientreactnativeexample/ReactNativeFlipper.java create mode 100644 react-native/example/android/build.gradle create mode 100644 react-native/example/android/gradle.properties create mode 100644 react-native/example/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 react-native/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 react-native/example/android/gradlew create mode 100644 react-native/example/android/gradlew.bat create mode 100644 react-native/example/android/settings.gradle create mode 100644 react-native/example/app.json create mode 100644 react-native/example/babel.config.js create mode 100644 react-native/example/index.js create mode 100644 react-native/example/ios/.xcode.env create mode 100644 react-native/example/ios/File.swift create mode 100644 react-native/example/ios/Podfile create mode 100644 react-native/example/ios/Podfile.lock create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample-Bridging-Header.h create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample.xcodeproj/project.pbxproj create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample.xcodeproj/xcshareddata/xcschemes/ThetaBleClientReactNativeExample.xcscheme create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample.xcworkspace/contents.xcworkspacedata create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/AppDelegate.h create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/AppDelegate.mm create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/Images.xcassets/Contents.json create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/Info.plist create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/LaunchScreen.storyboard create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExample/main.m create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExampleTests/Info.plist create mode 100644 react-native/example/ios/ThetaBleClientReactNativeExampleTests/ThetaClientBleReactNativeExampleTests.m create mode 100644 react-native/example/metro.config.js create mode 100644 react-native/example/package.json create mode 100644 react-native/example/react-native.config.js create mode 100644 react-native/example/src/App.tsx create mode 100644 react-native/example/src/components/ui/button/button.tsx create mode 100644 react-native/example/src/components/ui/button/index.ts create mode 100644 react-native/example/src/components/ui/button/styles.tsx create mode 100644 react-native/example/src/components/ui/input-number/index.ts create mode 100644 react-native/example/src/components/ui/input-number/input-number.tsx create mode 100644 react-native/example/src/components/ui/input-number/styles.tsx create mode 100644 react-native/example/src/components/ui/input-string/index.ts create mode 100644 react-native/example/src/components/ui/input-string/input-string.tsx create mode 100644 react-native/example/src/components/ui/input-string/styles.tsx create mode 100644 react-native/example/src/components/ui/item-list/index.ts create mode 100644 react-native/example/src/components/ui/item-list/item-list-popup-view/index.ts create mode 100644 react-native/example/src/components/ui/item-list/item-list-popup-view/item-list-popup-view.tsx create mode 100644 react-native/example/src/components/ui/item-list/item-list-popup-view/styles.tsx create mode 100644 react-native/example/src/components/ui/item-list/item-list-view/index.ts create mode 100644 react-native/example/src/components/ui/item-list/item-list-view/item-list-view.tsx create mode 100644 react-native/example/src/components/ui/item-list/item-list-view/styles.tsx create mode 100644 react-native/example/src/components/ui/item-list/item-selector-view/index.ts create mode 100644 react-native/example/src/components/ui/item-list/item-selector-view/item-selector-view.tsx create mode 100644 react-native/example/src/components/ui/item-list/item-selector-view/styles.tsx create mode 100644 react-native/example/src/components/ui/titled-switch/index.ts create mode 100644 react-native/example/src/components/ui/titled-switch/styles.tsx create mode 100644 react-native/example/src/components/ui/titled-switch/titled-switch.tsx create mode 100644 react-native/example/src/device-context.tsx create mode 100644 react-native/example/src/screen/camera-control-command-v2/camera-control-command-v2-screen.tsx create mode 100644 react-native/example/src/screen/camera-control-command-v2/index.ts create mode 100644 react-native/example/src/screen/camera-control-command-v2/styles.tsx create mode 100644 react-native/example/src/screen/camera-status-screen/camera-status-screen.tsx create mode 100644 react-native/example/src/screen/camera-status-screen/index.ts create mode 100644 react-native/example/src/screen/camera-status-screen/styles.tsx create mode 100644 react-native/example/src/screen/menu-screen/index.ts create mode 100644 react-native/example/src/screen/menu-screen/menu-screen.tsx create mode 100644 react-native/example/src/screen/menu-screen/styles.tsx create mode 100644 react-native/example/src/theta-webapi/get-theta-info-webapi.ts create mode 100644 react-native/example/src/theta-webapi/set-ble-on-webapi.ts create mode 100644 react-native/example/src/theta-webapi/set-ble-uuid-webapi.ts create mode 100644 react-native/example/yarn.lock create mode 100644 react-native/ios/CameraControlCommandV2Service.swift create mode 100644 react-native/ios/CameraControlCommandsService.swift create mode 100644 react-native/ios/CameraInformationService.swift create mode 100644 react-native/ios/CameraStatusCommandService.swift create mode 100644 react-native/ios/ShootingControlCommandService.swift create mode 100644 react-native/ios/ThetaBleClientConvertEnum.swift create mode 100644 react-native/ios/ThetaBleClientConvertObject.swift create mode 100644 react-native/ios/ThetaBleClientReactNative-Bridging-Header.h create mode 100644 react-native/ios/ThetaBleClientReactNative.m create mode 100644 react-native/ios/ThetaBleClientReactNative.swift create mode 100644 react-native/ios/ThetaBleClientReactNative.xcodeproj/project.pbxproj create mode 100755 react-native/mkpackage.sh create mode 100644 react-native/package.json create mode 100644 react-native/scripts/bootstrap.js create mode 100644 react-native/src/__mocks__/react-native.ts create mode 100644 react-native/src/__tests__/camera-control-v2/get-info.test.ts create mode 100644 react-native/src/__tests__/camera-control-v2/get-state.test.ts create mode 100644 react-native/src/__tests__/camera-control-v2/get-state2.test.ts create mode 100644 react-native/src/__tests__/camera-control-v2/state-notify.test.ts create mode 100644 react-native/src/__tests__/camera-control/plugin-list.test.ts create mode 100644 react-native/src/__tests__/camera-control/plugin-orders.test.ts create mode 100644 react-native/src/__tests__/camera-info.test.tsx create mode 100644 react-native/src/__tests__/cameta-status/battery-level-notify.test.ts create mode 100644 react-native/src/__tests__/cameta-status/battery-level.test.ts create mode 100644 react-native/src/__tests__/cameta-status/battery-status-notify.test.ts create mode 100644 react-native/src/__tests__/cameta-status/battery-status.test.ts create mode 100644 react-native/src/__tests__/cameta-status/camera-power-notify.test.ts create mode 100644 react-native/src/__tests__/cameta-status/camera-power.test.ts create mode 100644 react-native/src/__tests__/cameta-status/command-error-description-notify.test.ts create mode 100644 react-native/src/__tests__/cameta-status/plugin-control-notify.test.ts create mode 100644 react-native/src/__tests__/cameta-status/plugin-control.test.ts create mode 100644 react-native/src/__tests__/scan.test.tsx create mode 100644 react-native/src/__tests__/shooting-control/capture-mode.test.tsx create mode 100644 react-native/src/__tests__/shooting-control/take-picture.test.tsx create mode 100644 react-native/src/__tests__/theta-device-service.test.tsx create mode 100644 react-native/src/__tests__/theta-device.test.tsx create mode 100644 react-native/src/__tests__/values/camera-error.test.tsx create mode 100644 react-native/src/__tests__/values/capture-status.test.tsx create mode 100644 react-native/src/__tests__/values/charging-status.test.tsx create mode 100644 react-native/src/__tests__/values/shooting-function.test.tsx create mode 100644 react-native/src/index.tsx create mode 100644 react-native/src/native/index.ts create mode 100644 react-native/src/native/native-functions.ts create mode 100644 react-native/src/service/ble/index.ts create mode 100644 react-native/src/service/ble/plugin-control.ts create mode 100644 react-native/src/service/ble/plugin-list.ts create mode 100644 react-native/src/service/ble/plugin-order.ts create mode 100644 react-native/src/service/camera-control-command-v2.ts create mode 100644 react-native/src/service/camera-control-commands.ts create mode 100644 react-native/src/service/camera-information.ts create mode 100644 react-native/src/service/camera-status-command.ts create mode 100644 react-native/src/service/data/gps-info.ts create mode 100644 react-native/src/service/data/index.ts create mode 100644 react-native/src/service/data/theta-info.ts create mode 100644 react-native/src/service/data/theta-state.ts create mode 100644 react-native/src/service/data/theta-state2.ts create mode 100644 react-native/src/service/index.ts create mode 100644 react-native/src/service/shooting-control-command.ts create mode 100644 react-native/src/service/theta-service.ts create mode 100644 react-native/src/service/values/ble-service.ts create mode 100644 react-native/src/service/values/camera-error.ts create mode 100644 react-native/src/service/values/camera-power.ts create mode 100644 react-native/src/service/values/capture-mode.ts create mode 100644 react-native/src/service/values/capture-status.ts create mode 100644 react-native/src/service/values/charging-state.ts create mode 100644 react-native/src/service/values/command-error-description.ts create mode 100644 react-native/src/service/values/index.ts create mode 100644 react-native/src/service/values/plugin-power-status.ts create mode 100644 react-native/src/service/values/shooting-function.ts create mode 100644 react-native/src/service/values/theta-model.ts create mode 100644 react-native/src/theta-ble/index.ts create mode 100644 react-native/src/theta-ble/theta-ble.ts create mode 100644 react-native/src/theta-device/index.ts create mode 100644 react-native/src/theta-device/notify.ts create mode 100644 react-native/src/theta-device/theta-device.ts create mode 100644 react-native/src/values/index.ts create mode 100644 react-native/src/values/timeout.ts create mode 100644 react-native/theta-ble-client-react-native.podspec create mode 100644 react-native/tsconfig.build.json create mode 100644 react-native/tsconfig.json create mode 100644 react-native/yarn.lock create mode 100644 settings.gradle.kts diff --git a/.github/workflows/dummy.yaml b/.github/workflows/dummy.yaml new file mode 100644 index 0000000..c6ef730 --- /dev/null +++ b/.github/workflows/dummy.yaml @@ -0,0 +1,14 @@ +name: Dummy for test + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + dummy: + if: ${{ false }} + runs-on: ubuntu-latest + steps: + - run: "" diff --git a/.github/workflows/publish-maven.yaml b/.github/workflows/publish-maven.yaml new file mode 100644 index 0000000..7f0d096 --- /dev/null +++ b/.github/workflows/publish-maven.yaml @@ -0,0 +1,26 @@ +name: Publish Maven + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: macos-13 + steps: + - uses: actions/checkout@v3 + - name: Select Xcode version + run: sudo xcode-select -s '/Applications/Xcode_15.0.1.app/Contents/Developer' + - name: Show Xcode version + run: xcodebuild -version + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: publish maven + uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 + with: + arguments: publish diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..3257ce8 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,37 @@ +name: Test + +on: + push: + branches: [ "main" ] + paths: + - 'kotlin-multiplatform/**' + - 'react-native/**' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: macos-13 + steps: + - uses: actions/checkout@v3 + - name: Select Xcode version + run: sudo xcode-select -s '/Applications/Xcode_15.0.1.app/Contents/Developer' + - name: Show Xcode version + run: xcodebuild -version + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: test-kmm + uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 + with: + arguments: testDebugUnitTest + - name: Archive code coverage results + if: always() + uses: actions/upload-artifact@v1 + with: + name: code-coverage-report + path: kotlin-multiplatform/build/reports/tests/testDebugUnitTest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e510fa9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +.idea +.DS_Store +build +captures +.externalNativeBuild +.cxx +local.properties +xcuserdata \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eae8de4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 RICOH360 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f01731 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +[![test](https://github.com/ricohapi/theta-ble-client/actions/workflows/test.yaml/badge.svg)](https://github.com/ricohapi/theta-ble-client/actions/workflows/test.yaml) + +# THETA BLE Client + +This library provides a way to control RICOH THETA using [THETA Bluetooth API](https://github.com/ricohapi/theta-api-specs/tree/main/theta-bluetooth-api). +Your app can perform the following actions: +* Take a photo and video +* Acquire the status of THETA +* Acquire and set properties of THETA + +## Supported Environments +* Android native (Kotlin) +* iOS native (Swift) +* React Native + +## Supported Models +* THETA Z1 +* THETA X + +## Directory Structure +* theta-ble-client + * demos: Demo applications + * docs: Documentation + * kotlin-multiplatform: Library body ([Kotlin Multiplatform Mobile](https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html)) + * react-native: React Native package + +## Build + +### Android (aar) +``` +theta-ble-client$ ./gradlew assemble +``` + +aar is output to `theta-ble-client-$/kotlin-multiplatform/build/outputs/aar` + +### iOS (XCFramework) +``` +theta-ble-client$ ./gradlew podPublishXCFramework +``` + +XCFramework is output to `theta-ble-client$/kotlin-multiplatform/build/cocoapods/publish` + +### ReactNative +See README in each directory.(`react-native`) + +### Test +``` +theta-ble-client$ ./gradlew testReleaseUnitTest +``` + +## How to Use +See tutorial in `docs` directory. + + +## License + +[MIT License](LICENSE) diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..0b77444 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + //trick: for the same plugin versions in all sub-modules + id("com.android.library").version("8.1.2").apply(false) + kotlin("multiplatform").version("1.9.10").apply(false) + kotlin("plugin.serialization").version("1.9.10").apply(false) + id("org.jetbrains.dokka").version("1.9.10") +} + +buildscript { + dependencies { + classpath("org.jetbrains.dokka:versioning-plugin:1.9.10") + } +} + +tasks.register("clean", Delete::class) { +} diff --git a/demos/demo-android/.gitignore b/demos/demo-android/.gitignore new file mode 100755 index 0000000..57d8fee --- /dev/null +++ b/demos/demo-android/.gitignore @@ -0,0 +1,19 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties + +/mathlibrary +/spherelibrary +/thetalibrary diff --git a/demos/demo-android/LICENSE b/demos/demo-android/LICENSE new file mode 100644 index 0000000..eae8de4 --- /dev/null +++ b/demos/demo-android/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 RICOH360 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/demos/demo-android/README.ja.md b/demos/demo-android/README.ja.md new file mode 100755 index 0000000..5d40136 --- /dev/null +++ b/demos/demo-android/README.ja.md @@ -0,0 +1,20 @@ +# Android demo for theta-ble-client + +A simple sample Android application using [theta-ble-client](https://github.com/ricohapi/theta-ble-client). + +## 目的 + +* THETA BLE Clientを使う開発者に、簡単な実例を示す + +## Functions + +* List photos in Theta. +* View sphere photo in Theta. +* Take a photo with Theta. + +## 設計方針 + +* 非同期処理をコルーチンで書けるKotlinを使う +* UIの簡潔な記述ができる[Jetpack Compose](https://developer.android.com/jetpack/compose?hl=ja)を使う + + diff --git a/demos/demo-android/README.md b/demos/demo-android/README.md new file mode 100755 index 0000000..636d691 --- /dev/null +++ b/demos/demo-android/README.md @@ -0,0 +1,20 @@ +# Android demo for theta-ble-client + +A simple sample Android application using [theta-ble-client](https://github.com/ricohapi/theta-ble-client). + +## Objective + +* Show developers how to use THETA BLE Client. + +## Functions + +* List photos in Theta. +* View sphere photo in Theta. +* Take a photo with Theta. + +## Policy + +* Use Kotlin which coroutine simplifies code that executes asynchronously. +* Use [Jetpack Compose](https://developer.android.com/jetpack/compose) that can describe UI simply. + + diff --git a/demos/demo-android/app/.gitignore b/demos/demo-android/app/.gitignore new file mode 100755 index 0000000..42afabf --- /dev/null +++ b/demos/demo-android/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/demos/demo-android/app/build.gradle b/demos/demo-android/app/build.gradle new file mode 100755 index 0000000..21caa22 --- /dev/null +++ b/demos/demo-android/app/build.gradle @@ -0,0 +1,85 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'kotlinx-serialization' +} + +android { + compileSdk 34 + + defaultConfig { + applicationId "com.ricoh360.thetableclient.thetaBleClientDemo" + minSdk 26 + targetSdk 34 + versionCode 1 + versionName "1.0.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + buildConfig true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } + // for JUnit5 + testOptions { + unitTests.all { + useJUnitPlatform() + } + unitTests.returnDefaultValues = true // Disable exception "Method e in android.util.Log not mocked." + } + namespace 'com.ricoh360.thetableclient.thetaBleClientDemo' +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.12.0' + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation 'androidx.compose.runtime:runtime-livedata:1.5.4' + implementation 'androidx.activity:activity-compose:1.8.0' + implementation "androidx.navigation:navigation-compose:2.7.4" + implementation 'androidx.webkit:webkit:1.8.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + implementation 'com.jakewharton.timber:timber:5.0.1' + implementation 'io.coil-kt:coil-compose:2.2.2' + + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0' + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" + testImplementation 'org.junit.jupiter:junit-jupiter' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" + + implementation "com.ricoh360.thetaclient:theta-client:1.5.0" + + implementation "com.ricoh360.thetableclient:theta-ble-client-android:1.0.0" +} diff --git a/demos/demo-android/app/proguard-rules.pro b/demos/demo-android/app/proguard-rules.pro new file mode 100755 index 0000000..515f7ca --- /dev/null +++ b/demos/demo-android/app/proguard-rules.pro @@ -0,0 +1,94 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +############### for Retrofit: https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro +# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and +# EnclosingMethod is required to use InnerClasses. +-keepattributes Signature, InnerClasses, EnclosingMethod + +# Retrofit does reflection on method and parameter annotations. +-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations + +# Keep annotation default values (e.g., retrofit2.http.Field.encoded). +-keepattributes AnnotationDefault + +# Retain service method parameters when optimizing. +-keepclassmembers,allowshrinking,allowobfuscation interface * { + @retrofit2.http.* ; +} + +# Ignore JSR 305 annotations for embedding nullability information. +-dontwarn javax.annotation.** + +# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. +-dontwarn kotlin.Unit + +# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy +# and replaces all potential values with null. Explicitly keeping the interfaces prevents this. +-if interface * { @retrofit2.http.* ; } +-keep,allowobfuscation interface <1> + +# With R8 full mode generic signatures are stripped for classes that are not +# kept. Suspend functions are wrapped in continuations where the type argument +# is used. +-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation + +############### for serialization: https://github.com/Kotlin/kotlinx.serialization#using-the-plugins-block +# Keep `Companion` object fields of serializable classes. +# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. +-if @kotlinx.serialization.Serializable class ** +-keepclassmembers class <1> { + static <1>$Companion Companion; +} + +# Keep `serializer()` on companion objects (both default and named) of serializable classes. +-if @kotlinx.serialization.Serializable class ** { + static **$* *; +} +-keepclassmembers class <2>$<3> { + kotlinx.serialization.KSerializer serializer(...); +} + +# Keep `INSTANCE.serializer()` of serializable objects. +-if @kotlinx.serialization.Serializable class ** { + public static ** INSTANCE; +} +-keepclassmembers class <1> { + public static <1> INSTANCE; + kotlinx.serialization.KSerializer serializer(...); +} + +# @Serializable and @Polymorphic are used at runtime for polymorphic serialization. +-keepattributes RuntimeVisibleAnnotations,AnnotationDefault + +# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`. +# If you have any, uncomment and replace classes with those containing named companion objects. +#-keepattributes InnerClasses # Needed for `getDeclaredClasses`. +#-if @kotlinx.serialization.Serializable class +#com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions. +#com.example.myapplication.HasNamedCompanion2 +#{ +# static **$* *; +#} +#-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. +# static <1>$$serializer INSTANCE; +#} \ No newline at end of file diff --git a/demos/demo-android/app/src/androidTest/java/com/ricoh360/thetableclient/thetaBleClientDemo/ExampleInstrumentedTest.kt b/demos/demo-android/app/src/androidTest/java/com/ricoh360/thetableclient/thetaBleClientDemo/ExampleInstrumentedTest.kt new file mode 100755 index 0000000..c24d851 --- /dev/null +++ b/demos/demo-android/app/src/androidTest/java/com/ricoh360/thetableclient/thetaBleClientDemo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ricoh360.sample.thetaSimpleAndroidApp", appContext.packageName) + } +} diff --git a/demos/demo-android/app/src/main/AndroidManifest.xml b/demos/demo-android/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..5344acc --- /dev/null +++ b/demos/demo-android/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/assets/bundle.js b/demos/demo-android/app/src/main/assets/bundle.js new file mode 100755 index 0000000..2356f59 --- /dev/null +++ b/demos/demo-android/app/src/main/assets/bundle.js @@ -0,0 +1,30778 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.RICOH360Viewer = {})); +}(this, (function (exports) { 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + } + + function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function isFunction(x) { + return typeof x === 'function'; + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var _enable_super_gross_mode_that_will_cause_bad_things = false; + var config = { + Promise: undefined, + set useDeprecatedSynchronousErrorHandling(value) { + if (value) { + var error = /*@__PURE__*/ new Error(); + /*@__PURE__*/ console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack); + } + _enable_super_gross_mode_that_will_cause_bad_things = value; + }, + get useDeprecatedSynchronousErrorHandling() { + return _enable_super_gross_mode_that_will_cause_bad_things; + }, + }; + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function hostReportError(err) { + setTimeout(function () { throw err; }, 0); + } + + /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */ + var empty = { + closed: true, + next: function (value) { }, + error: function (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + hostReportError(err); + } + }, + complete: function () { } + }; + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var isArray = /*@__PURE__*/ (function () { return Array.isArray || (function (x) { return x && typeof x.length === 'number'; }); })(); + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function isObject(x) { + return x !== null && typeof x === 'object'; + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var UnsubscriptionErrorImpl = /*@__PURE__*/ (function () { + function UnsubscriptionErrorImpl(errors) { + Error.call(this); + this.message = errors ? + errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n ') : ''; + this.name = 'UnsubscriptionError'; + this.errors = errors; + return this; + } + UnsubscriptionErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype); + return UnsubscriptionErrorImpl; + })(); + var UnsubscriptionError = UnsubscriptionErrorImpl; + + /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_UnsubscriptionError PURE_IMPORTS_END */ + var Subscription = /*@__PURE__*/ (function () { + function Subscription(unsubscribe) { + this.closed = false; + this._parentOrParents = null; + this._subscriptions = null; + if (unsubscribe) { + this._ctorUnsubscribe = true; + this._unsubscribe = unsubscribe; + } + } + Subscription.prototype.unsubscribe = function () { + var errors; + if (this.closed) { + return; + } + var _a = this, _parentOrParents = _a._parentOrParents, _ctorUnsubscribe = _a._ctorUnsubscribe, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; + this.closed = true; + this._parentOrParents = null; + this._subscriptions = null; + if (_parentOrParents instanceof Subscription) { + _parentOrParents.remove(this); + } + else if (_parentOrParents !== null) { + for (var index = 0; index < _parentOrParents.length; ++index) { + var parent_1 = _parentOrParents[index]; + parent_1.remove(this); + } + } + if (isFunction(_unsubscribe)) { + if (_ctorUnsubscribe) { + this._unsubscribe = undefined; + } + try { + _unsubscribe.call(this); + } + catch (e) { + errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e]; + } + } + if (isArray(_subscriptions)) { + var index = -1; + var len = _subscriptions.length; + while (++index < len) { + var sub = _subscriptions[index]; + if (isObject(sub)) { + try { + sub.unsubscribe(); + } + catch (e) { + errors = errors || []; + if (e instanceof UnsubscriptionError) { + errors = errors.concat(flattenUnsubscriptionErrors(e.errors)); + } + else { + errors.push(e); + } + } + } + } + } + if (errors) { + throw new UnsubscriptionError(errors); + } + }; + Subscription.prototype.add = function (teardown) { + var subscription = teardown; + if (!teardown) { + return Subscription.EMPTY; + } + switch (typeof teardown) { + case 'function': + subscription = new Subscription(teardown); + case 'object': + if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') { + return subscription; + } + else if (this.closed) { + subscription.unsubscribe(); + return subscription; + } + else if (!(subscription instanceof Subscription)) { + var tmp = subscription; + subscription = new Subscription(); + subscription._subscriptions = [tmp]; + } + break; + default: { + throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); + } + } + var _parentOrParents = subscription._parentOrParents; + if (_parentOrParents === null) { + subscription._parentOrParents = this; + } + else if (_parentOrParents instanceof Subscription) { + if (_parentOrParents === this) { + return subscription; + } + subscription._parentOrParents = [_parentOrParents, this]; + } + else if (_parentOrParents.indexOf(this) === -1) { + _parentOrParents.push(this); + } + else { + return subscription; + } + var subscriptions = this._subscriptions; + if (subscriptions === null) { + this._subscriptions = [subscription]; + } + else { + subscriptions.push(subscription); + } + return subscription; + }; + Subscription.prototype.remove = function (subscription) { + var subscriptions = this._subscriptions; + if (subscriptions) { + var subscriptionIndex = subscriptions.indexOf(subscription); + if (subscriptionIndex !== -1) { + subscriptions.splice(subscriptionIndex, 1); + } + } + }; + Subscription.EMPTY = (function (empty) { + empty.closed = true; + return empty; + }(new Subscription())); + return Subscription; + }()); + function flattenUnsubscriptionErrors(errors) { + return errors.reduce(function (errs, err) { return errs.concat((err instanceof UnsubscriptionError) ? err.errors : err); }, []); + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var rxSubscriber = /*@__PURE__*/ (function () { + return typeof Symbol === 'function' + ? /*@__PURE__*/ Symbol('rxSubscriber') + : '@@rxSubscriber_' + /*@__PURE__*/ Math.random(); + })(); + + /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ + var Subscriber = /*@__PURE__*/ (function (_super) { + __extends(Subscriber, _super); + function Subscriber(destinationOrNext, error, complete) { + var _this = _super.call(this) || this; + _this.syncErrorValue = null; + _this.syncErrorThrown = false; + _this.syncErrorThrowable = false; + _this.isStopped = false; + switch (arguments.length) { + case 0: + _this.destination = empty; + break; + case 1: + if (!destinationOrNext) { + _this.destination = empty; + break; + } + if (typeof destinationOrNext === 'object') { + if (destinationOrNext instanceof Subscriber) { + _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; + _this.destination = destinationOrNext; + destinationOrNext.add(_this); + } + else { + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext); + } + break; + } + default: + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); + break; + } + return _this; + } + Subscriber.prototype[rxSubscriber] = function () { return this; }; + Subscriber.create = function (next, error, complete) { + var subscriber = new Subscriber(next, error, complete); + subscriber.syncErrorThrowable = false; + return subscriber; + }; + Subscriber.prototype.next = function (value) { + if (!this.isStopped) { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (!this.isStopped) { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (!this.isStopped) { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + this.destination.error(err); + this.unsubscribe(); + }; + Subscriber.prototype._complete = function () { + this.destination.complete(); + this.unsubscribe(); + }; + Subscriber.prototype._unsubscribeAndRecycle = function () { + var _parentOrParents = this._parentOrParents; + this._parentOrParents = null; + this.unsubscribe(); + this.closed = false; + this.isStopped = false; + this._parentOrParents = _parentOrParents; + return this; + }; + return Subscriber; + }(Subscription)); + var SafeSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SafeSubscriber, _super); + function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { + var _this = _super.call(this) || this; + _this._parentSubscriber = _parentSubscriber; + var next; + var context = _this; + if (isFunction(observerOrNext)) { + next = observerOrNext; + } + else if (observerOrNext) { + next = observerOrNext.next; + error = observerOrNext.error; + complete = observerOrNext.complete; + if (observerOrNext !== empty) { + context = Object.create(observerOrNext); + if (isFunction(context.unsubscribe)) { + _this.add(context.unsubscribe.bind(context)); + } + context.unsubscribe = _this.unsubscribe.bind(_this); + } + } + _this._context = context; + _this._next = next; + _this._error = error; + _this._complete = complete; + return _this; + } + SafeSubscriber.prototype.next = function (value) { + if (!this.isStopped && this._next) { + var _parentSubscriber = this._parentSubscriber; + if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._next, value); + } + else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + var useDeprecatedSynchronousErrorHandling = config.useDeprecatedSynchronousErrorHandling; + if (this._error) { + if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._error, err); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, this._error, err); + this.unsubscribe(); + } + } + else if (!_parentSubscriber.syncErrorThrowable) { + this.unsubscribe(); + if (useDeprecatedSynchronousErrorHandling) { + throw err; + } + hostReportError(err); + } + else { + if (useDeprecatedSynchronousErrorHandling) { + _parentSubscriber.syncErrorValue = err; + _parentSubscriber.syncErrorThrown = true; + } + else { + hostReportError(err); + } + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.complete = function () { + var _this = this; + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + if (this._complete) { + var wrappedComplete = function () { return _this._complete.call(_this._context); }; + if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(wrappedComplete); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, wrappedComplete); + this.unsubscribe(); + } + } + else { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { + try { + fn.call(this._context, value); + } + catch (err) { + this.unsubscribe(); + if (config.useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + hostReportError(err); + } + } + }; + SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { + if (!config.useDeprecatedSynchronousErrorHandling) { + throw new Error('bad call'); + } + try { + fn.call(this._context, value); + } + catch (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + parent.syncErrorValue = err; + parent.syncErrorThrown = true; + return true; + } + else { + hostReportError(err); + return true; + } + } + return false; + }; + SafeSubscriber.prototype._unsubscribe = function () { + var _parentSubscriber = this._parentSubscriber; + this._context = null; + this._parentSubscriber = null; + _parentSubscriber.unsubscribe(); + }; + return SafeSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _Subscriber PURE_IMPORTS_END */ + function canReportError(observer) { + while (observer) { + var _a = observer, closed_1 = _a.closed, destination = _a.destination, isStopped = _a.isStopped; + if (closed_1 || isStopped) { + return false; + } + else if (destination && destination instanceof Subscriber) { + observer = destination; + } + else { + observer = null; + } + } + return true; + } + + /** PURE_IMPORTS_START _Subscriber,_symbol_rxSubscriber,_Observer PURE_IMPORTS_END */ + function toSubscriber(nextOrObserver, error, complete) { + if (nextOrObserver) { + if (nextOrObserver instanceof Subscriber) { + return nextOrObserver; + } + if (nextOrObserver[rxSubscriber]) { + return nextOrObserver[rxSubscriber](); + } + } + if (!nextOrObserver && !error && !complete) { + return new Subscriber(empty); + } + return new Subscriber(nextOrObserver, error, complete); + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var observable = /*@__PURE__*/ (function () { return typeof Symbol === 'function' && Symbol.observable || '@@observable'; })(); + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function identity(x) { + return x; + } + + /** PURE_IMPORTS_START _identity PURE_IMPORTS_END */ + function pipe() { + var fns = []; + for (var _i = 0; _i < arguments.length; _i++) { + fns[_i] = arguments[_i]; + } + return pipeFromArray(fns); + } + function pipeFromArray(fns) { + if (fns.length === 0) { + return identity; + } + if (fns.length === 1) { + return fns[0]; + } + return function piped(input) { + return fns.reduce(function (prev, fn) { return fn(prev); }, input); + }; + } + + /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ + var Observable = /*@__PURE__*/ (function () { + function Observable(subscribe) { + this._isScalar = false; + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable = new Observable(); + observable.source = this; + observable.operator = operator; + return observable; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var operator = this.operator; + var sink = toSubscriber(observerOrNext, error, complete); + if (operator) { + sink.add(operator.call(sink, this.source)); + } + else { + sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? + this._subscribe(sink) : + this._trySubscribe(sink)); + } + if (config.useDeprecatedSynchronousErrorHandling) { + if (sink.syncErrorThrowable) { + sink.syncErrorThrowable = false; + if (sink.syncErrorThrown) { + throw sink.syncErrorValue; + } + } + } + return sink; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } + catch (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + sink.syncErrorThrown = true; + sink.syncErrorValue = err; + } + if (canReportError(sink)) { + sink.error(err); + } + else { + console.warn(err); + } + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscription; + subscription = _this.subscribe(function (value) { + try { + next(value); + } + catch (err) { + reject(err); + if (subscription) { + subscription.unsubscribe(); + } + } + }, reject, resolve); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var source = this.source; + return source && source.subscribe(subscriber); + }; + Observable.prototype[observable] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + if (operations.length === 0) { + return this; + } + return pipeFromArray(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; + }()); + function getPromiseCtor(promiseCtor) { + if (!promiseCtor) { + promiseCtor = Promise; + } + if (!promiseCtor) { + throw new Error('no Promise impl found'); + } + return promiseCtor; + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var ObjectUnsubscribedErrorImpl = /*@__PURE__*/ (function () { + function ObjectUnsubscribedErrorImpl() { + Error.call(this); + this.message = 'object unsubscribed'; + this.name = 'ObjectUnsubscribedError'; + return this; + } + ObjectUnsubscribedErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype); + return ObjectUnsubscribedErrorImpl; + })(); + var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl; + + /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */ + var SubjectSubscription = /*@__PURE__*/ (function (_super) { + __extends(SubjectSubscription, _super); + function SubjectSubscription(subject, subscriber) { + var _this = _super.call(this) || this; + _this.subject = subject; + _this.subscriber = subscriber; + _this.closed = false; + return _this; + } + SubjectSubscription.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.closed = true; + var subject = this.subject; + var observers = subject.observers; + this.subject = null; + if (!observers || observers.length === 0 || subject.isStopped || subject.closed) { + return; + } + var subscriberIndex = observers.indexOf(this.subscriber); + if (subscriberIndex !== -1) { + observers.splice(subscriberIndex, 1); + } + }; + return SubjectSubscription; + }(Subscription)); + + /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ + var SubjectSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SubjectSubscriber, _super); + function SubjectSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + return _this; + } + return SubjectSubscriber; + }(Subscriber)); + var Subject = /*@__PURE__*/ (function (_super) { + __extends(Subject, _super); + function Subject() { + var _this = _super.call(this) || this; + _this.observers = []; + _this.closed = false; + _this.isStopped = false; + _this.hasError = false; + _this.thrownError = null; + return _this; + } + Subject.prototype[rxSubscriber] = function () { + return new SubjectSubscriber(this); + }; + Subject.prototype.lift = function (operator) { + var subject = new AnonymousSubject(this, this); + subject.operator = operator; + return subject; + }; + Subject.prototype.next = function (value) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + if (!this.isStopped) { + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].next(value); + } + } + }; + Subject.prototype.error = function (err) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + this.hasError = true; + this.thrownError = err; + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].error(err); + } + this.observers.length = 0; + }; + Subject.prototype.complete = function () { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].complete(); + } + this.observers.length = 0; + }; + Subject.prototype.unsubscribe = function () { + this.isStopped = true; + this.closed = true; + this.observers = null; + }; + Subject.prototype._trySubscribe = function (subscriber) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else { + return _super.prototype._trySubscribe.call(this, subscriber); + } + }; + Subject.prototype._subscribe = function (subscriber) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else if (this.hasError) { + subscriber.error(this.thrownError); + return Subscription.EMPTY; + } + else if (this.isStopped) { + subscriber.complete(); + return Subscription.EMPTY; + } + else { + this.observers.push(subscriber); + return new SubjectSubscription(this, subscriber); + } + }; + Subject.prototype.asObservable = function () { + var observable = new Observable(); + observable.source = this; + return observable; + }; + Subject.create = function (destination, source) { + return new AnonymousSubject(destination, source); + }; + return Subject; + }(Observable)); + var AnonymousSubject = /*@__PURE__*/ (function (_super) { + __extends(AnonymousSubject, _super); + function AnonymousSubject(destination, source) { + var _this = _super.call(this) || this; + _this.destination = destination; + _this.source = source; + return _this; + } + AnonymousSubject.prototype.next = function (value) { + var destination = this.destination; + if (destination && destination.next) { + destination.next(value); + } + }; + AnonymousSubject.prototype.error = function (err) { + var destination = this.destination; + if (destination && destination.error) { + this.destination.error(err); + } + }; + AnonymousSubject.prototype.complete = function () { + var destination = this.destination; + if (destination && destination.complete) { + this.destination.complete(); + } + }; + AnonymousSubject.prototype._subscribe = function (subscriber) { + var source = this.source; + if (source) { + return this.source.subscribe(subscriber); + } + else { + return Subscription.EMPTY; + } + }; + return AnonymousSubject; + }(Subject)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function refCount() { + return function refCountOperatorFunction(source) { + return source.lift(new RefCountOperator(source)); + }; + } + var RefCountOperator = /*@__PURE__*/ (function () { + function RefCountOperator(connectable) { + this.connectable = connectable; + } + RefCountOperator.prototype.call = function (subscriber, source) { + var connectable = this.connectable; + connectable._refCount++; + var refCounter = new RefCountSubscriber(subscriber, connectable); + var subscription = source.subscribe(refCounter); + if (!refCounter.closed) { + refCounter.connection = connectable.connect(); + } + return subscription; + }; + return RefCountOperator; + }()); + var RefCountSubscriber = /*@__PURE__*/ (function (_super) { + __extends(RefCountSubscriber, _super); + function RefCountSubscriber(destination, connectable) { + var _this = _super.call(this, destination) || this; + _this.connectable = connectable; + return _this; + } + RefCountSubscriber.prototype._unsubscribe = function () { + var connectable = this.connectable; + if (!connectable) { + this.connection = null; + return; + } + this.connectable = null; + var refCount = connectable._refCount; + if (refCount <= 0) { + this.connection = null; + return; + } + connectable._refCount = refCount - 1; + if (refCount > 1) { + this.connection = null; + return; + } + var connection = this.connection; + var sharedConnection = connectable._connection; + this.connection = null; + if (sharedConnection && (!connection || sharedConnection === connection)) { + sharedConnection.unsubscribe(); + } + }; + return RefCountSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_Subject,_Observable,_Subscriber,_Subscription,_operators_refCount PURE_IMPORTS_END */ + var ConnectableObservable = /*@__PURE__*/ (function (_super) { + __extends(ConnectableObservable, _super); + function ConnectableObservable(source, subjectFactory) { + var _this = _super.call(this) || this; + _this.source = source; + _this.subjectFactory = subjectFactory; + _this._refCount = 0; + _this._isComplete = false; + return _this; + } + ConnectableObservable.prototype._subscribe = function (subscriber) { + return this.getSubject().subscribe(subscriber); + }; + ConnectableObservable.prototype.getSubject = function () { + var subject = this._subject; + if (!subject || subject.isStopped) { + this._subject = this.subjectFactory(); + } + return this._subject; + }; + ConnectableObservable.prototype.connect = function () { + var connection = this._connection; + if (!connection) { + this._isComplete = false; + connection = this._connection = new Subscription(); + connection.add(this.source + .subscribe(new ConnectableSubscriber(this.getSubject(), this))); + if (connection.closed) { + this._connection = null; + connection = Subscription.EMPTY; + } + } + return connection; + }; + ConnectableObservable.prototype.refCount = function () { + return refCount()(this); + }; + return ConnectableObservable; + }(Observable)); + var connectableObservableDescriptor = /*@__PURE__*/ (function () { + var connectableProto = ConnectableObservable.prototype; + return { + operator: { value: null }, + _refCount: { value: 0, writable: true }, + _subject: { value: null, writable: true }, + _connection: { value: null, writable: true }, + _subscribe: { value: connectableProto._subscribe }, + _isComplete: { value: connectableProto._isComplete, writable: true }, + getSubject: { value: connectableProto.getSubject }, + connect: { value: connectableProto.connect }, + refCount: { value: connectableProto.refCount } + }; + })(); + var ConnectableSubscriber = /*@__PURE__*/ (function (_super) { + __extends(ConnectableSubscriber, _super); + function ConnectableSubscriber(destination, connectable) { + var _this = _super.call(this, destination) || this; + _this.connectable = connectable; + return _this; + } + ConnectableSubscriber.prototype._error = function (err) { + this._unsubscribe(); + _super.prototype._error.call(this, err); + }; + ConnectableSubscriber.prototype._complete = function () { + this.connectable._isComplete = true; + this._unsubscribe(); + _super.prototype._complete.call(this); + }; + ConnectableSubscriber.prototype._unsubscribe = function () { + var connectable = this.connectable; + if (connectable) { + this.connectable = null; + var connection = connectable._connection; + connectable._refCount = 0; + connectable._subject = null; + connectable._connection = null; + if (connection) { + connection.unsubscribe(); + } + } + }; + return ConnectableSubscriber; + }(SubjectSubscriber)); + + /** PURE_IMPORTS_START tslib,_Subject,_util_ObjectUnsubscribedError PURE_IMPORTS_END */ + var BehaviorSubject = /*@__PURE__*/ (function (_super) { + __extends(BehaviorSubject, _super); + function BehaviorSubject(_value) { + var _this = _super.call(this) || this; + _this._value = _value; + return _this; + } + Object.defineProperty(BehaviorSubject.prototype, "value", { + get: function () { + return this.getValue(); + }, + enumerable: true, + configurable: true + }); + BehaviorSubject.prototype._subscribe = function (subscriber) { + var subscription = _super.prototype._subscribe.call(this, subscriber); + if (subscription && !subscription.closed) { + subscriber.next(this._value); + } + return subscription; + }; + BehaviorSubject.prototype.getValue = function () { + if (this.hasError) { + throw this.thrownError; + } + else if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else { + return this._value; + } + }; + BehaviorSubject.prototype.next = function (value) { + _super.prototype.next.call(this, this._value = value); + }; + return BehaviorSubject; + }(Subject)); + + /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */ + var Action = /*@__PURE__*/ (function (_super) { + __extends(Action, _super); + function Action(scheduler, work) { + return _super.call(this) || this; + } + Action.prototype.schedule = function (state, delay) { + return this; + }; + return Action; + }(Subscription)); + + /** PURE_IMPORTS_START tslib,_Action PURE_IMPORTS_END */ + var AsyncAction = /*@__PURE__*/ (function (_super) { + __extends(AsyncAction, _super); + function AsyncAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + _this.pending = false; + return _this; + } + AsyncAction.prototype.schedule = function (state, delay) { + if (delay === void 0) { + delay = 0; + } + if (this.closed) { + return this; + } + this.state = state; + var id = this.id; + var scheduler = this.scheduler; + if (id != null) { + this.id = this.recycleAsyncId(scheduler, id, delay); + } + this.pending = true; + this.delay = delay; + this.id = this.id || this.requestAsyncId(scheduler, this.id, delay); + return this; + }; + AsyncAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { + delay = 0; + } + return setInterval(scheduler.flush.bind(scheduler, this), delay); + }; + AsyncAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { + delay = 0; + } + if (delay !== null && this.delay === delay && this.pending === false) { + return id; + } + clearInterval(id); + return undefined; + }; + AsyncAction.prototype.execute = function (state, delay) { + if (this.closed) { + return new Error('executing a cancelled action'); + } + this.pending = false; + var error = this._execute(state, delay); + if (error) { + return error; + } + else if (this.pending === false && this.id != null) { + this.id = this.recycleAsyncId(this.scheduler, this.id, null); + } + }; + AsyncAction.prototype._execute = function (state, delay) { + var errored = false; + var errorValue = undefined; + try { + this.work(state); + } + catch (e) { + errored = true; + errorValue = !!e && e || new Error(e); + } + if (errored) { + this.unsubscribe(); + return errorValue; + } + }; + AsyncAction.prototype._unsubscribe = function () { + var id = this.id; + var scheduler = this.scheduler; + var actions = scheduler.actions; + var index = actions.indexOf(this); + this.work = null; + this.state = null; + this.pending = false; + this.scheduler = null; + if (index !== -1) { + actions.splice(index, 1); + } + if (id != null) { + this.id = this.recycleAsyncId(scheduler, id, null); + } + this.delay = null; + }; + return AsyncAction; + }(Action)); + + /** PURE_IMPORTS_START tslib,_AsyncAction PURE_IMPORTS_END */ + var QueueAction = /*@__PURE__*/ (function (_super) { + __extends(QueueAction, _super); + function QueueAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + return _this; + } + QueueAction.prototype.schedule = function (state, delay) { + if (delay === void 0) { + delay = 0; + } + if (delay > 0) { + return _super.prototype.schedule.call(this, state, delay); + } + this.delay = delay; + this.state = state; + this.scheduler.flush(this); + return this; + }; + QueueAction.prototype.execute = function (state, delay) { + return (delay > 0 || this.closed) ? + _super.prototype.execute.call(this, state, delay) : + this._execute(state, delay); + }; + QueueAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { + delay = 0; + } + if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) { + return _super.prototype.requestAsyncId.call(this, scheduler, id, delay); + } + return scheduler.flush(this); + }; + return QueueAction; + }(AsyncAction)); + + var Scheduler = /*@__PURE__*/ (function () { + function Scheduler(SchedulerAction, now) { + if (now === void 0) { + now = Scheduler.now; + } + this.SchedulerAction = SchedulerAction; + this.now = now; + } + Scheduler.prototype.schedule = function (work, delay, state) { + if (delay === void 0) { + delay = 0; + } + return new this.SchedulerAction(this, work).schedule(state, delay); + }; + Scheduler.now = function () { return Date.now(); }; + return Scheduler; + }()); + + /** PURE_IMPORTS_START tslib,_Scheduler PURE_IMPORTS_END */ + var AsyncScheduler = /*@__PURE__*/ (function (_super) { + __extends(AsyncScheduler, _super); + function AsyncScheduler(SchedulerAction, now) { + if (now === void 0) { + now = Scheduler.now; + } + var _this = _super.call(this, SchedulerAction, function () { + if (AsyncScheduler.delegate && AsyncScheduler.delegate !== _this) { + return AsyncScheduler.delegate.now(); + } + else { + return now(); + } + }) || this; + _this.actions = []; + _this.active = false; + _this.scheduled = undefined; + return _this; + } + AsyncScheduler.prototype.schedule = function (work, delay, state) { + if (delay === void 0) { + delay = 0; + } + if (AsyncScheduler.delegate && AsyncScheduler.delegate !== this) { + return AsyncScheduler.delegate.schedule(work, delay, state); + } + else { + return _super.prototype.schedule.call(this, work, delay, state); + } + }; + AsyncScheduler.prototype.flush = function (action) { + var actions = this.actions; + if (this.active) { + actions.push(action); + return; + } + var error; + this.active = true; + do { + if (error = action.execute(action.state, action.delay)) { + break; + } + } while (action = actions.shift()); + this.active = false; + if (error) { + while (action = actions.shift()) { + action.unsubscribe(); + } + throw error; + } + }; + return AsyncScheduler; + }(Scheduler)); + + /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */ + var QueueScheduler = /*@__PURE__*/ (function (_super) { + __extends(QueueScheduler, _super); + function QueueScheduler() { + return _super !== null && _super.apply(this, arguments) || this; + } + return QueueScheduler; + }(AsyncScheduler)); + + /** PURE_IMPORTS_START _QueueAction,_QueueScheduler PURE_IMPORTS_END */ + var queueScheduler = /*@__PURE__*/ new QueueScheduler(QueueAction); + var queue = queueScheduler; + + /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ + var EMPTY = /*@__PURE__*/ new Observable(function (subscriber) { return subscriber.complete(); }); + function empty$1(scheduler) { + return scheduler ? emptyScheduled(scheduler) : EMPTY; + } + function emptyScheduled(scheduler) { + return new Observable(function (subscriber) { return scheduler.schedule(function () { return subscriber.complete(); }); }); + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function isScheduler(value) { + return value && typeof value.schedule === 'function'; + } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var subscribeToArray = function (array) { + return function (subscriber) { + for (var i = 0, len = array.length; i < len && !subscriber.closed; i++) { + subscriber.next(array[i]); + } + subscriber.complete(); + }; + }; + + /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */ + function scheduleArray(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + var i = 0; + sub.add(scheduler.schedule(function () { + if (i === input.length) { + subscriber.complete(); + return; + } + subscriber.next(input[i++]); + if (!subscriber.closed) { + sub.add(this.schedule()); + } + })); + return sub; + }); + } + + /** PURE_IMPORTS_START _Observable,_util_subscribeToArray,_scheduled_scheduleArray PURE_IMPORTS_END */ + function fromArray(input, scheduler) { + if (!scheduler) { + return new Observable(subscribeToArray(input)); + } + else { + return scheduleArray(input, scheduler); + } + } + + /** PURE_IMPORTS_START _util_isScheduler,_fromArray,_scheduled_scheduleArray PURE_IMPORTS_END */ + function of() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var scheduler = args[args.length - 1]; + if (isScheduler(scheduler)) { + args.pop(); + return scheduleArray(args, scheduler); + } + else { + return fromArray(args); + } + } + + /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ + function throwError(error, scheduler) { + if (!scheduler) { + return new Observable(function (subscriber) { return subscriber.error(error); }); + } + else { + return new Observable(function (subscriber) { return scheduler.schedule(dispatch, 0, { error: error, subscriber: subscriber }); }); + } + } + function dispatch(_a) { + var error = _a.error, subscriber = _a.subscriber; + subscriber.error(error); + } + + /** PURE_IMPORTS_START _observable_empty,_observable_of,_observable_throwError PURE_IMPORTS_END */ + var Notification = /*@__PURE__*/ (function () { + function Notification(kind, value, error) { + this.kind = kind; + this.value = value; + this.error = error; + this.hasValue = kind === 'N'; + } + Notification.prototype.observe = function (observer) { + switch (this.kind) { + case 'N': + return observer.next && observer.next(this.value); + case 'E': + return observer.error && observer.error(this.error); + case 'C': + return observer.complete && observer.complete(); + } + }; + Notification.prototype.do = function (next, error, complete) { + var kind = this.kind; + switch (kind) { + case 'N': + return next && next(this.value); + case 'E': + return error && error(this.error); + case 'C': + return complete && complete(); + } + }; + Notification.prototype.accept = function (nextOrObserver, error, complete) { + if (nextOrObserver && typeof nextOrObserver.next === 'function') { + return this.observe(nextOrObserver); + } + else { + return this.do(nextOrObserver, error, complete); + } + }; + Notification.prototype.toObservable = function () { + var kind = this.kind; + switch (kind) { + case 'N': + return of(this.value); + case 'E': + return throwError(this.error); + case 'C': + return empty$1(); + } + throw new Error('unexpected notification kind value'); + }; + Notification.createNext = function (value) { + if (typeof value !== 'undefined') { + return new Notification('N', value); + } + return Notification.undefinedValueNotification; + }; + Notification.createError = function (err) { + return new Notification('E', undefined, err); + }; + Notification.createComplete = function () { + return Notification.completeNotification; + }; + Notification.completeNotification = new Notification('C'); + Notification.undefinedValueNotification = new Notification('N', undefined); + return Notification; + }()); + + /** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ + function observeOn(scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + return function observeOnOperatorFunction(source) { + return source.lift(new ObserveOnOperator(scheduler, delay)); + }; + } + var ObserveOnOperator = /*@__PURE__*/ (function () { + function ObserveOnOperator(scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + this.scheduler = scheduler; + this.delay = delay; + } + ObserveOnOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ObserveOnSubscriber(subscriber, this.scheduler, this.delay)); + }; + return ObserveOnOperator; + }()); + var ObserveOnSubscriber = /*@__PURE__*/ (function (_super) { + __extends(ObserveOnSubscriber, _super); + function ObserveOnSubscriber(destination, scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + var _this = _super.call(this, destination) || this; + _this.scheduler = scheduler; + _this.delay = delay; + return _this; + } + ObserveOnSubscriber.dispatch = function (arg) { + var notification = arg.notification, destination = arg.destination; + notification.observe(destination); + this.unsubscribe(); + }; + ObserveOnSubscriber.prototype.scheduleMessage = function (notification) { + var destination = this.destination; + destination.add(this.scheduler.schedule(ObserveOnSubscriber.dispatch, this.delay, new ObserveOnMessage(notification, this.destination))); + }; + ObserveOnSubscriber.prototype._next = function (value) { + this.scheduleMessage(Notification.createNext(value)); + }; + ObserveOnSubscriber.prototype._error = function (err) { + this.scheduleMessage(Notification.createError(err)); + this.unsubscribe(); + }; + ObserveOnSubscriber.prototype._complete = function () { + this.scheduleMessage(Notification.createComplete()); + this.unsubscribe(); + }; + return ObserveOnSubscriber; + }(Subscriber)); + var ObserveOnMessage = /*@__PURE__*/ (function () { + function ObserveOnMessage(notification, destination) { + this.notification = notification; + this.destination = destination; + } + return ObserveOnMessage; + }()); + + /** PURE_IMPORTS_START tslib,_Subject,_scheduler_queue,_Subscription,_operators_observeOn,_util_ObjectUnsubscribedError,_SubjectSubscription PURE_IMPORTS_END */ + var ReplaySubject = /*@__PURE__*/ (function (_super) { + __extends(ReplaySubject, _super); + function ReplaySubject(bufferSize, windowTime, scheduler) { + if (bufferSize === void 0) { + bufferSize = Number.POSITIVE_INFINITY; + } + if (windowTime === void 0) { + windowTime = Number.POSITIVE_INFINITY; + } + var _this = _super.call(this) || this; + _this.scheduler = scheduler; + _this._events = []; + _this._infiniteTimeWindow = false; + _this._bufferSize = bufferSize < 1 ? 1 : bufferSize; + _this._windowTime = windowTime < 1 ? 1 : windowTime; + if (windowTime === Number.POSITIVE_INFINITY) { + _this._infiniteTimeWindow = true; + _this.next = _this.nextInfiniteTimeWindow; + } + else { + _this.next = _this.nextTimeWindow; + } + return _this; + } + ReplaySubject.prototype.nextInfiniteTimeWindow = function (value) { + if (!this.isStopped) { + var _events = this._events; + _events.push(value); + if (_events.length > this._bufferSize) { + _events.shift(); + } + } + _super.prototype.next.call(this, value); + }; + ReplaySubject.prototype.nextTimeWindow = function (value) { + if (!this.isStopped) { + this._events.push(new ReplayEvent(this._getNow(), value)); + this._trimBufferThenGetEvents(); + } + _super.prototype.next.call(this, value); + }; + ReplaySubject.prototype._subscribe = function (subscriber) { + var _infiniteTimeWindow = this._infiniteTimeWindow; + var _events = _infiniteTimeWindow ? this._events : this._trimBufferThenGetEvents(); + var scheduler = this.scheduler; + var len = _events.length; + var subscription; + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else if (this.isStopped || this.hasError) { + subscription = Subscription.EMPTY; + } + else { + this.observers.push(subscriber); + subscription = new SubjectSubscription(this, subscriber); + } + if (scheduler) { + subscriber.add(subscriber = new ObserveOnSubscriber(subscriber, scheduler)); + } + if (_infiniteTimeWindow) { + for (var i = 0; i < len && !subscriber.closed; i++) { + subscriber.next(_events[i]); + } + } + else { + for (var i = 0; i < len && !subscriber.closed; i++) { + subscriber.next(_events[i].value); + } + } + if (this.hasError) { + subscriber.error(this.thrownError); + } + else if (this.isStopped) { + subscriber.complete(); + } + return subscription; + }; + ReplaySubject.prototype._getNow = function () { + return (this.scheduler || queue).now(); + }; + ReplaySubject.prototype._trimBufferThenGetEvents = function () { + var now = this._getNow(); + var _bufferSize = this._bufferSize; + var _windowTime = this._windowTime; + var _events = this._events; + var eventsCount = _events.length; + var spliceCount = 0; + while (spliceCount < eventsCount) { + if ((now - _events[spliceCount].time) < _windowTime) { + break; + } + spliceCount++; + } + if (eventsCount > _bufferSize) { + spliceCount = Math.max(spliceCount, eventsCount - _bufferSize); + } + if (spliceCount > 0) { + _events.splice(0, spliceCount); + } + return _events; + }; + return ReplaySubject; + }(Subject)); + var ReplayEvent = /*@__PURE__*/ (function () { + function ReplayEvent(time, value) { + this.time = time; + this.value = value; + } + return ReplayEvent; + }()); + + /** PURE_IMPORTS_START _AsyncAction,_AsyncScheduler PURE_IMPORTS_END */ + var asyncScheduler = /*@__PURE__*/ new AsyncScheduler(AsyncAction); + var async = asyncScheduler; + + /** PURE_IMPORTS_START tslib,_AsyncAction PURE_IMPORTS_END */ + var AnimationFrameAction = /*@__PURE__*/ (function (_super) { + __extends(AnimationFrameAction, _super); + function AnimationFrameAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + return _this; + } + AnimationFrameAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { + delay = 0; + } + if (delay !== null && delay > 0) { + return _super.prototype.requestAsyncId.call(this, scheduler, id, delay); + } + scheduler.actions.push(this); + return scheduler.scheduled || (scheduler.scheduled = requestAnimationFrame(function () { return scheduler.flush(null); })); + }; + AnimationFrameAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { + delay = 0; + } + if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) { + return _super.prototype.recycleAsyncId.call(this, scheduler, id, delay); + } + if (scheduler.actions.length === 0) { + cancelAnimationFrame(id); + scheduler.scheduled = undefined; + } + return undefined; + }; + return AnimationFrameAction; + }(AsyncAction)); + + /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */ + var AnimationFrameScheduler = /*@__PURE__*/ (function (_super) { + __extends(AnimationFrameScheduler, _super); + function AnimationFrameScheduler() { + return _super !== null && _super.apply(this, arguments) || this; + } + AnimationFrameScheduler.prototype.flush = function (action) { + this.active = true; + this.scheduled = undefined; + var actions = this.actions; + var error; + var index = -1; + var count = actions.length; + action = action || actions.shift(); + do { + if (error = action.execute(action.state, action.delay)) { + break; + } + } while (++index < count && (action = actions.shift())); + this.active = false; + if (error) { + while (++index < count && (action = actions.shift())) { + action.unsubscribe(); + } + throw error; + } + }; + return AnimationFrameScheduler; + }(AsyncScheduler)); + + /** PURE_IMPORTS_START _AnimationFrameAction,_AnimationFrameScheduler PURE_IMPORTS_END */ + var animationFrameScheduler = /*@__PURE__*/ new AnimationFrameScheduler(AnimationFrameAction); + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function noop() { } + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var ArgumentOutOfRangeErrorImpl = /*@__PURE__*/ (function () { + function ArgumentOutOfRangeErrorImpl() { + Error.call(this); + this.message = 'argument out of range'; + this.name = 'ArgumentOutOfRangeError'; + return this; + } + ArgumentOutOfRangeErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype); + return ArgumentOutOfRangeErrorImpl; + })(); + var ArgumentOutOfRangeError = ArgumentOutOfRangeErrorImpl; + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var EmptyErrorImpl = /*@__PURE__*/ (function () { + function EmptyErrorImpl() { + Error.call(this); + this.message = 'no elements in sequence'; + this.name = 'EmptyError'; + return this; + } + EmptyErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype); + return EmptyErrorImpl; + })(); + var EmptyError = EmptyErrorImpl; + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function map(project, thisArg) { + return function mapOperation(source) { + if (typeof project !== 'function') { + throw new TypeError('argument is not a function. Are you looking for `mapTo()`?'); + } + return source.lift(new MapOperator(project, thisArg)); + }; + } + var MapOperator = /*@__PURE__*/ (function () { + function MapOperator(project, thisArg) { + this.project = project; + this.thisArg = thisArg; + } + MapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg)); + }; + return MapOperator; + }()); + var MapSubscriber = /*@__PURE__*/ (function (_super) { + __extends(MapSubscriber, _super); + function MapSubscriber(destination, project, thisArg) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.count = 0; + _this.thisArg = thisArg || _this; + return _this; + } + MapSubscriber.prototype._next = function (value) { + var result; + try { + result = this.project.call(this.thisArg, value, this.count++); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return MapSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + var OuterSubscriber = /*@__PURE__*/ (function (_super) { + __extends(OuterSubscriber, _super); + function OuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + OuterSubscriber.prototype.notifyError = function (error, innerSub) { + this.destination.error(error); + }; + OuterSubscriber.prototype.notifyComplete = function (innerSub) { + this.destination.complete(); + }; + return OuterSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + var InnerSubscriber = /*@__PURE__*/ (function (_super) { + __extends(InnerSubscriber, _super); + function InnerSubscriber(parent, outerValue, outerIndex) { + var _this = _super.call(this) || this; + _this.parent = parent; + _this.outerValue = outerValue; + _this.outerIndex = outerIndex; + _this.index = 0; + return _this; + } + InnerSubscriber.prototype._next = function (value) { + this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this); + }; + InnerSubscriber.prototype._error = function (error) { + this.parent.notifyError(error, this); + this.unsubscribe(); + }; + InnerSubscriber.prototype._complete = function () { + this.parent.notifyComplete(this); + this.unsubscribe(); + }; + return InnerSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _hostReportError PURE_IMPORTS_END */ + var subscribeToPromise = function (promise) { + return function (subscriber) { + promise.then(function (value) { + if (!subscriber.closed) { + subscriber.next(value); + subscriber.complete(); + } + }, function (err) { return subscriber.error(err); }) + .then(null, hostReportError); + return subscriber; + }; + }; + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function getSymbolIterator() { + if (typeof Symbol !== 'function' || !Symbol.iterator) { + return '@@iterator'; + } + return Symbol.iterator; + } + var iterator = /*@__PURE__*/ getSymbolIterator(); + + /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */ + var subscribeToIterable = function (iterable) { + return function (subscriber) { + var iterator$1 = iterable[iterator](); + do { + var item = void 0; + try { + item = iterator$1.next(); + } + catch (err) { + subscriber.error(err); + return subscriber; + } + if (item.done) { + subscriber.complete(); + break; + } + subscriber.next(item.value); + if (subscriber.closed) { + break; + } + } while (true); + if (typeof iterator$1.return === 'function') { + subscriber.add(function () { + if (iterator$1.return) { + iterator$1.return(); + } + }); + } + return subscriber; + }; + }; + + /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */ + var subscribeToObservable = function (obj) { + return function (subscriber) { + var obs = obj[observable](); + if (typeof obs.subscribe !== 'function') { + throw new TypeError('Provided object does not correctly implement Symbol.observable'); + } + else { + return obs.subscribe(subscriber); + } + }; + }; + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; }); + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function isPromise(value) { + return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function'; + } + + /** PURE_IMPORTS_START _subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */ + var subscribeTo = function (result) { + if (!!result && typeof result[observable] === 'function') { + return subscribeToObservable(result); + } + else if (isArrayLike(result)) { + return subscribeToArray(result); + } + else if (isPromise(result)) { + return subscribeToPromise(result); + } + else if (!!result && typeof result[iterator] === 'function') { + return subscribeToIterable(result); + } + else { + var value = isObject(result) ? 'an invalid object' : "'" + result + "'"; + var msg = "You provided " + value + " where a stream was expected." + + ' You can provide an Observable, Promise, Array, or Iterable.'; + throw new TypeError(msg); + } + }; + + /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo,_Observable PURE_IMPORTS_END */ + function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, innerSubscriber) { + if (innerSubscriber === void 0) { + innerSubscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex); + } + if (innerSubscriber.closed) { + return undefined; + } + if (result instanceof Observable) { + return result.subscribe(innerSubscriber); + } + return subscribeTo(result)(innerSubscriber); + } + + /** PURE_IMPORTS_START tslib,_util_isScheduler,_util_isArray,_OuterSubscriber,_util_subscribeToResult,_fromArray PURE_IMPORTS_END */ + var NONE = {}; + function combineLatest() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var resultSelector = undefined; + var scheduler = undefined; + if (isScheduler(observables[observables.length - 1])) { + scheduler = observables.pop(); + } + if (typeof observables[observables.length - 1] === 'function') { + resultSelector = observables.pop(); + } + if (observables.length === 1 && isArray(observables[0])) { + observables = observables[0]; + } + return fromArray(observables, scheduler).lift(new CombineLatestOperator(resultSelector)); + } + var CombineLatestOperator = /*@__PURE__*/ (function () { + function CombineLatestOperator(resultSelector) { + this.resultSelector = resultSelector; + } + CombineLatestOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CombineLatestSubscriber(subscriber, this.resultSelector)); + }; + return CombineLatestOperator; + }()); + var CombineLatestSubscriber = /*@__PURE__*/ (function (_super) { + __extends(CombineLatestSubscriber, _super); + function CombineLatestSubscriber(destination, resultSelector) { + var _this = _super.call(this, destination) || this; + _this.resultSelector = resultSelector; + _this.active = 0; + _this.values = []; + _this.observables = []; + return _this; + } + CombineLatestSubscriber.prototype._next = function (observable) { + this.values.push(NONE); + this.observables.push(observable); + }; + CombineLatestSubscriber.prototype._complete = function () { + var observables = this.observables; + var len = observables.length; + if (len === 0) { + this.destination.complete(); + } + else { + this.active = len; + this.toRespond = len; + for (var i = 0; i < len; i++) { + var observable = observables[i]; + this.add(subscribeToResult(this, observable, undefined, i)); + } + } + }; + CombineLatestSubscriber.prototype.notifyComplete = function (unused) { + if ((this.active -= 1) === 0) { + this.destination.complete(); + } + }; + CombineLatestSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + var values = this.values; + var oldVal = values[outerIndex]; + var toRespond = !this.toRespond + ? 0 + : oldVal === NONE ? --this.toRespond : this.toRespond; + values[outerIndex] = innerValue; + if (toRespond === 0) { + if (this.resultSelector) { + this._tryResultSelector(values); + } + else { + this.destination.next(values.slice()); + } + } + }; + CombineLatestSubscriber.prototype._tryResultSelector = function (values) { + var result; + try { + result = this.resultSelector.apply(this, values); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return CombineLatestSubscriber; + }(OuterSubscriber)); + + /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_observable PURE_IMPORTS_END */ + function scheduleObservable(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + sub.add(scheduler.schedule(function () { + var observable$1 = input[observable](); + sub.add(observable$1.subscribe({ + next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); }, + error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); }, + complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); }, + })); + })); + return sub; + }); + } + + /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */ + function schedulePromise(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + sub.add(scheduler.schedule(function () { + return input.then(function (value) { + sub.add(scheduler.schedule(function () { + subscriber.next(value); + sub.add(scheduler.schedule(function () { return subscriber.complete(); })); + })); + }, function (err) { + sub.add(scheduler.schedule(function () { return subscriber.error(err); })); + }); + })); + return sub; + }); + } + + /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_iterator PURE_IMPORTS_END */ + function scheduleIterable(input, scheduler) { + if (!input) { + throw new Error('Iterable cannot be null'); + } + return new Observable(function (subscriber) { + var sub = new Subscription(); + var iterator$1; + sub.add(function () { + if (iterator$1 && typeof iterator$1.return === 'function') { + iterator$1.return(); + } + }); + sub.add(scheduler.schedule(function () { + iterator$1 = input[iterator](); + sub.add(scheduler.schedule(function () { + if (subscriber.closed) { + return; + } + var value; + var done; + try { + var result = iterator$1.next(); + value = result.value; + done = result.done; + } + catch (err) { + subscriber.error(err); + return; + } + if (done) { + subscriber.complete(); + } + else { + subscriber.next(value); + this.schedule(); + } + })); + })); + return sub; + }); + } + + /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */ + function isInteropObservable(input) { + return input && typeof input[observable] === 'function'; + } + + /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */ + function isIterable(input) { + return input && typeof input[iterator] === 'function'; + } + + /** PURE_IMPORTS_START _scheduleObservable,_schedulePromise,_scheduleArray,_scheduleIterable,_util_isInteropObservable,_util_isPromise,_util_isArrayLike,_util_isIterable PURE_IMPORTS_END */ + function scheduled(input, scheduler) { + if (input != null) { + if (isInteropObservable(input)) { + return scheduleObservable(input, scheduler); + } + else if (isPromise(input)) { + return schedulePromise(input, scheduler); + } + else if (isArrayLike(input)) { + return scheduleArray(input, scheduler); + } + else if (isIterable(input) || typeof input === 'string') { + return scheduleIterable(input, scheduler); + } + } + throw new TypeError((input !== null && typeof input || input) + ' is not observable'); + } + + /** PURE_IMPORTS_START _Observable,_util_subscribeTo,_scheduled_scheduled PURE_IMPORTS_END */ + function from(input, scheduler) { + if (!scheduler) { + if (input instanceof Observable) { + return input; + } + return new Observable(subscribeTo(input)); + } + else { + return scheduled(input, scheduler); + } + } + + /** PURE_IMPORTS_START tslib,_Subscriber,_Observable,_util_subscribeTo PURE_IMPORTS_END */ + var SimpleInnerSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SimpleInnerSubscriber, _super); + function SimpleInnerSubscriber(parent) { + var _this = _super.call(this) || this; + _this.parent = parent; + return _this; + } + SimpleInnerSubscriber.prototype._next = function (value) { + this.parent.notifyNext(value); + }; + SimpleInnerSubscriber.prototype._error = function (error) { + this.parent.notifyError(error); + this.unsubscribe(); + }; + SimpleInnerSubscriber.prototype._complete = function () { + this.parent.notifyComplete(); + this.unsubscribe(); + }; + return SimpleInnerSubscriber; + }(Subscriber)); + var SimpleOuterSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SimpleOuterSubscriber, _super); + function SimpleOuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + SimpleOuterSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + SimpleOuterSubscriber.prototype.notifyError = function (err) { + this.destination.error(err); + }; + SimpleOuterSubscriber.prototype.notifyComplete = function () { + this.destination.complete(); + }; + return SimpleOuterSubscriber; + }(Subscriber)); + function innerSubscribe(result, innerSubscriber) { + if (innerSubscriber.closed) { + return undefined; + } + if (result instanceof Observable) { + return result.subscribe(innerSubscriber); + } + return subscribeTo(result)(innerSubscriber); + } + + /** PURE_IMPORTS_START tslib,_map,_observable_from,_innerSubscribe PURE_IMPORTS_END */ + function mergeMap(project, resultSelector, concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; + } + if (typeof resultSelector === 'function') { + return function (source) { return source.pipe(mergeMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); }, concurrent)); }; + } + else if (typeof resultSelector === 'number') { + concurrent = resultSelector; + } + return function (source) { return source.lift(new MergeMapOperator(project, concurrent)); }; + } + var MergeMapOperator = /*@__PURE__*/ (function () { + function MergeMapOperator(project, concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; + } + this.project = project; + this.concurrent = concurrent; + } + MergeMapOperator.prototype.call = function (observer, source) { + return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent)); + }; + return MergeMapOperator; + }()); + var MergeMapSubscriber = /*@__PURE__*/ (function (_super) { + __extends(MergeMapSubscriber, _super); + function MergeMapSubscriber(destination, project, concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; + } + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.concurrent = concurrent; + _this.hasCompleted = false; + _this.buffer = []; + _this.active = 0; + _this.index = 0; + return _this; + } + MergeMapSubscriber.prototype._next = function (value) { + if (this.active < this.concurrent) { + this._tryNext(value); + } + else { + this.buffer.push(value); + } + }; + MergeMapSubscriber.prototype._tryNext = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (err) { + this.destination.error(err); + return; + } + this.active++; + this._innerSub(result); + }; + MergeMapSubscriber.prototype._innerSub = function (ish) { + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = innerSubscribe(ish, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } + }; + MergeMapSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.active === 0 && this.buffer.length === 0) { + this.destination.complete(); + } + this.unsubscribe(); + }; + MergeMapSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + MergeMapSubscriber.prototype.notifyComplete = function () { + var buffer = this.buffer; + this.active--; + if (buffer.length > 0) { + this._next(buffer.shift()); + } + else if (this.active === 0 && this.hasCompleted) { + this.destination.complete(); + } + }; + return MergeMapSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START _mergeMap,_util_identity PURE_IMPORTS_END */ + function mergeAll(concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; + } + return mergeMap(identity, concurrent); + } + + /** PURE_IMPORTS_START _mergeAll PURE_IMPORTS_END */ + function concatAll() { + return mergeAll(1); + } + + /** PURE_IMPORTS_START _of,_operators_concatAll PURE_IMPORTS_END */ + function concat() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return concatAll()(of.apply(void 0, observables)); + } + + /** PURE_IMPORTS_START _Observable,_util_isArray,_util_isFunction,_operators_map PURE_IMPORTS_END */ + function fromEvent(target, eventName, options, resultSelector) { + if (isFunction(options)) { + resultSelector = options; + options = undefined; + } + if (resultSelector) { + return fromEvent(target, eventName, options).pipe(map(function (args) { return isArray(args) ? resultSelector.apply(void 0, args) : resultSelector(args); })); + } + return new Observable(function (subscriber) { + function handler(e) { + if (arguments.length > 1) { + subscriber.next(Array.prototype.slice.call(arguments)); + } + else { + subscriber.next(e); + } + } + setupSubscription(target, eventName, handler, subscriber, options); + }); + } + function setupSubscription(sourceObj, eventName, handler, subscriber, options) { + var unsubscribe; + if (isEventTarget(sourceObj)) { + var source_1 = sourceObj; + sourceObj.addEventListener(eventName, handler, options); + unsubscribe = function () { return source_1.removeEventListener(eventName, handler, options); }; + } + else if (isJQueryStyleEventEmitter(sourceObj)) { + var source_2 = sourceObj; + sourceObj.on(eventName, handler); + unsubscribe = function () { return source_2.off(eventName, handler); }; + } + else if (isNodeStyleEventEmitter(sourceObj)) { + var source_3 = sourceObj; + sourceObj.addListener(eventName, handler); + unsubscribe = function () { return source_3.removeListener(eventName, handler); }; + } + else if (sourceObj && sourceObj.length) { + for (var i = 0, len = sourceObj.length; i < len; i++) { + setupSubscription(sourceObj[i], eventName, handler, subscriber, options); + } + } + else { + throw new TypeError('Invalid event target'); + } + subscriber.add(unsubscribe); + } + function isNodeStyleEventEmitter(sourceObj) { + return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function'; + } + function isJQueryStyleEventEmitter(sourceObj) { + return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function'; + } + function isEventTarget(sourceObj) { + return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function'; + } + + /** PURE_IMPORTS_START _isArray PURE_IMPORTS_END */ + function isNumeric(val) { + return !isArray(val) && (val - parseFloat(val) + 1) >= 0; + } + + /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric PURE_IMPORTS_END */ + function interval(period, scheduler) { + if (period === void 0) { + period = 0; + } + if (scheduler === void 0) { + scheduler = async; + } + if (!isNumeric(period) || period < 0) { + period = 0; + } + if (!scheduler || typeof scheduler.schedule !== 'function') { + scheduler = async; + } + return new Observable(function (subscriber) { + subscriber.add(scheduler.schedule(dispatch$1, period, { subscriber: subscriber, counter: 0, period: period })); + return subscriber; + }); + } + function dispatch$1(state) { + var subscriber = state.subscriber, counter = state.counter, period = state.period; + subscriber.next(counter); + this.schedule({ subscriber: subscriber, counter: counter + 1, period: period }, period); + } + + /** PURE_IMPORTS_START _Observable,_util_isScheduler,_operators_mergeAll,_fromArray PURE_IMPORTS_END */ + function merge() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var concurrent = Number.POSITIVE_INFINITY; + var scheduler = null; + var last = observables[observables.length - 1]; + if (isScheduler(last)) { + scheduler = observables.pop(); + if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') { + concurrent = observables.pop(); + } + } + else if (typeof last === 'number') { + concurrent = observables.pop(); + } + if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) { + return observables[0]; + } + return mergeAll(concurrent)(fromArray(observables, scheduler)); + } + + /** PURE_IMPORTS_START _Observable,_util_noop PURE_IMPORTS_END */ + var NEVER = /*@__PURE__*/ new Observable(noop); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function filter(predicate, thisArg) { + return function filterOperatorFunction(source) { + return source.lift(new FilterOperator(predicate, thisArg)); + }; + } + var FilterOperator = /*@__PURE__*/ (function () { + function FilterOperator(predicate, thisArg) { + this.predicate = predicate; + this.thisArg = thisArg; + } + FilterOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new FilterSubscriber(subscriber, this.predicate, this.thisArg)); + }; + return FilterOperator; + }()); + var FilterSubscriber = /*@__PURE__*/ (function (_super) { + __extends(FilterSubscriber, _super); + function FilterSubscriber(destination, predicate, thisArg) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.thisArg = thisArg; + _this.count = 0; + return _this; + } + FilterSubscriber.prototype._next = function (value) { + var result; + try { + result = this.predicate.call(this.thisArg, value, this.count++); + } + catch (err) { + this.destination.error(err); + return; + } + if (result) { + this.destination.next(value); + } + }; + return FilterSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_util_isArray,_fromArray,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ + function race() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + if (observables.length === 1) { + if (isArray(observables[0])) { + observables = observables[0]; + } + else { + return observables[0]; + } + } + return fromArray(observables, undefined).lift(new RaceOperator()); + } + var RaceOperator = /*@__PURE__*/ (function () { + function RaceOperator() { + } + RaceOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RaceSubscriber(subscriber)); + }; + return RaceOperator; + }()); + var RaceSubscriber = /*@__PURE__*/ (function (_super) { + __extends(RaceSubscriber, _super); + function RaceSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasFirst = false; + _this.observables = []; + _this.subscriptions = []; + return _this; + } + RaceSubscriber.prototype._next = function (observable) { + this.observables.push(observable); + }; + RaceSubscriber.prototype._complete = function () { + var observables = this.observables; + var len = observables.length; + if (len === 0) { + this.destination.complete(); + } + else { + for (var i = 0; i < len && !this.hasFirst; i++) { + var observable = observables[i]; + var subscription = subscribeToResult(this, observable, undefined, i); + if (this.subscriptions) { + this.subscriptions.push(subscription); + } + this.add(subscription); + } + this.observables = null; + } + }; + RaceSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + if (!this.hasFirst) { + this.hasFirst = true; + for (var i = 0; i < this.subscriptions.length; i++) { + if (i !== outerIndex) { + var subscription = this.subscriptions[i]; + subscription.unsubscribe(); + this.remove(subscription); + } + } + this.subscriptions = null; + } + this.destination.next(innerValue); + }; + return RaceSubscriber; + }(OuterSubscriber)); + + /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ + function timer(dueTime, periodOrScheduler, scheduler) { + if (dueTime === void 0) { + dueTime = 0; + } + var period = -1; + if (isNumeric(periodOrScheduler)) { + period = Number(periodOrScheduler) < 1 && 1 || Number(periodOrScheduler); + } + else if (isScheduler(periodOrScheduler)) { + scheduler = periodOrScheduler; + } + if (!isScheduler(scheduler)) { + scheduler = async; + } + return new Observable(function (subscriber) { + var due = isNumeric(dueTime) + ? dueTime + : (+dueTime - scheduler.now()); + return scheduler.schedule(dispatch$2, due, { + index: 0, period: period, subscriber: subscriber + }); + }); + } + function dispatch$2(state) { + var index = state.index, period = state.period, subscriber = state.subscriber; + subscriber.next(index); + if (subscriber.closed) { + return; + } + else if (period === -1) { + return subscriber.complete(); + } + state.index = index + 1; + this.schedule(state, period); + } + + /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ + function catchError(selector) { + return function catchErrorOperatorFunction(source) { + var operator = new CatchOperator(selector); + var caught = source.lift(operator); + return (operator.caught = caught); + }; + } + var CatchOperator = /*@__PURE__*/ (function () { + function CatchOperator(selector) { + this.selector = selector; + } + CatchOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CatchSubscriber(subscriber, this.selector, this.caught)); + }; + return CatchOperator; + }()); + var CatchSubscriber = /*@__PURE__*/ (function (_super) { + __extends(CatchSubscriber, _super); + function CatchSubscriber(destination, selector, caught) { + var _this = _super.call(this, destination) || this; + _this.selector = selector; + _this.caught = caught; + return _this; + } + CatchSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var result = void 0; + try { + result = this.selector(err, this.caught); + } + catch (err2) { + _super.prototype.error.call(this, err2); + return; + } + this._unsubscribeAndRecycle(); + var innerSubscriber = new SimpleInnerSubscriber(this); + this.add(innerSubscriber); + var innerSubscription = innerSubscribe(result, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + this.add(innerSubscription); + } + } + }; + return CatchSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function count(predicate) { + return function (source) { return source.lift(new CountOperator(predicate, source)); }; + } + var CountOperator = /*@__PURE__*/ (function () { + function CountOperator(predicate, source) { + this.predicate = predicate; + this.source = source; + } + CountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CountSubscriber(subscriber, this.predicate, this.source)); + }; + return CountOperator; + }()); + var CountSubscriber = /*@__PURE__*/ (function (_super) { + __extends(CountSubscriber, _super); + function CountSubscriber(destination, predicate, source) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.source = source; + _this.count = 0; + _this.index = 0; + return _this; + } + CountSubscriber.prototype._next = function (value) { + if (this.predicate) { + this._tryPredicate(value); + } + else { + this.count++; + } + }; + CountSubscriber.prototype._tryPredicate = function (value) { + var result; + try { + result = this.predicate(value, this.index++, this.source); + } + catch (err) { + this.destination.error(err); + return; + } + if (result) { + this.count++; + } + }; + CountSubscriber.prototype._complete = function () { + this.destination.next(this.count); + this.destination.complete(); + }; + return CountSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */ + function debounceTime(dueTime, scheduler) { + if (scheduler === void 0) { + scheduler = async; + } + return function (source) { return source.lift(new DebounceTimeOperator(dueTime, scheduler)); }; + } + var DebounceTimeOperator = /*@__PURE__*/ (function () { + function DebounceTimeOperator(dueTime, scheduler) { + this.dueTime = dueTime; + this.scheduler = scheduler; + } + DebounceTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler)); + }; + return DebounceTimeOperator; + }()); + var DebounceTimeSubscriber = /*@__PURE__*/ (function (_super) { + __extends(DebounceTimeSubscriber, _super); + function DebounceTimeSubscriber(destination, dueTime, scheduler) { + var _this = _super.call(this, destination) || this; + _this.dueTime = dueTime; + _this.scheduler = scheduler; + _this.debouncedSubscription = null; + _this.lastValue = null; + _this.hasValue = false; + return _this; + } + DebounceTimeSubscriber.prototype._next = function (value) { + this.clearDebounce(); + this.lastValue = value; + this.hasValue = true; + this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this)); + }; + DebounceTimeSubscriber.prototype._complete = function () { + this.debouncedNext(); + this.destination.complete(); + }; + DebounceTimeSubscriber.prototype.debouncedNext = function () { + this.clearDebounce(); + if (this.hasValue) { + var lastValue = this.lastValue; + this.lastValue = null; + this.hasValue = false; + this.destination.next(lastValue); + } + }; + DebounceTimeSubscriber.prototype.clearDebounce = function () { + var debouncedSubscription = this.debouncedSubscription; + if (debouncedSubscription !== null) { + this.remove(debouncedSubscription); + debouncedSubscription.unsubscribe(); + this.debouncedSubscription = null; + } + }; + return DebounceTimeSubscriber; + }(Subscriber)); + function dispatchNext(subscriber) { + subscriber.debouncedNext(); + } + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function defaultIfEmpty(defaultValue) { + if (defaultValue === void 0) { + defaultValue = null; + } + return function (source) { return source.lift(new DefaultIfEmptyOperator(defaultValue)); }; + } + var DefaultIfEmptyOperator = /*@__PURE__*/ (function () { + function DefaultIfEmptyOperator(defaultValue) { + this.defaultValue = defaultValue; + } + DefaultIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue)); + }; + return DefaultIfEmptyOperator; + }()); + var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { + __extends(DefaultIfEmptySubscriber, _super); + function DefaultIfEmptySubscriber(destination, defaultValue) { + var _this = _super.call(this, destination) || this; + _this.defaultValue = defaultValue; + _this.isEmpty = true; + return _this; + } + DefaultIfEmptySubscriber.prototype._next = function (value) { + this.isEmpty = false; + this.destination.next(value); + }; + DefaultIfEmptySubscriber.prototype._complete = function () { + if (this.isEmpty) { + this.destination.next(this.defaultValue); + } + this.destination.complete(); + }; + return DefaultIfEmptySubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START PURE_IMPORTS_END */ + function isDate(value) { + return value instanceof Date && !isNaN(+value); + } + + /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ + function delay(delay, scheduler) { + if (scheduler === void 0) { + scheduler = async; + } + var absoluteDelay = isDate(delay); + var delayFor = absoluteDelay ? (+delay - scheduler.now()) : Math.abs(delay); + return function (source) { return source.lift(new DelayOperator(delayFor, scheduler)); }; + } + var DelayOperator = /*@__PURE__*/ (function () { + function DelayOperator(delay, scheduler) { + this.delay = delay; + this.scheduler = scheduler; + } + DelayOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DelaySubscriber(subscriber, this.delay, this.scheduler)); + }; + return DelayOperator; + }()); + var DelaySubscriber = /*@__PURE__*/ (function (_super) { + __extends(DelaySubscriber, _super); + function DelaySubscriber(destination, delay, scheduler) { + var _this = _super.call(this, destination) || this; + _this.delay = delay; + _this.scheduler = scheduler; + _this.queue = []; + _this.active = false; + _this.errored = false; + return _this; + } + DelaySubscriber.dispatch = function (state) { + var source = state.source; + var queue = source.queue; + var scheduler = state.scheduler; + var destination = state.destination; + while (queue.length > 0 && (queue[0].time - scheduler.now()) <= 0) { + queue.shift().notification.observe(destination); + } + if (queue.length > 0) { + var delay_1 = Math.max(0, queue[0].time - scheduler.now()); + this.schedule(state, delay_1); + } + else { + this.unsubscribe(); + source.active = false; + } + }; + DelaySubscriber.prototype._schedule = function (scheduler) { + this.active = true; + var destination = this.destination; + destination.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, { + source: this, destination: this.destination, scheduler: scheduler + })); + }; + DelaySubscriber.prototype.scheduleNotification = function (notification) { + if (this.errored === true) { + return; + } + var scheduler = this.scheduler; + var message = new DelayMessage(scheduler.now() + this.delay, notification); + this.queue.push(message); + if (this.active === false) { + this._schedule(scheduler); + } + }; + DelaySubscriber.prototype._next = function (value) { + this.scheduleNotification(Notification.createNext(value)); + }; + DelaySubscriber.prototype._error = function (err) { + this.errored = true; + this.queue = []; + this.destination.error(err); + this.unsubscribe(); + }; + DelaySubscriber.prototype._complete = function () { + this.scheduleNotification(Notification.createComplete()); + this.unsubscribe(); + }; + return DelaySubscriber; + }(Subscriber)); + var DelayMessage = /*@__PURE__*/ (function () { + function DelayMessage(time, notification) { + this.time = time; + this.notification = notification; + } + return DelayMessage; + }()); + + /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ + function distinct(keySelector, flushes) { + return function (source) { return source.lift(new DistinctOperator(keySelector, flushes)); }; + } + var DistinctOperator = /*@__PURE__*/ (function () { + function DistinctOperator(keySelector, flushes) { + this.keySelector = keySelector; + this.flushes = flushes; + } + DistinctOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctSubscriber(subscriber, this.keySelector, this.flushes)); + }; + return DistinctOperator; + }()); + var DistinctSubscriber = /*@__PURE__*/ (function (_super) { + __extends(DistinctSubscriber, _super); + function DistinctSubscriber(destination, keySelector, flushes) { + var _this = _super.call(this, destination) || this; + _this.keySelector = keySelector; + _this.values = new Set(); + if (flushes) { + _this.add(innerSubscribe(flushes, new SimpleInnerSubscriber(_this))); + } + return _this; + } + DistinctSubscriber.prototype.notifyNext = function () { + this.values.clear(); + }; + DistinctSubscriber.prototype.notifyError = function (error) { + this._error(error); + }; + DistinctSubscriber.prototype._next = function (value) { + if (this.keySelector) { + this._useKeySelector(value); + } + else { + this._finalizeNext(value, value); + } + }; + DistinctSubscriber.prototype._useKeySelector = function (value) { + var key; + var destination = this.destination; + try { + key = this.keySelector(value); + } + catch (err) { + destination.error(err); + return; + } + this._finalizeNext(key, value); + }; + DistinctSubscriber.prototype._finalizeNext = function (key, value) { + var values = this.values; + if (!values.has(key)) { + values.add(key); + this.destination.next(value); + } + }; + return DistinctSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function distinctUntilChanged(compare, keySelector) { + return function (source) { return source.lift(new DistinctUntilChangedOperator(compare, keySelector)); }; + } + var DistinctUntilChangedOperator = /*@__PURE__*/ (function () { + function DistinctUntilChangedOperator(compare, keySelector) { + this.compare = compare; + this.keySelector = keySelector; + } + DistinctUntilChangedOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector)); + }; + return DistinctUntilChangedOperator; + }()); + var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { + __extends(DistinctUntilChangedSubscriber, _super); + function DistinctUntilChangedSubscriber(destination, compare, keySelector) { + var _this = _super.call(this, destination) || this; + _this.keySelector = keySelector; + _this.hasKey = false; + if (typeof compare === 'function') { + _this.compare = compare; + } + return _this; + } + DistinctUntilChangedSubscriber.prototype.compare = function (x, y) { + return x === y; + }; + DistinctUntilChangedSubscriber.prototype._next = function (value) { + var key; + try { + var keySelector = this.keySelector; + key = keySelector ? keySelector(value) : value; + } + catch (err) { + return this.destination.error(err); + } + var result = false; + if (this.hasKey) { + try { + var compare = this.compare; + result = compare(this.key, key); + } + catch (err) { + return this.destination.error(err); + } + } + else { + this.hasKey = true; + } + if (!result) { + this.key = key; + this.destination.next(value); + } + }; + return DistinctUntilChangedSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ + function distinctUntilKeyChanged(key, compare) { + return distinctUntilChanged(function (x, y) { return compare ? compare(x[key], y[key]) : x[key] === y[key]; }); + } + + /** PURE_IMPORTS_START tslib,_util_EmptyError,_Subscriber PURE_IMPORTS_END */ + function throwIfEmpty(errorFactory) { + if (errorFactory === void 0) { + errorFactory = defaultErrorFactory; + } + return function (source) { + return source.lift(new ThrowIfEmptyOperator(errorFactory)); + }; + } + var ThrowIfEmptyOperator = /*@__PURE__*/ (function () { + function ThrowIfEmptyOperator(errorFactory) { + this.errorFactory = errorFactory; + } + ThrowIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrowIfEmptySubscriber(subscriber, this.errorFactory)); + }; + return ThrowIfEmptyOperator; + }()); + var ThrowIfEmptySubscriber = /*@__PURE__*/ (function (_super) { + __extends(ThrowIfEmptySubscriber, _super); + function ThrowIfEmptySubscriber(destination, errorFactory) { + var _this = _super.call(this, destination) || this; + _this.errorFactory = errorFactory; + _this.hasValue = false; + return _this; + } + ThrowIfEmptySubscriber.prototype._next = function (value) { + this.hasValue = true; + this.destination.next(value); + }; + ThrowIfEmptySubscriber.prototype._complete = function () { + if (!this.hasValue) { + var err = void 0; + try { + err = this.errorFactory(); + } + catch (e) { + err = e; + } + this.destination.error(err); + } + else { + return this.destination.complete(); + } + }; + return ThrowIfEmptySubscriber; + }(Subscriber)); + function defaultErrorFactory() { + return new EmptyError(); + } + + /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ + function take(count) { + return function (source) { + if (count === 0) { + return empty$1(); + } + else { + return source.lift(new TakeOperator(count)); + } + }; + } + var TakeOperator = /*@__PURE__*/ (function () { + function TakeOperator(total) { + this.total = total; + if (this.total < 0) { + throw new ArgumentOutOfRangeError; + } + } + TakeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeSubscriber(subscriber, this.total)); + }; + return TakeOperator; + }()); + var TakeSubscriber = /*@__PURE__*/ (function (_super) { + __extends(TakeSubscriber, _super); + function TakeSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.count = 0; + return _this; + } + TakeSubscriber.prototype._next = function (value) { + var total = this.total; + var count = ++this.count; + if (count <= total) { + this.destination.next(value); + if (count === total) { + this.destination.complete(); + this.unsubscribe(); + } + } + }; + return TakeSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _observable_concat,_observable_of PURE_IMPORTS_END */ + function endWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + return function (source) { return concat(source, of.apply(void 0, array)); }; + } + + /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ + function exhaust() { + return function (source) { return source.lift(new SwitchFirstOperator()); }; + } + var SwitchFirstOperator = /*@__PURE__*/ (function () { + function SwitchFirstOperator() { + } + SwitchFirstOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchFirstSubscriber(subscriber)); + }; + return SwitchFirstOperator; + }()); + var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SwitchFirstSubscriber, _super); + function SwitchFirstSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasCompleted = false; + _this.hasSubscription = false; + return _this; + } + SwitchFirstSubscriber.prototype._next = function (value) { + if (!this.hasSubscription) { + this.hasSubscription = true; + this.add(innerSubscribe(value, new SimpleInnerSubscriber(this))); + } + }; + SwitchFirstSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (!this.hasSubscription) { + this.destination.complete(); + } + }; + SwitchFirstSubscriber.prototype.notifyComplete = function () { + this.hasSubscription = false; + if (this.hasCompleted) { + this.destination.complete(); + } + }; + return SwitchFirstSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber,_Subscription PURE_IMPORTS_END */ + function finalize(callback) { + return function (source) { return source.lift(new FinallyOperator(callback)); }; + } + var FinallyOperator = /*@__PURE__*/ (function () { + function FinallyOperator(callback) { + this.callback = callback; + } + FinallyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new FinallySubscriber(subscriber, this.callback)); + }; + return FinallyOperator; + }()); + var FinallySubscriber = /*@__PURE__*/ (function (_super) { + __extends(FinallySubscriber, _super); + function FinallySubscriber(destination, callback) { + var _this = _super.call(this, destination) || this; + _this.add(new Subscription(callback)); + return _this; + } + return FinallySubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ + function first(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, take(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); }; + } + + /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ + function takeLast(count) { + return function takeLastOperatorFunction(source) { + if (count === 0) { + return empty$1(); + } + else { + return source.lift(new TakeLastOperator(count)); + } + }; + } + var TakeLastOperator = /*@__PURE__*/ (function () { + function TakeLastOperator(total) { + this.total = total; + if (this.total < 0) { + throw new ArgumentOutOfRangeError; + } + } + TakeLastOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeLastSubscriber(subscriber, this.total)); + }; + return TakeLastOperator; + }()); + var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { + __extends(TakeLastSubscriber, _super); + function TakeLastSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.ring = new Array(); + _this.count = 0; + return _this; + } + TakeLastSubscriber.prototype._next = function (value) { + var ring = this.ring; + var total = this.total; + var count = this.count++; + if (ring.length < total) { + ring.push(value); + } + else { + var index = count % total; + ring[index] = value; + } + }; + TakeLastSubscriber.prototype._complete = function () { + var destination = this.destination; + var count = this.count; + if (count > 0) { + var total = this.count >= this.total ? this.total : this.count; + var ring = this.ring; + for (var i = 0; i < total; i++) { + var idx = (count++) % total; + destination.next(ring[idx]); + } + } + destination.complete(); + }; + return TakeLastSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ + function last(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, takeLast(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); }; + } + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function mapTo(value) { + return function (source) { return source.lift(new MapToOperator(value)); }; + } + var MapToOperator = /*@__PURE__*/ (function () { + function MapToOperator(value) { + this.value = value; + } + MapToOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MapToSubscriber(subscriber, this.value)); + }; + return MapToOperator; + }()); + var MapToSubscriber = /*@__PURE__*/ (function (_super) { + __extends(MapToSubscriber, _super); + function MapToSubscriber(destination, value) { + var _this = _super.call(this, destination) || this; + _this.value = value; + return _this; + } + MapToSubscriber.prototype._next = function (x) { + this.destination.next(this.value); + }; + return MapToSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function scan(accumulator, seed) { + var hasSeed = false; + if (arguments.length >= 2) { + hasSeed = true; + } + return function scanOperatorFunction(source) { + return source.lift(new ScanOperator(accumulator, seed, hasSeed)); + }; + } + var ScanOperator = /*@__PURE__*/ (function () { + function ScanOperator(accumulator, seed, hasSeed) { + if (hasSeed === void 0) { + hasSeed = false; + } + this.accumulator = accumulator; + this.seed = seed; + this.hasSeed = hasSeed; + } + ScanOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ScanSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed)); + }; + return ScanOperator; + }()); + var ScanSubscriber = /*@__PURE__*/ (function (_super) { + __extends(ScanSubscriber, _super); + function ScanSubscriber(destination, accumulator, _seed, hasSeed) { + var _this = _super.call(this, destination) || this; + _this.accumulator = accumulator; + _this._seed = _seed; + _this.hasSeed = hasSeed; + _this.index = 0; + return _this; + } + Object.defineProperty(ScanSubscriber.prototype, "seed", { + get: function () { + return this._seed; + }, + set: function (value) { + this.hasSeed = true; + this._seed = value; + }, + enumerable: true, + configurable: true + }); + ScanSubscriber.prototype._next = function (value) { + if (!this.hasSeed) { + this.seed = value; + this.destination.next(value); + } + else { + return this._tryNext(value); + } + }; + ScanSubscriber.prototype._tryNext = function (value) { + var index = this.index++; + var result; + try { + result = this.accumulator(this.seed, value, index); + } + catch (err) { + this.destination.error(err); + } + this.seed = result; + this.destination.next(result); + }; + return ScanSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ + function reduce(accumulator, seed) { + if (arguments.length >= 2) { + return function reduceOperatorFunctionWithSeed(source) { + return pipe(scan(accumulator, seed), takeLast(1), defaultIfEmpty(seed))(source); + }; + } + return function reduceOperatorFunction(source) { + return pipe(scan(function (acc, value, index) { return accumulator(acc, value, index + 1); }), takeLast(1))(source); + }; + } + + /** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */ + function multicast(subjectOrSubjectFactory, selector) { + return function multicastOperatorFunction(source) { + var subjectFactory; + if (typeof subjectOrSubjectFactory === 'function') { + subjectFactory = subjectOrSubjectFactory; + } + else { + subjectFactory = function subjectFactory() { + return subjectOrSubjectFactory; + }; + } + if (typeof selector === 'function') { + return source.lift(new MulticastOperator(subjectFactory, selector)); + } + var connectable = Object.create(source, connectableObservableDescriptor); + connectable.source = source; + connectable.subjectFactory = subjectFactory; + return connectable; + }; + } + var MulticastOperator = /*@__PURE__*/ (function () { + function MulticastOperator(subjectFactory, selector) { + this.subjectFactory = subjectFactory; + this.selector = selector; + } + MulticastOperator.prototype.call = function (subscriber, source) { + var selector = this.selector; + var subject = this.subjectFactory(); + var subscription = selector(subject).subscribe(subscriber); + subscription.add(source.subscribe(subject)); + return subscription; + }; + return MulticastOperator; + }()); + + /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + function pairwise() { + return function (source) { return source.lift(new PairwiseOperator()); }; + } + var PairwiseOperator = /*@__PURE__*/ (function () { + function PairwiseOperator() { + } + PairwiseOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new PairwiseSubscriber(subscriber)); + }; + return PairwiseOperator; + }()); + var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { + __extends(PairwiseSubscriber, _super); + function PairwiseSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasPrev = false; + return _this; + } + PairwiseSubscriber.prototype._next = function (value) { + var pair; + if (this.hasPrev) { + pair = [this.prev, value]; + } + else { + this.hasPrev = true; + } + this.prev = value; + if (pair) { + this.destination.next(pair); + } + }; + return PairwiseSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _map PURE_IMPORTS_END */ + function pluck() { + var properties = []; + for (var _i = 0; _i < arguments.length; _i++) { + properties[_i] = arguments[_i]; + } + var length = properties.length; + if (length === 0) { + throw new Error('list of properties cannot be empty.'); + } + return function (source) { return map(plucker(properties, length))(source); }; + } + function plucker(props, length) { + var mapper = function (x) { + var currentProp = x; + for (var i = 0; i < length; i++) { + var p = currentProp != null ? currentProp[props[i]] : undefined; + if (p !== void 0) { + currentProp = p; + } + else { + return undefined; + } + } + return currentProp; + }; + return mapper; + } + + /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ + function shareSubjectFactory() { + return new Subject(); + } + function share() { + return function (source) { return refCount()(multicast(shareSubjectFactory)(source)); }; + } + + /** PURE_IMPORTS_START _ReplaySubject PURE_IMPORTS_END */ + function shareReplay(configOrBufferSize, windowTime, scheduler) { + var config; + if (configOrBufferSize && typeof configOrBufferSize === 'object') { + config = configOrBufferSize; + } + else { + config = { + bufferSize: configOrBufferSize, + windowTime: windowTime, + refCount: false, + scheduler: scheduler + }; + } + return function (source) { return source.lift(shareReplayOperator(config)); }; + } + function shareReplayOperator(_a) { + var _b = _a.bufferSize, bufferSize = _b === void 0 ? Number.POSITIVE_INFINITY : _b, _c = _a.windowTime, windowTime = _c === void 0 ? Number.POSITIVE_INFINITY : _c, useRefCount = _a.refCount, scheduler = _a.scheduler; + var subject; + var refCount = 0; + var subscription; + var hasError = false; + var isComplete = false; + return function shareReplayOperation(source) { + refCount++; + var innerSub; + if (!subject || hasError) { + hasError = false; + subject = new ReplaySubject(bufferSize, windowTime, scheduler); + innerSub = subject.subscribe(this); + subscription = source.subscribe({ + next: function (value) { subject.next(value); }, + error: function (err) { + hasError = true; + subject.error(err); + }, + complete: function () { + isComplete = true; + subscription = undefined; + subject.complete(); + }, + }); + } + else { + innerSub = subject.subscribe(this); + } + this.add(function () { + refCount--; + innerSub.unsubscribe(); + if (subscription && !isComplete && useRefCount && refCount === 0) { + subscription.unsubscribe(); + subscription = undefined; + subject = undefined; + } + }); + }; + } + + /** PURE_IMPORTS_START _observable_concat,_util_isScheduler PURE_IMPORTS_END */ + function startWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + var scheduler = array[array.length - 1]; + if (isScheduler(scheduler)) { + array.pop(); + return function (source) { return concat(array, source, scheduler); }; + } + else { + return function (source) { return concat(array, source); }; + } + } + + /** PURE_IMPORTS_START tslib,_map,_observable_from,_innerSubscribe PURE_IMPORTS_END */ + function switchMap(project, resultSelector) { + if (typeof resultSelector === 'function') { + return function (source) { return source.pipe(switchMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; + } + return function (source) { return source.lift(new SwitchMapOperator(project)); }; + } + var SwitchMapOperator = /*@__PURE__*/ (function () { + function SwitchMapOperator(project) { + this.project = project; + } + SwitchMapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchMapSubscriber(subscriber, this.project)); + }; + return SwitchMapOperator; + }()); + var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { + __extends(SwitchMapSubscriber, _super); + function SwitchMapSubscriber(destination, project) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.index = 0; + return _this; + } + SwitchMapSubscriber.prototype._next = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (error) { + this.destination.error(error); + return; + } + this._innerSub(result); + }; + SwitchMapSubscriber.prototype._innerSub = function (result) { + var innerSubscription = this.innerSubscription; + if (innerSubscription) { + innerSubscription.unsubscribe(); + } + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + this.innerSubscription = innerSubscribe(result, innerSubscriber); + if (this.innerSubscription !== innerSubscriber) { + destination.add(this.innerSubscription); + } + }; + SwitchMapSubscriber.prototype._complete = function () { + var innerSubscription = this.innerSubscription; + if (!innerSubscription || innerSubscription.closed) { + _super.prototype._complete.call(this); + } + this.unsubscribe(); + }; + SwitchMapSubscriber.prototype._unsubscribe = function () { + this.innerSubscription = undefined; + }; + SwitchMapSubscriber.prototype.notifyComplete = function () { + this.innerSubscription = undefined; + if (this.isStopped) { + _super.prototype._complete.call(this); + } + }; + SwitchMapSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + return SwitchMapSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ + function switchAll() { + return switchMap(identity); + } + + /** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ + function switchMapTo(innerObservable, resultSelector) { + return resultSelector ? switchMap(function () { return innerObservable; }, resultSelector) : switchMap(function () { return innerObservable; }); + } + + /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ + function takeUntil(notifier) { + return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; + } + var TakeUntilOperator = /*@__PURE__*/ (function () { + function TakeUntilOperator(notifier) { + this.notifier = notifier; + } + TakeUntilOperator.prototype.call = function (subscriber, source) { + var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); + var notifierSubscription = innerSubscribe(this.notifier, new SimpleInnerSubscriber(takeUntilSubscriber)); + if (notifierSubscription && !takeUntilSubscriber.seenValue) { + takeUntilSubscriber.add(notifierSubscription); + return source.subscribe(takeUntilSubscriber); + } + return takeUntilSubscriber; + }; + return TakeUntilOperator; + }()); + var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { + __extends(TakeUntilSubscriber, _super); + function TakeUntilSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.seenValue = false; + return _this; + } + TakeUntilSubscriber.prototype.notifyNext = function () { + this.seenValue = true; + this.complete(); + }; + TakeUntilSubscriber.prototype.notifyComplete = function () { + }; + return TakeUntilSubscriber; + }(SimpleOuterSubscriber)); + + /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ + function tap(nextOrObserver, error, complete) { + return function tapOperatorFunction(source) { + return source.lift(new DoOperator(nextOrObserver, error, complete)); + }; + } + var DoOperator = /*@__PURE__*/ (function () { + function DoOperator(nextOrObserver, error, complete) { + this.nextOrObserver = nextOrObserver; + this.error = error; + this.complete = complete; + } + DoOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete)); + }; + return DoOperator; + }()); + var TapSubscriber = /*@__PURE__*/ (function (_super) { + __extends(TapSubscriber, _super); + function TapSubscriber(destination, observerOrNext, error, complete) { + var _this = _super.call(this, destination) || this; + _this._tapNext = noop; + _this._tapError = noop; + _this._tapComplete = noop; + _this._tapError = error || noop; + _this._tapComplete = complete || noop; + if (isFunction(observerOrNext)) { + _this._context = _this; + _this._tapNext = observerOrNext; + } + else if (observerOrNext) { + _this._context = observerOrNext; + _this._tapNext = observerOrNext.next || noop; + _this._tapError = observerOrNext.error || noop; + _this._tapComplete = observerOrNext.complete || noop; + } + return _this; + } + TapSubscriber.prototype._next = function (value) { + try { + this._tapNext.call(this._context, value); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(value); + }; + TapSubscriber.prototype._error = function (err) { + try { + this._tapError.call(this._context, err); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.error(err); + }; + TapSubscriber.prototype._complete = function () { + try { + this._tapComplete.call(this._context); + } + catch (err) { + this.destination.error(err); + return; + } + return this.destination.complete(); + }; + return TapSubscriber; + }(Subscriber)); + + /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ + function toArrayReducer(arr, item, index) { + if (index === 0) { + return [item]; + } + arr.push(item); + return arr; + } + function toArray() { + return reduce(toArrayReducer, []); + } + + /** PURE_IMPORTS_START tslib,_Subject,_Subscription,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ + function windowToggle(openings, closingSelector) { + return function (source) { return source.lift(new WindowToggleOperator(openings, closingSelector)); }; + } + var WindowToggleOperator = /*@__PURE__*/ (function () { + function WindowToggleOperator(openings, closingSelector) { + this.openings = openings; + this.closingSelector = closingSelector; + } + WindowToggleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowToggleSubscriber(subscriber, this.openings, this.closingSelector)); + }; + return WindowToggleOperator; + }()); + var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { + __extends(WindowToggleSubscriber, _super); + function WindowToggleSubscriber(destination, openings, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.openings = openings; + _this.closingSelector = closingSelector; + _this.contexts = []; + _this.add(_this.openSubscription = subscribeToResult(_this, openings, openings)); + return _this; + } + WindowToggleSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + if (contexts) { + var len = contexts.length; + for (var i = 0; i < len; i++) { + contexts[i].window.next(value); + } + } + }; + WindowToggleSubscriber.prototype._error = function (err) { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_1 = contexts[index]; + context_1.window.error(err); + context_1.subscription.unsubscribe(); + } + } + _super.prototype._error.call(this, err); + }; + WindowToggleSubscriber.prototype._complete = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_2 = contexts[index]; + context_2.window.complete(); + context_2.subscription.unsubscribe(); + } + } + _super.prototype._complete.call(this); + }; + WindowToggleSubscriber.prototype._unsubscribe = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_3 = contexts[index]; + context_3.window.unsubscribe(); + context_3.subscription.unsubscribe(); + } + } + }; + WindowToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + if (outerValue === this.openings) { + var closingNotifier = void 0; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(innerValue); + } + catch (e) { + return this.error(e); + } + var window_1 = new Subject(); + var subscription = new Subscription(); + var context_4 = { window: window_1, subscription: subscription }; + this.contexts.push(context_4); + var innerSubscription = subscribeToResult(this, closingNotifier, context_4); + if (innerSubscription.closed) { + this.closeWindow(this.contexts.length - 1); + } + else { + innerSubscription.context = context_4; + subscription.add(innerSubscription); + } + this.destination.next(window_1); + } + else { + this.closeWindow(this.contexts.indexOf(outerValue)); + } + }; + WindowToggleSubscriber.prototype.notifyError = function (err) { + this.error(err); + }; + WindowToggleSubscriber.prototype.notifyComplete = function (inner) { + if (inner !== this.openSubscription) { + this.closeWindow(this.contexts.indexOf(inner.context)); + } + }; + WindowToggleSubscriber.prototype.closeWindow = function (index) { + if (index === -1) { + return; + } + var contexts = this.contexts; + var context = contexts[index]; + var window = context.window, subscription = context.subscription; + contexts.splice(index, 1); + window.complete(); + subscription.unsubscribe(); + }; + return WindowToggleSubscriber; + }(OuterSubscriber)); + + /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ + function withLatestFrom() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return function (source) { + var project; + if (typeof args[args.length - 1] === 'function') { + project = args.pop(); + } + var observables = args; + return source.lift(new WithLatestFromOperator(observables, project)); + }; + } + var WithLatestFromOperator = /*@__PURE__*/ (function () { + function WithLatestFromOperator(observables, project) { + this.observables = observables; + this.project = project; + } + WithLatestFromOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project)); + }; + return WithLatestFromOperator; + }()); + var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { + __extends(WithLatestFromSubscriber, _super); + function WithLatestFromSubscriber(destination, observables, project) { + var _this = _super.call(this, destination) || this; + _this.observables = observables; + _this.project = project; + _this.toRespond = []; + var len = observables.length; + _this.values = new Array(len); + for (var i = 0; i < len; i++) { + _this.toRespond.push(i); + } + for (var i = 0; i < len; i++) { + var observable = observables[i]; + _this.add(subscribeToResult(_this, observable, undefined, i)); + } + return _this; + } + WithLatestFromSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + this.values[outerIndex] = innerValue; + var toRespond = this.toRespond; + if (toRespond.length > 0) { + var found = toRespond.indexOf(outerIndex); + if (found !== -1) { + toRespond.splice(found, 1); + } + } + }; + WithLatestFromSubscriber.prototype.notifyComplete = function () { + }; + WithLatestFromSubscriber.prototype._next = function (value) { + if (this.toRespond.length === 0) { + var args = [value].concat(this.values); + if (this.project) { + this._tryProject(args); + } + else { + this.destination.next(args); + } + } + }; + WithLatestFromSubscriber.prototype._tryProject = function (args) { + var result; + try { + result = this.project.apply(this, args); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return WithLatestFromSubscriber; + }(OuterSubscriber)); + + /** + * @class + * @classdesc Minimalistic event emitter mixin. + */ + function EventEmitter() {} + + /** + * Registers an event listener for the specified event. If the listener has + * already been registered for the event, this is a no-op. + * + * @param {string} name The event name. + * @param {function} fn The listener function. + */ + EventEmitter.prototype.addEventListener = function(name, fn) { + var eventMap = this.__events = this.__events || {}; + var handlerList = eventMap[name] = eventMap[name] || []; + if (handlerList.indexOf(fn) < 0) { + handlerList.push(fn); + } + }; + + /** + * Unregisters an event listener from the specified event. If the listener + * hasn't been registered for the event, this is a no-op. + * + * @param {string} name The event name. + * @param {function} fn The listener function. + */ + EventEmitter.prototype.removeEventListener = function(name, fn) { + var eventMap = this.__events = this.__events || {}; + var handlerList = eventMap[name]; + if (handlerList) { + var index = handlerList.indexOf(fn); + if (index >= 0) { + handlerList.splice(index, 1); + } + } + }; + + /** + * Emits an event, causing all registered event listeners for that event to be + * called in registration order. + * + * @param {string} name The event name. + * @param {...*} var_args Arguments to call listeners with. + */ + EventEmitter.prototype.emit = function(name, var_args) { + var eventMap = this.__events = this.__events || {}; + var handlerList = eventMap[name]; + var args = Array.prototype.slice.call(arguments, 1); + if (handlerList) { + for (var i = 0; i < handlerList.length; i++) { + var fn = handlerList[i]; + fn.apply(this, args); + } + } + }; + + /** + * Mixes in {@link EventEmitter} into a constructor function. + * + * @param {function} ctor The constructor function. + */ + function eventEmitter(ctor) { + for (var prop in EventEmitter.prototype) { + if (EventEmitter.prototype.hasOwnProperty(prop)) { + ctor.prototype[prop] = EventEmitter.prototype[prop]; + } + } + } + + var minimalEventEmitter = eventEmitter; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function getNow() { + if (typeof performance !== 'undefined' && performance.now) { + return function performanceNow() { + return performance.now(); + }; + } + return function dateNow() { + return Date.now(); + }; + } + + var now = getNow(); + + function WorkTask(fn, cb) { + this.fn = fn; + this.cb = cb; + this.cfn = null; + } + + + function WorkQueue(opts) { + this._queue = []; + this._delay = opts && opts.delay || 0; + this._paused = opts && !!opts.paused || false; + this._currentTask = null; + this._lastFinished = null; + } + + + WorkQueue.prototype.length = function() { + return this._queue.length; + }; + + + WorkQueue.prototype.push = function(fn, cb) { + + var task = new WorkTask(fn, cb); + + var cancel = this._cancel.bind(this, task); + + // Push the task into the queue. + this._queue.push(task); + + // Run the task if idle. + this._next(); + + return cancel; + + }; + + + WorkQueue.prototype.pause = function() { + if (!this._paused) { + this._paused = true; + } + }; + + + WorkQueue.prototype.resume = function() { + if (this._paused) { + this._paused = false; + this._next(); + } + }; + + + WorkQueue.prototype._start = function(task) { + + // Consistency check. + if (this._currentTask) { + throw new Error('WorkQueue: called start while running task'); + } + + // Mark queue as busy, so that concurrent tasks wait. + this._currentTask = task; + + // Execute the task. + var finish = this._finish.bind(this, task); + task.cfn = task.fn(finish); + + // Detect when a non-cancellable function has been queued. + if (typeof task.cfn !== 'function') { + throw new Error('WorkQueue: function is not cancellable'); + } + + }; + + + WorkQueue.prototype._finish = function(task) { + + var args = Array.prototype.slice.call(arguments, 1); + + // Consistency check. + if (this._currentTask !== task) { + throw new Error('WorkQueue: called finish on wrong task'); + } + + // Call the task callback on the return values. + task.cb.apply(null, args); + + // Mark as not busy and record task finish time, then advance to next task. + this._currentTask = null; + this._lastFinished = now(); + this._next(); + + }; + + + WorkQueue.prototype._cancel = function(task) { + + var args = Array.prototype.slice.call(arguments, 1); + + if (this._currentTask === task) { + + // Cancel running task. Because cancel passes control to the _finish + // callback we passed into fn, the cleanup logic will be handled there. + task.cfn.apply(null, args); + + } else { + + // Remove task from queue. + var pos = this._queue.indexOf(task); + if (pos >= 0) { + this._queue.splice(pos, 1); + task.cb.apply(null, args); + } + + } + + }; + + + WorkQueue.prototype._next = function() { + + if (this._paused) { + // Do not start tasks while paused. + return; + } + + if (!this._queue.length) { + // No tasks to run. + return; + } + + if (this._currentTask) { + // Will be called again when the current task finishes. + return; + } + + if (this._lastFinished != null) { + var elapsed = now() - this._lastFinished; + var remaining = this._delay - elapsed; + if (remaining > 0) { + // Too soon. Run again after the inter-task delay. + setTimeout(this._next.bind(this), remaining); + return; + } + } + + // Run the next task. + var task = this._queue.shift(); + this._start(task); + + }; + + + var WorkQueue_1 = WorkQueue; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * Converts a {@link RectSpec} into an equivalent {@link Rect}. + * + * A {@link RectSpec} is a convenient user API format, providing default values + * and the flexibility of specifying absolute, relative or mixed dimensions. + * + * A {@link Rect} is a more convenient format for the rendering pipeline. It is + * always expressed in normalized coordinates, and all its properties are + * guaranteed to be present. + * + * @param {number} totalWidth The total width of the rendering area in pixels. + * @param {number} totalHeight The total height of the rendering area in pixels. + * @param {RectSpec} spec The input spec, defaulting to the full rendering area + * if null or undefined. + * @param {Rect} result The output spec. If the argument is present, it is + * filled in and returned; otherwise, a fresh object is returned. + */ + function calcRect(totalWidth, totalHeight, spec, result) { + + result = result || {}; + + var width; + if (spec != null && spec.absoluteWidth != null) { + width = spec.absoluteWidth / totalWidth; + } else if (spec != null && spec.relativeWidth != null) { + width = spec.relativeWidth; + } else { + width = 1; + } + + var height; + if (spec && spec.absoluteHeight != null) { + height = spec.absoluteHeight / totalHeight; + } else if (spec != null && spec.relativeHeight != null) { + height = spec.relativeHeight; + } else { + height = 1; + } + + var x; + if (spec != null && spec.absoluteX != null) { + x = spec.absoluteX / totalWidth; + } else if (spec != null && spec.relativeX != null) { + x = spec.relativeX; + } else { + x = 0; + } + + var y; + if (spec != null && spec.absoluteY != null) { + y = spec.absoluteY / totalHeight; + } else if (spec != null && spec.relativeY != null) { + y = spec.relativeY; + } else { + y = 0; + } + + result.x = x; + result.y = y; + result.width = width; + result.height = height; + + return result; + } + + var calcRect_1 = calcRect; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Transform a synchronous function into an asynchronous one. + function async$1(fn) { + return function asynced(done) { + var err, ret; + try { + ret = fn(); + } catch (e) { + err = e; + } finally { + if (err) { + done(err); + } else { + done(null, ret); + } + } + }; + } + + var async_1 = async$1; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function once(fn) { + var called = false; + var value; + return function onced() { + if (!called) { + called = true; + value = fn.apply(null, arguments); + } + return value; + }; + } + + var once_1 = once; + + // A cancelable function is an asynchronous function (i.e., one whose last + // argument is a callback receiving an error plus zero or more return values) + // that (synchronously) returns a cancel() function. Calling cancel() should + // abort the asynchronous operation and call the callback with the arguments + // that were passed into cancel(). Calling cancel() twice, as with callbacks, + // is not guaranteed to be safe. + + // Wrap a non-cancellable asynchronous function into a cancelable one. + // + // Calling cancel() on the returned function will not interrupt the execution + // of the original function; it will merely ignore its return value. + // + // Usually, instead of wrapping your function, you want to implement cancel() + // yourself in order to have some abort logic. This utility function provides a + // straighforward solution for cases in which no custom abort logic is required. + function cancelize(fn) { + return function cancelized() { + if (!arguments.length) { + throw new Error('cancelized: expected at least one argument'); + } + var args = Array.prototype.slice.call(arguments, 0); + var done = args[args.length - 1] = once_1(args[args.length - 1]); + + function cancel() { + done.apply(null, arguments); + } + + fn.apply(null, args); + + return cancel; + }; + } + + var cancelize_1 = cancelize; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Sets an object's own properties to undefined. This may be called by + // destructors to avoid retaining references and help detect incorrect use of + // destroyed instances. + function clearOwnProperties(obj) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + obj[prop] = undefined; + } + } + } + + var clearOwnProperties_1 = clearOwnProperties; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @class RendererRegistry + * @classdesc + * + * A RendererRegistry maps pairs of {@link Geometry} and {@link View} type into + * the appropriate {@link Renderer} class. It is used by a {@link Stage} to + * determine the appropriate renderer for a {@link Layer}. + * + * See also {@link Stage#registerRenderer}. + */ + function RendererRegistry() { + this._renderers = {}; + } + + /** + * Registers a renderer for the given geometry and view type. + * @param {string} geometryType The geometry type, as given by + * {@link Geometry#type}. + * @param {string} viewType The view type, as given by {@link View#type}. + * @param {*} Renderer The renderer class. + */ + RendererRegistry.prototype.set = function(geometryType, viewType, Renderer) { + if (!this._renderers[geometryType]) { + this._renderers[geometryType] = {}; + } + this._renderers[geometryType][viewType] = Renderer; + }; + + /** + * Retrieves the renderer for the given geometry and view type. + * @param {string} geometryType The geometry type, as given by + * {@link Geometry#type}. + * @param {string} viewType The view type, as given by {@link View#type}. + * @param {*} Renderer The renderer class, or null if no such renderer has been + * registered. + */ + RendererRegistry.prototype.get = function(geometryType, viewType) { + var Renderer = this._renderers[geometryType] && + this._renderers[geometryType][viewType]; + return Renderer || null; + }; + + var RendererRegistry_1 = RendererRegistry; + + function forwardTileCmp(t1, t2) { + return t1.cmp(t2); + } + + function reverseTileCmp(t1, t2) { + return -t1.cmp(t2); + } + + /** + * Signals that the stage has been rendered. + * + * @param {boolean} stable Whether all tiles were successfully rendered without + * missing textures or resorting to fallbacks. + * @event Stage#renderComplete + */ + + /** + * Signals that the contents of the stage have been invalidated and must be + * rendered again. + * + * This is used by the {@link RenderLoop} implementation. + * + * @event Stage#renderInvalid + */ + + /** + * @interface Stage + * @classdesc + * + * A Stage is a container with the ability to render a stack of + * {@link Layer layers}. + * + * This is a superclass containing logic that is common to all implementations; + * it should never be instantiated directly. Instead, use one of the + * subclasses: {@link WebGlStage}, {@link CssStage} or {@link FlashStage}. + * + * @param {Object} opts + * @param {boolean} [opts.progressive=false] + * + * Options listed here may be passed into the `opts` constructor argument of + * subclasses. + * + * The `progressive` option controls whether resolution levels are loaded in + * order, from lowest to highest. This results in a more pleasing effect when + * zooming past several levels in a large panoramas, but consumes additional + * bandwidth. + */ + function Stage(opts) { + this._progressive = !!(opts && opts.progressive); + + // The list of layers in display order (background to foreground). + this._layers = []; + + // The list of renderers; the i-th renderer is for the i-th layer. + this._renderers = []; + + // The lists of tiles to load and render, populated during render(). + this._tilesToLoad = []; + this._tilesToRender = []; + + // Temporary tile lists. + this._tmpVisible = []; + this._tmpChildren = []; + + // Cached stage dimensions. + // Start with zero, which inhibits rendering until setSize() is called. + this._width = 0; + this._height = 0; + + // Temporary variable for rect. + this._tmpRect = {}; + + // Temporary variable for size. + this._tmpSize = {}; + + // Work queue for createTexture. + this._createTextureWorkQueue = new WorkQueue_1(); + + // Function to emit event when render parameters have changed. + this._emitRenderInvalid = this._emitRenderInvalid.bind(this); + + // The renderer registry maps each geometry/view pair into the respective + // Renderer class. + this._rendererRegistry = new RendererRegistry_1(); + } + + minimalEventEmitter(Stage); + + + /** + * Destructor. + */ + Stage.prototype.destroy = function() { + this.removeAllLayers(); + clearOwnProperties_1(this); + }; + + + /** + * Registers a {@link Renderer} for the given {@link Geometry} and {@link View} + * type. + * + * The {@link registerDefaultRenderers} utility function may be used to + * register all known renderers for a stage type into that stage. Most users + * will not need to register renderers, as {@link Viewer} does it for them. + * + * @param {string} geometryType The geometry type, as given by + * {@link Geometry#type}. + * @param {string} viewType The view type, as given by {@link View#type}. + * @param {*} Renderer The renderer class. + */ + Stage.prototype.registerRenderer = function(geometryType, viewType, Renderer) { + return this._rendererRegistry.set(geometryType, viewType, Renderer); + }; + + + /** + * Returns the underlying DOM element. + * + * Must be overridden by subclasses. + * + * @return {Element} + */ + Stage.prototype.domElement = function() { + throw new Error('Stage implementation must override domElement'); + }; + + + /** + * Get the stage width. + * @return {number} + */ + Stage.prototype.width = function() { + return this._width; + }; + + + /** + * Get the stage height. + * @return {number} + */ + Stage.prototype.height = function() { + return this._height; + }; + + + /** + * Get the stage dimensions. If an argument is supplied, it is filled in with + * the result and returned. Otherwise, a fresh object is filled in and returned. + * + * @param {Size=} size + */ + Stage.prototype.size = function(size) { + size = size || {}; + size.width = this._width; + size.height = this._height; + return size; + }; + + + /** + * Set the stage dimensions. + * + * This contains the size update logic common to all stage types. Subclasses + * must define the {@link Stage#setSizeForType} method to perform their own + * logic. + * + * @param {Size} size + */ + Stage.prototype.setSize = function(size) { + this._width = size.width; + this._height = size.height; + + this.setSizeForType(); // must be defined by subclasses. + + this.emit('resize'); + this._emitRenderInvalid(); + }; + + + /** + * Call {@link Stage#setSize} instead. + * + * This contains the size update logic specific to a stage type. It is called by + * {@link Stage#setSize} after the base class has been updated to reflect the + * new size, but before any events are emitted. + * + * @param {Size} size + */ + Stage.prototype.setSizeForType = function(size) { + throw new Error('Stage implementation must override setSizeForType'); + }; + + + /** + * Loads an {@link Asset} from an image. + * @param {string} url The image URL. + * @param {?Rect} rect A {@link Rect} describing a portion of the image, or null + * to use the full image. + * @param {function(?Error, Asset)} done The callback. + * @return {function()} A function to cancel loading. + */ + Stage.prototype.loadImage = function() { + throw new Error('Stage implementation must override loadImage'); + }; + + + Stage.prototype._emitRenderInvalid = function() { + this.emit('renderInvalid'); + }; + + + /** + * Verifies that the layer is valid for this stage, throwing an exception + * otherwise. + * + * @param {Layer} layer + * @throws {Error} If the layer is not valid for this stage. + */ + Stage.prototype.validateLayer = function(layer) { + throw new Error('Stage implementation must override validateLayer'); + }; + + + /** + * Returns a list of all {@link Layer layers} belonging to the stage. The + * returned list is in display order, background to foreground. + * @return {Layer[]} + */ + Stage.prototype.listLayers = function() { + // Return a copy to prevent unintended mutation by the caller. + return [].concat(this._layers); + }; + + + /** + * Return whether a {@link Layer layer} belongs to the stage. + * @param {Layer} layer + * @return {boolean} + */ + Stage.prototype.hasLayer = function(layer) { + return this._layers.indexOf(layer) >= 0; + }; + + + /** + * Adds a {@link Layer layer} into the stage. + * @param {Layer} layer The layer to add. + * @param {number|undefined} i The optional position, where 0 ≤ i ≤ n and n is + * the current number of layers. The default is n, which inserts at the + * top of the display stack. + * @throws An error if the layer already belongs to the stage or if the position + * is invalid. + */ + Stage.prototype.addLayer = function(layer, i) { + if (this._layers.indexOf(layer) >= 0) { + throw new Error('Layer already in stage'); + } + + if (i == null) { + i = this._layers.length; + } + if (i < 0 || i > this._layers.length) { + throw new Error('Invalid layer position'); + } + + this.validateLayer(layer); // must be defined by subclasses. + + var geometryType = layer.geometry().type; + var viewType = layer.view().type; + var rendererClass = this._rendererRegistry.get(geometryType, viewType); + if (!rendererClass) { + throw new Error('No ' + this.type + ' renderer avaiable for ' + + geometryType + ' geometry and ' + viewType + ' view'); + } + var renderer = this.createRenderer(rendererClass); + + this._layers.splice(i, 0, layer); + this._renderers.splice(i, 0, renderer); + + // Listeners for render invalid. + layer.addEventListener('viewChange', this._emitRenderInvalid); + layer.addEventListener('effectsChange', this._emitRenderInvalid); + layer.addEventListener('fixedLevelChange', this._emitRenderInvalid); + layer.addEventListener('textureStoreChange', this._emitRenderInvalid); + + this._emitRenderInvalid(); + }; + + + /** + * Moves a {@link Layer layer} into a different position in the display stack. + * @param {Layer} layer The layer to move. + * @param {number} i The position, where 0 ≤ i ≤ n-1 and n is the current number + * of layers. + * @throws An error if the layer does not belong to the stage or if the position + * is invalid. + */ + Stage.prototype.moveLayer = function(layer, i) { + var index = this._layers.indexOf(layer); + if (index < 0) { + throw new Error('No such layer in stage'); + } + + if (i < 0 || i >= this._layers.length) { + throw new Error('Invalid layer position'); + } + + layer = this._layers.splice(index, 1)[0]; + var renderer = this._renderers.splice(index, 1)[0]; + + this._layers.splice(i, 0, layer); + this._renderers.splice(i, 0, renderer); + + this._emitRenderInvalid(); + }; + + + /** + * Removes a {@link Layer} from the stage. + * @param {Layer} layer The layer to remove. + * @throws An error if the layer does not belong to the stage. + */ + Stage.prototype.removeLayer = function(layer) { + var index = this._layers.indexOf(layer); + if (index < 0) { + throw new Error('No such layer in stage'); + } + + var removedLayer = this._layers.splice(index, 1)[0]; + var renderer = this._renderers.splice(index, 1)[0]; + + this.destroyRenderer(renderer); + + removedLayer.removeEventListener('viewChange', this._emitRenderInvalid); + removedLayer.removeEventListener('effectsChange', this._emitRenderInvalid); + removedLayer.removeEventListener('fixedLevelChange', this._emitRenderInvalid); + removedLayer.removeEventListener('textureStoreChange', this._emitRenderInvalid); + + this._emitRenderInvalid(); + }; + + + /** + * Removes all {@link Layer layers} from the stage. + */ + Stage.prototype.removeAllLayers = function() { + while (this._layers.length > 0) { + this.removeLayer(this._layers[0]); + } + }; + + + /** + * Called before a frame is rendered. + * + * Must be overridden by subclasses. + */ + Stage.prototype.startFrame = function() { + throw new Error('Stage implementation must override startFrame'); + }; + + + /** + * Called after a frame is rendered. + * + * Must be overridden by subclasses. + */ + Stage.prototype.endFrame = function() { + throw new Error('Stage implementation must override endFrame'); + }; + + + /** + * Render the current frame. Usually called from a {@link RenderLoop}. + * + * This contains the rendering logic common to all stage types. Subclasses + * define the startFrame() and endFrame() methods to perform their own logic. + */ + Stage.prototype.render = function() { + var i, j; + + var tilesToLoad = this._tilesToLoad; + var tilesToRender = this._tilesToRender; + + var stableStage = true; + var stableLayer; + + // Get the stage dimensions. + var width = this._width; + var height = this._height; + + var rect = this._tmpRect; + var size = this._tmpSize; + + if (width <= 0 || height <= 0) { + return; + } + + this.startFrame(); // defined by subclasses + + // Signal start of frame to the texture stores. + for (i = 0; i < this._layers.length; i++) { + this._layers[i].textureStore().startFrame(); + } + + // Render layers. + for (i = 0; i < this._layers.length; i++) { + var layer = this._layers[i]; + var effects = layer.effects(); + var view = layer.view(); + var textureStore = layer.textureStore(); + var renderer = this._renderers[i]; + var depth = this._layers.length - i; + var tile, texture; + + // Convert the rect effect into a normalized rect. + // TODO: avoid doing this on every frame. + calcRect_1(width, height, effects && effects.rect, rect); + + if (rect.width <= 0 || rect.height <= 0) { + // Skip rendering on a null viewport. + continue; + } + + // Update the view size. + size.width = rect.width * this._width; + size.height = rect.height * this._height; + view.setSize(size); + + // Signal start of layer to the renderer. + renderer.startLayer(layer, rect); + + // We render with both alpha blending and depth testing enabled. Thus, when + // rendering a subsequent pixel at the same location than an existing one, + // the subsequent pixel gets discarded unless it has smaller depth, and is + // otherwise composited with the existing pixel. + // + // When using fallback tiles to fill a gap in the preferred resolution + // level, we prefer higher resolution fallbacks to lower resolution ones. + // However, where fallbacks overlap, we want higher resolution ones to + // prevail, and we don't want multiple fallbacks to be composited with each + // other, as that would produce a bad result when semitransparent textures + // are involved. + // + // In order to achieve this within the constraints of alpha blending and + // depth testing, the depth of a tile must be inversely proportional to its + // resolution, and higher-resolution tiles must be rendered before lower- + // resolution ones. + + // Collect the lists of tiles to load and render. + stableLayer = this._collectTiles(layer, textureStore); + + // Mark all the tiles whose textures must be loaded. + // This will either trigger loading (for textures not yet loaded) or + // prevent unloading (for textures already loaded). + for (j = 0; j < tilesToLoad.length; j++) { + tile = tilesToLoad[j]; + textureStore.markTile(tile); + } + + // Render tiles. + for (j = 0; j < tilesToRender.length; j++) { + tile = tilesToRender[j]; + texture = textureStore.texture(tile); + renderer.renderTile(tile, texture, layer, depth); + } + + layer.emit('renderComplete', stableLayer); + if (!stableLayer) { + stableStage = false; + } + + // Signal end of layer to the renderer. + renderer.endLayer(layer, rect); + } + + // Signal end of frame to the texture stores. + for (i = 0; i < this._layers.length; i++) { + this._layers[i].textureStore().endFrame(); + } + + this.endFrame(); // defined by subclasses + + this.emit('renderComplete', stableStage); + }; + + Stage.prototype._collectTiles = function(layer, textureStore) { + var tilesToLoad = this._tilesToLoad; + var tilesToRender = this._tilesToRender; + var tmpVisible = this._tmpVisible; + + tilesToLoad.length = 0; + tilesToRender.length = 0; + tmpVisible.length = 0; + + layer.visibleTiles(tmpVisible); + + var isStable = true; + + for (var i = 0; i < tmpVisible.length; i++) { + var tile = tmpVisible[i]; + var needsFallback; + this._collectTileToLoad(tile); + if (textureStore.texture(tile)) { + // The preferred texture is available. + // No fallback is required. + needsFallback = false; + this._collectTileToRender(tile); + } else { + // The preferred texture is unavailable. + // Collect children for rendering as a fallback. + needsFallback = this._collectChildren(tile, textureStore); + isStable = false; + } + // Collect all parents for loading, and the closest parent for rendering if + // a fallback is required. + this._collectParents(tile, textureStore, needsFallback); + } + + // Sort tiles to load in ascending resolution order. + tilesToLoad.sort(forwardTileCmp); + + // Sort tiles to render in descending resolution order. + tilesToRender.sort(reverseTileCmp); + + return isStable; + }; + + Stage.prototype._collectChildren = function(tile, textureStore) { + var tmpChildren = this._tmpChildren; + + var needsFallback = true; + + // Fall back as many levels as necessary on single-child geometries, but do + // not go beyond immediate children on multiple-child geometries, to avoid + // exploring an exponential number of tiles. + do { + tmpChildren.length = 0; + if (!tile.children(tmpChildren)) { + break; + } + needsFallback = false; + for (var i = 0; i < tmpChildren.length; i++) { + tile = tmpChildren[i]; + if (textureStore.texture(tile)) { + this._collectTileToLoad(tile); + this._collectTileToRender(tile); + } else { + needsFallback = true; + } + } + } while (needsFallback && tmpChildren.length === 1) + + return needsFallback; + }; + + Stage.prototype._collectParents = function(tile, textureStore, needsFallback) { + // Recursively visit parent tiles until: + // - all parents have been marked for loading, if progressive rendering is + // enabled; and + // - at least one parent has been marked for both loading and rendering, if + // a fallback is required. + var needsLoading = this._progressive; + while ((needsLoading || needsFallback) && (tile = tile.parent()) != null) { + if (needsFallback) { + if (textureStore.texture(tile)) { + this._collectTileToRender(tile); + needsFallback = false; + } else if (!this._progressive) { + continue; + } + } + if (!this._collectTileToLoad(tile)) { + needsLoading = false; + } + } + return needsFallback; + }; + + Stage.prototype._collectTileToLoad = function(tile) { + return this._collectTileIntoList(tile, this._tilesToLoad); + }; + + Stage.prototype._collectTileToRender = function(tile) { + return this._collectTileIntoList(tile, this._tilesToRender); + }; + + Stage.prototype._collectTileIntoList = function(tile, tileList) { + // TODO: Investigate whether it's worth it to make this better than O(n²). + var found = false; + for (var i = 0; i < tileList.length; i++) { + if (tile.equals(tileList[i])) { + found = true; + break; + } + } + if (!found) { + tileList.push(tile); + } + return !found; + }; + + /** + * Create a texture for the given tile and asset. Called by {@link TextureStore}. + * @param {Tile} tile + * @param {Asset} asset + * @param {Function} done + */ + Stage.prototype.createTexture = function(tile, asset, done) { + + var self = this; + + function makeTexture() { + return new self.TextureClass(self, tile, asset); + } + + var fn = cancelize_1(async_1(makeTexture)); + + return this._createTextureWorkQueue.push(fn, function(err, texture) { + done(err, tile, asset, texture); + }); + + }; + + /** + * The stage type, used to determine the appropriate renderer for a given + * geometry and view. + * + * Known values are `"webgl"`, `"css"` and `"flash"`. + * + * See also {@link Stage#registerRenderer}. + * + * @property {string} + * @name Stage#type + */ + + var Stage_1 = Stage; + + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function createCommonjsModule(fn, basedir, module) { + return module = { + path: basedir, + exports: {}, + require: function (path, base) { + return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); + } + }, fn(module, module.exports), module.exports; + } + + function getAugmentedNamespace(n) { + if (n.__esModule) return n; + var a = Object.defineProperty({}, '__esModule', {value: true}); + Object.keys(n).forEach(function (k) { + var d = Object.getOwnPropertyDescriptor(n, k); + Object.defineProperty(a, k, d.get ? d : { + enumerable: true, + get: function () { + return n[k]; + } + }); + }); + return a; + } + + function commonjsRequire () { + throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); + } + + // The global object. + var globalObject = (function() { + if (typeof window !== 'undefined') { + return window; + } + if (typeof self !== 'undefined') { + return self; + } + if (typeof commonjsGlobal !== 'undefined') { + return commonjsGlobal; + } + return null; + })(); + + var global_1 = globalObject; + + var propertyMap = { + HTMLImageElement: ['naturalWidth', 'naturalHeight'], + HTMLCanvasElement: ['width', 'height'], + ImageBitmap: ['width', 'height'] + }; + + /** + * @class StaticAsset + * @implements Asset + * @classdesc + * + * An immutable {@link Asset} compatible with {@link WebGlStage} and + * {@link CssStage}. + * + * @param {HTMLImageElement|HTMLCanvasElement|ImageBitmap} element The + * underlying pixel source. + * @throws If the pixel source is unsupported. + */ + function StaticAsset(element) { + var supported = false; + for (var type in propertyMap) { + if (global_1[type] && element instanceof global_1[type]) { + supported = true; + this._widthProp = propertyMap[type][0]; + this._heightProp = propertyMap[type][1]; + break; + } + } + if (!supported) { + throw new Error('Unsupported pixel source'); + } + + this._element = element; + } + + minimalEventEmitter(StaticAsset); + + /** + * Destructor. + */ + StaticAsset.prototype.destroy = function() { + clearOwnProperties_1(this); + }; + + StaticAsset.prototype.element = function() { + return this._element; + }; + + StaticAsset.prototype.width = function() { + return this._element[this._widthProp]; + }; + + StaticAsset.prototype.height = function() { + return this._element[this._heightProp]; + }; + + StaticAsset.prototype.timestamp = function() { + return 0; + }; + + StaticAsset.prototype.isDynamic = function() { + return false; + }; + + var Static = StaticAsset; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Make ctor a subclass of superCtor. + // Do not depend on ES5 Object.create semantics because of older browsers. + function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + + var inherits_1 = inherits; + + /** + * @class NetworkError + * @extends {Error} + * @classdesc + * + * Signals an error that occurred while fetching a URL. This is used by + * {@link Loader loaders} to distinguish network failures from other errors. + */ + function NetworkError(message) { + // See: https://stackoverflow.com/questions/1382107/whats-a-good-way-to-extend-error-in-javascript + this.constructor.super_.apply(this, arguments); + this.message = message; + } + + inherits_1(NetworkError, Error); + + var NetworkError_1 = NetworkError; + + // N.B. HtmlImageLoader is broken on IE8 for images that require resizing, due + // to the unavailable HTML5 canvas element and the naturalWidth/naturalHeight + // properties of image elements. This is currently not a problem because the + // HTML-based renderers (WebGL and CSS) do not work on IE8 anyway. It could + // become a problem in the future if we decide to support CSS rendering of flat + // panoramas on IE8. + + // TODO: Move the load queue into the loader. + + /** + * @class HtmlImageLoader + * @implements ImageLoader + * @classdesc + * + * A {@link Loader} for HTML images. + * + * @param {Stage} stage The stage which is going to request images to be loaded. + */ + function HtmlImageLoader(stage) { + if (stage.type !== 'webgl' && stage.type !== 'css') { + throw new Error('Stage type incompatible with loader'); + } + this._stage = stage; + } + + /** + * Loads an {@link Asset} from an image. + * @param {string} url The image URL. + * @param {?Rect} rect A {@link Rect} describing a portion of the image, or null + * to use the full image. + * @param {function(?Error, Asset)} done The callback. + * @return {function()} A function to cancel loading. + */ + HtmlImageLoader.prototype.loadImage = function(url, rect, done) { + var img = new Image(); + + // Allow cross-domain image loading. + // This is required to be able to create WebGL textures from images fetched + // from a different domain. Note that setting the crossorigin attribute to + // 'anonymous' will trigger a CORS preflight for cross-domain requests, but no + // credentials (cookies or HTTP auth) will be sent; to do so, the attribute + // would have to be set to 'use-credentials' instead. Unfortunately, this is + // not a safe choice, as it causes requests to fail when the response contains + // an Access-Control-Allow-Origin header with a wildcard. See the section + // "Credentialed requests and wildcards" on: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS + img.crossOrigin = 'anonymous'; + + var x = rect && rect.x || 0; + var y = rect && rect.y || 0; + var width = rect && rect.width || 1; + var height = rect && rect.height || 1; + + done = once_1(done); + + img.onload = function() { + if (x === 0 && y === 0 && width === 1 && height === 1) { + done(null, new Static(img)); + } + else { + x *= img.naturalWidth; + y *= img.naturalHeight; + width *= img.naturalWidth; + height *= img.naturalHeight; + + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var context = canvas.getContext('2d'); + + context.drawImage(img, x, y, width, height, 0, 0, width, height); + + done(null, new Static(canvas)); + } + }; + + img.onerror = function() { + // TODO: is there any way to distinguish a network error from other + // kinds of errors? For now we always return NetworkError since this + // prevents images to be retried continuously while we are offline. + done(new NetworkError_1('Network error: ' + url)); + }; + + img.src = url; + + function cancel() { + img.onload = img.onerror = null; + img.src = ''; + done.apply(null, arguments); + } + + return cancel; + }; + + var HtmlImage = HtmlImageLoader; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Detect WebGl support. + // Keep stages/WebGl.js in sync with this. + function checkWebGlSupported() { + var canvas = document.createElement('canvas'); + var gl = canvas.getContext && (canvas.getContext('webgl') || + canvas.getContext('experimental-webgl')); + return !!gl; + } + + // Cache result. + var supported; + function webGlSupported() { + if (supported !== undefined) { + return supported; + } + return (supported = checkWebGlSupported()); + } + + var WebGl = webGlSupported; + + var es5 = createCommonjsModule(function (module, exports) { + !function(e,t){module.exports=t();}(commonjsGlobal,(function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i});},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0});},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=90)}({17:function(e,t,r){t.__esModule=!0,t.default=void 0;var i=r(18),n=function(){function e(){}return e.getFirstMatch=function(e,t){var r=t.match(e);return r&&r.length>0&&r[1]||""},e.getSecondMatch=function(e,t){var r=t.match(e);return r&&r.length>1&&r[2]||""},e.matchAndReturnConst=function(e,t,r){if(e.test(t))return r},e.getWindowsVersionName=function(e){switch(e){case"NT":return "NT";case"XP":return "XP";case"NT 5.0":return "2000";case"NT 5.1":return "XP";case"NT 5.2":return "2003";case"NT 6.0":return "Vista";case"NT 6.1":return "7";case"NT 6.2":return "8";case"NT 6.3":return "8.1";case"NT 10.0":return "10";default:return}},e.getMacOSVersionName=function(e){var t=e.split(".").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),10===t[0])switch(t[1]){case 5:return "Leopard";case 6:return "Snow Leopard";case 7:return "Lion";case 8:return "Mountain Lion";case 9:return "Mavericks";case 10:return "Yosemite";case 11:return "El Capitan";case 12:return "Sierra";case 13:return "High Sierra";case 14:return "Mojave";case 15:return "Catalina";default:return}},e.getAndroidVersionName=function(e){var t=e.split(".").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(1===t[0]&&t[1]<5))return 1===t[0]&&t[1]<6?"Cupcake":1===t[0]&&t[1]>=6?"Donut":2===t[0]&&t[1]<2?"Eclair":2===t[0]&&2===t[1]?"Froyo":2===t[0]&&t[1]>2?"Gingerbread":3===t[0]?"Honeycomb":4===t[0]&&t[1]<1?"Ice Cream Sandwich":4===t[0]&&t[1]<4?"Jelly Bean":4===t[0]&&t[1]>=4?"KitKat":5===t[0]?"Lollipop":6===t[0]?"Marshmallow":7===t[0]?"Nougat":8===t[0]?"Oreo":9===t[0]?"Pie":void 0},e.getVersionPrecision=function(e){return e.split(".").length},e.compareVersions=function(t,r,i){void 0===i&&(i=!1);var n=e.getVersionPrecision(t),s=e.getVersionPrecision(r),o=Math.max(n,s),a=0,u=e.map([t,r],(function(t){var r=o-e.getVersionPrecision(t),i=t+new Array(r+1).join(".0");return e.map(i.split("."),(function(e){return new Array(20-e.length).join("0")+e})).reverse()}));for(i&&(a=o-Math.min(n,s)),o-=1;o>=a;){if(u[0][o]>u[1][o])return 1;if(u[0][o]===u[1][o]){if(o===a)return 0;o-=1;}else if(u[0][o]0){var o=Object.keys(r),a=o.find((function(e){return t.isOS(e)}));if(a){var u=this.satisfies(r[a]);if(void 0!==u)return u}var d=o.find((function(e){return t.isPlatform(e)}));if(d){var c=this.satisfies(r[d]);if(void 0!==c)return c}}if(s>0){var f=Object.keys(n).find((function(e){return t.isBrowser(e,!0)}));if(void 0!==f)return this.compareVersion(n[f])}},t.isBrowser=function(e,t){void 0===t&&(t=!1);var r=this.getBrowserName().toLowerCase(),i=e.toLowerCase(),n=a.default.getBrowserTypeByAlias(i);return t&&n&&(i=n.toLowerCase()),i===r},t.compareVersion=function(e){var t=[0],r=e,i=!1,n=this.getBrowserVersion();if("string"==typeof n)return ">"===e[0]||"<"===e[0]?(r=e.substr(1),"="===e[1]?(i=!0,r=e.substr(2)):t=[],">"===e[0]?t.push(1):t.push(-1)):"="===e[0]?r=e.substr(1):"~"===e[0]&&(i=!0,r=e.substr(1)),t.indexOf(a.default.compareVersions(n,r,i))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e){return this.isBrowser(e)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return void 0===e&&(e=[]),e.some((function(e){return t.is(e)}))},e}();t.default=d,e.exports=t.default;},92:function(e,t,r){t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i};var s=/version\/(\d+(\.?_?\d+)+)/i,o=[{test:[/googlebot/i],describe:function(e){var t={name:"Googlebot"},r=n.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/opera/i],describe:function(e){var t={name:"Opera"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/opr\/|opios/i],describe:function(e){var t={name:"Opera"},r=n.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:"Samsung Internet for Android"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Whale/i],describe:function(e){var t={name:"NAVER Whale Browser"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:"MZ Browser"},r=n.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/focus/i],describe:function(e){var t={name:"Focus"},r=n.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/swing/i],describe:function(e){var t={name:"Swing"},r=n.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/coast/i],describe:function(e){var t={name:"Opera Coast"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/yabrowser/i],describe:function(e){var t={name:"Yandex Browser"},r=n.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:"UC Browser"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:"Maxthon"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/epiphany/i],describe:function(e){var t={name:"Epiphany"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/puffin/i],describe:function(e){var t={name:"Puffin"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sleipnir/i],describe:function(e){var t={name:"Sleipnir"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/k-meleon/i],describe:function(e){var t={name:"K-Meleon"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/micromessenger/i],describe:function(e){var t={name:"WeChat"},r=n.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?"QQ Browser Lite":"QQ Browser"},r=n.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/msie|trident/i],describe:function(e){var t={name:"Internet Explorer"},r=n.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/\sedg\//i],describe:function(e){var t={name:"Microsoft Edge"},r=n.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:"Microsoft Edge"},r=n.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/vivaldi/i],describe:function(e){var t={name:"Vivaldi"},r=n.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/seamonkey/i],describe:function(e){var t={name:"SeaMonkey"},r=n.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sailfish/i],describe:function(e){var t={name:"Sailfish"},r=n.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,e);return r&&(t.version=r),t}},{test:[/silk/i],describe:function(e){var t={name:"Amazon Silk"},r=n.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/phantom/i],describe:function(e){var t={name:"PhantomJS"},r=n.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/slimerjs/i],describe:function(e){var t={name:"SlimerJS"},r=n.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t={name:"BlackBerry"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:"WebOS Browser"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/bada/i],describe:function(e){var t={name:"Bada"},r=n.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/tizen/i],describe:function(e){var t={name:"Tizen"},r=n.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qupzilla/i],describe:function(e){var t={name:"QupZilla"},r=n.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:"Firefox"},r=n.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/chromium/i],describe:function(e){var t={name:"Chromium"},r=n.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:"Chrome"},r=n.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/GSA/i],describe:function(e){var t={name:"Google Search"},r=n.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t={name:"Android Browser"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/playstation 4/i],describe:function(e){var t={name:"PlayStation 4"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:"Safari"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/.*/i],describe:function(e){var t=-1!==e.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return {name:n.default.getFirstMatch(t,e),version:n.default.getSecondMatch(t,e)}}}];t.default=o,e.exports=t.default;},93:function(e,t,r){t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/Roku\/DVP/],describe:function(e){var t=n.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,e);return {name:s.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=n.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,e);return {name:s.OS_MAP.WindowsPhone,version:t}}},{test:[/windows/i],describe:function(e){var t=n.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,e),r=n.default.getWindowsVersionName(t);return {name:s.OS_MAP.Windows,version:t,versionName:r}}},{test:[/macintosh/i],describe:function(e){var t=n.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,e).replace(/[_\s]/g,"."),r=n.default.getMacOSVersionName(t),i={name:s.OS_MAP.MacOS,version:t};return r&&(i.versionName=r),i}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=n.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,e).replace(/[_\s]/g,".");return {name:s.OS_MAP.iOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t=n.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,e),r=n.default.getAndroidVersionName(t),i={name:s.OS_MAP.Android,version:t};return r&&(i.versionName=r),i}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=n.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,e),r={name:s.OS_MAP.WebOS};return t&&t.length&&(r.version=t),r}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t=n.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,e)||n.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,e)||n.default.getFirstMatch(/\bbb(\d+)/i,e);return {name:s.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=n.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,e);return {name:s.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=n.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,e);return {name:s.OS_MAP.Tizen,version:t}}},{test:[/linux/i],describe:function(){return {name:s.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return {name:s.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(e){var t=n.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,e);return {name:s.OS_MAP.PlayStation4,version:t}}}];t.default=o,e.exports=t.default;},94:function(e,t,r){t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/googlebot/i],describe:function(){return {type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(e){var t=n.default.getFirstMatch(/(can-l01)/i,e)&&"Nova",r={type:s.PLATFORMS_MAP.mobile,vendor:"Huawei"};return t&&(r.model=t),r}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return {type:s.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return {type:s.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return {type:s.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return {type:s.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return {type:s.PLATFORMS_MAP.tablet}}},{test:function(e){var t=e.test(/ipod|iphone/i),r=e.test(/like (ipod|iphone)/i);return t&&!r},describe:function(e){var t=n.default.getFirstMatch(/(ipod|iphone)/i,e);return {type:s.PLATFORMS_MAP.mobile,vendor:"Apple",model:t}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return {type:s.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return {type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return "blackberry"===e.getBrowserName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(e){return "bada"===e.getBrowserName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return "windows phone"===e.getBrowserName()},describe:function(){return {type:s.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(".")[0]);return "android"===e.getOSName(!0)&&t>=3},describe:function(){return {type:s.PLATFORMS_MAP.tablet}}},{test:function(e){return "android"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return "macos"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(e){return "windows"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return "linux"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return "playstation 4"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.tv}}},{test:function(e){return "roku"===e.getOSName(!0)},describe:function(){return {type:s.PLATFORMS_MAP.tv}}}];t.default=o,e.exports=t.default;},95:function(e,t,r){t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:function(e){return "microsoft edge"===e.getBrowserName(!0)},describe:function(e){if(/\sedg\//i.test(e))return {name:s.ENGINE_MAP.Blink};var t=n.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,e);return {name:s.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:s.ENGINE_MAP.Trident},r=n.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:s.ENGINE_MAP.Presto},r=n.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=e.test(/gecko/i),r=e.test(/like gecko/i);return t&&!r},describe:function(e){var t={name:s.ENGINE_MAP.Gecko},r=n.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return {name:s.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:s.ENGINE_MAP.WebKit},r=n.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,e);return r&&(t.version=r),t}}];t.default=o,e.exports=t.default;}})})); + }); + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var defaultPixelRatio = 1; + + function pixelRatio() { + if (typeof window !== 'undefined') { + if (window.devicePixelRatio) { + return window.devicePixelRatio; + } + else { + var screen = window.screen; + if (screen && screen.deviceXDPI && screen.logicalXDPI) { + return screen.deviceXDPI / screen.logicalXDPI; + } else if (screen && screen.systemXDPI && screen.logicalXDPI) { + return screen.systemXDPI / screen.logicalXDPI; + } + } + } + return defaultPixelRatio; + } + + var pixelRatio_1 = pixelRatio; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Returns whether n is a power of two. + function ispot(n) { + return (n & (n - 1)) == 0; + } + + var ispot_1 = ispot; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + function prefixProperty(property) { + + var style = document.documentElement.style; + var prefixList = ['Moz', 'Webkit', 'Khtml', 'O', 'ms']; + + for (var i = 0; i < prefixList.length; i++) { + var prefix = prefixList[i]; + var capitalizedProperty = property[0].toUpperCase() + property.slice(1); + var prefixedProperty = prefix + capitalizedProperty; + + if (prefixedProperty in style) { + return prefixedProperty; + } + } + + return property; + + } + + + function getWithVendorPrefix(property) { + var prefixedProperty = prefixProperty(property); + return function getPropertyWithVendorPrefix(element) { + return element.style[prefixedProperty]; + }; + + } + + + function setWithVendorPrefix(property) { + var prefixedProperty = prefixProperty(property); + return function setPropertyWithVendorPrefix(element, val) { + return (element.style[prefixedProperty] = val); + }; + } + + + var setTransform = setWithVendorPrefix('transform'); + var setTransformOrigin = setWithVendorPrefix('transformOrigin'); + + + function setNullTransform(element) { + setTransform(element, 'translateZ(0)'); + } + + + function setNullTransformOrigin(element) { + setTransformOrigin(element, '0 0 0'); + } + + + function setAbsolute(element) { + element.style.position = 'absolute'; + } + + + function setPixelPosition(element, x, y) { + element.style.left = x + 'px'; + element.style.top = y + 'px'; + } + + + function setPixelSize(element, width, height) { + element.style.width = width + 'px'; + element.style.height = height + 'px'; + } + + + function setNullSize(element) { + element.style.width = element.style.height = 0; + } + + + function setFullSize(element) { + element.style.width = element.style.height = '100%'; + } + + + function setOverflowHidden(element) { + element.style.overflow = 'hidden'; + } + + + function setOverflowVisible(element) { + element.style.overflow = 'visible'; + } + + + function setNoPointerEvents(element) { + element.style.pointerEvents = 'none'; + } + + + function setBlocking(element) { + element.style.backgroundColor = '#000'; + element.style.opacity = '0'; + element.style.filter = 'alpha(opacity=0)'; + } + + + var dom = { + prefixProperty: prefixProperty, + getWithVendorPrefix: getWithVendorPrefix, + setWithVendorPrefix: setWithVendorPrefix, + setTransform: setTransform, + setTransformOrigin: setTransformOrigin, + setNullTransform: setNullTransform, + setNullTransformOrigin: setNullTransformOrigin, + setAbsolute: setAbsolute, + setPixelPosition: setPixelPosition, + setPixelSize: setPixelSize, + setNullSize: setNullSize, + setFullSize: setFullSize, + setOverflowHidden: setOverflowHidden, + setOverflowVisible: setOverflowVisible, + setNoPointerEvents: setNoPointerEvents, + setBlocking: setBlocking + }; + + var setAbsolute$1 = dom.setAbsolute; + var setFullSize$1 = dom.setFullSize; + + + var debug = typeof MARZIPANODEBUG !== 'undefined' && MARZIPANODEBUG.webGl; + + + // Browser-specific workarounds. + var browserQuirks = { + // Whether to use texImage2D instead of texSubImage2D when repainting an + // existing texture from a video element. On most browsers texSubImage2D is + // faster, but on Chrome the performance degrades significantly. See: + // https://bugs.chromium.org/p/chromium/issues/detail?id=612542 + videoUseTexImage2D: es5.chrome + }; + + + function initWebGlContext(canvas, opts) { + var options = { + alpha: true, + premultipliedAlpha: true, + antialias: !!(opts && opts.antialias), + preserveDrawingBuffer: !!(opts && opts.preserveDrawingBuffer) + }; + + if (debug && typeof WebGLDebugUtils !== 'undefined') { + console.log('Using WebGL lost context simulator'); + canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas); + } + + // Keep support/WebGl.js in sync with this. + var gl = (canvas.getContext) && (canvas.getContext('webgl', options) || canvas.getContext('experimental-webgl', options)); + + if (!gl) { + throw new Error('Could not get WebGL context'); + } + + if (debug && typeof WebGLDebugUtils !== "undefined") { + gl = WebGLDebugUtils.makeDebugContext(gl); + console.log('Using WebGL debug context'); + } + + return gl; + } + + /** + * @class WebGlStage + * @extends Stage + * @classdesc + * + * A {@link Stage} implementation using WebGl. + * + * @param {Object} opts + * @param {boolean} [opts.antialias=false] + * @param {boolean} [opts.preserveDrawingBuffer=false] + * @param {boolean} [opts.generateMipmaps=false] + * + * The `antialias` and `preserveDrawingBuffer` options control the WebGL + * context attributes of the same name. The `alpha` and `premultipliedAlpha` + * WebGL context attributes are set to their default true value and cannot + * be overriden; this allows semitransparent textures to be composited with + * the page. See: + * https://www.khronos.org/registry/webgl/specs/1.0/#WEBGLCONTEXTATTRIBUTES + * + * The `generateMipmaps` option controls texture mipmap generation. Mipmaps + * may improve rendering quality, at the cost of increased memory usage. + * Due to technical limitations, they are only generated for textures whose + * dimensions are a power of two. See: + * https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support + * + * Also see the available {@link Stage} options. + */ + function WebGlStage(opts) { + opts = opts || {}; + + var self = this; + + this.constructor.super_.call(this, opts); + + this._generateMipmaps = opts.generateMipmaps != null ? + opts.generateMipmaps : false; + + this._loader = new HtmlImage(this); + + this._domElement = document.createElement('canvas'); + + setAbsolute$1(this._domElement); + setFullSize$1(this._domElement); + + this._gl = initWebGlContext(this._domElement, opts); + + this._handleContextLoss = function() { + self.emit('webglcontextlost'); + self._gl = null; + }; + + // Handle WebGl context loss. + this._domElement.addEventListener('webglcontextlost', this._handleContextLoss); + + // WebGl renderers are singletons for a given stage. This list stores the + // existing renderers so they can be reused across layers with the same + // geometry and view type. + this._rendererInstances = []; + } + + inherits_1(WebGlStage, Stage_1); + + + /** + * Destructor. + */ + WebGlStage.prototype.destroy = function() { + this._domElement.removeEventListener('webglcontextlost', this._handleContextLoss); + // Delegate clearing own properties to the Stage destructor. + this.constructor.super_.prototype.destroy.call(this); + }; + + + WebGlStage.supported = function() { + return WebGl(); + }; + + + /** + * Returns the underlying DOM element. + * + * @return {Element} + */ + WebGlStage.prototype.domElement = function() { + return this._domElement; + }; + + + /** + * Returns the underlying WebGL rendering context. + * + * @return {WebGLRenderingContext } + */ + WebGlStage.prototype.webGlContext = function() { + return this._gl; + }; + + + WebGlStage.prototype.setSizeForType = function() { + // Update the size of the canvas coordinate space. + // + // The size is obtained by taking the stage dimensions, which are set in CSS + // pixels, and multiplying them by the device pixel ratio. Crucially, this + // must be the only place where the WebGL rendering pipeline accesses the + // pixel ratio; subsequent uses should reference the `drawingBufferWidth` and + // `drawingBufferHeight` properties on the WebGLRenderingContext. Failing to + // do so will break the rendering if the pixel ratio changes but the stage + // size does not, e.g. when moving the window across screens. + var ratio = pixelRatio_1(); + this._domElement.width = ratio * this._width; + this._domElement.height = ratio * this._height; + }; + + + WebGlStage.prototype.loadImage = function(url, rect, done) { + return this._loader.loadImage(url, rect, done); + }; + + + WebGlStage.prototype.maxTextureSize = function() { + return this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE); + }; + + + WebGlStage.prototype.validateLayer = function(layer) { + var tileSize = layer.geometry().maxTileSize(); + var maxTextureSize = this.maxTextureSize(); + if (tileSize > maxTextureSize) { + throw new Error('Layer has level with tile size larger than maximum texture size (' + tileSize + ' vs. ' + maxTextureSize + ')'); + } + }; + + + WebGlStage.prototype.createRenderer = function(Renderer) { + var rendererInstances = this._rendererInstances; + for (var i = 0; i < rendererInstances.length; i++) { + if (rendererInstances[i] instanceof Renderer) { + return rendererInstances[i]; + } + } + var renderer = new Renderer(this._gl); + rendererInstances.push(renderer); + return renderer; + }; + + + WebGlStage.prototype.destroyRenderer = function(renderer) { + var rendererInstances = this._rendererInstances; + if (this._renderers.indexOf(renderer) < 0) { + renderer.destroy(); + var index = rendererInstances.indexOf(renderer); + if (index >= 0) { + rendererInstances.splice(index, 1); + } + } + }; + + + WebGlStage.prototype.startFrame = function() { + + var gl = this._gl; + + if (!gl) { + throw new Error('Bad WebGL context - maybe context was lost?'); + } + + // Set the WebGL viewport. + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + // Clear framebuffer. + gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Enable depth testing. + gl.enable(gl.DEPTH_TEST); + + // Enable blending. ONE and ONE_MINUS_SRC_ALPHA are the right choices for + // premultiplied textures. + gl.enable(gl.BLEND); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + }; + + + WebGlStage.prototype.endFrame = function() {}; + + + WebGlStage.prototype.takeSnapshot = function (options) { + + // Validate passed argument + if (typeof options !== 'object' || options == null) { + options = {}; + } + + var quality = options.quality; + + // Set default quality if it is not passed + if (typeof quality == 'undefined') { + quality = 75; + } + + // Throw if quality is of invlid type or out of bounds + if (typeof quality !== 'number' || quality < 0 || quality > 100) { + throw new Error('WebGLStage: Snapshot quality needs to be a number between 0 and 100'); + } + + // Canvas method "toDataURL" needs to be called in the same + // context as where the actual rendering is done. Hence this. + this.render(); + + // Return the snapshot + return this._domElement.toDataURL('image/jpeg',quality/100); + }; + + + WebGlStage.type = WebGlStage.prototype.type = 'webgl'; + + + function WebGlTexture(stage, tile, asset) { + this._stage = stage; + this._gl = stage._gl; + this._texture = null; + this._timestamp = null; + this._width = this._height = null; + this.refresh(tile, asset); + } + + + WebGlTexture.prototype.refresh = function(tile, asset) { + + var gl = this._gl; + var stage = this._stage; + var texture; + + // Check whether the texture needs to be updated. + var timestamp = asset.timestamp(); + if (timestamp === this._timestamp) { + return; + } + + // Get asset element. + var element = asset.element(); + + // Get asset dimensions. + var width = asset.width(); + var height = asset.height(); + + if (width !== this._width || height !== this._height) { + + // If the texture dimensions have changed since the last refresh, create + // a new texture with the correct size. + + // Check if texture dimensions would exceed the maximum texture size. + var maxSize = stage.maxTextureSize(); + if (width > maxSize) { + throw new Error('Texture width larger than max size (' + width + ' vs. ' + maxSize + ')'); + } + if (height > maxSize) { + throw new Error('Texture height larger than max size (' + height + ' vs. ' + maxSize + ')'); + } + + // Delete the current texture if it exists. + // This is necessary for Chrome on Android. If it isn't done the textures + // do not render when the size changes. + if (this._texture) { + gl.deleteTexture(texture); + } + + // The texture must be premultiplied by alpha to ensure correct blending of + // semitransparent textures. For details, see: + // http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/ + texture = this._texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, element); + + } else { + + // If the texture dimensions remain the same, repaint the existing texture. + // Repainting with texSubImage2D is usually faster than with texImage2D, + // except in the case noted in browserQuirks. + + texture = this._texture; + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + + if (element instanceof HTMLVideoElement && browserQuirks.videoUseTexImage2D) { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, element); + } else { + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, element); + } + + } + + // Generate mipmap if the corresponding stage option is set and the texture + // dimensions are powers of two. + if (stage._generateMipmaps && ispot_1(width) && ispot_1(height)) { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); + gl.generateMipmap(gl.TEXTURE_2D); + } else { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + } + + // Clamp texture to edges. + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + // Unbind texture. + gl.bindTexture(gl.TEXTURE_2D, null); + + // Update texture dimensions and timestamp. + this._timestamp = timestamp; + this._width = width; + this._height = height; + + }; + + + WebGlTexture.prototype.destroy = function() { + if (this._texture) { + this._gl.deleteTexture(this._texture); + } + clearOwnProperties_1(this); + }; + + + WebGlStage.TextureClass = WebGlStage.prototype.TextureClass = WebGlTexture; + + + var WebGl$1 = WebGlStage; + + var prefixProperty$1 = dom.prefixProperty; + + // Detect CSS 3D transforms support. Adapted from Modernizr. + function checkCssSupported() { + // First, check if the 'perspective' CSS property or a vendor-prefixed + // variant is available. + var perspectiveProperty = prefixProperty$1('perspective'); + var el = document.createElement('div'); + var supported = typeof el.style[perspectiveProperty] !== 'undefined'; + + // Certain versions of Chrome disable 3D transforms even though the CSS + // property exists. In those cases, we use the following media query, + // which only succeeds if the feature is indeed enabled. + if (supported && perspectiveProperty === 'WebkitPerspective') { + var id = '__marzipano_test_css3d_support__'; + var st = document.createElement('style'); + st.textContent = '@media(-webkit-transform-3d){#' + id + '{height: 3px;})'; + document.getElementsByTagName('head')[0].appendChild(st); + el.id = id; + document.body.appendChild(el); + // The offsetHeight seems to be different than 3 at some zoom levels on + // Chrome (and maybe other browsers). Test for > 0 instead. + supported = el.offsetHeight > 0; + st.parentNode.removeChild(st); + el.parentNode.removeChild(el); + } + + return supported; + } + + // Cache result. + var supported$1; + function cssSupported() { + if (supported$1 !== undefined) { + return supported$1; + } + return (supported$1 = checkCssSupported()); + } + + var Css = cssSupported; + + var setAbsolute$2 = dom.setAbsolute; + var setFullSize$2 = dom.setFullSize; + var setNullTransformOrigin$1 = dom.setNullTransformOrigin; + + + + // Browser-specific workarounds. + var browserQuirks$1 = { + + // On most browsers we need to pad the tile edges with repeated pixels so + // that the borders between neighboring tiles aren't apparent. + // On iOS this isn't required, but we must disable it because the padding is + // incorrectly rendered on top of the neighboring tile. + padSize: es5.ios ? 0 : 3, + + // In order to prevent fallback tiles from overlapping their children, iOS + // requires smaller zoom levels to be placed below larger zoom levels in + // the CSS 3D coordinate space. + reverseLevelDepth: es5.ios, + + // A null transform on the layer element is required so that transitions + // between layers work on iOS. + useNullTransform: es5.ios, + + // On Webkit and Gecko browsers, some tiles become invisible at certain + // angles, usually non-floor tiles when looking straight down. Setting the + // translateZ following the perspective transform to a slightly larger value + // than the latter seems to work around this glitch. + perspectiveNudge: es5.webkit || es5.gecko ? 0.001 : 0 + + }; + + + /** + * @class CssStage + * @extends Stage + * @classdesc + * + * A {@link Stage} implementation using CSS 3D Transforms. + * + * @param {Object} opts + * + * Also see the available {@link Stage} options. + */ + function CssStage(opts) { + this.constructor.super_.call(this, opts); + + this._loader = new HtmlImage(this); + + this._domElement = document.createElement('div'); + + setAbsolute$2(this._domElement); + setFullSize$2(this._domElement); + + // N.B. the CSS stage requires device adaptation to be configured through + // the tag on the containing document. + // Failure to do so will cause clipping and padding bugs to occur, + // at least on iOS <= 7. + } + + inherits_1(CssStage, Stage_1); + + + /** + * Destructor. + */ + CssStage.prototype.destroy = function() { + // Delegate clearing own properties to the Stage destructor. + this.constructor.super_.prototype.destroy.call(this); + }; + + + CssStage.supported = function() { + return Css(); + }; + + + /** + * Returns the underlying DOM element. + * + * @return {Element} + */ + CssStage.prototype.domElement = function() { + return this._domElement; + }; + + + CssStage.prototype.setSizeForType = function() {}; + + + CssStage.prototype.loadImage = function(url, rect, done) { + return this._loader.loadImage(url, rect, done); + }; + + + CssStage.prototype.validateLayer = function(layer) { + return; // always valid + }; + + + CssStage.prototype.createRenderer = function(Renderer) { + return new Renderer(this._domElement, browserQuirks$1); + }; + + CssStage.prototype.destroyRenderer = function(renderer) { + renderer.destroy(); + }; + + + CssStage.prototype.startFrame = function() {}; + + + CssStage.prototype.endFrame = function() {}; + + + CssStage.prototype.takeSnapshot = function() { + throw new Error('CssStage: takeSnapshot not implemented'); + }; + + + CssStage.type = CssStage.prototype.type = 'css'; + + + function CssTexture(stage, tile, asset) { + + var canvas = document.createElement('canvas'); + setAbsolute$2(canvas); + setNullTransformOrigin$1(canvas); + + this._canvas = canvas; + this._timestamp = null; + this.refresh(tile, asset); + + } + + + CssTexture.prototype.refresh = function(tile, asset) { + + // Check whether the texture needs to be updated. + var timestamp = asset.timestamp(); + if (timestamp === this._timestamp) { + return; + } + this._timestamp = timestamp; + + var canvas = this._canvas; + var ctx = canvas.getContext('2d'); + + // Get asset element. + var element = asset.element(); + + // Get tile dimensions. + var tileWidth = tile.width(); + var tileHeight = tile.height(); + + // Get padding sizes. + var padSize = browserQuirks$1.padSize; + var padTop = tile.padTop() ? padSize : 0; + var padBottom = tile.padBottom() ? padSize : 0; + var padLeft = tile.padLeft() ? padSize : 0; + var padRight = tile.padRight() ? padSize : 0; + + // Set canvas size. + canvas.width = padLeft + tileWidth + padRight; + canvas.height = padTop + tileHeight + padBottom; + + // Draw image. + ctx.drawImage(element, padLeft, padTop, tileWidth, tileHeight); + + var i; + + // Draw top padding. + for (i = 0; i < padTop; i++) { + ctx.drawImage(canvas, padLeft, padTop, tileWidth, 1, + padLeft, i, tileWidth, 1); + } + + // Draw left padding. + for (i = 0; i < padLeft; i++) { + ctx.drawImage(canvas, padLeft, padTop, 1, tileHeight, + i, padTop, 1, tileHeight); + } + + // Draw bottom padding. + for (i = 0; i < padBottom; i++) { + ctx.drawImage(canvas, padLeft, padTop + tileHeight - 1, tileWidth, 1, + padLeft, padTop + tileHeight + i, tileWidth, 1); + } + + // Draw right padding. + for (i = 0; i < padRight; i++) { + ctx.drawImage(canvas, padLeft + tileWidth - 1, padTop, 1, tileHeight, + padLeft + tileWidth + i, padTop, 1, tileHeight); + } + + }; + + + CssTexture.prototype.destroy = function() { + // TODO: investigate whether keeping a pool of canvases instead of + // creating new ones on demand improves performance. + clearOwnProperties_1(this); + }; + + + CssStage.TextureClass = CssStage.prototype.TextureClass = CssTexture; + + + var Css$1 = CssStage; + + /** + * @class FlashAsset + * @implements Asset + * @classdesc + * + * An immutable {@link Asset} compatible with {@link FlashStage}. + * + * The asset's underlying pixel source is a unique image ID associated with + * a Flash application. + * + * @param {Element} flashElement The HTML element for the Flash application. + * @param {number} imageId The unique image ID inside the Flash application. + */ + function FlashAsset(flashElement, imageId) { + this._flashElement = flashElement; + this._imageId = imageId; + } + + minimalEventEmitter(FlashAsset); + + /** + * Destructor. + */ + FlashAsset.prototype.destroy = function() { + this._flashElement.unloadImage(this._imageId); + clearOwnProperties_1(this); + }; + + FlashAsset.prototype.element = function() { + return this._imageId; + }; + + FlashAsset.prototype.width = function() { + // Not actually used anywhere. + return 0; + }; + + FlashAsset.prototype.height = function() { + // Not actually used anywhere. + return 0; + }; + + FlashAsset.prototype.timestamp = function() { + return 0; + }; + + FlashAsset.prototype.isDynamic = function() { + return false; + }; + + var Flash = FlashAsset; + + // TODO: Move the load queue into the loader. + + /** + * @class FlashImageLoader + * @implements ImageLoader + * @classdesc + * + * A {@link Loader} for Flash images. + * + * @param {Stage} stage The stage which is going to request images to be loaded. + */ + function FlashImageLoader(stage) { + if (stage.type !== 'flash') { + throw new Error('Stage type incompatible with loader'); + } + this._stage = stage; + } + + /** + * Loads an {@link Asset} from an image. + * @param {string} url The image URL. + * @param {?Rect} rect A {@link Rect} describing a portion of the image, or null + * to use the full image. + * @param {function(?Error, Asset)} done The callback. + * @return {function()} A function to cancel loading. + */ + FlashImageLoader.prototype.loadImage = function(url, rect, done) { + var stage = this._stage; + var flashElement = stage.flashElement(); + + var x = rect && rect.x || 0; + var y = rect && rect.y || 0; + var width = rect && rect.width || 1; + var height = rect && rect.height || 1; + + var imageId = flashElement.loadImage(url, width, height, x, y); + + done = once_1(done); + + // TODO: use a single callback for all imageLoaded events. + + function callback(err, callbackId) { + // There is a single callback for all load events, so make sure this + // is the right one. + if (callbackId !== imageId) { + return; + } + + stage.removeFlashCallbackListener('imageLoaded', callback); + + // TODO: is there any way to distinguish a network error from other + // kinds of errors? For now we always return NetworkError since this + // prevents images to be retried continuously while we are offline. + if (err) { + done(new NetworkError_1('Network error: ' + url)); + } else { + done(null, new Flash(flashElement, imageId)); + } + } + + stage.addFlashCallbackListener('imageLoaded', callback); + + function cancel() { + flashElement.cancelImage(imageId); + stage.removeFlashCallbackListener('imageLoaded', callback); + done.apply(null, arguments); + } + + return cancel; + }; + + var FlashImage = FlashImageLoader; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Detect supported Flash version. Returns [major, minor, rev] or null. + // Adapted from https://code.google.com/p/swfobject + function detectFlashVersion() { + var playerVersion = null; + + var plugins = navigator.plugins; + var mimeTypes = navigator.mimeTypes; + + var d = null; + + if (plugins && plugins['Shockwave Flash'] && mimeTypes && + mimeTypes['application/x-shockwave-flash'] && + mimeTypes['application/x-shockwave-flash'].enabledPlugin) { + d = plugins['Shockwave Flash'].description; + d = d.replace(/^.*\s+(\S+\s+\S+$)/, '$1'); + playerVersion = [0, 0, 0]; + playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, '$1'), 10); + playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, '$1'), 10); + playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, '$1'), 10) : 0; + } + else if (window.ActiveXObject) { + try { + var a = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); + if (a && (d = a.GetVariable('$version'))) { + d = d.split(' ')[1].split(','); + playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; + } + } + catch (e) {} + } + + return playerVersion; + } + + // Flash support detection. + function checkFlashSupported() { + var version = detectFlashVersion(); + // Only support 10.1 and above. Flash 10.0 does not work for some reason. + return version && (version[0] >= 11 || (version[0] === 10 && version[1] >= 1)); + } + + // Cache result. + var supported$2; + function flashSupported() { + if (supported$2 !== undefined) { + return supported$2; + } + return (supported$2 = checkFlashSupported()); + } + + var Flash$1 = flashSupported; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function defer(fn, args) { + function deferred() { + if (args && args.length > 0) { + fn.apply(null, args); + } else { + fn(); + } + } + setTimeout(deferred, 0); + } + + var defer_1 = defer; + + var setAbsolute$3 = dom.setAbsolute; + var setFullSize$3 = dom.setFullSize; + var setBlocking$1 = dom.setBlocking; + + + // Default Flash wmode. + var defaultWMode = 'transparent'; + + // Default Flash SWF path. By default, expect the SWF to be named marzipano.swf + // and located in the same directory as the current script. The default path + // may be overridden by passing the `swfPath` option into the Viewer or Stage + // constructor. + var defaultSwfPath = function() { + var script = document.currentScript; + if (!script) { + // This will produce the wrong result if the current script is loaded with + // the `async` or `defer` options, or exec'ed from a string. The user is + // expected to supply a custom `swfPath` in these cases. + var scripts = document.getElementsByTagName('script'); + script = scripts.length ? scripts[scripts.length-1] : null; + } + if (!script) { + return null; + } + var path = script.src; + var slash = path.lastIndexOf('/'); + if (slash >= 0) { + path = path.slice(0, slash + 1); + } else { + path = ''; + } + return path + 'marzipano.swf'; + }(); + + // Callbacks must be exposed in a global object to be called from Flash. + // The global object maps each stage ID into the respective callbacks. + // To prevent multiple Marzipano instances from clobbering the callbacks + // for each other's stages, the next available stage ID must be shared among + // the instances. We cache this value in a special property of the global + // callback object. + var callbackObjectName = 'MarzipanoFlashCallbackMap'; + if (!(callbackObjectName in window)) { + window[callbackObjectName] = { __next: 0 }; + } + + // Get the next available Flash stage ID. + function nextFlashStageId() { + return window[callbackObjectName].__next++; + } + + // Names of the callbacks called from Flash. Presently there is only one. + var callbackNames = [ 'imageLoaded' ]; + + // Browser-specific workarounds. + var flashQuirks = { + // How many repeated pixels to add around tile edges to suppress visible seams. + padSize: 3 + }; + + /** + * @class FlashStage + * @extends Stage + * @classdesc + * + * A {@link Stage} implementation using Flash. + * + * @param {Object} opts + * @param {string} [opts.wmode='transparent'] + * @param {string} [opts.swfPath] + * + * The `wmode` option controls transparency, layering and compositing of the + * Flash element into the web page. For more information see: + * http://helpx.adobe.com/flash/kb/flash-object-embed-tag-attributes.html + * + * The `swfPath` option denotes the path to the `marzipano.swf` file. It + * defaults to the location of `marzipano.js` by looking for a script tag with + * that name. + * + * Also see the available {@link Stage} options. + */ + function FlashStage(opts) { + this.constructor.super_.call(this, opts); + + this._wmode = opts && opts.wmode || defaultWMode; + this._swfPath = opts && opts.swfPath || defaultSwfPath; + + if (!defaultSwfPath) { + throw new Error('Missing SWF path'); + } + + // Setup JavaScript callbacks to be called from Flash land when + // asynchronous operations terminate. + this._flashStageId = nextFlashStageId(); + this._callbacksObj = window[callbackObjectName][this._flashStageId] = {}; + this._stageCallbacksObjVarName = callbackObjectName + '[' + this._flashStageId + ']'; + this._callbackListeners = {}; + for (var i = 0; i < callbackNames.length; i++) { + this._callbacksObj[callbackNames[i]] = this._callListeners(callbackNames[i]); + } + + this._loader = new FlashImage(this); + + // Queue for loadImage calls. + // The queue starts paused so that loadImage calls occurring before Flash + // is ready do not start right away (as they would fail). + // TODO: This is awkward. The stage must signal that it's ready to load + // images, but queuing should otherwise be implemented by the loader. + this._loadImageQueue = new WorkQueue_1(); + this._loadImageQueue.pause(); + + // Whether flash is ready to be called from JavaScript. + this._flashReady = false; + + // Add an ID to each renderer/layer, so that it can be identified within + // the ActionScript program. + this._nextLayerId = 0; + + // Create the DOM elements. + var elements = createDomElements(this._swfPath, this._flashStageId, this._stageCallbacksObjVarName); + this._domElement = elements.root; + this._blockingElement = elements.blocking; + this._flashElement = elements.flash; + + // Wake up the render loop when we are ready (only after element is added to the DOM) + this._checkReadyTimer = setInterval(this._checkReady.bind(this), 50); + } + + inherits_1(FlashStage, Stage_1); + + + /** + * Destructor. + */ + FlashStage.prototype.destroy = function() { + window[callbackObjectName][this._flashStageId] = null; + if (this._checkReadyTimer != null) { + clearInterval(this._checkReadyTimer); + } + // Delegate clearing own properties to the Stage destructor. + this.constructor.super_.prototype.destroy.call(this); + }; + + + FlashStage.supported = function() { + return Flash$1(); + }; + + + /** + * Returns the underlying DOM element. + * @return {Element} + */ + FlashStage.prototype.domElement = function() { + return this._domElement; + }; + + + /** + * Returns the underlying Flash element. + * @return {Element} + */ + FlashStage.prototype.flashElement = function() { + return this._flashElement; + }; + + + FlashStage.prototype.setSizeForType = function() {}; + + + FlashStage.prototype.loadImage = function(url, rect, done) { + // TODO: Move the queuing into the loader, which avoids this nonsense. + var loadFn = this._loader.loadImage.bind(this._loader, url, rect); + return this._loadImageQueue.push(loadFn, done); + }; + + + FlashStage.prototype.validateLayer = function(layer) { + return; // always valid + }; + + + FlashStage.prototype.addFlashCallbackListener = function(callbackName, f) { + this._callbackListeners[callbackName] = this._callbackListeners[callbackName] || []; + this._callbackListeners[callbackName].push(f); + }; + + + FlashStage.prototype.removeFlashCallbackListener = function(callbackName, f) { + var listeners = this._callbackListeners[callbackName] || []; + var index = listeners.indexOf(f); + if (index >= 0) { + listeners.splice(index, 1); + } + }; + + + FlashStage.prototype._callListeners = function(callbackName) { + + var self = this; + + return function callListeners() { + var listeners = self._callbackListeners[callbackName] || []; + for (var i = 0; i < listeners.length; i++) { + // JavaScript executed on calls from Flash does not throw exceptions. + // Executing the callback in a new stack frame fixes this. + var listener = listeners[i]; + defer_1(listener, arguments); + } + }; + }; + + + FlashStage.prototype._checkReady = function() { + if (!this._flashElement || + !this._flashElement.isReady || + !this._flashElement.isReady()) { + // Not ready yet. + return false; + } + + // Mark as ready. + this._flashReady = true; + + // Disable interval timer. + clearTimeout(this._checkReadyTimer); + this._checkReadyTimer = null; + + // Resume image loading queue. + this._loadImageQueue.resume(); + + // Force next render. + this.emit('renderInvalid'); + + return true; + }; + + + function createDomElements(swfPath, id, stageCallbacksObjVarName) { + var rootElement = document.createElement('div'); + setAbsolute$3(rootElement); + setFullSize$3(rootElement); + + // The Flash object must have `id` and `name` attributes, otherwise + // ExternalInterface calls will not work. + var elementId = "marzipano-flash-stage-" + id; + + var objectStr = ''; + + var paramsStr = ''; + paramsStr += ''; + paramsStr += ''; + paramsStr += ''; + paramsStr += ''; + + objectStr += paramsStr; + objectStr += ''; + + // Embed Flash into the DOM. + // Adding children into an element doesn't work, so we create a + // temporary element and set its innerHTML. + var tmpElement = document.createElement('div'); + tmpElement.innerHTML = objectStr; + var flashElement = tmpElement.firstChild; + setAbsolute$3(flashElement); + setFullSize$3(flashElement); + rootElement.appendChild(flashElement); + + // Create blocking element to prevent events from being caught by Flash. + var blockingElement = document.createElement('div'); + setAbsolute$3(blockingElement); + setFullSize$3(blockingElement); + setBlocking$1(blockingElement); + rootElement.appendChild(blockingElement); + + return { root: rootElement, flash: flashElement, blocking: blockingElement }; + } + + + FlashStage.prototype.createRenderer = function(Renderer) { + return new Renderer(this._flashElement, ++this._nextLayerId, flashQuirks); + }; + + + FlashStage.prototype.destroyRenderer = function(renderer) { + renderer.destroy(); + }; + + + FlashStage.prototype.startFrame = function() {}; + + + FlashStage.prototype.endFrame = function() {}; + + + FlashStage.prototype.takeSnapshot = function (options) { + // Validate argument. + if (typeof options !== 'object' || options == null) { + options = {}; + } + + var quality = options.quality; + + // Set default quality if it is not passed in. + if (typeof quality == 'undefined') { + quality = 75; + } + + // Throw if quality is of invlid type or out of bounds. + if (typeof quality !== 'number' || quality < 0 || quality > 100) { + throw new Error('FlashStage: Snapshot quality needs to be a number between 0 and 100'); + } + + // Return the snapshot by executing a flash-exported method. + return this._flashElement.takeSnapshot(quality); + }; + + + FlashStage.type = FlashStage.prototype.type = 'flash'; + + + function FlashTexture(stage, tile, asset) { + + // Get image id. + var imageId = asset.element(); + + // Get tile dimensions. + var tileWidth = tile.width(); + var tileHeight = tile.height(); + + // Get padding sizes. + var padSize = flashQuirks.padSize; + var padTop = tile.padTop() ? padSize : 0; + var padBottom = tile.padBottom() ? padSize : 0; + var padLeft = tile.padLeft() ? padSize : 0; + var padRight = tile.padRight() ? padSize : 0; + + var textureId = stage._flashElement.createTexture(imageId, tileWidth, tileHeight, padTop, padBottom, padLeft, padRight); + + this._stage = stage; + this._textureId = textureId; + } + + + FlashTexture.prototype.refresh = function(tile, asset) { + // TODO: This is required for the Flash stage to support dynamic textures. + // However, there are currently no dynamic textures that work with the + // Flash stage. + }; + + + FlashTexture.prototype.destroy = function() { + this._stage._flashElement.destroyTexture(this._textureId); + clearOwnProperties_1(this); + }; + + + FlashStage.TextureClass = FlashStage.prototype.TextureClass = FlashTexture; + + + var Flash$2 = FlashStage; + + /** + * Common utilities + * @module glMatrix + */ + // Configuration Constants + var EPSILON = 0.000001; + var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; + var RANDOM = Math.random; + /** + * Sets the type of array used when creating new vectors and matrices + * + * @param {Type} type Array type, such as Float32Array or Array + */ + + function setMatrixArrayType(type) { + ARRAY_TYPE = type; + } + var degree = Math.PI / 180; + /** + * Convert Degree To Radian + * + * @param {Number} a Angle in Degrees + */ + + function toRadian(a) { + return a * degree; + } + /** + * Tests whether or not the arguments have approximately the same value, within an absolute + * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less + * than or equal to 1.0, and a relative tolerance is used for larger values) + * + * @param {Number} a The first number to test. + * @param {Number} b The second number to test. + * @returns {Boolean} True if the numbers are approximately equal, false otherwise. + */ + + function equals(a, b) { + return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b)); + } + if (!Math.hypot) Math.hypot = function () { + var y = 0, + i = arguments.length; + + while (i--) { + y += arguments[i] * arguments[i]; + } + + return Math.sqrt(y); + }; + + var common = /*#__PURE__*/Object.freeze({ + __proto__: null, + EPSILON: EPSILON, + get ARRAY_TYPE () { return ARRAY_TYPE; }, + RANDOM: RANDOM, + setMatrixArrayType: setMatrixArrayType, + toRadian: toRadian, + equals: equals + }); + + /** + * 2x2 Matrix + * @module mat2 + */ + + /** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ + + function create() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + } + + out[0] = 1; + out[3] = 1; + return out; + } + /** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ + + function clone(a) { + var out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ + + function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ + + function identity$1(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } + /** + * Create a new mat2 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out A new 2x2 matrix + */ + + function fromValues(m00, m01, m10, m11) { + var out = new ARRAY_TYPE(4); + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; + } + /** + * Set the components of a mat2 to the given values + * + * @param {mat2} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out + */ + + function set(out, m00, m01, m10, m11) { + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; + } + /** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ + + function transpose(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache + // some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; + } + /** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ + + function invert(out, a) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; // Calculate the determinant + + var det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + return out; + } + /** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ + + function adjoint(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + return out; + } + /** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant(a) { + return a[0] * a[3] - a[2] * a[1]; + } + /** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ + + function multiply(out, a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; + } + /** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ + + function rotate(out, a, rad) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; + } + /** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ + + function scale(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.rotate(dest, dest, rad); + * + * @param {mat2} out mat2 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ + + function fromRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.scale(dest, dest, vec); + * + * @param {mat2} out mat2 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2} out + */ + + function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + return out; + } + /** + * Returns a string representation of a mat2 + * + * @param {mat2} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str(a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; + } + /** + * Returns Frobenius norm of a mat2 + * + * @param {mat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob(a) { + return Math.hypot(a[0], a[1], a[2], a[3]); + } + /** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {mat2} L the lower triangular matrix + * @param {mat2} D the diagonal matrix + * @param {mat2} U the upper triangular matrix + * @param {mat2} a the input matrix to factorize + */ + + function LDU(L, D, U, a) { + L[2] = a[2] / a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; + } + /** + * Adds two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ + + function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ + + function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$1(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)); + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2} out + */ + + function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; + } + /** + * Adds two mat2's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2} out the receiving vector + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2} out + */ + + function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + return out; + } + /** + * Alias for {@link mat2.multiply} + * @function + */ + + var mul = multiply; + /** + * Alias for {@link mat2.subtract} + * @function + */ + + var sub = subtract; + + var mat2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create, + clone: clone, + copy: copy, + identity: identity$1, + fromValues: fromValues, + set: set, + transpose: transpose, + invert: invert, + adjoint: adjoint, + determinant: determinant, + multiply: multiply, + rotate: rotate, + scale: scale, + fromRotation: fromRotation, + fromScaling: fromScaling, + str: str, + frob: frob, + LDU: LDU, + add: add, + subtract: subtract, + exactEquals: exactEquals, + equals: equals$1, + multiplyScalar: multiplyScalar, + multiplyScalarAndAdd: multiplyScalarAndAdd, + mul: mul, + sub: sub + }); + + /** + * 2x3 Matrix + * @module mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+     * [a, b, c,
+     *  d, tx, ty]
+     * 
+ * This is a short form for the 3x3 matrix: + *
+     * [a, b, 0,
+     *  c, d, 0,
+     *  tx, ty, 1]
+     * 
+ * The last column is ignored so the array is shorter and operations are faster. + */ + + /** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ + + function create$1() { + var out = new ARRAY_TYPE(6); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[4] = 0; + out[5] = 0; + } + + out[0] = 1; + out[3] = 1; + return out; + } + /** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ + + function clone$1(a) { + var out = new ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; + } + /** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ + + function copy$1(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; + } + /** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ + + function identity$2(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Create a new mat2d with the given values + * + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} A new mat2d + */ + + function fromValues$1(a, b, c, d, tx, ty) { + var out = new ARRAY_TYPE(6); + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; + } + /** + * Set the components of a mat2d to the given values + * + * @param {mat2d} out the receiving matrix + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} out + */ + + function set$1(out, a, b, c, d, tx, ty) { + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; + } + /** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ + + function invert$1(out, a) { + var aa = a[0], + ab = a[1], + ac = a[2], + ad = a[3]; + var atx = a[4], + aty = a[5]; + var det = aa * ad - ab * ac; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; + } + /** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$1(a) { + return a[0] * a[3] - a[1] * a[2]; + } + /** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ + + function multiply$1(out, a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; + } + /** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ + + function rotate$1(out, a, rad) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; + } + /** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ + + function scale$1(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; + } + /** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ + + function translate(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.rotate(dest, dest, rad); + * + * @param {mat2d} out mat2d receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ + + function fromRotation$1(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.scale(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2d} out + */ + + function fromScaling$1(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.translate(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Translation vector + * @returns {mat2d} out + */ + + function fromTranslation(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = v[0]; + out[5] = v[1]; + return out; + } + /** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$1(a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; + } + /** + * Returns Frobenius norm of a mat2d + * + * @param {mat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$1(a) { + return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1); + } + /** + * Adds two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ + + function add$1(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ + + function subtract$1(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2d} out + */ + + function multiplyScalar$1(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + return out; + } + /** + * Adds two mat2d's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2d} out the receiving vector + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2d} out + */ + + function multiplyScalarAndAdd$1(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$1(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$2(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)); + } + /** + * Alias for {@link mat2d.multiply} + * @function + */ + + var mul$1 = multiply$1; + /** + * Alias for {@link mat2d.subtract} + * @function + */ + + var sub$1 = subtract$1; + + var mat2d = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$1, + clone: clone$1, + copy: copy$1, + identity: identity$2, + fromValues: fromValues$1, + set: set$1, + invert: invert$1, + determinant: determinant$1, + multiply: multiply$1, + rotate: rotate$1, + scale: scale$1, + translate: translate, + fromRotation: fromRotation$1, + fromScaling: fromScaling$1, + fromTranslation: fromTranslation, + str: str$1, + frob: frob$1, + add: add$1, + subtract: subtract$1, + multiplyScalar: multiplyScalar$1, + multiplyScalarAndAdd: multiplyScalarAndAdd$1, + exactEquals: exactEquals$1, + equals: equals$2, + mul: mul$1, + sub: sub$1 + }); + + /** + * 3x3 Matrix + * @module mat3 + */ + + /** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ + + function create$2() { + var out = new ARRAY_TYPE(9); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + } + + out[0] = 1; + out[4] = 1; + out[8] = 1; + return out; + } + /** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out + */ + + function fromMat4(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; + } + /** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ + + function clone$2(a) { + var out = new ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; + } + /** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ + + function copy$2(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; + } + /** + * Create a new mat3 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} A new mat3 + */ + + function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) { + var out = new ARRAY_TYPE(9); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; + } + /** + * Set the components of a mat3 to the given values + * + * @param {mat3} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} out + */ + + function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; + } + /** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ + + function identity$3(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ + + function transpose$1(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], + a02 = a[2], + a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; + } else { + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; + } + + return out; + } + /** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ + + function invert$2(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; // Calculate the determinant + + var det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; + } + /** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ + + function adjoint$1(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + out[0] = a11 * a22 - a12 * a21; + out[1] = a02 * a21 - a01 * a22; + out[2] = a01 * a12 - a02 * a11; + out[3] = a12 * a20 - a10 * a22; + out[4] = a00 * a22 - a02 * a20; + out[5] = a02 * a10 - a00 * a12; + out[6] = a10 * a21 - a11 * a20; + out[7] = a01 * a20 - a00 * a21; + out[8] = a00 * a11 - a01 * a10; + return out; + } + /** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$2(a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); + } + /** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ + + function multiply$2(out, a, b) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + var b00 = b[0], + b01 = b[1], + b02 = b[2]; + var b10 = b[3], + b11 = b[4], + b12 = b[5]; + var b20 = b[6], + b21 = b[7], + b22 = b[8]; + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; + } + /** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ + + function translate$1(out, a, v) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a10 = a[3], + a11 = a[4], + a12 = a[5], + a20 = a[6], + a21 = a[7], + a22 = a[8], + x = v[0], + y = v[1]; + out[0] = a00; + out[1] = a01; + out[2] = a02; + out[3] = a10; + out[4] = a11; + out[5] = a12; + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; + } + /** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ + + function rotate$2(out, a, rad) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a10 = a[3], + a11 = a[4], + a12 = a[5], + a20 = a[6], + a21 = a[7], + a22 = a[8], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; + } + /** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ + + function scale$2(out, a, v) { + var x = v[0], + y = v[1]; + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.translate(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Translation vector + * @returns {mat3} out + */ + + function fromTranslation$1(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = v[0]; + out[7] = v[1]; + out[8] = 1; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.rotate(dest, dest, rad); + * + * @param {mat3} out mat3 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ + + function fromRotation$2(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = -s; + out[4] = c; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.scale(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat3} out + */ + + function fromScaling$2(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = v[1]; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ + + function fromMat2d(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; + } + /** + * Calculates a 3x3 matrix from the given quaternion + * + * @param {mat3} out mat3 receiving operation result + * @param {quat} q Quaternion to create matrix from + * + * @returns {mat3} out + */ + + function fromQuat(out, q) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var yx = y * x2; + var yy = y * y2; + var zx = z * x2; + var zy = z * y2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; + return out; + } + /** + * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix + * + * @param {mat3} out mat3 receiving operation result + * @param {mat4} a Mat4 to derive the normal matrix from + * + * @returns {mat3} out + */ + + function normalFromMat4(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + return out; + } + /** + * Generates a 2D projection matrix with the given bounds + * + * @param {mat3} out mat3 frustum matrix will be written into + * @param {number} width Width of your gl context + * @param {number} height Height of gl context + * @returns {mat3} out + */ + + function projection(out, width, height) { + out[0] = 2 / width; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = -2 / height; + out[5] = 0; + out[6] = -1; + out[7] = 1; + out[8] = 1; + return out; + } + /** + * Returns a string representation of a mat3 + * + * @param {mat3} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$2(a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; + } + /** + * Returns Frobenius norm of a mat3 + * + * @param {mat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$2(a) { + return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + } + /** + * Adds two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ + + function add$2(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ + + function subtract$2(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat3} out + */ + + function multiplyScalar$2(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + return out; + } + /** + * Adds two mat3's after multiplying each element of the second operand by a scalar value. + * + * @param {mat3} out the receiving vector + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat3} out + */ + + function multiplyScalarAndAdd$2(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + out[6] = a[6] + b[6] * scale; + out[7] = a[7] + b[7] * scale; + out[8] = a[8] + b[8] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$2(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$3(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7], + a8 = a[8]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)); + } + /** + * Alias for {@link mat3.multiply} + * @function + */ + + var mul$2 = multiply$2; + /** + * Alias for {@link mat3.subtract} + * @function + */ + + var sub$2 = subtract$2; + + var mat3 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$2, + fromMat4: fromMat4, + clone: clone$2, + copy: copy$2, + fromValues: fromValues$2, + set: set$2, + identity: identity$3, + transpose: transpose$1, + invert: invert$2, + adjoint: adjoint$1, + determinant: determinant$2, + multiply: multiply$2, + translate: translate$1, + rotate: rotate$2, + scale: scale$2, + fromTranslation: fromTranslation$1, + fromRotation: fromRotation$2, + fromScaling: fromScaling$2, + fromMat2d: fromMat2d, + fromQuat: fromQuat, + normalFromMat4: normalFromMat4, + projection: projection, + str: str$2, + frob: frob$2, + add: add$2, + subtract: subtract$2, + multiplyScalar: multiplyScalar$2, + multiplyScalarAndAdd: multiplyScalarAndAdd$2, + exactEquals: exactEquals$2, + equals: equals$3, + mul: mul$2, + sub: sub$2 + }); + + /** + * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. + * @module mat4 + */ + + /** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ + + function create$3() { + var out = new ARRAY_TYPE(16); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } + + out[0] = 1; + out[5] = 1; + out[10] = 1; + out[15] = 1; + return out; + } + /** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ + + function clone$3(a) { + var out = new ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ + + function copy$3(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Create a new mat4 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} A new mat4 + */ + + function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + var out = new ARRAY_TYPE(16); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; + } + /** + * Set the components of a mat4 to the given values + * + * @param {mat4} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} out + */ + + function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; + } + /** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ + + function identity$4(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ + + function transpose$2(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a12 = a[6], + a13 = a[7]; + var a23 = a[11]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; + } + /** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ + + function invert$3(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; + } + /** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ + + function adjoint$2(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12); + out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11); + return out; + } + /** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$3(a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + } + /** + * Multiplies two mat4s + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ + + function multiply$3(out, a, b) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; // Cache only the current line of the second matrix + + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[4]; + b1 = b[5]; + b2 = b[6]; + b3 = b[7]; + out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[8]; + b1 = b[9]; + b2 = b[10]; + b3 = b[11]; + out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[12]; + b1 = b[13]; + b2 = b[14]; + b3 = b[15]; + out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + return out; + } + /** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ + + function translate$2(out, a, v) { + var x = v[0], + y = v[1], + z = v[2]; + var a00, a01, a02, a03; + var a10, a11, a12, a13; + var a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; + a01 = a[1]; + a02 = a[2]; + a03 = a[3]; + a10 = a[4]; + a11 = a[5]; + a12 = a[6]; + a13 = a[7]; + a20 = a[8]; + a21 = a[9]; + a22 = a[10]; + a23 = a[11]; + out[0] = a00; + out[1] = a01; + out[2] = a02; + out[3] = a03; + out[4] = a10; + out[5] = a11; + out[6] = a12; + out[7] = a13; + out[8] = a20; + out[9] = a21; + out[10] = a22; + out[11] = a23; + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; + } + /** + * Scales the mat4 by the dimensions in the given vec3 not using vectorization + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ + + function scale$3(out, a, v) { + var x = v[0], + y = v[1], + z = v[2]; + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Rotates a mat4 by the given angle around the given axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ + + function rotate$3(out, a, rad, axis) { + var x = axis[0], + y = axis[1], + z = axis[2]; + var len = Math.hypot(x, y, z); + var s, c, t; + var a00, a01, a02, a03; + var a10, a11, a12, a13; + var a20, a21, a22, a23; + var b00, b01, b02; + var b10, b11, b12; + var b20, b21, b22; + + if (len < EPSILON) { + return null; + } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + a00 = a[0]; + a01 = a[1]; + a02 = a[2]; + a03 = a[3]; + a10 = a[4]; + a11 = a[5]; + a12 = a[6]; + a13 = a[7]; + a20 = a[8]; + a21 = a[9]; + a22 = a[10]; + a23 = a[11]; // Construct the elements of the rotation matrix + + b00 = x * x * t + c; + b01 = y * x * t + z * s; + b02 = z * x * t - y * s; + b10 = x * y * t - z * s; + b11 = y * y * t + c; + b12 = z * y * t + x * s; + b20 = x * z * t + y * s; + b21 = y * z * t - x * s; + b22 = z * z * t + c; // Perform rotation-specific matrix multiplication + + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { + // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + return out; + } + /** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateX(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; + } + /** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateY(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; + } + /** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateZ(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Translation vector + * @returns {mat4} out + */ + + function fromTranslation$2(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.scale(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Scaling vector + * @returns {mat4} out + */ + + function fromScaling$3(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = v[1]; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = v[2]; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a given angle around a given axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotate(dest, dest, rad, axis); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ + + function fromRotation$3(out, rad, axis) { + var x = axis[0], + y = axis[1], + z = axis[2]; + var len = Math.hypot(x, y, z); + var s, c, t; + + if (len < EPSILON) { + return null; + } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; // Perform rotation-specific matrix multiplication + + out[0] = x * x * t + c; + out[1] = y * x * t + z * s; + out[2] = z * x * t - y * s; + out[3] = 0; + out[4] = x * y * t - z * s; + out[5] = y * y * t + c; + out[6] = z * y * t + x * s; + out[7] = 0; + out[8] = x * z * t + y * s; + out[9] = y * z * t - x * s; + out[10] = z * z * t + c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the X axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateX(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromXRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = c; + out[6] = s; + out[7] = 0; + out[8] = 0; + out[9] = -s; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the Y axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateY(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromYRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = c; + out[1] = 0; + out[2] = -s; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = s; + out[9] = 0; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the Z axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateZ(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromZRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = 0; + out[4] = -s; + out[5] = c; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ + + function fromRotationTranslation(out, q, v) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a new mat4 from a dual quat. + * + * @param {mat4} out Matrix + * @param {quat2} a Dual Quaternion + * @returns {mat4} mat4 receiving operation result + */ + + function fromQuat2(out, a) { + var translation = new ARRAY_TYPE(3); + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7]; + var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense + + if (magnitude > 0) { + translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude; + translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude; + translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude; + } else { + translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; + translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; + translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; + } + + fromRotationTranslation(out, a, translation); + return out; + } + /** + * Returns the translation vector component of a transformation + * matrix. If a matrix is built with fromRotationTranslation, + * the returned vector will be the same as the translation vector + * originally supplied. + * @param {vec3} out Vector to receive translation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ + + function getTranslation(out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; + return out; + } + /** + * Returns the scaling factor component of a transformation + * matrix. If a matrix is built with fromRotationTranslationScale + * with a normalized Quaternion paramter, the returned vector will be + * the same as the scaling vector + * originally supplied. + * @param {vec3} out Vector to receive scaling factor component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ + + function getScaling(out, mat) { + var m11 = mat[0]; + var m12 = mat[1]; + var m13 = mat[2]; + var m21 = mat[4]; + var m22 = mat[5]; + var m23 = mat[6]; + var m31 = mat[8]; + var m32 = mat[9]; + var m33 = mat[10]; + out[0] = Math.hypot(m11, m12, m13); + out[1] = Math.hypot(m21, m22, m23); + out[2] = Math.hypot(m31, m32, m33); + return out; + } + /** + * Returns a quaternion representing the rotational component + * of a transformation matrix. If a matrix is built with + * fromRotationTranslation, the returned quaternion will be the + * same as the quaternion originally supplied. + * @param {quat} out Quaternion to receive the rotation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {quat} out + */ + + function getRotation(out, mat) { + var scaling = new ARRAY_TYPE(3); + getScaling(scaling, mat); + var is1 = 1 / scaling[0]; + var is2 = 1 / scaling[1]; + var is3 = 1 / scaling[2]; + var sm11 = mat[0] * is1; + var sm12 = mat[1] * is2; + var sm13 = mat[2] * is3; + var sm21 = mat[4] * is1; + var sm22 = mat[5] * is2; + var sm23 = mat[6] * is3; + var sm31 = mat[8] * is1; + var sm32 = mat[9] * is2; + var sm33 = mat[10] * is3; + var trace = sm11 + sm22 + sm33; + var S = 0; + + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (sm23 - sm32) / S; + out[1] = (sm31 - sm13) / S; + out[2] = (sm12 - sm21) / S; + } else if (sm11 > sm22 && sm11 > sm33) { + S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2; + out[3] = (sm23 - sm32) / S; + out[0] = 0.25 * S; + out[1] = (sm12 + sm21) / S; + out[2] = (sm31 + sm13) / S; + } else if (sm22 > sm33) { + S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2; + out[3] = (sm31 - sm13) / S; + out[0] = (sm12 + sm21) / S; + out[1] = 0.25 * S; + out[2] = (sm23 + sm32) / S; + } else { + S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2; + out[3] = (sm12 - sm21) / S; + out[0] = (sm31 + sm13) / S; + out[1] = (sm23 + sm32) / S; + out[2] = 0.25 * S; + } + + return out; + } + /** + * Creates a matrix from a quaternion rotation, vector translation and vector scale + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @returns {mat4} out + */ + + function fromRotationTranslationScale(out, q, v, s) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + var sx = s[0]; + var sy = s[1]; + var sz = s[2]; + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * mat4.translate(dest, origin); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * mat4.translate(dest, negativeOrigin); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @param {vec3} o The origin vector around which to scale and rotate + * @returns {mat4} out + */ + + function fromRotationTranslationScaleOrigin(out, q, v, s, o) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + var sx = s[0]; + var sy = s[1]; + var sz = s[2]; + var ox = o[0]; + var oy = o[1]; + var oz = o[2]; + var out0 = (1 - (yy + zz)) * sx; + var out1 = (xy + wz) * sx; + var out2 = (xz - wy) * sx; + var out4 = (xy - wz) * sy; + var out5 = (1 - (xx + zz)) * sy; + var out6 = (yz + wx) * sy; + var out8 = (xz + wy) * sz; + var out9 = (yz - wx) * sz; + var out10 = (1 - (xx + yy)) * sz; + out[0] = out0; + out[1] = out1; + out[2] = out2; + out[3] = 0; + out[4] = out4; + out[5] = out5; + out[6] = out6; + out[7] = 0; + out[8] = out8; + out[9] = out9; + out[10] = out10; + out[11] = 0; + out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz); + out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz); + out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz); + out[15] = 1; + return out; + } + /** + * Calculates a 4x4 matrix from the given quaternion + * + * @param {mat4} out mat4 receiving operation result + * @param {quat} q Quaternion to create matrix from + * + * @returns {mat4} out + */ + + function fromQuat$1(out, q) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var yx = y * x2; + var yy = y * y2; + var zx = z * x2; + var zy = z * y2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ + + function frustum(out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left); + var tb = 1 / (top - bottom); + var nf = 1 / (near - far); + out[0] = near * 2 * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = near * 2 * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = far * near * 2 * nf; + out[15] = 0; + return out; + } + /** + * Generates a perspective projection matrix with the given bounds. + * Passing null/undefined/no value for far will generate infinite projection matrix. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum, can be null or Infinity + * @returns {mat4} out + */ + + function perspective(out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf; + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[15] = 0; + + if (far != null && far !== Infinity) { + nf = 1 / (near - far); + out[10] = (far + near) * nf; + out[14] = 2 * far * near * nf; + } else { + out[10] = -1; + out[14] = -2 * near; + } + + return out; + } + /** + * Generates a perspective projection matrix with the given field of view. + * This is primarily useful for generating projection matrices to be used + * with the still experiemental WebVR API. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ + + function perspectiveFromFieldOfView(out, fov, near, far) { + var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0); + var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0); + var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0); + var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0); + var xScale = 2.0 / (leftTan + rightTan); + var yScale = 2.0 / (upTan + downTan); + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = (upTan - downTan) * yScale * 0.5; + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = far * near / (near - far); + out[15] = 0.0; + return out; + } + /** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ + + function ortho(out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right); + var bt = 1 / (bottom - top); + var nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; + } + /** + * Generates a look-at matrix with the given eye position, focal point, and up axis. + * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ + + function lookAt(out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len; + var eyex = eye[0]; + var eyey = eye[1]; + var eyez = eye[2]; + var upx = up[0]; + var upy = up[1]; + var upz = up[2]; + var centerx = center[0]; + var centery = center[1]; + var centerz = center[2]; + + if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { + return identity$4(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + len = 1 / Math.hypot(z0, z1, z2); + z0 *= len; + z1 *= len; + z2 *= len; + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.hypot(x0, x1, x2); + + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + len = Math.hypot(y0, y1, y2); + + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + return out; + } + /** + * Generates a matrix that makes something look at something else. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ + + function targetTo(out, eye, target, up) { + var eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2]; + var z0 = eyex - target[0], + z1 = eyey - target[1], + z2 = eyez - target[2]; + var len = z0 * z0 + z1 * z1 + z2 * z2; + + if (len > 0) { + len = 1 / Math.sqrt(len); + z0 *= len; + z1 *= len; + z2 *= len; + } + + var x0 = upy * z2 - upz * z1, + x1 = upz * z0 - upx * z2, + x2 = upx * z1 - upy * z0; + len = x0 * x0 + x1 * x1 + x2 * x2; + + if (len > 0) { + len = 1 / Math.sqrt(len); + x0 *= len; + x1 *= len; + x2 *= len; + } + + out[0] = x0; + out[1] = x1; + out[2] = x2; + out[3] = 0; + out[4] = z1 * x2 - z2 * x1; + out[5] = z2 * x0 - z0 * x2; + out[6] = z0 * x1 - z1 * x0; + out[7] = 0; + out[8] = z0; + out[9] = z1; + out[10] = z2; + out[11] = 0; + out[12] = eyex; + out[13] = eyey; + out[14] = eyez; + out[15] = 1; + return out; + } + /** + * Returns a string representation of a mat4 + * + * @param {mat4} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$3(a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; + } + /** + * Returns Frobenius norm of a mat4 + * + * @param {mat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$3(a) { + return Math.hypot(a[0], a[1], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); + } + /** + * Adds two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ + + function add$3(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; + out[10] = a[10] + b[10]; + out[11] = a[11] + b[11]; + out[12] = a[12] + b[12]; + out[13] = a[13] + b[13]; + out[14] = a[14] + b[14]; + out[15] = a[15] + b[15]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ + + function subtract$3(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + out[9] = a[9] - b[9]; + out[10] = a[10] - b[10]; + out[11] = a[11] - b[11]; + out[12] = a[12] - b[12]; + out[13] = a[13] - b[13]; + out[14] = a[14] - b[14]; + out[15] = a[15] - b[15]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat4} out + */ + + function multiplyScalar$3(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + out[9] = a[9] * b; + out[10] = a[10] * b; + out[11] = a[11] * b; + out[12] = a[12] * b; + out[13] = a[13] * b; + out[14] = a[14] * b; + out[15] = a[15] * b; + return out; + } + /** + * Adds two mat4's after multiplying each element of the second operand by a scalar value. + * + * @param {mat4} out the receiving vector + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat4} out + */ + + function multiplyScalarAndAdd$3(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + out[6] = a[6] + b[6] * scale; + out[7] = a[7] + b[7] * scale; + out[8] = a[8] + b[8] * scale; + out[9] = a[9] + b[9] * scale; + out[10] = a[10] + b[10] * scale; + out[11] = a[11] + b[11] * scale; + out[12] = a[12] + b[12] * scale; + out[13] = a[13] + b[13] * scale; + out[14] = a[14] + b[14] * scale; + out[15] = a[15] + b[15] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$3(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$4(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7]; + var a8 = a[8], + a9 = a[9], + a10 = a[10], + a11 = a[11]; + var a12 = a[12], + a13 = a[13], + a14 = a[14], + a15 = a[15]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + var b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7]; + var b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11]; + var b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15)); + } + /** + * Alias for {@link mat4.multiply} + * @function + */ + + var mul$3 = multiply$3; + /** + * Alias for {@link mat4.subtract} + * @function + */ + + var sub$3 = subtract$3; + + var mat4 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$3, + clone: clone$3, + copy: copy$3, + fromValues: fromValues$3, + set: set$3, + identity: identity$4, + transpose: transpose$2, + invert: invert$3, + adjoint: adjoint$2, + determinant: determinant$3, + multiply: multiply$3, + translate: translate$2, + scale: scale$3, + rotate: rotate$3, + rotateX: rotateX, + rotateY: rotateY, + rotateZ: rotateZ, + fromTranslation: fromTranslation$2, + fromScaling: fromScaling$3, + fromRotation: fromRotation$3, + fromXRotation: fromXRotation, + fromYRotation: fromYRotation, + fromZRotation: fromZRotation, + fromRotationTranslation: fromRotationTranslation, + fromQuat2: fromQuat2, + getTranslation: getTranslation, + getScaling: getScaling, + getRotation: getRotation, + fromRotationTranslationScale: fromRotationTranslationScale, + fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin, + fromQuat: fromQuat$1, + frustum: frustum, + perspective: perspective, + perspectiveFromFieldOfView: perspectiveFromFieldOfView, + ortho: ortho, + lookAt: lookAt, + targetTo: targetTo, + str: str$3, + frob: frob$3, + add: add$3, + subtract: subtract$3, + multiplyScalar: multiplyScalar$3, + multiplyScalarAndAdd: multiplyScalarAndAdd$3, + exactEquals: exactEquals$3, + equals: equals$4, + mul: mul$3, + sub: sub$3 + }); + + /** + * 3 Dimensional Vector + * @module vec3 + */ + + /** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ + + function create$4() { + var out = new ARRAY_TYPE(3); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + + return out; + } + /** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ + + function clone$4(a) { + var out = new ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; + } + /** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ + + function length(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + return Math.hypot(x, y, z); + } + /** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ + + function fromValues$4(x, y, z) { + var out = new ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ + + function copy$4(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; + } + /** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ + + function set$4(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function add$4(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function subtract$4(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; + } + /** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function multiply$4(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; + } + /** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function divide(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; + } + /** + * Math.ceil the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to ceil + * @returns {vec3} out + */ + + function ceil(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + return out; + } + /** + * Math.floor the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to floor + * @returns {vec3} out + */ + + function floor(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + return out; + } + /** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function min(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; + } + /** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function max(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; + } + /** + * Math.round the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to round + * @returns {vec3} out + */ + + function round(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + return out; + } + /** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ + + function scale$4(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; + } + /** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ + + function scaleAndAdd(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ + + function distance(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + return Math.hypot(x, y, z); + } + /** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + return x * x + y * y + z * z; + } + /** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + return x * x + y * y + z * z; + } + /** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ + + function negate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; + } + /** + * Returns the inverse of the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to invert + * @returns {vec3} out + */ + + function inverse(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + return out; + } + /** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ + + function normalize(out, a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var len = x * x + y * y + z * z; + + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + } + + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + return out; + } + /** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + /** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ + + function cross(out, a, b) { + var ax = a[0], + ay = a[1], + az = a[2]; + var bx = b[0], + by = b[1], + bz = b[2]; + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; + } + /** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function lerp(out, a, b, t) { + var ax = a[0]; + var ay = a[1]; + var az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; + } + /** + * Performs a hermite interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function hermite(out, a, b, c, d, t) { + var factorTimes2 = t * t; + var factor1 = factorTimes2 * (2 * t - 3) + 1; + var factor2 = factorTimes2 * (t - 2) + t; + var factor3 = factorTimes2 * (t - 1); + var factor4 = factorTimes2 * (3 - 2 * t); + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + return out; + } + /** + * Performs a bezier interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function bezier(out, a, b, c, d, t) { + var inverseFactor = 1 - t; + var inverseFactorTimesTwo = inverseFactor * inverseFactor; + var factorTimes2 = t * t; + var factor1 = inverseFactorTimesTwo * inverseFactor; + var factor2 = 3 * t * inverseFactorTimesTwo; + var factor3 = 3 * factorTimes2 * inverseFactor; + var factor4 = factorTimes2 * t; + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ + + function random(out, scale) { + scale = scale || 1.0; + var r = RANDOM() * 2.0 * Math.PI; + var z = RANDOM() * 2.0 - 1.0; + var zScale = Math.sqrt(1.0 - z * z) * scale; + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; + } + /** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ + + function transformMat4(out, a, m) { + var x = a[0], + y = a[1], + z = a[2]; + var w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1.0; + out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; + out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; + out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; + return out; + } + /** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat3} m the 3x3 matrix to transform with + * @returns {vec3} out + */ + + function transformMat3(out, a, m) { + var x = a[0], + y = a[1], + z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; + } + /** + * Transforms the vec3 with a quat + * Can also be used for dual quaternions. (Multiply it with the real part) + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out + */ + + function transformQuat(out, a, q) { + // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3]; + var x = a[0], + y = a[1], + z = a[2]; // var qvec = [qx, qy, qz]; + // var uv = vec3.cross([], qvec, a); + + var uvx = qy * z - qz * y, + uvy = qz * x - qx * z, + uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv); + + var uuvx = qy * uvz - qz * uvy, + uuvy = qz * uvx - qx * uvz, + uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w); + + var w2 = qw * 2; + uvx *= w2; + uvy *= w2; + uvz *= w2; // vec3.scale(uuv, uuv, 2); + + uuvx *= 2; + uuvy *= 2; + uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv)); + + out[0] = x + uvx + uuvx; + out[1] = y + uvy + uuvy; + out[2] = z + uvz + uuvz; + return out; + } + /** + * Rotate a 3D vector around the x-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ + + function rotateX$1(out, a, b, c) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + r[0] = p[0]; + r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c); + r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Rotate a 3D vector around the y-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ + + function rotateY$1(out, a, b, c) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c); + r[1] = p[1]; + r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Rotate a 3D vector around the z-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ + + function rotateZ$1(out, a, b, c) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c); + r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c); + r[2] = p[2]; //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Get the angle between two 3D vectors + * @param {vec3} a The first operand + * @param {vec3} b The second operand + * @returns {Number} The angle in radians + */ + + function angle(a, b) { + var tempA = fromValues$4(a[0], a[1], a[2]); + var tempB = fromValues$4(b[0], b[1], b[2]); + normalize(tempA, tempA); + normalize(tempB, tempB); + var cosine = dot(tempA, tempB); + + if (cosine > 1.0) { + return 0; + } else if (cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } + } + /** + * Set the components of a vec3 to zero + * + * @param {vec3} out the receiving vector + * @returns {vec3} out + */ + + function zero(out) { + out[0] = 0.0; + out[1] = 0.0; + out[2] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {vec3} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$4(a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; + } + /** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$4(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$5(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2]; + var b0 = b[0], + b1 = b[1], + b2 = b[2]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)); + } + /** + * Alias for {@link vec3.subtract} + * @function + */ + + var sub$4 = subtract$4; + /** + * Alias for {@link vec3.multiply} + * @function + */ + + var mul$4 = multiply$4; + /** + * Alias for {@link vec3.divide} + * @function + */ + + var div = divide; + /** + * Alias for {@link vec3.distance} + * @function + */ + + var dist = distance; + /** + * Alias for {@link vec3.squaredDistance} + * @function + */ + + var sqrDist = squaredDistance; + /** + * Alias for {@link vec3.length} + * @function + */ + + var len = length; + /** + * Alias for {@link vec3.squaredLength} + * @function + */ + + var sqrLen = squaredLength; + /** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach = function () { + var vec = create$4(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + + if (!stride) { + stride = 3; + } + + if (!offset) { + offset = 0; + } + + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + vec[2] = a[i + 2]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + a[i + 2] = vec[2]; + } + + return a; + }; + }(); + + var vec3 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$4, + clone: clone$4, + length: length, + fromValues: fromValues$4, + copy: copy$4, + set: set$4, + add: add$4, + subtract: subtract$4, + multiply: multiply$4, + divide: divide, + ceil: ceil, + floor: floor, + min: min, + max: max, + round: round, + scale: scale$4, + scaleAndAdd: scaleAndAdd, + distance: distance, + squaredDistance: squaredDistance, + squaredLength: squaredLength, + negate: negate, + inverse: inverse, + normalize: normalize, + dot: dot, + cross: cross, + lerp: lerp, + hermite: hermite, + bezier: bezier, + random: random, + transformMat4: transformMat4, + transformMat3: transformMat3, + transformQuat: transformQuat, + rotateX: rotateX$1, + rotateY: rotateY$1, + rotateZ: rotateZ$1, + angle: angle, + zero: zero, + str: str$4, + exactEquals: exactEquals$4, + equals: equals$5, + sub: sub$4, + mul: mul$4, + div: div, + dist: dist, + sqrDist: sqrDist, + len: len, + sqrLen: sqrLen, + forEach: forEach + }); + + /** + * 4 Dimensional Vector + * @module vec4 + */ + + /** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ + + function create$5() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } + + return out; + } + /** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ + + function clone$5(a) { + var out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ + + function fromValues$5(x, y, z, w) { + var out = new ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; + } + /** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ + + function copy$5(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ + + function set$5(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; + } + /** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function add$5(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function subtract$5(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; + } + /** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function multiply$5(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; + } + /** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function divide$1(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; + } + /** + * Math.ceil the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to ceil + * @returns {vec4} out + */ + + function ceil$1(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + out[3] = Math.ceil(a[3]); + return out; + } + /** + * Math.floor the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to floor + * @returns {vec4} out + */ + + function floor$1(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + out[3] = Math.floor(a[3]); + return out; + } + /** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function min$1(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; + } + /** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ + + function max$1(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; + } + /** + * Math.round the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to round + * @returns {vec4} out + */ + + function round$1(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + out[3] = Math.round(a[3]); + return out; + } + /** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ + + function scale$5(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; + } + /** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ + + function scaleAndAdd$1(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ + + function distance$1(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + var w = b[3] - a[3]; + return Math.hypot(x, y, z, w); + } + /** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance$1(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + var w = b[3] - a[3]; + return x * x + y * y + z * z + w * w; + } + /** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ + + function length$1(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + return Math.hypot(x, y, z, w); + } + /** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength$1(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + return x * x + y * y + z * z + w * w; + } + /** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ + + function negate$1(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; + } + /** + * Returns the inverse of the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to invert + * @returns {vec4} out + */ + + function inverse$1(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + out[3] = 1.0 / a[3]; + return out; + } + /** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ + + function normalize$1(out, a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + var len = x * x + y * y + z * z + w * w; + + if (len > 0) { + len = 1 / Math.sqrt(len); + } + + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + return out; + } + /** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot$1(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + /** + * Returns the cross-product of three vectors in a 4-dimensional space + * + * @param {vec4} result the receiving vector + * @param {vec4} U the first vector + * @param {vec4} V the second vector + * @param {vec4} W the third vector + * @returns {vec4} result + */ + + function cross$1(out, u, v, w) { + var A = v[0] * w[1] - v[1] * w[0], + B = v[0] * w[2] - v[2] * w[0], + C = v[0] * w[3] - v[3] * w[0], + D = v[1] * w[2] - v[2] * w[1], + E = v[1] * w[3] - v[3] * w[1], + F = v[2] * w[3] - v[3] * w[2]; + var G = u[0]; + var H = u[1]; + var I = u[2]; + var J = u[3]; + out[0] = H * F - I * E + J * D; + out[1] = -(G * F) + I * C - J * B; + out[2] = G * E - H * C + J * A; + out[3] = -(G * D) + H * B - I * A; + return out; + } + /** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec4} out + */ + + function lerp$1(out, a, b, t) { + var ax = a[0]; + var ay = a[1]; + var az = a[2]; + var aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ + + function random$1(out, scale) { + scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a + // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646. + // http://projecteuclid.org/euclid.aoms/1177692644; + + var v1, v2, v3, v4; + var s1, s2; + + do { + v1 = RANDOM() * 2 - 1; + v2 = RANDOM() * 2 - 1; + s1 = v1 * v1 + v2 * v2; + } while (s1 >= 1); + + do { + v3 = RANDOM() * 2 - 1; + v4 = RANDOM() * 2 - 1; + s2 = v3 * v3 + v4 * v4; + } while (s2 >= 1); + + var d = Math.sqrt((1 - s1) / s2); + out[0] = scale * v1; + out[1] = scale * v2; + out[2] = scale * v3 * d; + out[3] = scale * v4 * d; + return out; + } + /** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ + + function transformMat4$1(out, a, m) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; + } + /** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ + + function transformQuat$1(out, a, q) { + var x = a[0], + y = a[1], + z = a[2]; + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3]; // calculate quat * vec + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat + + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + out[3] = a[3]; + return out; + } + /** + * Set the components of a vec4 to zero + * + * @param {vec4} out the receiving vector + * @returns {vec4} out + */ + + function zero$1(out) { + out[0] = 0.0; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {vec4} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$5(a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; + } + /** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$5(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$6(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)); + } + /** + * Alias for {@link vec4.subtract} + * @function + */ + + var sub$5 = subtract$5; + /** + * Alias for {@link vec4.multiply} + * @function + */ + + var mul$5 = multiply$5; + /** + * Alias for {@link vec4.divide} + * @function + */ + + var div$1 = divide$1; + /** + * Alias for {@link vec4.distance} + * @function + */ + + var dist$1 = distance$1; + /** + * Alias for {@link vec4.squaredDistance} + * @function + */ + + var sqrDist$1 = squaredDistance$1; + /** + * Alias for {@link vec4.length} + * @function + */ + + var len$1 = length$1; + /** + * Alias for {@link vec4.squaredLength} + * @function + */ + + var sqrLen$1 = squaredLength$1; + /** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach$1 = function () { + var vec = create$5(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + + if (!stride) { + stride = 4; + } + + if (!offset) { + offset = 0; + } + + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + vec[2] = a[i + 2]; + vec[3] = a[i + 3]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + a[i + 2] = vec[2]; + a[i + 3] = vec[3]; + } + + return a; + }; + }(); + + var vec4 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$5, + clone: clone$5, + fromValues: fromValues$5, + copy: copy$5, + set: set$5, + add: add$5, + subtract: subtract$5, + multiply: multiply$5, + divide: divide$1, + ceil: ceil$1, + floor: floor$1, + min: min$1, + max: max$1, + round: round$1, + scale: scale$5, + scaleAndAdd: scaleAndAdd$1, + distance: distance$1, + squaredDistance: squaredDistance$1, + length: length$1, + squaredLength: squaredLength$1, + negate: negate$1, + inverse: inverse$1, + normalize: normalize$1, + dot: dot$1, + cross: cross$1, + lerp: lerp$1, + random: random$1, + transformMat4: transformMat4$1, + transformQuat: transformQuat$1, + zero: zero$1, + str: str$5, + exactEquals: exactEquals$5, + equals: equals$6, + sub: sub$5, + mul: mul$5, + div: div$1, + dist: dist$1, + sqrDist: sqrDist$1, + len: len$1, + sqrLen: sqrLen$1, + forEach: forEach$1 + }); + + /** + * Quaternion + * @module quat + */ + + /** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ + + function create$6() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + + out[3] = 1; + return out; + } + /** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ + + function identity$5(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } + /** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ + + function setAxisAngle(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; + } + /** + * Gets the rotation axis and angle for a given + * quaternion. If a quaternion is created with + * setAxisAngle, this method will return the same + * values as providied in the original parameter list + * OR functionally equivalent values. + * Example: The quaternion formed by axis [0, 0, 1] and + * angle -90 is the same as the quaternion formed by + * [0, 0, 1] and 270. This method favors the latter. + * @param {vec3} out_axis Vector receiving the axis of rotation + * @param {quat} q Quaternion to be decomposed + * @return {Number} Angle, in radians, of the rotation + */ + + function getAxisAngle(out_axis, q) { + var rad = Math.acos(q[3]) * 2.0; + var s = Math.sin(rad / 2.0); + + if (s > EPSILON) { + out_axis[0] = q[0] / s; + out_axis[1] = q[1] / s; + out_axis[2] = q[2] / s; + } else { + // If s is zero, return any axis (no rotation - axis does not matter) + out_axis[0] = 1; + out_axis[1] = 0; + out_axis[2] = 0; + } + + return rad; + } + /** + * Gets the angular distance between two unit quaternions + * + * @param {quat} a Origin unit quaternion + * @param {quat} b Destination unit quaternion + * @return {Number} Angle, in radians, between the two quaternions + */ + + function getAngle(a, b) { + var dotproduct = dot$2(a, b); + return Math.acos(2 * dotproduct * dotproduct - 1); + } + /** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ + + function multiply$6(out, a, b) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = b[0], + by = b[1], + bz = b[2], + bw = b[3]; + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; + } + /** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateX$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; + } + /** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateY$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var by = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; + } + /** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateZ$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bz = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; + } + /** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out + */ + + function calculateW(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; + } + /** + * Calculate the exponential of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate the exponential of + * @returns {quat} out + */ + + function exp(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var r = Math.sqrt(x * x + y * y + z * z); + var et = Math.exp(w); + var s = r > 0 ? et * Math.sin(r) / r : 0; + out[0] = x * s; + out[1] = y * s; + out[2] = z * s; + out[3] = et * Math.cos(r); + return out; + } + /** + * Calculate the natural logarithm of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate the exponential of + * @returns {quat} out + */ + + function ln(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var r = Math.sqrt(x * x + y * y + z * z); + var t = r > 0 ? Math.atan2(r, w) / r : 0; + out[0] = x * t; + out[1] = y * t; + out[2] = z * t; + out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w); + return out; + } + /** + * Calculate the scalar power of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate the exponential of + * @param {Number} b amount to scale the quaternion by + * @returns {quat} out + */ + + function pow(out, a, b) { + ln(out, a); + scale$6(out, out, b); + exp(out, out); + return out; + } + /** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + */ + + function slerp(out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = b[0], + by = b[1], + bz = b[2], + bw = b[3]; + var omega, cosom, sinom, scale0, scale1; // calc cosine + + cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary) + + if (cosom < 0.0) { + cosom = -cosom; + bx = -bx; + by = -by; + bz = -bz; + bw = -bw; + } // calculate coefficients + + + if (1.0 - cosom > EPSILON) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } // calculate final values + + + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + return out; + } + /** + * Generates a random unit quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ + + function random$2(out) { + // Implementation of http://planning.cs.uiuc.edu/node198.html + // TODO: Calling random 3 times is probably not the fastest solution + var u1 = RANDOM(); + var u2 = RANDOM(); + var u3 = RANDOM(); + var sqrt1MinusU1 = Math.sqrt(1 - u1); + var sqrtU1 = Math.sqrt(u1); + out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); + out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); + out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); + out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); + return out; + } + /** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out + */ + + function invert$4(out, a) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3; + var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + out[0] = -a0 * invDot; + out[1] = -a1 * invDot; + out[2] = -a2 * invDot; + out[3] = a3 * invDot; + return out; + } + /** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ + + function conjugate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; + } + /** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ + + function fromMat3(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; + + if (fTrace > 0.0) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + + out[3] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; // 1/(4w) + + out[0] = (m[5] - m[7]) * fRoot; + out[1] = (m[6] - m[2]) * fRoot; + out[2] = (m[1] - m[3]) * fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if (m[4] > m[0]) i = 1; + if (m[8] > m[i * 3 + i]) i = 2; + var j = (i + 1) % 3; + var k = (i + 2) % 3; + fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot; + out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot; + out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot; + } + + return out; + } + /** + * Creates a quaternion from the given euler angle x, y, z. + * + * @param {quat} out the receiving quaternion + * @param {x} Angle to rotate around X axis in degrees. + * @param {y} Angle to rotate around Y axis in degrees. + * @param {z} Angle to rotate around Z axis in degrees. + * @returns {quat} out + * @function + */ + + function fromEuler(out, x, y, z) { + var halfToRad = 0.5 * Math.PI / 180.0; + x *= halfToRad; + y *= halfToRad; + z *= halfToRad; + var sx = Math.sin(x); + var cx = Math.cos(x); + var sy = Math.sin(y); + var cy = Math.cos(y); + var sz = Math.sin(z); + var cz = Math.cos(z); + out[0] = sx * cy * cz - cx * sy * sz; + out[1] = cx * sy * cz + sx * cy * sz; + out[2] = cx * cy * sz - sx * sy * cz; + out[3] = cx * cy * cz + sx * sy * sz; + return out; + } + /** + * Returns a string representation of a quatenion + * + * @param {quat} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$6(a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; + } + /** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ + + var clone$6 = clone$5; + /** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ + + var fromValues$6 = fromValues$5; + /** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ + + var copy$6 = copy$5; + /** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ + + var set$6 = set$5; + /** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ + + var add$6 = add$5; + /** + * Alias for {@link quat.multiply} + * @function + */ + + var mul$6 = multiply$6; + /** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ + + var scale$6 = scale$5; + /** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ + + var dot$2 = dot$1; + /** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + * @function + */ + + var lerp$2 = lerp$1; + /** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + */ + + var length$2 = length$1; + /** + * Alias for {@link quat.length} + * @function + */ + + var len$2 = length$2; + /** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ + + var squaredLength$2 = squaredLength$1; + /** + * Alias for {@link quat.squaredLength} + * @function + */ + + var sqrLen$2 = squaredLength$2; + /** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ + + var normalize$2 = normalize$1; + /** + * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {quat} a The first quaternion. + * @param {quat} b The second quaternion. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + var exactEquals$6 = exactEquals$5; + /** + * Returns whether or not the quaternions have approximately the same elements in the same position. + * + * @param {quat} a The first vector. + * @param {quat} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + var equals$7 = equals$6; + /** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ + + var rotationTo = function () { + var tmpvec3 = create$4(); + var xUnitVec3 = fromValues$4(1, 0, 0); + var yUnitVec3 = fromValues$4(0, 1, 0); + return function (out, a, b) { + var dot$1 = dot(a, b); + + if (dot$1 < -0.999999) { + cross(tmpvec3, xUnitVec3, a); + if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); + normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot$1 > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot$1; + return normalize$2(out, out); + } + }; + }(); + /** + * Performs a spherical linear interpolation with two control points + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {quat} c the third operand + * @param {quat} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + */ + + var sqlerp = function () { + var temp1 = create$6(); + var temp2 = create$6(); + return function (out, a, b, c, d, t) { + slerp(temp1, a, d, t); + slerp(temp2, b, c, t); + slerp(out, temp1, temp2, 2 * t * (1 - t)); + return out; + }; + }(); + /** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ + + var setAxes = function () { + var matr = create$2(); + return function (out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + return normalize$2(out, fromMat3(out, matr)); + }; + }(); + + var quat = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$6, + identity: identity$5, + setAxisAngle: setAxisAngle, + getAxisAngle: getAxisAngle, + getAngle: getAngle, + multiply: multiply$6, + rotateX: rotateX$2, + rotateY: rotateY$2, + rotateZ: rotateZ$2, + calculateW: calculateW, + exp: exp, + ln: ln, + pow: pow, + slerp: slerp, + random: random$2, + invert: invert$4, + conjugate: conjugate, + fromMat3: fromMat3, + fromEuler: fromEuler, + str: str$6, + clone: clone$6, + fromValues: fromValues$6, + copy: copy$6, + set: set$6, + add: add$6, + mul: mul$6, + scale: scale$6, + dot: dot$2, + lerp: lerp$2, + length: length$2, + len: len$2, + squaredLength: squaredLength$2, + sqrLen: sqrLen$2, + normalize: normalize$2, + exactEquals: exactEquals$6, + equals: equals$7, + rotationTo: rotationTo, + sqlerp: sqlerp, + setAxes: setAxes + }); + + /** + * Dual Quaternion
+ * Format: [real, dual]
+ * Quaternion format: XYZW
+ * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.
+ * @module quat2 + */ + + /** + * Creates a new identity dual quat + * + * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation] + */ + + function create$7() { + var dq = new ARRAY_TYPE(8); + + if (ARRAY_TYPE != Float32Array) { + dq[0] = 0; + dq[1] = 0; + dq[2] = 0; + dq[4] = 0; + dq[5] = 0; + dq[6] = 0; + dq[7] = 0; + } + + dq[3] = 1; + return dq; + } + /** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat2} a dual quaternion to clone + * @returns {quat2} new dual quaternion + * @function + */ + + function clone$7(a) { + var dq = new ARRAY_TYPE(8); + dq[0] = a[0]; + dq[1] = a[1]; + dq[2] = a[2]; + dq[3] = a[3]; + dq[4] = a[4]; + dq[5] = a[5]; + dq[6] = a[6]; + dq[7] = a[7]; + return dq; + } + /** + * Creates a new dual quat initialized with the given values + * + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component + * @param {Number} y2 Y component + * @param {Number} z2 Z component + * @param {Number} w2 W component + * @returns {quat2} new dual quaternion + * @function + */ + + function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) { + var dq = new ARRAY_TYPE(8); + dq[0] = x1; + dq[1] = y1; + dq[2] = z1; + dq[3] = w1; + dq[4] = x2; + dq[5] = y2; + dq[6] = z2; + dq[7] = w2; + return dq; + } + /** + * Creates a new dual quat from the given values (quat and translation) + * + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component (translation) + * @param {Number} y2 Y component (translation) + * @param {Number} z2 Z component (translation) + * @returns {quat2} new dual quaternion + * @function + */ + + function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) { + var dq = new ARRAY_TYPE(8); + dq[0] = x1; + dq[1] = y1; + dq[2] = z1; + dq[3] = w1; + var ax = x2 * 0.5, + ay = y2 * 0.5, + az = z2 * 0.5; + dq[4] = ax * w1 + ay * z1 - az * y1; + dq[5] = ay * w1 + az * x1 - ax * z1; + dq[6] = az * w1 + ax * y1 - ay * x1; + dq[7] = -ax * x1 - ay * y1 - az * z1; + return dq; + } + /** + * Creates a dual quat from a quaternion and a translation + * + * @param {quat2} dual quaternion receiving operation result + * @param {quat} q a normalized quaternion + * @param {vec3} t tranlation vector + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromRotationTranslation$1(out, q, t) { + var ax = t[0] * 0.5, + ay = t[1] * 0.5, + az = t[2] * 0.5, + bx = q[0], + by = q[1], + bz = q[2], + bw = q[3]; + out[0] = bx; + out[1] = by; + out[2] = bz; + out[3] = bw; + out[4] = ax * bw + ay * bz - az * by; + out[5] = ay * bw + az * bx - ax * bz; + out[6] = az * bw + ax * by - ay * bx; + out[7] = -ax * bx - ay * by - az * bz; + return out; + } + /** + * Creates a dual quat from a translation + * + * @param {quat2} dual quaternion receiving operation result + * @param {vec3} t translation vector + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromTranslation$3(out, t) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = t[0] * 0.5; + out[5] = t[1] * 0.5; + out[6] = t[2] * 0.5; + out[7] = 0; + return out; + } + /** + * Creates a dual quat from a quaternion + * + * @param {quat2} dual quaternion receiving operation result + * @param {quat} q the quaternion + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromRotation$4(out, q) { + out[0] = q[0]; + out[1] = q[1]; + out[2] = q[2]; + out[3] = q[3]; + out[4] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + return out; + } + /** + * Creates a new dual quat from a matrix (4x4) + * + * @param {quat2} out the dual quaternion + * @param {mat4} a the matrix + * @returns {quat2} dual quat receiving operation result + * @function + */ + + function fromMat4$1(out, a) { + //TODO Optimize this + var outer = create$6(); + getRotation(outer, a); + var t = new ARRAY_TYPE(3); + getTranslation(t, a); + fromRotationTranslation$1(out, outer, t); + return out; + } + /** + * Copy the values from one dual quat to another + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the source dual quaternion + * @returns {quat2} out + * @function + */ + + function copy$7(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + return out; + } + /** + * Set a dual quat to the identity dual quaternion + * + * @param {quat2} out the receiving quaternion + * @returns {quat2} out + */ + + function identity$6(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + return out; + } + /** + * Set the components of a dual quat to the given values + * + * @param {quat2} out the receiving quaternion + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component + * @param {Number} y2 Y component + * @param {Number} z2 Z component + * @param {Number} w2 W component + * @returns {quat2} out + * @function + */ + + function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) { + out[0] = x1; + out[1] = y1; + out[2] = z1; + out[3] = w1; + out[4] = x2; + out[5] = y2; + out[6] = z2; + out[7] = w2; + return out; + } + /** + * Gets the real part of a dual quat + * @param {quat} out real part + * @param {quat2} a Dual Quaternion + * @return {quat} real part + */ + + var getReal = copy$6; + /** + * Gets the dual part of a dual quat + * @param {quat} out dual part + * @param {quat2} a Dual Quaternion + * @return {quat} dual part + */ + + function getDual(out, a) { + out[0] = a[4]; + out[1] = a[5]; + out[2] = a[6]; + out[3] = a[7]; + return out; + } + /** + * Set the real component of a dual quat to the given quaternion + * + * @param {quat2} out the receiving quaternion + * @param {quat} q a quaternion representing the real part + * @returns {quat2} out + * @function + */ + + var setReal = copy$6; + /** + * Set the dual component of a dual quat to the given quaternion + * + * @param {quat2} out the receiving quaternion + * @param {quat} q a quaternion representing the dual part + * @returns {quat2} out + * @function + */ + + function setDual(out, q) { + out[4] = q[0]; + out[5] = q[1]; + out[6] = q[2]; + out[7] = q[3]; + return out; + } + /** + * Gets the translation of a normalized dual quat + * @param {vec3} out translation + * @param {quat2} a Dual Quaternion to be decomposed + * @return {vec3} translation + */ + + function getTranslation$1(out, a) { + var ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3]; + out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; + out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; + out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; + return out; + } + /** + * Translates a dual quat by the given vector + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to translate + * @param {vec3} v vector to translate by + * @returns {quat2} out + */ + + function translate$3(out, a, v) { + var ax1 = a[0], + ay1 = a[1], + az1 = a[2], + aw1 = a[3], + bx1 = v[0] * 0.5, + by1 = v[1] * 0.5, + bz1 = v[2] * 0.5, + ax2 = a[4], + ay2 = a[5], + az2 = a[6], + aw2 = a[7]; + out[0] = ax1; + out[1] = ay1; + out[2] = az1; + out[3] = aw1; + out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2; + out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2; + out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2; + out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2; + return out; + } + /** + * Rotates a dual quat around the X axis + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateX$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateX$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat around the Y axis + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateY$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateY$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat around the Z axis + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateZ$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateZ$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat by a given quaternion (a * q) + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to rotate + * @param {quat} q quaternion to rotate by + * @returns {quat2} out + */ + + function rotateByQuatAppend(out, a, q) { + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3], + ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax * qw + aw * qx + ay * qz - az * qy; + out[1] = ay * qw + aw * qy + az * qx - ax * qz; + out[2] = az * qw + aw * qz + ax * qy - ay * qx; + out[3] = aw * qw - ax * qx - ay * qy - az * qz; + ax = a[4]; + ay = a[5]; + az = a[6]; + aw = a[7]; + out[4] = ax * qw + aw * qx + ay * qz - az * qy; + out[5] = ay * qw + aw * qy + az * qx - ax * qz; + out[6] = az * qw + aw * qz + ax * qy - ay * qx; + out[7] = aw * qw - ax * qx - ay * qy - az * qz; + return out; + } + /** + * Rotates a dual quat by a given quaternion (q * a) + * + * @param {quat2} out the receiving dual quaternion + * @param {quat} q quaternion to rotate by + * @param {quat2} a the dual quaternion to rotate + * @returns {quat2} out + */ + + function rotateByQuatPrepend(out, q, a) { + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3], + bx = a[0], + by = a[1], + bz = a[2], + bw = a[3]; + out[0] = qx * bw + qw * bx + qy * bz - qz * by; + out[1] = qy * bw + qw * by + qz * bx - qx * bz; + out[2] = qz * bw + qw * bz + qx * by - qy * bx; + out[3] = qw * bw - qx * bx - qy * by - qz * bz; + bx = a[4]; + by = a[5]; + bz = a[6]; + bw = a[7]; + out[4] = qx * bw + qw * bx + qy * bz - qz * by; + out[5] = qy * bw + qw * by + qz * bx - qx * bz; + out[6] = qz * bw + qw * bz + qx * by - qy * bx; + out[7] = qw * bw - qx * bx - qy * by - qz * bz; + return out; + } + /** + * Rotates a dual quat around a given axis. Does the normalisation automatically + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the dual quaternion to rotate + * @param {vec3} axis the axis to rotate around + * @param {Number} rad how far the rotation should be + * @returns {quat2} out + */ + + function rotateAroundAxis(out, a, axis, rad) { + //Special case for rad = 0 + if (Math.abs(rad) < EPSILON) { + return copy$7(out, a); + } + + var axisLength = Math.hypot(axis[0], axis[1], axis[2]); + rad = rad * 0.5; + var s = Math.sin(rad); + var bx = s * axis[0] / axisLength; + var by = s * axis[1] / axisLength; + var bz = s * axis[2] / axisLength; + var bw = Math.cos(rad); + var ax1 = a[0], + ay1 = a[1], + az1 = a[2], + aw1 = a[3]; + out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + var ax = a[4], + ay = a[5], + az = a[6], + aw = a[7]; + out[4] = ax * bw + aw * bx + ay * bz - az * by; + out[5] = ay * bw + aw * by + az * bx - ax * bz; + out[6] = az * bw + aw * bz + ax * by - ay * bx; + out[7] = aw * bw - ax * bx - ay * by - az * bz; + return out; + } + /** + * Adds two dual quat's + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the first operand + * @param {quat2} b the second operand + * @returns {quat2} out + * @function + */ + + function add$7(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + return out; + } + /** + * Multiplies two dual quat's + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a the first operand + * @param {quat2} b the second operand + * @returns {quat2} out + */ + + function multiply$7(out, a, b) { + var ax0 = a[0], + ay0 = a[1], + az0 = a[2], + aw0 = a[3], + bx1 = b[4], + by1 = b[5], + bz1 = b[6], + bw1 = b[7], + ax1 = a[4], + ay1 = a[5], + az1 = a[6], + aw1 = a[7], + bx0 = b[0], + by0 = b[1], + bz0 = b[2], + bw0 = b[3]; + out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0; + out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0; + out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0; + out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0; + out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0; + out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0; + out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0; + out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0; + return out; + } + /** + * Alias for {@link quat2.multiply} + * @function + */ + + var mul$7 = multiply$7; + /** + * Scales a dual quat by a scalar number + * + * @param {quat2} out the receiving dual quat + * @param {quat2} a the dual quat to scale + * @param {Number} b amount to scale the dual quat by + * @returns {quat2} out + * @function + */ + + function scale$7(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + return out; + } + /** + * Calculates the dot product of two dual quat's (The dot product of the real parts) + * + * @param {quat2} a the first operand + * @param {quat2} b the second operand + * @returns {Number} dot product of a and b + * @function + */ + + var dot$3 = dot$2; + /** + * Performs a linear interpolation between two dual quats's + * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5) + * + * @param {quat2} out the receiving dual quat + * @param {quat2} a the first operand + * @param {quat2} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat2} out + */ + + function lerp$3(out, a, b, t) { + var mt = 1 - t; + if (dot$3(a, b) < 0) t = -t; + out[0] = a[0] * mt + b[0] * t; + out[1] = a[1] * mt + b[1] * t; + out[2] = a[2] * mt + b[2] * t; + out[3] = a[3] * mt + b[3] * t; + out[4] = a[4] * mt + b[4] * t; + out[5] = a[5] * mt + b[5] * t; + out[6] = a[6] * mt + b[6] * t; + out[7] = a[7] * mt + b[7] * t; + return out; + } + /** + * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a dual quat to calculate inverse of + * @returns {quat2} out + */ + + function invert$5(out, a) { + var sqlen = squaredLength$3(a); + out[0] = -a[0] / sqlen; + out[1] = -a[1] / sqlen; + out[2] = -a[2] / sqlen; + out[3] = a[3] / sqlen; + out[4] = -a[4] / sqlen; + out[5] = -a[5] / sqlen; + out[6] = -a[6] / sqlen; + out[7] = a[7] / sqlen; + return out; + } + /** + * Calculates the conjugate of a dual quat + * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result. + * + * @param {quat2} out the receiving quaternion + * @param {quat2} a quat to calculate conjugate of + * @returns {quat2} out + */ + + function conjugate$1(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + out[4] = -a[4]; + out[5] = -a[5]; + out[6] = -a[6]; + out[7] = a[7]; + return out; + } + /** + * Calculates the length of a dual quat + * + * @param {quat2} a dual quat to calculate length of + * @returns {Number} length of a + * @function + */ + + var length$3 = length$2; + /** + * Alias for {@link quat2.length} + * @function + */ + + var len$3 = length$3; + /** + * Calculates the squared length of a dual quat + * + * @param {quat2} a dual quat to calculate squared length of + * @returns {Number} squared length of a + * @function + */ + + var squaredLength$3 = squaredLength$2; + /** + * Alias for {@link quat2.squaredLength} + * @function + */ + + var sqrLen$3 = squaredLength$3; + /** + * Normalize a dual quat + * + * @param {quat2} out the receiving dual quaternion + * @param {quat2} a dual quaternion to normalize + * @returns {quat2} out + * @function + */ + + function normalize$3(out, a) { + var magnitude = squaredLength$3(a); + + if (magnitude > 0) { + magnitude = Math.sqrt(magnitude); + var a0 = a[0] / magnitude; + var a1 = a[1] / magnitude; + var a2 = a[2] / magnitude; + var a3 = a[3] / magnitude; + var b0 = a[4]; + var b1 = a[5]; + var b2 = a[6]; + var b3 = a[7]; + var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = (b0 - a0 * a_dot_b) / magnitude; + out[5] = (b1 - a1 * a_dot_b) / magnitude; + out[6] = (b2 - a2 * a_dot_b) / magnitude; + out[7] = (b3 - a3 * a_dot_b) / magnitude; + } + + return out; + } + /** + * Returns a string representation of a dual quatenion + * + * @param {quat2} a dual quaternion to represent as a string + * @returns {String} string representation of the dual quat + */ + + function str$7(a) { + return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')'; + } + /** + * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {quat2} a the first dual quaternion. + * @param {quat2} b the second dual quaternion. + * @returns {Boolean} true if the dual quaternions are equal, false otherwise. + */ + + function exactEquals$7(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7]; + } + /** + * Returns whether or not the dual quaternions have approximately the same elements in the same position. + * + * @param {quat2} a the first dual quat. + * @param {quat2} b the second dual quat. + * @returns {Boolean} true if the dual quats are equal, false otherwise. + */ + + function equals$8(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)); + } + + var quat2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$7, + clone: clone$7, + fromValues: fromValues$7, + fromRotationTranslationValues: fromRotationTranslationValues, + fromRotationTranslation: fromRotationTranslation$1, + fromTranslation: fromTranslation$3, + fromRotation: fromRotation$4, + fromMat4: fromMat4$1, + copy: copy$7, + identity: identity$6, + set: set$7, + getReal: getReal, + getDual: getDual, + setReal: setReal, + setDual: setDual, + getTranslation: getTranslation$1, + translate: translate$3, + rotateX: rotateX$3, + rotateY: rotateY$3, + rotateZ: rotateZ$3, + rotateByQuatAppend: rotateByQuatAppend, + rotateByQuatPrepend: rotateByQuatPrepend, + rotateAroundAxis: rotateAroundAxis, + add: add$7, + multiply: multiply$7, + mul: mul$7, + scale: scale$7, + dot: dot$3, + lerp: lerp$3, + invert: invert$5, + conjugate: conjugate$1, + length: length$3, + len: len$3, + squaredLength: squaredLength$3, + sqrLen: sqrLen$3, + normalize: normalize$3, + str: str$7, + exactEquals: exactEquals$7, + equals: equals$8 + }); + + /** + * 2 Dimensional Vector + * @module vec2 + */ + + /** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ + + function create$8() { + var out = new ARRAY_TYPE(2); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + } + + return out; + } + /** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ + + function clone$8(a) { + var out = new ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; + } + /** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ + + function fromValues$8(x, y) { + var out = new ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; + } + /** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out + */ + + function copy$8(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; + } + /** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ + + function set$8(out, x, y) { + out[0] = x; + out[1] = y; + return out; + } + /** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function add$8(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function subtract$6(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; + } + /** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function multiply$8(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; + } + /** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function divide$2(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; + } + /** + * Math.ceil the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to ceil + * @returns {vec2} out + */ + + function ceil$2(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + return out; + } + /** + * Math.floor the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to floor + * @returns {vec2} out + */ + + function floor$2(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + return out; + } + /** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function min$2(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; + } + /** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ + + function max$2(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; + } + /** + * Math.round the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to round + * @returns {vec2} out + */ + + function round$2(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + return out; + } + /** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ + + function scale$8(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; + } + /** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ + + function scaleAndAdd$2(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ + + function distance$2(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.hypot(x, y); + } + /** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance$2(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x * x + y * y; + } + /** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ + + function length$4(a) { + var x = a[0], + y = a[1]; + return Math.hypot(x, y); + } + /** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength$4(a) { + var x = a[0], + y = a[1]; + return x * x + y * y; + } + /** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ + + function negate$2(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; + } + /** + * Returns the inverse of the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to invert + * @returns {vec2} out + */ + + function inverse$2(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + return out; + } + /** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ + + function normalize$4(out, a) { + var x = a[0], + y = a[1]; + var len = x * x + y * y; + + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + } + + out[0] = a[0] * len; + out[1] = a[1] * len; + return out; + } + /** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot$4(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + /** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ + + function cross$2(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; + } + /** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec2} out + */ + + function lerp$4(out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ + + function random$3(out, scale) { + scale = scale || 1.0; + var r = RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; + } + /** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat2(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; + } + /** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat2d(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; + } + /** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat3$1(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; + } + /** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat4$2(out, a, m) { + var x = a[0]; + var y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; + } + /** + * Rotate a 2D vector + * @param {vec2} out The receiving vec2 + * @param {vec2} a The vec2 point to rotate + * @param {vec2} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec2} out + */ + + function rotate$4(out, a, b, c) { + //Translate point to the origin + var p0 = a[0] - b[0], + p1 = a[1] - b[1], + sinC = Math.sin(c), + cosC = Math.cos(c); //perform rotation and translate to correct position + + out[0] = p0 * cosC - p1 * sinC + b[0]; + out[1] = p0 * sinC + p1 * cosC + b[1]; + return out; + } + /** + * Get the angle between two 2D vectors + * @param {vec2} a The first operand + * @param {vec2} b The second operand + * @returns {Number} The angle in radians + */ + + function angle$1(a, b) { + var x1 = a[0], + y1 = a[1], + x2 = b[0], + y2 = b[1]; + var len1 = x1 * x1 + y1 * y1; + + if (len1 > 0) { + //TODO: evaluate use of glm_invsqrt here? + len1 = 1 / Math.sqrt(len1); + } + + var len2 = x2 * x2 + y2 * y2; + + if (len2 > 0) { + //TODO: evaluate use of glm_invsqrt here? + len2 = 1 / Math.sqrt(len2); + } + + var cosine = (x1 * x2 + y1 * y2) * len1 * len2; + + if (cosine > 1.0) { + return 0; + } else if (cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } + } + /** + * Set the components of a vec2 to zero + * + * @param {vec2} out the receiving vector + * @returns {vec2} out + */ + + function zero$2(out) { + out[0] = 0.0; + out[1] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {vec2} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$8(a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; + } + /** + * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$8(a, b) { + return a[0] === b[0] && a[1] === b[1]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$9(a, b) { + var a0 = a[0], + a1 = a[1]; + var b0 = b[0], + b1 = b[1]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)); + } + /** + * Alias for {@link vec2.length} + * @function + */ + + var len$4 = length$4; + /** + * Alias for {@link vec2.subtract} + * @function + */ + + var sub$6 = subtract$6; + /** + * Alias for {@link vec2.multiply} + * @function + */ + + var mul$8 = multiply$8; + /** + * Alias for {@link vec2.divide} + * @function + */ + + var div$2 = divide$2; + /** + * Alias for {@link vec2.distance} + * @function + */ + + var dist$2 = distance$2; + /** + * Alias for {@link vec2.squaredDistance} + * @function + */ + + var sqrDist$2 = squaredDistance$2; + /** + * Alias for {@link vec2.squaredLength} + * @function + */ + + var sqrLen$4 = squaredLength$4; + /** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach$2 = function () { + var vec = create$8(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + + if (!stride) { + stride = 2; + } + + if (!offset) { + offset = 0; + } + + if (count) { + l = Math.min(count * stride + offset, a.length); + } else { + l = a.length; + } + + for (i = offset; i < l; i += stride) { + vec[0] = a[i]; + vec[1] = a[i + 1]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + } + + return a; + }; + }(); + + var vec2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$8, + clone: clone$8, + fromValues: fromValues$8, + copy: copy$8, + set: set$8, + add: add$8, + subtract: subtract$6, + multiply: multiply$8, + divide: divide$2, + ceil: ceil$2, + floor: floor$2, + min: min$2, + max: max$2, + round: round$2, + scale: scale$8, + scaleAndAdd: scaleAndAdd$2, + distance: distance$2, + squaredDistance: squaredDistance$2, + length: length$4, + squaredLength: squaredLength$4, + negate: negate$2, + inverse: inverse$2, + normalize: normalize$4, + dot: dot$4, + cross: cross$2, + lerp: lerp$4, + random: random$3, + transformMat2: transformMat2, + transformMat2d: transformMat2d, + transformMat3: transformMat3$1, + transformMat4: transformMat4$2, + rotate: rotate$4, + angle: angle$1, + zero: zero$2, + str: str$8, + exactEquals: exactEquals$8, + equals: equals$9, + len: len$4, + sub: sub$6, + mul: mul$8, + div: div$2, + dist: dist$2, + sqrDist: sqrDist$2, + sqrLen: sqrLen$4, + forEach: forEach$2 + }); + + var esm = /*#__PURE__*/Object.freeze({ + __proto__: null, + glMatrix: common, + mat2: mat2, + mat2d: mat2d, + mat3: mat3, + mat4: mat4, + quat: quat, + quat2: quat2, + vec2: vec2, + vec3: vec3, + vec4: vec4 + }); + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + var clamp_1 = clamp; + + var require$$67 = /*@__PURE__*/getAugmentedNamespace(esm); + + // These are used to set the WebGl depth for a tile. + var MAX_LAYERS = 256; // Max number of layers per stage. + var MAX_LEVELS = 256; // Max number of levels per layer. + + + var vec4$1 = require$$67.vec4; + var vec3$1 = require$$67.vec3; + var mat4$1 = require$$67.mat4; + + + function createShader(gl, type, src) { + var shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(shader); + } + return shader; + } + + + function createShaderProgram(gl, vertexSrc, fragmentSrc, attribList, uniformList) { + + var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSrc); + var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSrc); + + var shaderProgram = gl.createProgram(); + + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + throw gl.getProgramInfoLog(shaderProgram); + } + + for (var i = 0; i < attribList.length; i++) { + var attrib = attribList[i]; + shaderProgram[attrib] = gl.getAttribLocation(shaderProgram, attrib); + if (shaderProgram[attrib] === -1) { + throw new Error('Shader program has no ' + attrib + ' attribute'); + } + } + + for (var j = 0; j < uniformList.length; j++) { + var uniform = uniformList[j]; + shaderProgram[uniform] = gl.getUniformLocation(shaderProgram, uniform); + if (shaderProgram[uniform] === -1) { + throw new Error('Shader program has no ' + uniform + ' uniform'); + } + } + + return shaderProgram; + } + + + function destroyShaderProgram(gl, shaderProgram) { + var shaderList = gl.getAttachedShaders(shaderProgram); + for (var i = 0; i < shaderList.length; i++) { + var shader = shaderList[i]; + gl.detachShader(shaderProgram, shader); + gl.deleteShader(shader); + } + gl.deleteProgram(shaderProgram); + } + + + function createConstantBuffer(gl, target, usage, value) { + var buffer = gl.createBuffer(); + gl.bindBuffer(target, buffer); + gl.bufferData(target, value, usage); + return buffer; + } + + + function createConstantBuffers(gl, vertexIndices, vertexPositions, textureCoords) { + return { + vertexIndices: createConstantBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, gl.STATIC_DRAW, new Uint16Array(vertexIndices)), + vertexPositions: createConstantBuffer(gl, gl.ARRAY_BUFFER, gl.STATIC_DRAW, new Float32Array(vertexPositions)), + textureCoords: createConstantBuffer(gl, gl.ARRAY_BUFFER, gl.STATIC_DRAW, new Float32Array(textureCoords)) + }; + } + + + function destroyConstantBuffers(gl, constantBuffers) { + gl.deleteBuffer(constantBuffers.vertexIndices); + gl.deleteBuffer(constantBuffers.vertexPositions); + gl.deleteBuffer(constantBuffers.textureCoords); + } + + + function enableAttributes(gl, shaderProgram) { + var numAttrs = gl.getProgramParameter(shaderProgram, gl.ACTIVE_ATTRIBUTES); + for (var i = 0; i < numAttrs; i++) { + gl.enableVertexAttribArray(i); + } + } + + + function disableAttributes(gl, shaderProgram) { + var numAttrs = gl.getProgramParameter(shaderProgram, gl.ACTIVE_ATTRIBUTES); + for (var i = 0; i < numAttrs; i++) { + gl.disableVertexAttribArray(i); + } + } + + + function setTexture(gl, shaderProgram, texture) { + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture._texture); + gl.uniform1i(shaderProgram.uSampler, 0); + } + + + function setDepth(gl, shaderProgram, layerZ, tileZ) { + var depth = (((layerZ + 1) * MAX_LEVELS) - tileZ) / (MAX_LEVELS * MAX_LAYERS); + gl.uniform1f(shaderProgram.uDepth, depth); + } + + + var defaultOpacity = 1.0; + var defaultColorOffset = vec4$1.create(); + var defaultColorMatrix = mat4$1.create(); + mat4$1.identity(defaultColorMatrix); + + function setupPixelEffectUniforms(gl, effects, uniforms) { + var opacity = defaultOpacity; + if (effects && effects.opacity != null) { + opacity = effects.opacity; + } + gl.uniform1f(uniforms.opacity, opacity); + + var colorOffset = defaultColorOffset; + if (effects && effects.colorOffset) { + colorOffset = effects.colorOffset; + } + gl.uniform4fv(uniforms.colorOffset, colorOffset); + + var colorMatrix = defaultColorMatrix; + if (effects && effects.colorMatrix) { + colorMatrix = effects.colorMatrix; + } + gl.uniformMatrix4fv(uniforms.colorMatrix, false, colorMatrix); + } + + + // Temporary vectors for setViewport. + var translateVector = vec3$1.create(); + var scaleVector = vec3$1.create(); + + + // Sets the WebGL viewport and returns a viewport clamping compensation matrix. + // + // Negative viewport origin coordinates cause rendering issues. Letting the + // viewport dimensions extend beyond the visible area do not seem to cause + // rendering issues, but they may still have an impact on performance. + // Therefore, when the scene's rect is not fully contained in the rendering + // area, we clamp the viewport to the rendering area, and return a compensation + // matrix to scale and translate vertices accordingly. + function setViewport(gl, layer, rect, viewportMatrix) { + if (rect.x === 0 && rect.width === 1 && rect.y === 0 && rect.height === 1) { + // Fast path for full rect. + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + mat4$1.identity(viewportMatrix); + return; + } + + var offsetX = rect.x; + var clampedOffsetX = clamp_1(offsetX, 0, 1); + var leftExcess = clampedOffsetX - offsetX; + var maxClampedWidth = 1 - clampedOffsetX; + var clampedWidth = clamp_1(rect.width - leftExcess, 0, maxClampedWidth); + var rightExcess = rect.width - clampedWidth; + + var offsetY = 1 - rect.height - rect.y; + var clampedOffsetY = clamp_1(offsetY, 0, 1); + var bottomExcess = clampedOffsetY - offsetY; + var maxClampedHeight = 1 - clampedOffsetY; + var clampedHeight = clamp_1(rect.height - bottomExcess, 0, maxClampedHeight); + var topExcess = rect.height - clampedHeight; + + vec3$1.set( + scaleVector, + rect.width / clampedWidth, + rect.height / clampedHeight, + 1); + + vec3$1.set( + translateVector, + (rightExcess - leftExcess) / clampedWidth, + (topExcess - bottomExcess) / clampedHeight, + 0); + + mat4$1.identity(viewportMatrix); + mat4$1.translate(viewportMatrix, viewportMatrix, translateVector); + mat4$1.scale(viewportMatrix, viewportMatrix, scaleVector); + + gl.viewport(gl.drawingBufferWidth * clampedOffsetX, + gl.drawingBufferHeight * clampedOffsetY, + gl.drawingBufferWidth * clampedWidth, + gl.drawingBufferHeight * clampedHeight); + } + + var WebGlCommon = { + createShaderProgram: createShaderProgram, + destroyShaderProgram: destroyShaderProgram, + createConstantBuffers: createConstantBuffers, + destroyConstantBuffers: destroyConstantBuffers, + enableAttributes: enableAttributes, + disableAttributes: disableAttributes, + setTexture: setTexture, + setDepth: setDepth, + setViewport: setViewport, + setupPixelEffectUniforms: setupPixelEffectUniforms + }; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var vertexNormal = [ + 'attribute vec3 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + + 'uniform float uDepth;', + 'uniform mat4 uViewportMatrix;', + 'uniform mat4 uProjMatrix;', + + 'varying vec2 vTextureCoord;', + + 'void main(void) {', + ' gl_Position = uViewportMatrix * uProjMatrix * vec4(aVertexPosition.xy, 0.0, 1.0);', + ' gl_Position.z = uDepth * gl_Position.w;', + ' vTextureCoord = aTextureCoord;', + '}' + ].join('\n'); + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var fragmentNormal = [ + '#ifdef GL_FRAGMENT_PRECISION_HIGH', + 'precision highp float;', + '#else', + 'precision mediump float;', + '#endif', + + 'uniform sampler2D uSampler;', + 'uniform float uOpacity;', + 'uniform vec4 uColorOffset;', + 'uniform mat4 uColorMatrix;', + + 'varying vec2 vTextureCoord;', + + 'void main(void) {', + ' vec4 color = texture2D(uSampler, vTextureCoord) * uColorMatrix + uColorOffset;', + ' gl_FragColor = vec4(color.rgba * uOpacity);', + '}' + ].join('\n'); + + var mat4$2 = require$$67.mat4; + var vec3$2 = require$$67.vec3; + + + + var createConstantBuffers$1 = WebGlCommon.createConstantBuffers; + var destroyConstantBuffers$1 = WebGlCommon.destroyConstantBuffers; + var createShaderProgram$1 = WebGlCommon.createShaderProgram; + var destroyShaderProgram$1 = WebGlCommon.destroyShaderProgram; + var enableAttributes$1 = WebGlCommon.enableAttributes; + var disableAttributes$1 = WebGlCommon.disableAttributes; + var setViewport$1 = WebGlCommon.setViewport; + var setupPixelEffectUniforms$1 = WebGlCommon.setupPixelEffectUniforms; + + var setDepth$1 = WebGlCommon.setDepth; + var setTexture$1 = WebGlCommon.setTexture; + + + + + var vertexIndices = [0, 1, 2, 0, 2, 3]; + var vertexPositions = [-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, 0.0]; + var textureCoords = [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]; + + var attribList = ['aVertexPosition', 'aTextureCoord']; + var uniformList = [ + 'uDepth', 'uOpacity', 'uSampler', 'uProjMatrix', 'uViewportMatrix', + 'uColorOffset', 'uColorMatrix' + ]; + + + function WebGlBaseRenderer(gl) { + this.gl = gl; + + // The projection matrix positions the tiles in world space. + // We compute it in Javascript because lack of precision in the vertex shader + // causes seams to appear between adjacent tiles at large zoom levels. + this.projMatrix = mat4$2.create(); + + // The viewport matrix responsible for viewport clamping. + // See setViewport() for an explanation of how it works. + this.viewportMatrix = mat4$2.create(); + + // Translation and scale vectors for tiles. + this.translateVector = vec3$2.create(); + this.scaleVector = vec3$2.create(); + + this.constantBuffers = createConstantBuffers$1(gl, vertexIndices, vertexPositions, textureCoords); + + this.shaderProgram = createShaderProgram$1(gl, vertexNormal, fragmentNormal, attribList, uniformList); + } + + WebGlBaseRenderer.prototype.destroy = function() { + destroyConstantBuffers$1(this.gl, this.constantBuffers); + destroyShaderProgram$1(this.gl, this.shaderProgram); + clearOwnProperties_1(this); + }; + + WebGlBaseRenderer.prototype.startLayer = function(layer, rect) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + var constantBuffers = this.constantBuffers; + var viewportMatrix = this.viewportMatrix; + + gl.useProgram(shaderProgram); + + enableAttributes$1(gl, shaderProgram); + + setViewport$1(gl, layer, rect, viewportMatrix); + gl.uniformMatrix4fv(shaderProgram.uViewportMatrix, false, viewportMatrix); + + gl.bindBuffer(gl.ARRAY_BUFFER, constantBuffers.vertexPositions); + gl.vertexAttribPointer(shaderProgram.aVertexPosition, 3, gl.FLOAT, gl.FALSE, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, constantBuffers.textureCoords); + gl.vertexAttribPointer(shaderProgram.aTextureCoord, 2, gl.FLOAT, gl.FALSE, 0, 0); + + setupPixelEffectUniforms$1(gl, layer.effects(), { + opacity: shaderProgram.uOpacity, + colorOffset: shaderProgram.uColorOffset, + colorMatrix: shaderProgram.uColorMatrix + }); + }; + + + WebGlBaseRenderer.prototype.endLayer = function(layer, rect) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + disableAttributes$1(gl, shaderProgram); + }; + + + WebGlBaseRenderer.prototype.renderTile = function(tile, texture, layer, layerZ) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + var constantBuffers = this.constantBuffers; + var projMatrix = this.projMatrix; + var translateVector = this.translateVector; + var scaleVector = this.scaleVector; + + translateVector[0] = tile.centerX(); + translateVector[1] = tile.centerY(); + translateVector[2] = -0.5; + + scaleVector[0] = tile.scaleX(); + scaleVector[1] = tile.scaleY(); + scaleVector[2] = 1.0; + + mat4$2.copy(projMatrix, layer.view().projection()); + mat4$2.rotateX(projMatrix, projMatrix, tile.rotX()); + mat4$2.rotateY(projMatrix, projMatrix, tile.rotY()); + mat4$2.translate(projMatrix, projMatrix, translateVector); + mat4$2.scale(projMatrix, projMatrix, scaleVector); + + gl.uniformMatrix4fv(shaderProgram.uProjMatrix, false, projMatrix); + + setDepth$1(gl, shaderProgram, layerZ, tile.z); + + setTexture$1(gl, shaderProgram, texture); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, constantBuffers.vertexIndices); + gl.drawElements(gl.TRIANGLES, vertexIndices.length, gl.UNSIGNED_SHORT, 0); + }; + + + var WebGlBase = WebGlBaseRenderer; + + /** + * @class WebGlCubeRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link CubeGeometry} and {@link RectilinearView}, appropriate + * for a {@link WebGlStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function WebGlCubeRenderer() { + this.constructor.super_.apply(this, arguments); + } + + inherits_1(WebGlCubeRenderer, WebGlBase); + + var WebGlCube = WebGlCubeRenderer; + + /** + * @class WebGlFlatRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link FlatGeometry} and {@link FlatView}, appropriate for a + * {@link WebGlStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function WebGlFlatRenderer() { + this.constructor.super_.apply(this, arguments); + } + + inherits_1(WebGlFlatRenderer, WebGlBase); + + var WebGlFlat = WebGlFlatRenderer; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var vertexEquirect = [ + 'attribute vec3 aVertexPosition;', + + 'uniform float uDepth;', + 'uniform mat4 uViewportMatrix;', + 'uniform mat4 uInvProjMatrix;', + + 'varying vec4 vRay;', + + 'void main(void) {', + ' vRay = uInvProjMatrix * vec4(aVertexPosition.xy, 1.0, 1.0);', + ' gl_Position = uViewportMatrix * vec4(aVertexPosition.xy, uDepth, 1.0);', + '}' + ].join('\n'); + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var fragmentEquirect = [ + '#ifdef GL_FRAGMENT_PRECISION_HIGH', + 'precision highp float;', + '#else', + 'precision mediump float', + '#endif', + + 'uniform sampler2D uSampler;', + 'uniform float uOpacity;', + 'uniform float uTextureX;', + 'uniform float uTextureY;', + 'uniform float uTextureWidth;', + 'uniform float uTextureHeight;', + 'uniform vec4 uColorOffset;', + 'uniform mat4 uColorMatrix;', + + 'varying vec4 vRay;', + + 'const float PI = 3.14159265358979323846264;', + + 'void main(void) {', + ' float r = inversesqrt(vRay.x * vRay.x + vRay.y * vRay.y + vRay.z * vRay.z);', + ' float phi = acos(vRay.y * r);', + ' float theta = atan(vRay.x, -1.0*vRay.z);', + ' float s = 0.5 + 0.5 * theta / PI;', + ' float t = 1.0 - phi / PI;', + + ' s = s * uTextureWidth + uTextureX;', + ' t = t * uTextureHeight + uTextureY;', + + ' vec4 color = texture2D(uSampler, vec2(s, t)) * uColorMatrix + uColorOffset;', + ' gl_FragColor = vec4(color.rgba * uOpacity);', + '}' + ].join('\n'); + + var mat4$3 = require$$67.mat4; + + + + var createConstantBuffers$2 = WebGlCommon.createConstantBuffers; + var destroyConstantBuffers$2 = WebGlCommon.destroyConstantBuffers; + var createShaderProgram$2 = WebGlCommon.createShaderProgram; + var destroyShaderProgram$2 = WebGlCommon.destroyShaderProgram; + var enableAttributes$2 = WebGlCommon.enableAttributes; + var disableAttributes$2 = WebGlCommon.disableAttributes; + var setViewport$2 = WebGlCommon.setViewport; + var setupPixelEffectUniforms$2 = WebGlCommon.setupPixelEffectUniforms; + + var setDepth$2 = WebGlCommon.setDepth; + var setTexture$2 = WebGlCommon.setTexture; + + + + + var vertexIndices$1 = [0, 1, 2, 0, 2, 3]; + var vertexPositions$1 = [-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]; + var textureCoords$1 = [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]; + + var attribList$1 = ['aVertexPosition']; + var uniformList$1 = [ + 'uDepth', 'uOpacity', 'uSampler', 'uInvProjMatrix', 'uViewportMatrix', + 'uColorOffset', 'uColorMatrix', 'uTextureX', 'uTextureY', 'uTextureWidth', + 'uTextureHeight' + ]; + + + /** + * @class WebGlEquirectRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link EquirectGeometry} and {@link RectilinearView}, + * appropriate for {@link WebGlStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function WebGlEquirectRenderer(gl) { + this.gl = gl; + + // The inverse projection matrix. + this.invProjMatrix = mat4$3.create(); + + // The viewport matrix responsible for viewport clamping. + // See setViewport() for an explanation of how it works. + this.viewportMatrix = mat4$3.create(); + + this.constantBuffers = createConstantBuffers$2(gl, vertexIndices$1, vertexPositions$1, textureCoords$1); + + this.shaderProgram = createShaderProgram$2(gl, vertexEquirect, fragmentEquirect, attribList$1, uniformList$1); + } + + WebGlEquirectRenderer.prototype.destroy = function() { + destroyConstantBuffers$2(this.gl, this.constantBuffers); + destroyShaderProgram$2(this.gl, this.shaderProgram); + clearOwnProperties_1(this); + }; + + + WebGlEquirectRenderer.prototype.startLayer = function(layer, rect) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + var constantBuffers = this.constantBuffers; + var invProjMatrix = this.invProjMatrix; + var viewportMatrix = this.viewportMatrix; + + gl.useProgram(shaderProgram); + + enableAttributes$2(gl, shaderProgram); + + setViewport$2(gl, layer, rect, viewportMatrix); + gl.uniformMatrix4fv(shaderProgram.uViewportMatrix, false, viewportMatrix); + + gl.bindBuffer(gl.ARRAY_BUFFER, constantBuffers.vertexPositions); + gl.vertexAttribPointer(shaderProgram.aVertexPosition, 3, gl.FLOAT, gl.FALSE, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, constantBuffers.textureCoords); + + // Compute and set the inverse projection matrix. + mat4$3.copy(invProjMatrix, layer.view().projection()); + mat4$3.invert(invProjMatrix, invProjMatrix); + + gl.uniformMatrix4fv(shaderProgram.uInvProjMatrix, false, invProjMatrix); + + // Compute and set the texture scale and crop offsets. + var textureCrop = layer.effects().textureCrop || {}; + var textureX = textureCrop.x != null ? textureCrop.x : 0; + var textureY = textureCrop.y != null ? textureCrop.y : 0; + var textureWidth = textureCrop.width != null ? textureCrop.width : 1; + var textureHeight = textureCrop.height != null ? textureCrop.height : 1; + + gl.uniform1f(shaderProgram.uTextureX, textureX); + gl.uniform1f(shaderProgram.uTextureY, textureY); + gl.uniform1f(shaderProgram.uTextureWidth, textureWidth); + gl.uniform1f(shaderProgram.uTextureHeight, textureHeight); + + setupPixelEffectUniforms$2(gl, layer.effects(), { + opacity: shaderProgram.uOpacity, + colorOffset: shaderProgram.uColorOffset, + colorMatrix: shaderProgram.uColorMatrix + }); + }; + + + WebGlEquirectRenderer.prototype.endLayer = function(layer, rect) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + disableAttributes$2(gl, shaderProgram); + }; + + + WebGlEquirectRenderer.prototype.renderTile = function(tile, texture, layer, layerZ) { + var gl = this.gl; + var shaderProgram = this.shaderProgram; + var constantBuffers = this.constantBuffers; + + setDepth$2(gl, shaderProgram, layerZ, tile.z); + + setTexture$2(gl, shaderProgram, texture); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, constantBuffers.vertexIndices); + gl.drawElements(gl.TRIANGLES, vertexIndices$1.length, gl.UNSIGNED_SHORT, 0); + }; + + + var WebGlEquirect = WebGlEquirectRenderer; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Jenkins one-at-a-time hash + // http://www.burtleburtle.net/bob/hash/doobs.html + // Input: an array of integers + // Output: an integer + + function hash() { + var h = 0; + for (var i = 0; i < arguments.length; i++) { + var k = arguments[i]; + h += k; + h += k << 10; + h ^= k >> 6; + } + h += h << 3; + h ^= h >> 11; + h += h << 15; + return h >= 0 ? h : -h; + } + + var hash_1 = hash; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * Modulo operation + * + * @memberof util + * @param {Number} dividend + * @param {Number} divisor + * @returns {Number} Value in range `[0,divisor[` + */ + function mod(a, b) { + return (+a % (b = +b) + b) % b; + } + + var mod_1 = mod; + + var defaultCapacity = 64; + + // A set data structure for elements implementing hash() and equals(). + // The capacity, if given, is just a hint; the set is allowed to exceed it, but + // performance may suffer. + function Set$1(capacity) { + if (capacity != null && + (!isFinite(capacity) || Math.floor(capacity) !== capacity || capacity < 1)) { + throw new Error('Set: invalid capacity'); + } + this._capacity = this._capacity || defaultCapacity; + + this._buckets = []; + for (var i = 0; i < this._capacity; i++) { + this._buckets.push([]); + } + this._size = 0; + } + + // Adds an element, replacing an existing element. + // Returns the replaced element, or null if no element was replaced. + Set$1.prototype.add = function(element) { + var h = mod_1(element.hash(), this._capacity); + var bucket = this._buckets[h]; + for (var i = 0; i < bucket.length; i++) { + var existingElement = bucket[i]; + if (element.equals(existingElement)) { + bucket[i] = element; + return existingElement; + } + } + bucket.push(element); + this._size++; + return null; + }; + + // Removes an element. + // Returns the removed element, or null if the element was not found. + Set$1.prototype.remove = function(element) { + var h = mod_1(element.hash(), this._capacity); + var bucket = this._buckets[h]; + for (var i = 0; i < bucket.length; i++) { + var existingElement = bucket[i]; + if (element.equals(existingElement)) { + // Splice manually to avoid Array#splice return value allocation. + for (var j = i; j < bucket.length - 1; j++) { + bucket[j] = bucket[j+1]; + } + bucket.length = bucket.length - 1; + this._size--; + return existingElement; + } + } + return null; + }; + + // Returns whether an element is in the set. + Set$1.prototype.has = function(element) { + var h = mod_1(element.hash(), this._capacity); + var bucket = this._buckets[h]; + for (var i = 0; i < bucket.length; i++) { + var existingElement = bucket[i]; + if (element.equals(existingElement)) { + return true; + } + } + return false; + }; + + // Returns the number of elements in the set. + Set$1.prototype.size = function() { + return this._size; + }; + + // Removes all elements from the set. + Set$1.prototype.clear = function() { + for (var i = 0; i < this._capacity; i++) { + this._buckets[i].length = 0; + } + this._size = 0; + }; + + // Calls fn(element) for each element in the set, in an unspecified order. + // Returns the number of times fn was called. + // The result is unspecified if the set is mutated during iteration. + Set$1.prototype.forEach = function(fn) { + var count = 0; + for (var i = 0; i < this._capacity; i++) { + var bucket = this._buckets[i]; + for (var j = 0; j < bucket.length; j++) { + fn(bucket[j]); + count += 1; + } + } + return count; + }; + + var _Set = Set$1; + + /** + * @class TileSearcher + * @classdesc + * + * A TileSearcher performs searches for visible tiles. + */ + function TileSearcher() { + // Stack of tiles to be explored. + this._stack = []; + + // Set of already explored tiles. + this._visited = new _Set(); + + // Tile vertices. Allocated by Tile#vertices on first use. + this._vertices = null; + } + + /** + * Performs a search for visible tiles by starting at a given tile and + * recursively exploring neighbors until no more visible tiles are found. + * + * @param {View} view The view used to deem whether a tile is visible. + * @param {Tile} tile The starting tile. + * @param {Tile[]} result An array to append the visible tiles to, including the + * starting tile when visible. Existing array members are preserved. + * @return {number} The number of visible tiles found. + */ + TileSearcher.prototype.search = function(view, startingTile, result) { + var stack = this._stack; + var visited = this._visited; + var vertices = this._vertices; + + var count = 0; + + // Clear internal state. + this._clear(); + + stack.push(startingTile); + + while (stack.length > 0) { + var tile = stack.pop(); + + if (visited.has(tile)) { + // Skip already visited tile. + continue; + } + + if (!view.intersects(tile.vertices(vertices))) { + // Skip non-visible tile. + continue; + } + + // Mark tile as visited. + visited.add(tile); + + // Add neighbors to the stack of tiles to explore. + var neighbors = tile.neighbors(); + for (var i = 0; i < neighbors.length; i++) { + stack.push(neighbors[i]); + } + + // Add to result. + result.push(tile); + + count++; + } + + // Reuse the vertices array in future searches. + this._vertices = vertices; + + // Clear internal state. + this._clear(); + + return count; + }; + + TileSearcher.prototype._clear = function() { + this._stack.length = 0; + this._visited.clear(); + }; + + var TileSearcher_1 = TileSearcher; + + // An LruMap holds up to a maximum number of key-value pairs, ordered by their + // time of insertion. When the addition of a key-value pair would cause the + // capacity to be exceeded, the oldest key-value pair in the set is evicted. + // As a special case, an LruMap with zero capacity always rejects the insertion + // of a key-value pair. + // + // Keys must implement hash() and equals(). Note that the implementation doesn't + // currently use hash(), but a future version might. + function LruMap(capacity) { + if (!isFinite(capacity) || Math.floor(capacity) !== capacity || capacity < 0) { + throw new Error('LruMap: invalid capacity'); + } + this._capacity = capacity; + + // Keys and values are stored in circular arrays ordered by decreasing age. + // Start is the index of the oldest key/value and size is the number of valid + // key/values; the region containing valid keys/values may wrap around. + this._keys = new Array(this._capacity); + this._values = new Array(this._capacity); + this._start = 0; + this._size = 0; + } + + LruMap.prototype._index = function(i) { + return mod_1(this._start + i, this._capacity); + }; + + // Returns the value associated to the specified key, or null if not found. + LruMap.prototype.get = function(key) { + for (var i = 0; i < this._size; i++) { + var existingKey = this._keys[this._index(i)]; + if (key.equals(existingKey)) { + return this._values[this._index(i)]; + } + } + return null; + }; + + // Associates the specified value with the specified key, possibly replacing the + // currently associated value. The key-value pair becomes the newest. If the map + // is at capacity, the oldest key-value pair is removed. Returns the removed + // key, or null otherwise. If the capacity is zero, does nothing and returns + // the key. + LruMap.prototype.set = function(key, value) { + if (this._capacity === 0) { + return key; + } + this.del(key); + var evictedKey = + this._size === this._capacity ? this._keys[this._index(0)] : null; + this._keys[this._index(this._size)] = key; + this._values[this._index(this._size)] = value; + if (this._size < this._capacity) { + this._size++; + } else { + this._start = this._index(1); + } + return evictedKey; + }; + + // Removes the key-value pair associated with the specified key. + // Returns the removed value, or null if not found. + LruMap.prototype.del = function(key) { + for (var i = 0; i < this._size; i++) { + if (key.equals(this._keys[this._index(i)])) { + var existingValue = this._values[this._index(i)]; + for (var j = i; j < this._size - 1; j++) { + this._keys[this._index(j)] = this._keys[this._index(j + 1)]; + this._values[this._index(j)] = this._values[this._index(j + 1)]; + } + this._size--; + return existingValue; + } + } + return null; + }; + + // Returns whether there is a value associated with the specified key. + LruMap.prototype.has = function(key) { + for (var i = 0; i < this._size; i++) { + if (key.equals(this._keys[this._index(i)])) { + return true; + } + } + return false; + }; + + // Returns the number of key-value pairs in the map. + LruMap.prototype.size = function() { + return this._size; + }; + + // Removes all key-value pairs from the map. + LruMap.prototype.clear = function() { + this._keys.length = 0; + this._values.length = 0; + this._start = 0; + this._size = 0; + }; + + // Calls fn(key, value) for each item in the map, in an unspecified order. + // Returns the number of times fn was called. + // The result is unspecified if the map is mutated during iteration. + LruMap.prototype.forEach = function(fn) { + var count = 0; + for (var i = 0; i < this._size; i++) { + fn(this._keys[this._index(i)], this._values[this._index(i)]); + count += 1; + } + return count; + }; + + var LruMap_1 = LruMap; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function Level(levelProperties) { + this._fallbackOnly = !!levelProperties.fallbackOnly; + } + + Level.prototype.numHorizontalTiles = function() { + return Math.ceil(this.width() / this.tileWidth()); + }; + + Level.prototype.numVerticalTiles = function() { + return Math.ceil(this.height() / this.tileHeight()); + }; + + Level.prototype.fallbackOnly = function() { + return this._fallbackOnly; + }; + + var Level_1 = Level; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function cmp(x, y) { + if (x < y) { + return -1; + } + if (x > y) { + return 1; + } + return 0; + } + + var cmp_1 = cmp; + + function makeLevelList(levelPropertiesList, LevelClass) { + var list = []; + + for (var i = 0; i < levelPropertiesList.length; i++) { + list.push(new LevelClass(levelPropertiesList[i])); + } + + list.sort(function(level1, level2) { + return cmp_1(level1.width(), level2.width()); + }); + + return list; + } + + function makeSelectableLevelList(levelList) { + var list = []; + + for (var i = 0; i < levelList.length; i++) { + if (!levelList[i]._fallbackOnly) { + list.push(levelList[i]); + } + } + + if (!list.length) { + throw new Error('No selectable levels in list'); + } + + return list; + } + + var common$1 = { + makeLevelList: makeLevelList, + makeSelectableLevelList: makeSelectableLevelList + }; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function type(x) { + var typ = typeof x; + if (typ === 'object') { + if (x === null) { + return 'null'; + } + if (Object.prototype.toString.call(x) === '[object Array]') { + return 'array'; + } + if (Object.prototype.toString.call(x) === '[object RegExp]') { + return 'regexp'; + } + } + return typ; + } + + var type_1 = type; + + var makeLevelList$1 = common$1.makeLevelList; + var makeSelectableLevelList$1 = common$1.makeSelectableLevelList; + + + + var vec3$3 = require$$67.vec3; + var vec4$2 = require$$67.vec4; + + var neighborsCacheSize = 64; + + // Some renderer implementations require tiles to be padded around with + // repeated pixels to prevent the appearance of visible seams between tiles. + // + // In order to prevent the padding from being visible, the tiles must be + // padded and stacked such that the padding on one of the sides, when present, + // stacks below the neighboring tile on that side. + // + // The padding rules are as follows: + // * Define a tile to be X-marginal if it contacts the X-edge of its cube face. + // * Pad top if the tile is top-marginal and the face is F or U. + // * Pad bottom unless the tile is bottom-marginal or the face is F or D. + // * Pad left if the tile is left-marginal and the face is F, L, U or D. + // * Pad right unless the tile is right-marginal or the face is F, R, U or D. + // + // The stacking rules are as follows: + // * Within an image, stack smaller zoom levels below larger zoom levels. + // * Within a level, stack tiles bottom to top in FUDLRB face order. + // * Within a face, stack tiles bottom to top in ascending Y coordinate order. + // * Within a row, stack tiles bottom to top in ascending X coordinate order. + // + // Crucially, these rules affect the implementation of the tile cmp() method, + // which determines the stacking order, and of the pad*() tile methods, which + // determine the amount of padding on each of the four sides of a tile. + + // Initials for cube faces in stacking order. + var faceList = 'fudlrb'; + + // Rotation of each face, relative to the front face. + var faceRotation = { + f: { x: 0, y: 0 }, + b: { x: 0, y: Math.PI }, + l: { x: 0, y: Math.PI/2 }, + r: { x: 0, y: -Math.PI/2 }, + u: { x: Math.PI/2, y: 0 }, + d: { x: -Math.PI/2, y: 0 } + }; + + // Zero vector. + var origin = vec3$3.create(); + + // Rotate a vector in ZXY order. + function rotateVector(vec, z, x, y) { + if (z) { + vec3$3.rotateZ(vec, vec, origin, z); + } + if (x) { + vec3$3.rotateX(vec, vec, origin, x); + } + if (y) { + vec3$3.rotateY(vec, vec, origin, y); + } + } + + // Normalized vectors pointing to the center of each face. + var faceVectors = {}; + for (var i = 0; i < faceList.length; i++) { + var face = faceList[i]; + var rotation = faceRotation[face]; + var v = vec3$3.fromValues(0, 0, -1); + rotateVector(v, 0, rotation.x, rotation.y); + faceVectors[face] = v; + } + + // Map each face to its adjacent faces. + // The order is as suggested by the front face. + var adjacentFace = { + f: [ 'l', 'r', 'u', 'd' ], + b: [ 'r', 'l', 'u', 'd' ], + l: [ 'b', 'f', 'u', 'd' ], + r: [ 'f', 'b', 'u', 'd' ], + u: [ 'l', 'r', 'b', 'f' ], + d: [ 'l', 'r', 'f', 'b' ] + }; + + // Offsets to apply to the (x,y) coordinates of a tile to get its neighbors. + var neighborOffsets = [ + [ 0, 1 ], // top + [ 1, 0 ], // right + [ 0, -1 ], // bottom + [ -1, 0 ] // left + ]; + + + /** + * @class CubeTile + * @implements Tile + * @classdesc + * + * A tile in a @{CubeGeometry}. + */ + function CubeTile(face, x, y, z, geometry) { + this.face = face; + this.x = x; + this.y = y; + this.z = z; + this._geometry = geometry; + this._level = geometry.levelList[z]; + } + + + CubeTile.prototype.rotX = function() { + return faceRotation[this.face].x; + }; + + + CubeTile.prototype.rotY = function() { + return faceRotation[this.face].y; + }; + + + CubeTile.prototype.centerX = function() { + return (this.x + 0.5) / this._level.numHorizontalTiles() - 0.5; + }; + + + CubeTile.prototype.centerY = function() { + return 0.5 - (this.y + 0.5) / this._level.numVerticalTiles(); + }; + + + CubeTile.prototype.scaleX = function() { + return 1 / this._level.numHorizontalTiles(); + }; + + + CubeTile.prototype.scaleY = function() { + return 1 / this._level.numVerticalTiles(); + }; + + + CubeTile.prototype.width = function() { + return this._level.tileWidth(); + }; + + + CubeTile.prototype.height = function() { + return this._level.tileHeight(); + }; + + + CubeTile.prototype.levelWidth = function() { + return this._level.width(); + }; + + + CubeTile.prototype.levelHeight = function() { + return this._level.height(); + }; + + + CubeTile.prototype.atTopLevel = function() { + return this.z === 0; + }; + + + CubeTile.prototype.atBottomLevel = function() { + return this.z === this._geometry.levelList.length - 1; + }; + + + CubeTile.prototype.atTopEdge = function() { + return this.y === 0; + }; + + + CubeTile.prototype.atBottomEdge = function() { + return this.y === this._level.numVerticalTiles() - 1; + }; + + + CubeTile.prototype.atLeftEdge = function() { + return this.x === 0; + }; + + + CubeTile.prototype.atRightEdge = function() { + return this.x === this._level.numHorizontalTiles() - 1; + }; + + + CubeTile.prototype.padTop = function() { + return this.atTopEdge() && /[fu]/.test(this.face); + }; + + + CubeTile.prototype.padBottom = function() { + return !this.atBottomEdge() || /[fd]/.test(this.face); + }; + + + CubeTile.prototype.padLeft = function() { + return this.atLeftEdge() && /[flud]/.test(this.face); + }; + + + CubeTile.prototype.padRight = function() { + return !this.atRightEdge() || /[frud]/.test(this.face); + }; + + + CubeTile.prototype.vertices = function(result) { + if (!result) { + result = [vec3$3.create(), vec3$3.create(), vec3$3.create(), vec3$3.create()]; + } + + var rot = faceRotation[this.face]; + + function makeVertex(vec, x, y) { + vec3$3.set(vec, x, y, -0.5); + rotateVector(vec, 0, rot.x, rot.y); + } + + var left = this.centerX() - this.scaleX() / 2; + var right = this.centerX() + this.scaleX() / 2; + var bottom = this.centerY() - this.scaleY() / 2; + var top = this.centerY() + this.scaleY() / 2; + + makeVertex(result[0], left, top); + makeVertex(result[1], right, top); + makeVertex(result[2], right, bottom); + makeVertex(result[3], left, bottom); + + return result; + }; + + + CubeTile.prototype.parent = function() { + + if (this.atTopLevel()) { + return null; + } + + var face = this.face; + var z = this.z; + var x = this.x; + var y = this.y; + + var geometry = this._geometry; + var level = geometry.levelList[z]; + var parentLevel = geometry.levelList[z-1]; + + var tileX = Math.floor(x / level.numHorizontalTiles() * parentLevel.numHorizontalTiles()); + var tileY = Math.floor(y / level.numVerticalTiles() * parentLevel.numVerticalTiles()); + var tileZ = z-1; + + return new CubeTile(face, tileX, tileY, tileZ, geometry); + + }; + + + CubeTile.prototype.children = function(result) { + + if (this.atBottomLevel()) { + return null; + } + + var face = this.face; + var z = this.z; + var x = this.x; + var y = this.y; + + var geometry = this._geometry; + var level = geometry.levelList[z]; + var childLevel = geometry.levelList[z+1]; + + var nHoriz = childLevel.numHorizontalTiles() / level.numHorizontalTiles(); + var nVert = childLevel.numVerticalTiles() / level.numVerticalTiles(); + + result = result || []; + + for (var h = 0; h < nHoriz; h++) { + for (var v = 0; v < nVert; v++) { + var tileX = nHoriz * x + h; + var tileY = nVert * y + v; + var tileZ = z+1; + result.push(new CubeTile(face, tileX, tileY, tileZ, geometry)); + } + } + + return result; + + }; + + + CubeTile.prototype.neighbors = function() { + + var geometry = this._geometry; + var cache = geometry._neighborsCache; + + // Satisfy from cache when available. + var cachedResult = cache.get(this); + if (cachedResult) { + return cachedResult; + } + + var vec = geometry._vec; + + var face = this.face; + var x = this.x; + var y = this.y; + var z = this.z; + var level = this._level; + + var numX = level.numHorizontalTiles(); + var numY = level.numVerticalTiles(); + + var result = []; + + for (var i = 0; i < neighborOffsets.length; i++) { + var xOffset = neighborOffsets[i][0]; + var yOffset = neighborOffsets[i][1]; + + var newX = x + xOffset; + var newY = y + yOffset; + var newZ = z; + var newFace = face; + + if (newX < 0 || newX >= numX || newY < 0 || newY >= numY) { + + // If the neighboring tile belongs to a different face, calculate a + // vector pointing to the edge between the two faces at the point the + // tile and its neighbor meet, and convert it into tile coordinates for + // the neighboring face. + + var xCoord = this.centerX(); + var yCoord = this.centerY(); + + // First, calculate the vector as if the initial tile belongs to the + // front face, so that the tile x,y coordinates map directly into the + // x,y axes. + + if (newX < 0) { + vec3$3.set(vec, -0.5, yCoord, -0.5); + newFace = adjacentFace[face][0]; + } else if (newX >= numX) { + vec3$3.set(vec, 0.5, yCoord, -0.5); + newFace = adjacentFace[face][1]; + } else if (newY < 0) { + vec3$3.set(vec, xCoord, 0.5, -0.5); + newFace = adjacentFace[face][2]; + } else if (newY >= numY) { + vec3$3.set(vec, xCoord, -0.5, -0.5); + newFace = adjacentFace[face][3]; + } + + var rot; + + // Then, rotate the vector into the actual face the initial tile + // belongs to. + + rot = faceRotation[face]; + rotateVector(vec, 0, rot.x, rot.y); + + // Finally, rotate the vector from the neighboring face into the front + // face. Again, this is so that the neighboring tile x,y coordinates + // map directly into the x,y axes. + + rot = faceRotation[newFace]; + rotateVector(vec, 0, -rot.x, -rot.y); + + // Calculate the neighboring tile coordinates. + + newX = clamp_1(Math.floor((0.5 + vec[0]) * numX), 0, numX - 1); + newY = clamp_1(Math.floor((0.5 - vec[1]) * numY), 0, numY - 1); + } + + result.push(new CubeTile(newFace, newX, newY, newZ, geometry)); + } + + // Store into cache to satisfy future requests. + cache.set(this, result); + + return result; + + }; + + + CubeTile.prototype.hash = function() { + return hash_1(faceList.indexOf(this.face), this.z, this.y, this.x); + }; + + + CubeTile.prototype.equals = function(that) { + return (this.geometry === that.geometry && + this.face === that.face && + this.z === that.z && + this.y === that.y && + this.x === that.x); + }; + + + CubeTile.prototype.cmp = function(that) { + return (cmp_1(this.z, that.z) || + cmp_1(faceList.indexOf(this.face), faceList.indexOf(that.face)) || + cmp_1(this.y, that.y) || cmp_1(this.x, that.x)); + }; + + + CubeTile.prototype.str = function() { + return 'CubeTile(' + tile.face + ', ' + tile.x + ', ' + tile.y + ', ' + tile.z + ')'; + }; + + + function CubeLevel(levelProperties) { + this.constructor.super_.call(this, levelProperties); + + this._size = levelProperties.size; + this._tileSize = levelProperties.tileSize; + + if (this._size % this._tileSize !== 0) { + throw new Error('Level size is not multiple of tile size: ' + + this._size + ' ' + this._tileSize); + } + } + + inherits_1(CubeLevel, Level_1); + + + CubeLevel.prototype.width = function() { + return this._size; + }; + + + CubeLevel.prototype.height = function() { + return this._size; + }; + + + CubeLevel.prototype.tileWidth = function() { + return this._tileSize; + }; + + + CubeLevel.prototype.tileHeight = function() { + return this._tileSize; + }; + + + CubeLevel.prototype._validateWithParentLevel = function(parentLevel) { + + var width = this.width(); + var height = this.height(); + var tileWidth = this.tileWidth(); + var tileHeight = this.tileHeight(); + var numHorizontal = this.numHorizontalTiles(); + var numVertical = this.numVerticalTiles(); + + var parentWidth = parentLevel.width(); + var parentHeight = parentLevel.height(); + var parentTileWidth = parentLevel.tileWidth(); + var parentTileHeight = parentLevel.tileHeight(); + var parentNumHorizontal = parentLevel.numHorizontalTiles(); + var parentNumVertical = parentLevel.numVerticalTiles(); + + if (width % parentWidth !== 0) { + throw new Error('Level width must be multiple of parent level: ' + + width + ' vs. ' + parentWidth); + } + + if (height % parentHeight !== 0) { + throw new Error('Level height must be multiple of parent level: ' + + height + ' vs. ' + parentHeight); + } + + if (numHorizontal % parentNumHorizontal !== 0) { + throw new Error('Number of horizontal tiles must be multiple of parent level: ' + + numHorizontal + " (" + width + '/' + tileWidth + ')' + " vs. " + + parentNumHorizontal + " (" + parentWidth + '/' + parentTileWidth + ')'); + } + + if (numVertical % parentNumVertical !== 0) { + throw new Error('Number of vertical tiles must be multiple of parent level: ' + + numVertical + " (" + height + '/' + tileHeight + ')' + " vs. " + + parentNumVertical + " (" + parentHeight + '/' + parentTileHeight + ')'); + } + + }; + + + /** + * @class CubeGeometry + * @implements Geometry + * @classdesc + * + * A {@link Geometry} implementation suitable for tiled cube images with + * multiple resolution levels. + * + * The following restrictions apply: + * - All tiles in a level must be square and form a rectangular grid; + * - The size of a level must be a multiple of the tile size; + * - The size of a level must be a multiple of the parent level size; + * - The number of tiles in a level must be a multiple of the number of tiles + * in the parent level. + * + * @param {Object[]} levelPropertiesList Level description + * @param {number} levelPropertiesList[].size Cube face size in pixels + * @param {number} levelPropertiesList[].tileSize Tile size in pixels + */ + function CubeGeometry(levelPropertiesList) { + if (type_1(levelPropertiesList) !== 'array') { + throw new Error('Level list must be an array'); + } + + this.levelList = makeLevelList$1(levelPropertiesList, CubeLevel); + this.selectableLevelList = makeSelectableLevelList$1(this.levelList); + + for (var i = 1; i < this.levelList.length; i++) { + this.levelList[i]._validateWithParentLevel(this.levelList[i-1]); + } + + this._tileSearcher = new TileSearcher_1(this); + + this._neighborsCache = new LruMap_1(neighborsCacheSize); + + this._vec = vec4$2.create(); + + this._viewSize = {}; + } + + + CubeGeometry.prototype.maxTileSize = function() { + var maxTileSize = 0; + for (var i = 0; i < this.levelList.length; i++) { + var level = this.levelList[i]; + maxTileSize = Math.max(maxTileSize, level.tileWidth, level.tileHeight); + } + return maxTileSize; + }; + + + CubeGeometry.prototype.levelTiles = function(level, result) { + + var levelIndex = this.levelList.indexOf(level); + var maxX = level.numHorizontalTiles() - 1; + var maxY = level.numVerticalTiles() - 1; + + result = result || []; + + for (var f = 0; f < faceList.length; f++) { + var face = faceList[f]; + for (var x = 0; x <= maxX; x++) { + for (var y = 0; y <= maxY; y++) { + result.push(new CubeTile(face, x, y, levelIndex, this)); + } + } + } + + return result; + + }; + + + CubeGeometry.prototype._closestTile = function(view, level) { + var ray = this._vec; + + // Compute a view ray into the central screen point. + vec4$2.set(ray, 0, 0, 1, 1); + vec4$2.transformMat4(ray, ray, view.inverseProjection()); + + var minAngle = Infinity; + var closestFace = null; + + // Find the face whose vector makes a minimal angle with the view ray. + // This is the face into which the view ray points. + for (var face in faceVectors) { + var vector = faceVectors[face]; + // For a small angle between two normalized vectors, angle ~ 1-cos(angle). + var angle = 1 - vec3$3.dot(vector, ray); + if (angle < minAngle) { + minAngle = angle; + closestFace = face; + } + } + + // Project view ray onto cube, i.e., normalize the coordinate with + // largest absolute value to ±0.5. + var max = Math.max(Math.abs(ray[0]), Math.abs(ray[1]), Math.abs(ray[2])) / 0.5; + for (var i = 0; i < 3; i++) { + ray[i] = ray[i] / max; + } + + // Rotate view ray into front face. + var rot = faceRotation[closestFace]; + rotateVector(ray, 0, -rot.x, -rot.y); + + // Get the desired zoom level. + var tileZ = this.levelList.indexOf(level); + var numX = level.numHorizontalTiles(); + var numY = level.numVerticalTiles(); + + // Find the coordinates of the tile that the view ray points into. + var tileX = clamp_1(Math.floor((0.5 + ray[0]) * numX), 0, numX - 1); + var tileY = clamp_1(Math.floor((0.5 - ray[1]) * numY), 0, numY - 1); + + return new CubeTile(closestFace, tileX, tileY, tileZ, this); + }; + + + CubeGeometry.prototype.visibleTiles = function(view, level, result) { + var viewSize = this._viewSize; + var tileSearcher = this._tileSearcher; + + result = result || []; + + view.size(viewSize); + if (viewSize.width === 0 || viewSize.height === 0) { + // No tiles are visible if the viewport is empty. + return result; + } + + var startingTile = this._closestTile(view, level); + var count = tileSearcher.search(view, startingTile, result); + if (!count) { + throw new Error('Starting tile is not visible'); + } + + return result; + }; + + + CubeGeometry.Tile = CubeGeometry.prototype.Tile = CubeTile; + CubeGeometry.type = CubeGeometry.prototype.type = 'cube'; + CubeTile.type = CubeTile.prototype.type = 'cube'; + + + var Cube = CubeGeometry; + + var defaultCapacity$1 = 64; + + // A map data structure for keys implementing hash() and equals() and arbitrary + // values. The capacity, if given, is just a hint; the map is allowed to exceed + // it, but performance may suffer. + function Map$1(capacity) { + if (capacity != null && + (!isFinite(capacity) || Math.floor(capacity) !== capacity || capacity < 1)) { + throw new Error('Map: invalid capacity'); + } + this._capacity = capacity || defaultCapacity$1; + + this._keyBuckets = []; + this._valBuckets = []; + for (var i = 0; i < this._capacity; i++) { + this._keyBuckets.push([]); + this._valBuckets.push([]); + } + this._size = 0; + } + + // Returns the value associated with the specified key, or null if not found. + Map$1.prototype.get = function(key) { + var h = mod_1(key.hash(), this._capacity); + var keyBucket = this._keyBuckets[h]; + for (var i = 0; i < keyBucket.length; i++) { + var existingKey = keyBucket[i]; + if (key.equals(existingKey)) { + var valBucket = this._valBuckets[h]; + var existingValue = valBucket[i]; + return existingValue; + } + } + return null; + }; + + // Associates the specified value with the specified key, possibly replacing the + // currently associated value. + // Returns the replaced value, or null if no value was replaced. + Map$1.prototype.set = function(key, val) { + var h = mod_1(key.hash(), this._capacity); + var keyBucket = this._keyBuckets[h]; + var valBucket = this._valBuckets[h]; + for (var i = 0; i < keyBucket.length; i++) { + var existingKey = keyBucket[i]; + if (key.equals(existingKey)) { + var existingValue = valBucket[i]; + keyBucket[i] = key; + valBucket[i] = val; + return existingValue; + } + } + keyBucket.push(key); + valBucket.push(val); + this._size++; + return null; + }; + + // Removes the key-value pair associated with the specified key. + // Returns the removed value, or null if not found. + Map$1.prototype.del = function(key) { + var h = mod_1(key.hash(), this._capacity); + var keyBucket = this._keyBuckets[h]; + var valBucket = this._valBuckets[h]; + for (var i = 0; i < keyBucket.length; i++) { + var existingKey = keyBucket[i]; + if (key.equals(existingKey)) { + var existingValue = valBucket[i]; + // Splice manually to avoid Array#splice return value allocation. + for (var j = i; j < keyBucket.length - 1; j++) { + keyBucket[j] = keyBucket[j+1]; + valBucket[j] = valBucket[j+1]; + } + keyBucket.length = keyBucket.length - 1; + valBucket.length = valBucket.length - 1; + this._size--; + return existingValue; + } + } + return null; + }; + + // Returns whether there is a value associated with the specified key. + Map$1.prototype.has = function(key) { + var h = mod_1(key.hash(), this._capacity); + var keyBucket = this._keyBuckets[h]; + for (var i = 0; i < keyBucket.length; i++) { + var existingKey = keyBucket[i]; + if (key.equals(existingKey)) { + return true; + } + } + return false; + }; + + // Returns the number of key-value pairs in the map. + Map$1.prototype.size = function() { + return this._size; + }; + + // Removes all key-value pairs from the map. + Map$1.prototype.clear = function() { + for (var i = 0; i < this._capacity; i++) { + this._keyBuckets[i].length = 0; + this._valBuckets[i].length = 0; + } + this._size = 0; + }; + + // Calls fn(key, value) for each key-value pair in the map, in an unspecified + // order. Returns the number of times fn was called. + // The result is unspecified if the map is mutated during iteration. + Map$1.prototype.forEach = function(fn) { + var count = 0; + for (var i = 0; i < this._capacity; i++) { + var keyBucket = this._keyBuckets[i]; + var valBucket = this._valBuckets[i]; + for (var j = 0; j < keyBucket.length; j++) { + fn(keyBucket[j], valBucket[j]); + count += 1; + } + } + return count; + }; + + var _Map = Map$1; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Convert a number to a string in decimal notation. + function decimal(x) { + // Double-precision floats have 15 significant decimal digits. + return x.toPrecision(15); + } + + var decimal_1 = decimal; + + var setOverflowHidden$1 = dom.setOverflowHidden; + var setNoPointerEvents$1 = dom.setNoPointerEvents; + var setNullTransform$1 = dom.setNullTransform; + var setTransform$1 = dom.setTransform; + + + var debug$1 = typeof MARZIPANODEBUG !== 'undefined' && MARZIPANODEBUG.css; + + + function tileCmp(a, b) { + return a.cmp(b); + } + + + function CssBaseRenderer(root, quirks, tileClass) { + + this._root = root; + + this._browserQuirks = quirks; + + // Create a container for this renderer's tiles, so we can style them + // as a whole separately from other renderers in the same stage. + var domElement = document.createElement('div'); + root.appendChild(domElement); + + domElement.style.position = 'absolute'; + + // For some weird reason, this prevents flickering on Safari Desktop. + setOverflowHidden$1(domElement); + + // Prevent touch events on tiles from messing up pinching gestures on iOS. + setNoPointerEvents$1(domElement); + + if (this._browserQuirks.useNullTransform) { + setNullTransform$1(domElement); + } + + this.domElement = domElement; + + this._oldTileList = []; + this._newTileList = []; + + this._textureMap = new _Map(); + } + + + CssBaseRenderer.prototype.destroy = function() { + this._root.removeChild(this.domElement); + clearOwnProperties_1(this); + }; + + + CssBaseRenderer.prototype.startLayer = function(layer, rect) { + var domElement = this.domElement; + + // Set viewport effect. + var stageWidth = this._root.clientWidth; + var stageHeight = this._root.clientHeight; + domElement.style.left = decimal_1(stageWidth * rect.left) + 'px'; + domElement.style.top = decimal_1(stageHeight * rect.top) + 'px'; + domElement.style.width = decimal_1(stageWidth * rect.width) + 'px'; + domElement.style.height = decimal_1(stageHeight * rect.height) + 'px'; + + // Set opacity effect. + var opacity = 1.0; + var effects = layer.effects(); + if (effects && effects.opacity != null) { + opacity = effects.opacity; + } + domElement.style.opacity = opacity; + + // Clear temporary variables. + this._newTileList.length = 0; + this._textureMap.clear(); + }; + + + CssBaseRenderer.prototype.renderTile = function(tile, texture) { + this._newTileList.push(tile); + this._textureMap.set(tile, texture); + }; + + + CssBaseRenderer.prototype.endLayer = function(layer, rect) { + + var domElement = this.domElement; + var oldTileList = this._oldTileList; + var newTileList = this._newTileList; + var textureMap = this._textureMap; + var oldIndex, newIndex, oldTile, newTile; + var texture, canvas; + var currentNode, nextNode; + + var view = layer.view(); + + // Iterate the old and new tile lists in a consistent order and perform + // insertions and removals as we go. This minimizes the number of DOM + // operations performed. + + // Neither the tile list nor the texture list may contain duplicates, + // otherwise this logic will fail. + + // Consistency check. + if (domElement.children.length !== oldTileList.length) { + throw new Error('DOM not in sync with tile list'); + } + + newTileList.sort(tileCmp); + + oldIndex = 0; + oldTile = oldTileList[oldIndex]; + currentNode = domElement.firstChild; + + for (newIndex = 0; newIndex < newTileList.length; newIndex++) { + + newTile = newTileList[newIndex]; + + // Iterate old list until it catches up with the new list. + while (oldIndex < oldTileList.length) { + + if (oldTile.cmp(newTile) >= 0) { + // Caught up. + break; + } + + // Tile is no longer visible. + // Remove it from the DOM. + nextNode = currentNode.nextSibling; + domElement.removeChild(currentNode); + currentNode = nextNode; + oldTile = oldTileList[++oldIndex]; + } + + // Get the texture for the current tile. + texture = textureMap.get(newTile); + canvas = texture ? texture._canvas : null; + + // Consistency check. + if (!canvas) { + throw new Error('Rendering tile with missing texture'); + } + + if (oldTile && oldTile.cmp(newTile) === 0) { + // The old and new tile are the same. + + // Consistency check. + if (canvas != currentNode) { + throw new Error('DOM not in sync with tile list'); + } + + currentNode = currentNode.nextSibling; + oldTile = oldTileList[++oldIndex]; + + } else { + // The new tile comes before the old tile. + // Insert it into the DOM. + domElement.insertBefore(canvas, currentNode); + } + + // Set the CSS transform on the current tile. + setTransform$1(canvas, this.calculateTransform(newTile, texture, view)); + + if (debug$1) { + canvas.setAttribute('data-tile', newTile.str()); + } + } + + // Remove trailing tiles that are no longer visible from the DOM. + while (currentNode) { + nextNode = currentNode.nextSibling; + domElement.removeChild(currentNode); + currentNode = nextNode; + } + + // Consistenty check. + if (domElement.children.length !== newTileList.length) { + throw new Error('DOM not in sync with tile list'); + } + + // The old and new tile lists swap roles between iterations. + var tmp = this._oldTileList; + this._oldTileList = this._newTileList; + this._newTileList = tmp; + }; + + + var CssBase = CssBaseRenderer; + + var CubeTile$1 = Cube.Tile; + + + + + + /** + * @class CssCubeRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link CubeGeometry} and {@link RectilinearView}, appropriate + * for a {@link CssStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function CssCubeRenderer(root, quirks) { + this.constructor.super_.call(this, root, quirks, CubeTile$1); + } + + inherits_1(CssCubeRenderer, CssBase); + + + CssCubeRenderer.prototype.calculateTransform = function(tile, texture, view) { + + var padSize = this._browserQuirks.padSize; + var reverseLevelDepth = this._browserQuirks.reverseLevelDepth; + var perspectiveNudge = this._browserQuirks.perspectiveNudge; + + var transform = ''; + + // Calculate the cube size for this level. + var cubeSize = reverseLevelDepth ? 256 - tile.z : tile.levelWidth(); + + // Place top left corner of tile at viewport center to serve as the center + // of rotation. + // We do not rotate about the center of the tile because, for some mysterious + // reason, this seems to occasionally crash Chrome. + var size = view.size(); + var viewportWidth = size.width; + var viewportHeight = size.height; + transform += 'translate3d(' + decimal_1(viewportWidth/2) + 'px, ' + decimal_1(viewportHeight/2) + 'px, 0px) '; + + // Set the perspective depth. + var perspective = 0.5 * viewportHeight / Math.tan(view.fov() / 2); + var distance = perspective + perspectiveNudge; + transform += 'perspective(' + decimal_1(perspective) + 'px) translateZ(' + decimal_1(distance) + 'px) '; + + // Set the camera rotation. + var viewRotZ = -view.roll(); + var viewRotX = -view.pitch(); + var viewRotY = view.yaw(); + transform += 'rotateZ(' + decimal_1(viewRotZ) + 'rad) rotateX(' + decimal_1(viewRotX) + 'rad) rotateY(' + decimal_1(viewRotY) + 'rad) '; + + // Set the cube face orientation. + var tileRotX = -tile.rotX(); + var tileRotY = tile.rotY(); + transform += 'rotateX(' + decimal_1(tileRotX) + 'rad) rotateY(' + decimal_1(tileRotY) + 'rad) '; + + // Move tile into its position within the cube face. + var cornerX = tile.centerX() - tile.scaleX() / 2; + var cornerY = -(tile.centerY() + tile.scaleY() / 2); + var translX = cornerX * cubeSize; + var translY = cornerY * cubeSize; + var translZ = -cubeSize / 2; + transform += 'translate3d(' + decimal_1(translX) + 'px, ' + decimal_1(translY) + 'px, ' + decimal_1(translZ) + 'px) '; + + // Scale tile into correct size. + if (reverseLevelDepth) { + var scaleX = cubeSize * tile.scaleX() / tile.width(); + var scaleY = cubeSize * tile.scaleY() / tile.height(); + transform += 'scale(' + decimal_1(scaleX) + ', ' + decimal_1(scaleY) + ') '; + } + + // Compensate for padding around the tile. + var padLeft = tile.padLeft() ? padSize : 0; + var padTop = tile.padTop() ? padSize : 0; + if (padLeft !== 0 || padTop !== 0) { + transform += 'translate3d(' + decimal_1(-padLeft) + 'px, ' + decimal_1(-padTop) + 'px, 0) '; + } + + return transform; + + }; + + + var CssCube = CssCubeRenderer; + + var makeLevelList$2 = common$1.makeLevelList; + var makeSelectableLevelList$2 = common$1.makeSelectableLevelList; + + + + + var vec2$1 = require$$67.vec2; + var vec4$3 = require$$67.vec4; + + var neighborsCacheSize$1 = 64; + + // Some renderer implementations require tiles to be padded around with + // repeated pixels to prevent the appearance of visible seams between tiles. + // + // In order to prevent the padding from being visible, the tiles must be + // padded and stacked such that the padding on one of the sides, when present, + // stacks below the neighboring tile on that side. + // + // Padding rules: + // * Pad tiles on the right and on the bottom. + // + // Stacking rules: + // * Within an image, stack smaller zoom levels below larger zoom levels. + // * Within a level, stack tiles bottom to top in ascending Y coordinate order. + // * Within a row, stack tiles bottom to top in ascending X coordinate order. + + // Offsets to apply to the (x,y) coordinates of a tile to get its neighbors. + var neighborOffsets$1 = [ + [ 0, 1 ], // top + [ 1, 0 ], // right + [ 0, -1 ], // bottom + [ -1, 0 ] // left + ]; + + + /** + * @class FlatTile + * @implements Tile + * @classdesc + * + * A tile in a {@link FlatGeometry}. + */ + function FlatTile(x, y, z, geometry) { + this.x = x; + this.y = y; + this.z = z; + this._geometry = geometry; + this._level = geometry.levelList[z]; + } + + + FlatTile.prototype.rotX = function() { + return 0; + }; + + + FlatTile.prototype.rotY = function() { + return 0; + }; + + + FlatTile.prototype.centerX = function() { + var levelWidth = this._level.width(); + var tileWidth = this._level.tileWidth(); + return (this.x * tileWidth + 0.5 * this.width()) / levelWidth - 0.5; + }; + + + FlatTile.prototype.centerY = function() { + var levelHeight = this._level.height(); + var tileHeight = this._level.tileHeight(); + return 0.5 - (this.y * tileHeight + 0.5 * this.height()) / levelHeight; + }; + + + FlatTile.prototype.scaleX = function() { + var levelWidth = this._level.width(); + return this.width() / levelWidth; + }; + + + FlatTile.prototype.scaleY = function() { + var levelHeight = this._level.height(); + return this.height() / levelHeight; + }; + + + FlatTile.prototype.width = function() { + var levelWidth = this._level.width(); + var tileWidth = this._level.tileWidth(); + if (this.atRightEdge()) { + var widthRemainder = mod_1(levelWidth, tileWidth); + return widthRemainder || tileWidth; + } else { + return tileWidth; + } + }; + + + FlatTile.prototype.height = function() { + var levelHeight = this._level.height(); + var tileHeight = this._level.tileHeight(); + if (this.atBottomEdge()) { + var heightRemainder = mod_1(levelHeight, tileHeight); + return heightRemainder || tileHeight; + } else { + return tileHeight; + } + }; + + + FlatTile.prototype.levelWidth = function() { + return this._level.width(); + }; + + + FlatTile.prototype.levelHeight = function() { + return this._level.height(); + }; + + + FlatTile.prototype.atTopLevel = function() { + return this.z === 0; + }; + + + FlatTile.prototype.atBottomLevel = function() { + return this.z === this._geometry.levelList.length - 1; + }; + + + FlatTile.prototype.atTopEdge = function() { + return this.y === 0; + }; + + + FlatTile.prototype.atBottomEdge = function() { + return this.y === this._level.numVerticalTiles() - 1; + }; + + + FlatTile.prototype.atLeftEdge = function() { + return this.x === 0; + }; + + + FlatTile.prototype.atRightEdge = function() { + return this.x === this._level.numHorizontalTiles() - 1; + }; + + + FlatTile.prototype.padTop = function() { + return false; + }; + + + FlatTile.prototype.padBottom = function() { + return !this.atBottomEdge(); + }; + + + FlatTile.prototype.padLeft = function() { + return false; + }; + + + FlatTile.prototype.padRight = function() { + return !this.atRightEdge(); + }; + + + FlatTile.prototype.vertices = function(result) { + if (!result) { + result = [vec2$1.create(), vec2$1.create(), vec2$1.create(), vec2$1.create()]; + } + + var left = this.centerX() - this.scaleX() / 2; + var right = this.centerX() + this.scaleX() / 2; + var bottom = this.centerY() - this.scaleY() / 2; + var top = this.centerY() + this.scaleY() / 2; + + vec2$1.set(result[0], left, top); + vec2$1.set(result[1], right, top); + vec2$1.set(result[2], right, bottom); + vec2$1.set(result[3], left, bottom); + + return result; + }; + + + FlatTile.prototype.parent = function() { + + + if (this.atTopLevel()) { + return null; + } + + var geometry = this._geometry; + + var z = this.z - 1; + // TODO: Currently assuming each level is double the size of previous one. + // Fix to support other multiples. + var x = Math.floor(this.x / 2); + var y = Math.floor(this.y / 2); + + return new FlatTile(x, y, z, geometry); + + }; + + + FlatTile.prototype.children = function(result) { + if (this.atBottomLevel()) { + return null; + } + + var geometry = this._geometry; + var z = this.z + 1; + + result = result || []; + + // TODO: Currently assuming each level is double the size of previous one. + // Fix to support other multiples. + result.push(new FlatTile(2*this.x , 2*this.y , z, geometry)); + result.push(new FlatTile(2*this.x , 2*this.y+1, z, geometry)); + result.push(new FlatTile(2*this.x+1, 2*this.y , z, geometry)); + result.push(new FlatTile(2*this.x+1, 2*this.y+1, z, geometry)); + + return result; + + }; + + + FlatTile.prototype.neighbors = function() { + + var geometry = this._geometry; + var cache = geometry._neighborsCache; + + // Satisfy from cache when available. + var cachedResult = cache.get(this); + if (cachedResult) { + return cachedResult; + } + + var x = this.x; + var y = this.y; + var z = this.z; + var level = this._level; + + var numX = level.numHorizontalTiles() - 1; + var numY = level.numVerticalTiles() - 1; + + var result = []; + + for (var i = 0; i < neighborOffsets$1.length; i++) { + var xOffset = neighborOffsets$1[i][0]; + var yOffset = neighborOffsets$1[i][1]; + + var newX = x + xOffset; + var newY = y + yOffset; + var newZ = z; + + if (0 <= newX && newX <= numX && 0 <= newY && newY <= numY) { + result.push(new FlatTile(newX, newY, newZ, geometry)); + } + } + + // Store into cache to satisfy future requests. + cache.set(this, result); + + return result; + + }; + + + FlatTile.prototype.hash = function() { + return hash_1(this.z, this.y, this.x); + }; + + + FlatTile.prototype.equals = function(that) { + return (this.geometry === that.geometry && + this.z === that.z && this.y === that.y && this.x === that.x); + }; + + + FlatTile.prototype.cmp = function(that) { + return (cmp_1(this.z, that.z) || cmp_1(this.y, that.y) || cmp_1(this.x, that.x)); + }; + + + FlatTile.prototype.str = function() { + return 'FlatTile(' + tile.x + ', ' + tile.y + ', ' + tile.z + ')'; + }; + + + function FlatLevel(levelProperties) { + this.constructor.super_.call(this, levelProperties); + + this._width = levelProperties.width; + this._height = levelProperties.height; + this._tileWidth = levelProperties.tileWidth; + this._tileHeight = levelProperties.tileHeight; + } + + inherits_1(FlatLevel, Level_1); + + + FlatLevel.prototype.width = function() { + return this._width; + }; + + + FlatLevel.prototype.height = function() { + return this._height; + }; + + + FlatLevel.prototype.tileWidth = function() { + return this._tileWidth; + }; + + + FlatLevel.prototype.tileHeight = function() { + return this._tileHeight; + }; + + + FlatLevel.prototype._validateWithParentLevel = function(parentLevel) { + + var width = this.width(); + var height = this.height(); + var tileWidth = this.tileWidth(); + var tileHeight = this.tileHeight(); + + var parentWidth = parentLevel.width(); + var parentHeight = parentLevel.height(); + var parentTileWidth = parentLevel.tileWidth(); + var parentTileHeight = parentLevel.tileHeight(); + + if (width % parentWidth !== 0) { + return new Error('Level width must be multiple of parent level: ' + + width + ' vs. ' + parentWidth); + } + + if (height % parentHeight !== 0) { + return new Error('Level height must be multiple of parent level: ' + + height + ' vs. ' + parentHeight); + } + + if (tileWidth % parentTileWidth !== 0) { + return new Error('Level tile width must be multiple of parent level: ' + + tileWidth + ' vs. ' + parentTileWidth); + } + + if (tileHeight % parentTileHeight !== 0) { + return new Error('Level tile height must be multiple of parent level: ' + + tileHeight + ' vs. ' + parentTileHeight); + } + + }; + + + /** + * @class FlatGeometry + * @implements Geometry + * @classdesc + * + * A {@link Geometry} implementation suitable for tiled flat images with + * multiple resolution levels. + * + * The following restrictions apply: + * - All tiles must be square, except when in the last row or column position, + * and must form a rectangular grid; + * - The width and height of a level must be multiples of the parent level + * width and height. + * + * @param {Object[]} levelPropertiesList Level description + * @param {number} levelPropertiesList[].width Level width in pixels + * @param {number} levelPropertiesList[].tileWidth Tile width in pixels for + * square tiles + * @param {number} levelPropertiesList[].height Level height in pixels + * @param {number} levelPropertiesList[].tileHeight Tile height in pixels for + * square tiles + */ + function FlatGeometry(levelPropertiesList) { + if (type_1(levelPropertiesList) !== 'array') { + throw new Error('Level list must be an array'); + } + + this.levelList = makeLevelList$2(levelPropertiesList, FlatLevel); + this.selectableLevelList = makeSelectableLevelList$2(this.levelList); + + for (var i = 1; i < this.levelList.length; i++) { + this.levelList[i]._validateWithParentLevel(this.levelList[i-1]); + } + + this._tileSearcher = new TileSearcher_1(this); + + this._neighborsCache = new LruMap_1(neighborsCacheSize$1); + + this._vec = vec4$3.create(); + + this._viewSize = {}; + } + + + FlatGeometry.prototype.maxTileSize = function() { + var maxTileSize = 0; + for (var i = 0; i < this.levelList.length; i++) { + var level = this.levelList[i]; + maxTileSize = Math.max(maxTileSize, level.tileWidth, level.tileHeight); + } + return maxTileSize; + }; + + + FlatGeometry.prototype.levelTiles = function(level, result) { + + var levelIndex = this.levelList.indexOf(level); + var maxX = level.numHorizontalTiles() - 1; + var maxY = level.numVerticalTiles() - 1; + + if (!result) { + result = []; + } + + for (var x = 0; x <= maxX; x++) { + for (var y = 0; y <= maxY; y++) { + result.push(new FlatTile(x, y, levelIndex, this)); + } + } + + return result; + + }; + + + FlatGeometry.prototype._closestTile = function(view, level) { + var ray = this._vec; + + // Compute a view ray into the central screen point. + vec4$3.set(ray, 0, 0, 1, 1); + vec4$3.transformMat4(ray, ray, view.inverseProjection()); + + // Compute the image coordinates that the view ray points into. + var x = 0.5 + ray[0]; + var y = 0.5 - ray[1]; + + // Get the desired zoom level. + var tileZ = this.levelList.indexOf(level); + var levelWidth = level.width(); + var levelHeight = level.height(); + var tileWidth = level.tileWidth(); + var tileHeight = level.tileHeight(); + var numX = level.numHorizontalTiles(); + var numY = level.numVerticalTiles(); + + // Find the coordinates of the tile that the view ray points into. + var tileX = clamp_1(Math.floor(x * levelWidth / tileWidth), 0, numX - 1); + var tileY = clamp_1(Math.floor(y * levelHeight / tileHeight), 0, numY - 1); + + return new FlatTile(tileX, tileY, tileZ, this); + }; + + + FlatGeometry.prototype.visibleTiles = function(view, level, result) { + var viewSize = this._viewSize; + var tileSearcher = this._tileSearcher; + + result = result || []; + + view.size(viewSize); + if (viewSize.width === 0 || viewSize.height === 0) { + // No tiles are visible if the viewport is empty. + return result; + } + + var startingTile = this._closestTile(view, level); + var count = tileSearcher.search(view, startingTile, result); + if (!count) { + throw new Error('Starting tile is not visible'); + } + + return result; + }; + + + FlatGeometry.Tile = FlatGeometry.prototype.Tile = FlatTile; + FlatGeometry.type = FlatGeometry.prototype.type = 'flat'; + FlatTile.type = FlatTile.prototype.type = 'flat'; + + + var Flat = FlatGeometry; + + var FlatTile$1 = Flat.Tile; + + + + + + /** + * @class CssFlatRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link FlatGeometry} and {@link FlatView}, appropriate for a + * {@link CssStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function CssFlatRenderer(root, quirks) { + this.constructor.super_.call(this, root, quirks, FlatTile$1); + } + + inherits_1(CssFlatRenderer, CssBase); + + + CssFlatRenderer.prototype.calculateTransform = function(tile, texture, view) { + + var padSize = this._browserQuirks.padSize; + + var transform = ''; + + // Place top left corner of tile at the center of the viewport. + var viewportWidth = view.width(); + var viewportHeight = view.height(); + transform += 'translateX(' + decimal_1(viewportWidth/2) + 'px) translateY(' + decimal_1(viewportHeight/2) + 'px) '; + + // Determine the zoom factor. + var zoomX = viewportWidth / view._zoomX(); + var zoomY = viewportHeight / view._zoomY(); + + // Move tile into its position within the image. + var cornerX = tile.centerX() - tile.scaleX() / 2 + 0.5; + var cornerY = 0.5 - tile.centerY() - tile.scaleY() / 2; + var translX = cornerX * zoomX; + var translY = cornerY * zoomY; + transform += 'translateX(' + decimal_1(translX) + 'px) translateY(' + decimal_1(translY) + 'px) '; + + // Apply view offsets. + var offX = -view.x() * zoomX; + var offY = -view.y() * zoomY; + transform += 'translateX(' + decimal_1(offX) + 'px) translateY(' + decimal_1(offY) + 'px) '; + + // Compensate for padding around the tile. + var padLeft = tile.padLeft() ? padSize : 0; + var padTop = tile.padTop() ? padSize : 0; + if (padLeft !== 0 || padTop !== 0) { + transform += 'translateX(' + decimal_1(-padLeft) + 'px) translateY(' + decimal_1(-padTop) + 'px) '; + } + + // Scale tile into correct size. + var scaleX = zoomX / tile.levelWidth(); + var scaleY = zoomY / tile.levelHeight(); + transform += 'scale(' + decimal_1(scaleX) + ', ' + decimal_1(scaleY) + ') '; + + return transform; + + }; + + + var CssFlat = CssFlatRenderer; + + function tileCmp$1(a, b) { + return a.cmp(b); + } + + + function FlashBaseRenderer(flashElement, layerId, quirks, tileClass) { + + this._flashElement = flashElement; + this._layerId = layerId; + this._quirks = quirks; + + this._tileList = []; + + this._textureMap = new _Map(); + + // Whether the Flash layer for this renderer has already been created + // by calling flashElement.createLayer(). Note that we cannot do this + // right here because Flash may not be initialized yet. + this._layerCreated = false; + } + + + FlashBaseRenderer.prototype.destroy = function() { + if (this._layerCreated) { + this._flashElement.destroyLayer(this._layerId); + } + clearOwnProperties_1(this); + }; + + + FlashBaseRenderer.prototype.startLayer = function(layer, rect) { + if (!this._flashElement.isReady || !this._flashElement.isReady()) { + return; + } + if (!this._layerCreated) { + this._flashElement.createLayer(this._layerId); + this._layerCreated = true; + } + this._tileList.length = 0; + this._textureMap.clear(); + }; + + + FlashBaseRenderer.prototype.renderTile = function(tile, texture) { + this._tileList.push(tile); + this._textureMap.set(tile, texture); + }; + + + FlashBaseRenderer.prototype.endLayer = function(layer, rect) { + if (!this._flashElement.isReady || !this._flashElement.isReady()) { + return; + } + + // Sort tiles so they are rendered in an order coherent with their padding. + var tileList = this._tileList; + tileList.sort(tileCmp$1); + + this._renderOnFlash(layer, rect); + }; + + + var FlashBase = FlashBaseRenderer; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @memberof util + * @param {number} rad + * @return {number} + */ + function radToDeg(rad) { + return rad * 180 / Math.PI; + } + + var radToDeg_1 = radToDeg; + + var CubeTile$2 = Cube.Tile; + + + + + + /** + * @class FlashCubeRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link CubeGeometry} and {@link RectilinearView}, appropriate + * for a {@link FlashStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function FlashCubeRenderer(flashElement, layerId, quirks) { + this.constructor.super_.call(this, flashElement, layerId, quirks, CubeTile$2); + this._flashTileList = []; + } + + inherits_1(FlashCubeRenderer, FlashBase); + + + FlashCubeRenderer.prototype._renderOnFlash = function(layer, rect) { + + var flashElement = this._flashElement; + var layerId = this._layerId; + var padSize = this._quirks.padSize; + + var tileList = this._tileList; + var textureMap = this._textureMap; + + var flashTileList = this._flashTileList; + flashTileList.length = 0; + + for (var i = 0; i < tileList.length; i++) { + var tile = tileList[i]; + var texture = textureMap.get(tile); + if (!texture) { + throw new Error('Rendering tile with missing texture'); + } + + // Get padding sizes. + var padTop = tile.padTop() ? padSize : 0; + var padBottom = tile.padBottom() ? padSize : 0; + var padLeft = tile.padLeft() ? padSize : 0; + var padRight = tile.padRight() ? padSize : 0; + + flashTileList.push({ + textureId: texture._textureId, + face: tile.face, + width: tile.width(), + height: tile.height(), + centerX: tile.centerX(), + centerY: tile.centerY(), + rotX: radToDeg_1(tile.rotX()), + rotY: radToDeg_1(tile.rotY()), + levelSize: tile.levelWidth(), + padTop: padTop, + padBottom: padBottom, + padLeft: padLeft, + padRight: padRight + }); + } + + // Get viewport position and size. + var stageWidth = this._flashElement.clientWidth; + var stageHeight = this._flashElement.clientHeight; + var viewportX = stageWidth * rect.x; + var viewportY = stageHeight * rect.y; + var viewportWidth = stageWidth * rect.width; + var viewportHeight = stageHeight * rect.height; + + // Get opacity value. + var opacity = 1.0; + var effects = layer.effects(); + if (effects && effects.opacity != null) { + opacity = effects.opacity; + } + + // Get view parameters. + var view = layer.view(); + var yaw = view.yaw(); + var pitch = view.pitch(); + var roll = view.roll(); + var fov = view.fov(); + + flashElement.drawCubeTiles( + layerId, viewportWidth, viewportHeight, viewportX, viewportY, opacity, + yaw, pitch, roll, fov, flashTileList); + }; + + + var FlashCube = FlashCubeRenderer; + + var FlatTile$2 = Flat.Tile; + + + + /** + * @class FlashFlatRenderer + * @implements Renderer + * @classdesc + * + * A renderer for {@link FlatGeometry} and {@link FlatView}, appropriate for a + * {@link FlashStage}. + * + * Most users do not need to instantiate this class. Renderers are created and + * destroyed by {@link Stage} as necessary. + */ + function FlashFlatRenderer(flashElement, layerId, quirks) { + this.constructor.super_.call(this, flashElement, layerId, quirks, FlatTile$2); + this._flashTileList = []; + } + + inherits_1(FlashFlatRenderer, FlashBase); + + + FlashFlatRenderer.prototype._renderOnFlash = function(layer, rect) { + + var flashElement = this._flashElement; + var layerId = this._layerId; + var padSize = this._quirks.padSize; + + var tileList = this._tileList; + var textureMap = this._textureMap; + + var flashTileList = this._flashTileList; + flashTileList.length = 0; + + for (var i = 0; i < tileList.length; i++) { + var tile = tileList[i]; + var texture = textureMap.get(tile); + if (!texture) { + throw new Error('Rendering tile with missing texture'); + } + + // Get padding sizes. + var padTop = tile.padTop() ? padSize : 0; + var padBottom = tile.padBottom() ? padSize : 0; + var padLeft = tile.padLeft() ? padSize : 0; + var padRight = tile.padRight() ? padSize : 0; + + flashTileList.push({ + textureId: texture._textureId, + width: tile.width(), + height: tile.height(), + centerX: tile.centerX(), + centerY: tile.centerY(), + scaleX: tile.scaleX(), + scaleY: tile.scaleY(), + levelWidth: tile.levelWidth(), + levelHeight: tile.levelHeight(), + padTop: padTop, + padBottom: padBottom, + padLeft: padLeft, + padRight: padRight + }); + } + + // Get viewport position and size. + var stageWidth = this._flashElement.clientWidth; + var stageHeight = this._flashElement.clientHeight; + var viewportX = stageWidth * rect.x; + var viewportY = stageHeight * rect.y; + var viewportWidth = stageWidth * rect.width; + var viewportHeight = stageHeight * rect.height; + + // Get opacity value. + var opacity = 1.0; + var effects = layer.effects(); + if (effects && effects.opacity != null) { + opacity = effects.opacity; + } + + // Get view parameters. + var view = layer.view(); + var x = view.x(); + var y = view.y(); + var zoomX = view._zoomX(); + var zoomY = view._zoomY(); + + flashElement.drawFlatTiles( + layerId, viewportWidth, viewportHeight, viewportX, viewportY, opacity, + x, y, zoomX, zoomY, flashTileList); + }; + + + var FlashFlat = FlashFlatRenderer; + + /** + * Registers all known renderers for the given stage type into that stage. + * Most users will not need to register renderers, as {@link Viewer} does it for + * them. + * + * @param {Stage} stage The stage where the renderers are to be registered. + * @throws An error if the stage type is unknown. + */ + function registerDefaultRenderers(stage) { + switch (stage.type) { + case 'webgl': + stage.registerRenderer('flat', 'flat', WebGlFlat); + stage.registerRenderer('cube', 'rectilinear', WebGlCube); + stage.registerRenderer('equirect', 'rectilinear', WebGlEquirect); + break; + case 'css': + stage.registerRenderer('flat', 'flat', CssFlat); + stage.registerRenderer('cube', 'rectilinear', CssCube); + break; + case 'flash': + stage.registerRenderer('flat', 'flat', FlashFlat); + stage.registerRenderer('cube', 'rectilinear', FlashCube); + break; + default: + throw new Error('Unknown stage type: ' + stage.type); + } + } + + var registerDefaultRenderers_1 = registerDefaultRenderers; + + /** + * @class EquirectTile + * @implements Tile + * @classdesc + * + * A tile in an @{EquirectGeometry}. + */ + function EquirectTile(z, geometry) { + this.z = z; + this._geometry = geometry; + this._level = geometry.levelList[z]; + } + + + EquirectTile.prototype.rotX = function() { + return 0; + }; + + + EquirectTile.prototype.rotY = function() { + return 0; + }; + + + EquirectTile.prototype.centerX = function() { + return 0.5; + }; + + + EquirectTile.prototype.centerY = function() { + return 0.5; + }; + + + EquirectTile.prototype.scaleX = function() { + return 1; + }; + + + EquirectTile.prototype.scaleY = function() { + return 1; + }; + + + EquirectTile.prototype.width = function() { + return this._level.tileWidth(); + }; + + + EquirectTile.prototype.height = function() { + return this._level.tileHeight(); + }; + + + EquirectTile.prototype.levelWidth = function() { + return this._level.width(); + }; + + + EquirectTile.prototype.levelHeight = function() { + return this._level.height(); + }; + + + EquirectTile.prototype.atTopLevel = function() { + return this.z === 0; + }; + + + EquirectTile.prototype.atBottomLevel = function() { + return this.z === this._geometry.levelList.length - 1; + }; + + + EquirectTile.prototype.atTopEdge = function() { + return true; + }; + + + EquirectTile.prototype.atBottomEdge = function() { + return true; + }; + + + EquirectTile.prototype.atLeftEdge = function() { + return true; + }; + + + EquirectTile.prototype.atRightEdge = function() { + return true; + }; + + + EquirectTile.prototype.padTop = function() { + return false; + }; + + + EquirectTile.prototype.padBottom = function() { + return false; + }; + + + EquirectTile.prototype.padLeft = function() { + return false; + }; + + + EquirectTile.prototype.padRight = function() { + return false; + }; + + + EquirectTile.prototype.parent = function() { + if (this.atTopLevel()) { + return null; + } + return new EquirectTile(this.z - 1, this._geometry); + }; + + + EquirectTile.prototype.children = function(result) { + if (this.atBottomLevel()) { + return null; + } + result = result || []; + result.push(new EquirectTile(this.z + 1, this._geometry)); + return result; + }; + + + EquirectTile.prototype.neighbors = function() { + return []; + }; + + + EquirectTile.prototype.hash = function() { + return hash_1(this.z); + }; + + + EquirectTile.prototype.equals = function(that) { + return this.geometry === that.geometry && this.z === that.z; + }; + + + EquirectTile.prototype.cmp = function(that) { + return cmp_1(this.z, that.z); + }; + + + EquirectTile.prototype.str = function() { + return 'EquirectTile(' + tile.z + ')'; + }; + + + function EquirectLevel(levelProperties) { + this.constructor.super_.call(this, levelProperties); + this._width = levelProperties.width; + } + + inherits_1(EquirectLevel, Level_1); + + + EquirectLevel.prototype.width = function() { + return this._width; + }; + + + EquirectLevel.prototype.height = function() { + return this._width/2; + }; + + + EquirectLevel.prototype.tileWidth = function() { + return this._width; + }; + + + EquirectLevel.prototype.tileHeight = function() { + return this._width/2; + }; + + + /** + * @class EquirectGeometry + * @implements Geometry + * @classdesc + * + * A {@link Geometry} implementation suitable for equirectangular images with a + * 2:1 aspect ratio. + * + * @param {Object[]} levelPropertiesList Level description + * @param {number} levelPropertiesList[].width Level width in pixels + */ + function EquirectGeometry(levelPropertiesList) { + if (type_1(levelPropertiesList) !== 'array') { + throw new Error('Level list must be an array'); + } + + this.levelList = common$1.makeLevelList(levelPropertiesList, EquirectLevel); + this.selectableLevelList = common$1.makeSelectableLevelList(this.levelList); + } + + + EquirectGeometry.prototype.maxTileSize = function() { + var maxTileSize = 0; + for (var i = 0; i < this.levelList.length; i++) { + var level = this.levelList[i]; + maxTileSize = Math.max(maxTileSize, level.tileWidth, level.tileHeight); + } + return maxTileSize; + }; + + + EquirectGeometry.prototype.levelTiles = function(level, result) { + var levelIndex = this.levelList.indexOf(level); + result = result || []; + result.push(new EquirectTile(levelIndex, this)); + return result; + }; + + + EquirectGeometry.prototype.visibleTiles = function(view, level, result) { + var tile = new EquirectTile(this.levelList.indexOf(level), this); + result = result || []; + result.length = 0; + result.push(tile); + }; + + + EquirectGeometry.Tile = EquirectGeometry.prototype.Tile = EquirectTile; + EquirectGeometry.type = EquirectGeometry.prototype.type = 'equirect'; + EquirectTile.type = EquirectTile.prototype.type = 'equirect'; + + + var Equirect = EquirectGeometry; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * Convert fov + * + * For example, to convert from hfov to vfov one would call + * `convert(hfov, width, height)` + * + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function convert(fov, fromDimension, toDimension) { + return 2 * Math.atan(toDimension * Math.tan(fov / 2) / fromDimension); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function htov(fov, width, height) { + return convert(fov, width, height); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function htod(fov, width, height) { + return convert(fov, width, Math.sqrt(width * width + height * height)); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function vtoh(fov, width, height) { + return convert(fov, height, width); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function vtod(fov, width, height) { + return convert(fov, height, Math.sqrt(width * width + height * height)); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function dtoh(fov, width, height) { + return convert(fov, Math.sqrt(width * width + height * height), width); + } + + /** + * @param {number} fov + * @param {number} fromDimension + * @param {number} toDimension + * @return {number} + * @memberof util.convertFov + */ + function dtov(fov, width, height) { + return convert(fov, Math.sqrt(width * width + height * height), height); + } + + /** + * @namespace util.convertFov + */ + var convertFov = { + convert: convert, + htov: htov, + htod: htod, + vtoh: vtoh, + vtod: vtod, + dtoh: dtoh, + dtov: dtov + }; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function real(x) { + return typeof x === 'number' && isFinite(x); + } + + var real_1 = real; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * Compose multiple functions + * + * `compose(f, g)` returns `function(x) { return f(g(x)); }` + * + * @memberof util + * @param {Function[]} functions The functions to compose + * @return {Function} + */ + function compose() { + var fnList = arguments; + return function composed(initialArg) { + var ret = initialArg; + for (var i = 0; i < fnList.length; i++) { + var fn = fnList[i]; + ret = fn.call(null, ret); + } + return ret; + }; + } + + var compose_1 = compose; + + var mat4$4 = require$$67.mat4; + var vec4$4 = require$$67.vec4; + + + + + + + + + + // Default viewport dimensions. + // Start with zero to ensure that those values are handled correctly. + var defaultWidth = 0; + var defaultHeight = 0; + + // Default view parameters. + var defaultYaw = 0; + var defaultPitch = 0; + var defaultRoll = 0; + var defaultFov = Math.PI/4; + var defaultProjectionCenterX = 0; + var defaultProjectionCenterY = 0; + + // A fov of exactly 0 or π breaks some computations, so we constrain it to the + // [fovLimitEpsilon, π - fovLimitEpsilon] interval. We use 6 decimal places for + // the epsilon value to avoid broken rendering due to loss of precision in + // floating point computations. + var fovLimitEpsilon = 0.000001; + + + /** + * @interface RectilinearViewParams + * + * A camera configuration for a {@link RectilinearView}. + * + * @property {number} yaw The yaw angle, in the [-π, π] range. + * When `yaw < 0`, the view rotates to the left. + * When `yaw > 0`, the view rotates to the right. + * + * @property {number} pitch The pitch angle, in the [-π, π] range. + * When `pitch < 0`, the view rotates downwards. + * When `pitch > 0`, the view rotates upwards. + * + * @property {number} roll The roll angle, in the [-π, π] range. + * When `roll < 0`, the view rotates clockwise. + * When `roll > 0`, the view rotates counter-clockwise. + * + * @property {fov} fov The vertical field of view, in the [0, π] range. + */ + + + /** + * @interface RectilinearViewCoords + * + * The position of a point in a 360° image. + * + * @property {number} yaw The yaw angle, in the [-π, π] range. + * @property {number} pitch The pitch angle, in the [-π, π] range. + */ + + + /** + * @typedef {function} RectilinearViewLimiter + * + * View limiter for a {@link RectilinearView}. + * + * A view limiter is a function that receives a {@link RectilinearViewParams} + * object, optionally modifies it in place, and returns it. It can be used to + * enforce constraints on the view parameters. + * + * See {@link RectilinearView.limit} for commonly used limiters. They may be + * composed together or with user-defined limiters with {@link util.compose}. + * + * @param {RectilinearViewParams} params + * @return {RectilinearViewParams} + */ + + /** + * @class RectilinearView + * @implements View + * @classdesc + * + * A {@link View} implementing a rectilinear projection for 360° images. + * + * @param {RectilinearViewParams=} params The initial view parameters. If + * unspecified, defaults to `{yaw: 0, pitch: 0, roll: 0, fov: Math.PI/4 }`. + * @param {RectilinearViewLimiter=} limiter The view limiter. If unspecified, + * no view limiting is applied. See {@link RectilinearView.limit} for + * commonly used limiters. + */ + function RectilinearView(params, limiter) { + // The initial values for the view parameters. + this._yaw = params && params.yaw != null ? params.yaw : defaultYaw; + this._pitch = params && params.pitch != null ? params.pitch : defaultPitch; + this._roll = params && params.roll != null ? params.roll : defaultRoll; + this._fov = params && params.fov != null ? params.fov : defaultFov; + this._width = params && params.width != null ? + params.width : defaultWidth; + this._height = params && params.height != null ? + params.height : defaultHeight; + this._projectionCenterX = params && params.projectionCenterX != null ? + params.projectionCenterX : defaultProjectionCenterX; + this._projectionCenterY = params && params.projectionCenterY != null ? + params.projectionCenterY : defaultProjectionCenterY; + + // The initial value for the view limiter. + this._limiter = limiter || null; + + // The last calculated projection matrix and its inverse. + this._projMatrix = mat4$4.create(); + this._invProjMatrix = mat4$4.create(); + + // The last calculated view frustum. + this._frustum = [ + vec4$4.create(), // left + vec4$4.create(), // right + vec4$4.create(), // bottom + vec4$4.create(), // top + vec4$4.create() // camera + ]; + + // Whether the projection matrices and the view frustum need to be updated. + this._projectionChanged = true; + + // Temporary variables used for calculations. + this._params = {}; + this._fovs = {}; + this._tmpVec = vec4$4.create(); + + // Force view limiting on initial parameters. + this._update(); + } + + minimalEventEmitter(RectilinearView); + + + /** + * Destructor. + */ + RectilinearView.prototype.destroy = function() { + clearOwnProperties_1(this); + }; + + + /** + * Get the yaw angle. + * @return {number} + */ + RectilinearView.prototype.yaw = function() { + return this._yaw; + }; + + + /** + * Get the pitch angle. + * @return {number} + */ + RectilinearView.prototype.pitch = function() { + return this._pitch; + }; + + + /** + * Get the roll angle. + * @return {number} + */ + RectilinearView.prototype.roll = function() { + return this._roll; + }; + + + RectilinearView.prototype.projectionCenterX = function() { + return this._projectionCenterX; + }; + + + RectilinearView.prototype.projectionCenterY = function() { + return this._projectionCenterY; + }; + + + /** + * Get the fov value. + * @return {number} + */ + RectilinearView.prototype.fov = function() { + return this._fov; + }; + + + /** + * Get the viewport width. + * @return {number} + */ + RectilinearView.prototype.width = function() { + return this._width; + }; + + + /** + * Get the viewport height. + * @return {number} + */ + RectilinearView.prototype.height = function() { + return this._height; + }; + + + /** + * Get the viewport dimensions. If an argument is supplied, it is filled in with + * the result and returned. Otherwise, a fresh object is filled in and returned. + * @param {Size=} size + * @return {Size} + */ + RectilinearView.prototype.size = function(size) { + size = size || {}; + size.width = this._width; + size.height = this._height; + return size; + }; + + + /** + * Get the view parameters. If an argument is supplied, it is filled in with the + * result and returned. Otherwise, a fresh object is filled in and returned. + * @param {RectilinearViewParams=} obj + * @return {RectilinearViewParams} + */ + RectilinearView.prototype.parameters = function(params) { + params = params || {}; + params.yaw = this._yaw; + params.pitch = this._pitch; + params.roll = this._roll; + params.fov = this._fov; + return params; + }; + + + /** + * Get the view limiter, or null if unset. + * @return {?RectilinearViewLimiter} + */ + RectilinearView.prototype.limiter = function() { + return this._limiter; + }; + + + /** + * Set the yaw angle. + * @param {number} yaw + */ + RectilinearView.prototype.setYaw = function(yaw) { + this._resetParams(); + this._params.yaw = yaw; + this._update(this._params); + }; + + + /** + * Set the pitch angle. + * @param {number} pitch + */ + RectilinearView.prototype.setPitch = function(pitch) { + this._resetParams(); + this._params.pitch = pitch; + this._update(this._params); + }; + + + /** + * Set the roll angle. + * @param {number} roll + */ + RectilinearView.prototype.setRoll = function(roll) { + this._resetParams(); + this._params.roll = roll; + this._update(this._params); + }; + + + /** + * Set the fov value. + * @param {number} fov + */ + RectilinearView.prototype.setFov = function(fov) { + this._resetParams(); + this._params.fov = fov; + this._update(this._params); + }; + + + RectilinearView.prototype.setProjectionCenterX = function(projectionCenterX) { + this._resetParams(); + this._params.projectionCenterX = projectionCenterX; + this._update(this._params); + }; + + + RectilinearView.prototype.setProjectionCenterY = function(projectionCenterY) { + this._resetParams(); + this._params.projectionCenterY = projectionCenterY; + this._update(this._params); + }; + + + /** + * Add yawOffset to the current yaw value. + * @param {number} yawOffset + */ + RectilinearView.prototype.offsetYaw = function(yawOffset) { + this.setYaw(this._yaw + yawOffset); + }; + + + /** + * Add pitchOffset to the current pitch value. + * @param {number} pitchOffset + */ + RectilinearView.prototype.offsetPitch = function(pitchOffset) { + this.setPitch(this._pitch + pitchOffset); + }; + + + /** + * Add rollOffset to the current roll value. + * @param {number} rollOffset + */ + RectilinearView.prototype.offsetRoll = function(rollOffset) { + this.setRoll(this._roll + rollOffset); + }; + + + /** + * Add fovOffset to the current fov value. + * @param {number} fovOffset + */ + RectilinearView.prototype.offsetFov = function(fovOffset) { + this.setFov(this._fov + fovOffset); + }; + + + /** + * Set the viewport dimensions. + * @param {Size} size + */ + RectilinearView.prototype.setSize = function(size) { + this._resetParams(); + this._params.width = size.width; + this._params.height = size.height; + this._update(this._params); + }; + + + /** + * Set the view parameters. Unspecified parameters are left unchanged. + * @param {RectilinearViewParameters} params + */ + RectilinearView.prototype.setParameters = function(params) { + this._resetParams(); + this._params.yaw = params.yaw; + this._params.pitch = params.pitch; + this._params.roll = params.roll; + this._params.fov = params.fov; + this._params.projectionCenterX = params.projectionCenterX; + this._params.projectionCenterY = params.projectionCenterY; + this._update(this._params); + }; + + + /** + * Set the view limiter. + * @param {?RectilinearViewLimiter} limiter The new limiter, or null to unset. + */ + RectilinearView.prototype.setLimiter = function(limiter) { + this._limiter = limiter || null; + this._update(); + }; + + + RectilinearView.prototype._resetParams = function() { + var params = this._params; + params.yaw = null; + params.pitch = null; + params.roll = null; + params.fov = null; + params.width = null; + params.height = null; + }; + + + RectilinearView.prototype._update = function(params) { + + // Avoid object allocation when no parameters are supplied. + if (params == null) { + this._resetParams(); + params = this._params; + } + + // Save old parameters for later comparison. + var oldYaw = this._yaw; + var oldPitch = this._pitch; + var oldRoll = this._roll; + var oldFov = this._fov; + var oldProjectionCenterX = this._projectionCenterX; + var oldProjectionCenterY = this._projectionCenterY; + var oldWidth = this._width; + var oldHeight = this._height; + + // Fill in object with the new set of parameters to pass into the limiter. + params.yaw = params.yaw != null ? params.yaw : oldYaw; + params.pitch = params.pitch != null ? params.pitch : oldPitch; + params.roll = params.roll != null ? params.roll : oldRoll; + params.fov = params.fov != null ? params.fov : oldFov; + params.width = params.width != null ? params.width : oldWidth; + params.height = params.height != null ? params.height : oldHeight; + params.projectionCenterX = params.projectionCenterX != null ? + params.projectionCenterX : oldProjectionCenterX; + params.projectionCenterY = params.projectionCenterY != null ? + params.projectionCenterY : oldProjectionCenterY; + + // Apply view limiting when defined. + if (this._limiter) { + params = this._limiter(params); + if (!params) { + throw new Error('Bad view limiter'); + } + } + + // Normalize parameters. + params = this._normalize(params); + + // Grab the limited parameters. + var newYaw = params.yaw; + var newPitch = params.pitch; + var newRoll = params.roll; + var newFov = params.fov; + var newWidth = params.width; + var newHeight = params.height; + var newProjectionCenterX = params.projectionCenterX; + var newProjectionCenterY = params.projectionCenterY; + + // Consistency check. + if (!real_1(newYaw) || !real_1(newPitch) || !real_1(newRoll) || + !real_1(newFov) || !real_1(newWidth) || !real_1(newHeight) || + !real_1(newProjectionCenterX) || !real_1(newProjectionCenterY)) { + throw new Error('Bad view - suspect a broken limiter'); + } + + // Update parameters. + this._yaw = newYaw; + this._pitch = newPitch; + this._roll = newRoll; + this._fov = newFov; + this._width = newWidth; + this._height = newHeight; + this._projectionCenterX = newProjectionCenterX; + this._projectionCenterY = newProjectionCenterY; + + // Check whether the parameters changed and emit the corresponding events. + if (newYaw !== oldYaw || newPitch !== oldPitch || newRoll !== oldRoll || + newFov !== oldFov || newWidth !== oldWidth || newHeight !== oldHeight || + newProjectionCenterX !== oldProjectionCenterX || + newProjectionCenterY !== oldProjectionCenterY) { + this._projectionChanged = true; + this.emit('change'); + } + if (newWidth !== oldWidth || newHeight !== oldHeight) { + this.emit('resize'); + } + + }; + + + RectilinearView.prototype._normalize = function(params) { + + this._normalizeCoordinates(params); + + // Make sure that neither the horizontal nor the vertical fields of view + // exceed π - fovLimitEpsilon. + var hfovPi = convertFov.htov(Math.PI, params.width, params.height); + var maxFov = isNaN(hfovPi) ? Math.PI : Math.min(Math.PI, hfovPi); + params.fov = clamp_1(params.fov, fovLimitEpsilon, maxFov - fovLimitEpsilon); + + return params; + }; + + + RectilinearView.prototype._normalizeCoordinates = function(params) { + // Constrain yaw, pitch and roll to the [-π, π] interval. + if ('yaw' in params) { + params.yaw = mod_1(params.yaw - Math.PI, -2*Math.PI) + Math.PI; + } + if ('pitch' in params) { + params.pitch = mod_1(params.pitch - Math.PI, -2*Math.PI) + Math.PI; + } + if ('roll' in params) { + params.roll = mod_1(params.roll - Math.PI, -2*Math.PI) + Math.PI; + } + return params; + }; + + + /** + * Normalize view coordinates so that they are the closest to the current view. + * Useful for tweening the view through the shortest path. If a result argument + * is supplied, it is filled in with the result and returned. Otherwise, a fresh + * object is filled in and returned. + * + * @param {RectilinearViewCoords} coords The view coordinates. + * @param {RectilinearViewCoords} result The result argument for the normalized + * view coordinates. + */ + RectilinearView.prototype.normalizeToClosest = function(coords, result) { + + var viewYaw = this._yaw; + var viewPitch = this._pitch; + + var coordYaw = coords.yaw; + var coordPitch = coords.pitch; + + // Check if the yaw is closer after subtracting or adding a full circle. + var prevYaw = coordYaw - 2*Math.PI; + var nextYaw = coordYaw + 2*Math.PI; + if (Math.abs(prevYaw - viewYaw) < Math.abs(coordYaw - viewYaw)) { + coordYaw = prevYaw; + } + else if (Math.abs(nextYaw - viewYaw) < Math.abs(coordYaw - viewYaw)) { + coordYaw = nextYaw; + } + + // Check if the pitch is closer after subtracting or adding a full circle. + var prevPitch = coordPitch - 2*Math.PI; + var nextPitch = coordPitch + 2*Math.PI; + if (Math.abs(prevPitch - viewPitch) < Math.abs(coordPitch - viewPitch)) { + coordPitch = prevPitch; + } + else if (Math.abs(prevPitch - viewPitch) < Math.abs(coordPitch - viewPitch)) { + coordPitch = nextPitch; + } + + result = result || {}; + result.yaw = coordYaw; + result.pitch = coordPitch; + return result; + + }; + + + RectilinearView.prototype.updateWithControlParameters = function(parameters) { + // axisScaledX and axisScaledY are scaled according to their own axis + // x and y are scaled by the same value + + // If the viewport dimensions are zero, assume a square viewport + // when converting from hfov to vfov. + var vfov = this._fov; + var hfov = convertFov.vtoh(vfov, this._width, this._height); + if (isNaN(hfov)) { + hfov = vfov; + } + + // TODO: revisit this after we rethink the control parameters. + this.offsetYaw(parameters.axisScaledX * hfov + parameters.x * 2 * hfov + parameters.yaw); + this.offsetPitch(parameters.axisScaledY * vfov + parameters.y * 2 * hfov + parameters.pitch); + this.offsetRoll(-parameters.roll); + this.offsetFov(parameters.zoom * vfov); + }; + + + RectilinearView.prototype._updateProjection = function() { + var projMatrix = this._projMatrix; + var invProjMatrix = this._invProjMatrix; + var frustum = this._frustum; + + if (this._projectionChanged) { + var width = this._width; + var height = this._height; + + var vfov = this._fov; + var hfov = convertFov.vtoh(vfov, width, height); + var aspect = width / height; + + var projectionCenterX = this._projectionCenterX; + var projectionCenterY = this._projectionCenterY; + + if (projectionCenterX !== 0 || projectionCenterY !== 0) { + var offsetAngleX = Math.atan(projectionCenterX * 2 * Math.tan(hfov/2)); + var offsetAngleY = Math.atan(projectionCenterY * 2 * Math.tan(vfov/2)); + var fovs = this._fovs; + fovs.leftDegrees = (hfov/2 + offsetAngleX) * 180/Math.PI; + fovs.rightDegrees = (hfov/2 - offsetAngleX) * 180/Math.PI; + fovs.upDegrees = (vfov/2 + offsetAngleY) * 180/Math.PI; + fovs.downDegrees = (vfov/2 - offsetAngleY) * 180/Math.PI; + mat4$4.perspectiveFromFieldOfView(projMatrix, fovs, -1, 1); + } else { + mat4$4.perspective(projMatrix, vfov, aspect, -1, 1); + } + + mat4$4.rotateZ(projMatrix, projMatrix, this._roll); + mat4$4.rotateX(projMatrix, projMatrix, this._pitch); + mat4$4.rotateY(projMatrix, projMatrix, this._yaw); + + mat4$4.invert(invProjMatrix, projMatrix); + + this._matrixToFrustum(projMatrix, frustum); + + this._projectionChanged = false; + } + }; + + + RectilinearView.prototype._matrixToFrustum = function(p, f) { + // Extract frustum planes from projection matrix. + // http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf + vec4$4.set(f[0], p[3] + p[0], p[7] + p[4], p[11] + p[8], 0); // left + vec4$4.set(f[1], p[3] - p[0], p[7] - p[4], p[11] - p[8], 0); // right + vec4$4.set(f[2], p[3] + p[1], p[7] + p[5], p[11] + p[9], 0); // top + vec4$4.set(f[3], p[3] - p[1], p[7] - p[5], p[11] - p[9], 0); // bottom + vec4$4.set(f[4], p[3] + p[2], p[7] + p[6], p[11] + p[10], 0); // camera + }; + + + /** + * Returns the projection matrix for the current view. + * @returns {mat4} + */ + RectilinearView.prototype.projection = function() { + this._updateProjection(); + return this._projMatrix; + }; + + + /** + * Returns the inverse projection matrix for the current view. + * @returns {mat4} + */ + RectilinearView.prototype.inverseProjection = function() { + this._updateProjection(); + return this._invProjMatrix; + }; + + + /** + * Return whether the view frustum intersects the given rectangle. + * + * This function may return false positives, but never false negatives. + * It is used for frustum culling, i.e., excluding invisible tiles from the + * rendering process. + * + * @param {vec2[]} rectangle The vertices of the rectangle. + */ + RectilinearView.prototype.intersects = function(rectangle) { + this._updateProjection(); + + var frustum = this._frustum; + var vertex = this._tmpVec; + + // Check whether the rectangle is on the outer side of any of the frustum + // planes. This is a sufficient condition, though not necessary, for the + // rectangle to be completely outside the frustum. + for (var i = 0; i < frustum.length; i++) { + var plane = frustum[i]; + var inside = false; + for (var j = 0; j < rectangle.length; j++) { + var corner = rectangle[j]; + vec4$4.set(vertex, corner[0], corner[1], corner[2], 0); + if (vec4$4.dot(plane, vertex) >= 0) { + inside = true; + } + } + if (!inside) { + return false; + } + } + return true; + }; + + + /** + * Select the level that should be used to render the view. + * @param {Level[]} levelList the list of levels from which to select. + * @return {Level} the selected level. + */ + RectilinearView.prototype.selectLevel = function(levelList) { + + // Multiply the viewport width by the device pixel ratio to get the required + // horizontal resolution in pixels. + // + // Calculate the fraction of a cube face that would be visible given the + // current vertical field of view. Then, for each level, multiply by the + // level height to get the height in pixels of the portion that would be + // visible. + // + // Search for the smallest level that satifies the the required height, + // falling back on the largest level if none do. + + var requiredPixels = pixelRatio_1() * this._height; + var coverFactor = Math.tan(0.5 * this._fov); + + for (var i = 0; i < levelList.length; i++) { + var level = levelList[i]; + if (coverFactor * level.height() >= requiredPixels) { + return level; + } + } + + return levelList[levelList.length - 1]; + + }; + + + /** + * Convert view parameters into screen position. If a result argument is + * provided, it is filled in and returned. Otherwise, a fresh object is filled + * in and returned. + * + * @param {RectilinearViewCoords} coords The view coordinates. + * @param {Coords=} result The result argument for the screen coordinates. + * @return {Coords} + */ + RectilinearView.prototype.coordinatesToScreen = function(coords, result) { + var ray = this._tmpVec; + + if (!result) { + result = {}; + } + + var width = this._width; + var height = this._height; + + // Undefined on a null viewport. + if (width <= 0 || height <= 0) { + result.x = null; + result.y = null; + return null; + } + + // Compute view ray pointing into the (yaw, pitch) direction. + var yaw = coords.yaw; + var pitch = coords.pitch; + var x = Math.sin(yaw) * Math.cos(pitch); + var y = -Math.sin(coords.pitch); + var z = -Math.cos(yaw) * Math.cos(pitch); + vec4$4.set(ray, x, y, z, 1); + + // Project view ray onto clip space. + vec4$4.transformMat4(ray, ray, this.projection()); + + // w in clip space equals -z in camera space. + if (ray[3] >= 0) { + // Point is in front of camera. + // Convert to viewport coordinates. + result.x = width * (ray[0] / ray[3] + 1) / 2; + result.y = height * (1 - ray[1] / ray[3]) / 2; + } else { + // Point is behind camera. + result.x = null; + result.y = null; + return null; + } + + return result; + }; + + + /** + * Convert screen coordinates into view coordinates. If a result argument is + * provided, it is filled in with the result and returned. Otherwise, a fresh + * object is filled in and returned. + * + * @param {Coords} coords The screen coordinates. + * @param {RectilinearViewCoords=} result The view coordinates. + * @return {RectilinearViewCoords} + */ + RectilinearView.prototype.screenToCoordinates = function(coords, result) { + var ray = this._tmpVec; + + if (!result) { + result = {}; + } + + var width = this._width; + var height = this._height; + + // Convert viewport coordinates to clip space. + var vecx = 2 * coords.x / width - 1; + var vecy = 1 - 2 * coords.y / height; + vec4$4.set(ray, vecx, vecy, 1, 1); + + // Project back to world space. + vec4$4.transformMat4(ray, ray, this.inverseProjection()); + + // Convert to spherical coordinates. + var r = Math.sqrt(ray[0] * ray[0] + ray[1] * ray[1] + ray[2] * ray[2]); + result.yaw = Math.atan2(ray[0], -ray[2]); + result.pitch = Math.acos(ray[1] / r) - Math.PI/2; + + this._normalizeCoordinates(result); + + return result; + }; + + + /** + * Calculate the perspective transform required to position an element with + * perspective. + * + * @param {RectilinearViewCoords} coords The view coordinates. + * @param {number} radius Radius of the sphere embedding the element. + * @param {string} extraTransforms Extra transformations to be applied after + * the element is positioned. This may be used to rotate the element. + * @return {string} The CSS 3D transform to be applied to the element. + */ + RectilinearView.prototype.coordinatesToPerspectiveTransform = function( + coords, radius, extraTransforms) { + extraTransforms = extraTransforms || ""; + + var height = this._height; + var width = this._width; + var fov = this._fov; + var perspective = 0.5 * height / Math.tan(fov / 2); + + var transform = ''; + + // Center hotspot in screen. + transform += 'translateX(' + decimal_1(width/2) + 'px) '; + transform += 'translateY(' + decimal_1(height/2) + 'px) '; + transform += 'translateX(-50%) translateY(-50%) '; + + // Set the perspective depth. + transform += 'perspective(' + decimal_1(perspective) + 'px) '; + transform += 'translateZ(' + decimal_1(perspective) + 'px) '; + + // Set the camera rotation. + transform += 'rotateZ(' + decimal_1(-this._roll) + 'rad) '; + transform += 'rotateX(' + decimal_1(-this._pitch) + 'rad) '; + transform += 'rotateY(' + decimal_1(this._yaw) + 'rad) '; + + // Set the hotspot rotation. + transform += 'rotateY(' + decimal_1(-coords.yaw) + 'rad) '; + transform += 'rotateX(' + decimal_1(coords.pitch) + 'rad) '; + + // Move back to sphere. + transform += 'translateZ(' + decimal_1(-radius) + 'px) '; + + // Apply the extra transformations + transform += extraTransforms + ' '; + + return transform; + }; + + + /** + * Factory functions for view limiters. See {@link RectilinearViewLimiter}. + * @namespace + */ + RectilinearView.limit = { + + /** + * Returns a view limiter that constrains the yaw angle. + * @param {number} min The minimum yaw value. + * @param {number} max The maximum yaw value. + * @return {RectilinearViewLimiter} + */ + yaw: function(min, max) { + return function limitYaw(params) { + params.yaw = clamp_1(params.yaw, min, max); + return params; + }; + }, + + /** + * Returns a view limiter that constrains the pitch angle. + * @param {number} min The minimum pitch value. + * @param {number} max The maximum pitch value. + * @return {RectilinearViewLimiter} + */ + pitch: function(min, max) { + return function limitPitch(params) { + params.pitch = clamp_1(params.pitch, min, max); + return params; + }; + }, + + /** + * Returns a view limiter that constrains the roll angle. + * @param {number} min The minimum roll value. + * @param {number} max The maximum roll value. + * @return {RectilinearViewLimiter} + */ + roll: function(min, max) { + return function limitRoll(params) { + params.roll = clamp_1(params.roll, min, max); + return params; + }; + }, + + /** + * Returns a view limiter that constrains the horizontal field of view. + * @param {number} min The minimum horizontal field of view. + * @param {number} max The maximum horizontal field of view. + * @return {RectilinearViewLimiter} + */ + hfov: function(min, max) { + return function limitHfov(params) { + var width = params.width; + var height = params.height; + if (width > 0 && height > 0) { + var vmin = convertFov.htov(min, width, height); + var vmax = convertFov.htov(max, width, height); + params.fov = clamp_1(params.fov, vmin, vmax); + } + return params; + }; + }, + + /** + * Returns a view limiter that constrains the vertical field of view. + * @param {number} min The minimum vertical field of view. + * @param {number} max The maximum vertical field of view. + * @return {RectilinearViewLimiter} + */ + vfov: function(min, max) { + return function limitVfov(params) { + params.fov = clamp_1(params.fov, min, max); + return params; + }; + }, + + /** + * Returns a view limiter that prevents zooming in beyond the given + * resolution. + * @param {number} size The cube face width in pixels or, equivalently, one + * fourth of the equirectangular width in pixels. + * @return {RectilinearViewLimiter} + */ + resolution: function(size) { + return function limitResolution(params) { + var height = params.height; + if (height) { + var requiredPixels = pixelRatio_1() * height; + var minFov = 2 * Math.atan(requiredPixels / size); + params.fov = clamp_1(params.fov, minFov, Infinity); + } + return params; + }; + }, + + /** + * Returns a view limiter that limits the horizontal and vertical field of + * view, prevents zooming in past the image resolution, and limits the pitch + * range to prevent the camera wrapping around at the poles. These are the + * most common view constraints for a 360° panorama. + * @param {number} maxResolution The cube face width in pixels or, + * equivalently, one fourth of the equirectangular width in pixels. + * @param {number} maxVFov The maximum vertical field of view. + * @param {number} [maxHFov=maxVFov] The maximum horizontal field of view. + * @return {RectilinearViewLimiter} + */ + traditional: function(maxResolution, maxVFov, maxHFov) { + maxHFov = maxHFov != null ? maxHFov : maxVFov; + + return compose_1( + RectilinearView.limit.resolution(maxResolution), + RectilinearView.limit.vfov(0, maxVFov), + RectilinearView.limit.hfov(0, maxHFov), + RectilinearView.limit.pitch(-Math.PI/2, Math.PI/2)); + } + + }; + + + RectilinearView.type = RectilinearView.prototype.type = 'rectilinear'; + + + var Rectilinear = RectilinearView; + + var mat4$5 = require$$67.mat4; + var vec4$5 = require$$67.vec4; + + + + + + // Default viewport dimensions. + // Start with zero to ensure that those values are handled correctly. + var defaultWidth$1 = 0; + var defaultHeight$1 = 0; + + // Default view parameters. + var defaultX = 0.5; + var defaultY = 0.5; + var defaultZoom = 1; + + // Constant values used to simplify the frustum culling logic. + // planeAxes[i] indicates the coordinate value that defines a frustum plane. + // planeCmp[i] indicates how point and plane coordinates should be compared + // to determine whether the point is on the outer side of the plane. + var planeAxes = [ + 1, // top + 0, // right + 1, // bottom + 0 // left + ]; + var planeCmp = [ + -1, // top + -1, // right + 1, // bottom + 1 // left + ]; + + // A zoom of exactly 0 breaks some computations, so we force a minimum positive + // value. We use 6 decimal places for the epsilon value to avoid broken + // rendering due to loss of precision in floating point computations. + var zoomLimitEpsilon = 0.000001; + + + /** + * @interface FlatViewParams + * + * A camera configuration for a {@link FlatView}. + * + * @property {number} x The horizontal coordinate of the image point displayed + * at the viewport center, in the [0, 1] range. + * When `x === 0.5`, the image is centered horizontally. + * When `x === 0`, the left edge of the image is at the viewport center. + * When `x === 1`, the right edge of the image is at the viewport center. + * @property {number} y The vertical coordinate of the image point displayed at + * the viewport center, in the [0, 1] range. + * When `y === 0.5`, the image is centered vertically. + * When `y === 0`, the top edge of the image is at the viewport center. + * When `y === 1`, the bottom edge of the image is at the viewport center. + * @property {number} zoom The horizontal zoom, in the [0, ∞) range. + * When `zoom === 1`, the viewport is as wide as the image. + * When `zoom < 1`, the image is zoomed in. + * When `zoom > 1`, the image is zoomed out. + * @property {number} mediaAspectRatio The image aspect ratio. + * When `mediaAspectRatio === 1`, the image width equals its height. + * When `mediaAspectRatio < 1`, the image width is less than its height. + * When `mediaAspectRatio > 1`, the image height is less than its width. + */ + + + /** + * @interface FlatViewCoords + * + * The position of a point in a flat image. + * + * @property {number} x The horizontal coordinate, in the [0, 1] range. + * @property {number} y The vertical coordinate, in the [0, 1] range. + */ + + + /** + * @typedef {function} FlatViewLimiter + * + * View limiter for a {@link FlatView}. + * + * A view limiter is a function that receives a {@link FlatViewParams} object, + * optionally modifies it in place, and returns it. It can be used to enforce + * constraints on the view parameters. + * + * See {@link FlatView.limit} for commonly used limiters. They may be composed + * together or with user-defined limiters with {@link util.compose}. + * + * @param {FlatViewParams} params + * @return {FlatViewParams} + */ + + + /** + * @class FlatView + * @implements View + * @classdesc + * + * A {@link View} implementing an orthogonal projection for flat images. + * + * @param {FlatViewParams} params The initial view parameters. The + * `mediaAspectRatio` parameter must always be set. The other parameters + * default to `{x: 0.5, y: 0.5, z: 1 }` if unspecified. + * @param {FlatViewLimiter=} limiter The view limiter. If unspecified, no view + * limiting is applied. See {@link FlatView.limit} for commonly used + * limiters. + */ + function FlatView(params, limiter) { + // Require an aspect ratio to be specified. + if (!(params && params.mediaAspectRatio != null)) { + throw new Error('mediaAspectRatio must be defined'); + } + + // The initial values for the view parameters. + this._x = params && params.x != null ? params.x : defaultX; + this._y = params && params.y != null ? params.y : defaultY; + this._zoom = params && params.zoom != null ? params.zoom : defaultZoom; + this._mediaAspectRatio = params.mediaAspectRatio; + this._width = params && params.width != null ? + params.width : defaultWidth$1; + this._height = params && params.height != null ? + params.height : defaultHeight$1; + + // The initial value for the view limiter. + this._limiter = limiter || null; + + // The last calculated projection matrix and its inverse. + this._projMatrix = mat4$5.create(); + this._invProjMatrix = mat4$5.create(); + + // The last calculated view frustum. + this._frustum = [ + 0, // top + 0, // right + 0, // bottom + 0 // left + ]; + + // Whether the projection matrices and view frustum need to be updated. + this._projectionChanged = true; + + // Temporary variables used for calculations. + this._params = {}; + this._vec = vec4$5.create(); + + // Force view limiting on initial parameters. + this._update(); + } + + minimalEventEmitter(FlatView); + + + /** + * Destructor. + */ + FlatView.prototype.destroy = function() { + clearOwnProperties_1(this); + }; + + + /** + * Get the x parameter. + * @return {number} + */ + FlatView.prototype.x = function() { + return this._x; + }; + + + /** + * Get the y parameter. + * @return {number} + */ + FlatView.prototype.y = function() { + return this._y; + }; + + + /** + * Get the zoom value. + * @return {number} + */ + FlatView.prototype.zoom = function() { + return this._zoom; + }; + + + /** + * Get the media aspect ratio. + * @return {number} + */ + FlatView.prototype.mediaAspectRatio = function() { + return this._mediaAspectRatio; + }; + + + /** + * Get the viewport width. + * @return {number} + */ + FlatView.prototype.width = function() { + return this._width; + }; + + + /** + * Get the viewport height. + * @return {number} + */ + FlatView.prototype.height = function() { + return this._height; + }; + + + /** + * Get the viewport dimensions. If an argument is supplied, it is filled in with + * the result and returned. Otherwise, a fresh object is filled in and returned. + * @param {Size=} size + * @return {Size} + */ + FlatView.prototype.size = function(size) { + size = size || {}; + size.width = this._width; + size.height = this._height; + return size; + }; + + + /** + * Get the view parameters. If an argument is supplied, it is filled in with the + * result and returned. Otherwise, a fresh object is filled in and returned. + * @param {FlatViewParams=} params + * @return {FlatViewParams} + */ + FlatView.prototype.parameters = function(params) { + params = params || {}; + params.x = this._x; + params.y = this._y; + params.zoom = this._zoom; + params.mediaAspectRatio = this._mediaAspectRatio; + return params; + }; + + + /** + * Get the view limiter, or null if unset. + * @return {?FlatViewLimiter} + */ + FlatView.prototype.limiter = function() { + return this._limiter; + }; + + + /** + * Set the x parameter. + * @param {number} x + */ + FlatView.prototype.setX = function(x) { + this._resetParams(); + this._params.x = x; + this._update(this._params); + }; + + + /** + * Set the y parameter. + * @param {number} y + */ + FlatView.prototype.setY = function(y) { + this._resetParams(); + this._params.y = y; + this._update(this._params); + }; + + + /** + * Set the zoom value. + * @param {number} zoom + */ + FlatView.prototype.setZoom = function(zoom) { + this._resetParams(); + this._params.zoom = zoom; + this._update(this._params); + }; + + + /** + * Add xOffset to the x parameter. + * @param {number} xOffset + */ + FlatView.prototype.offsetX = function(xOffset) { + this.setX(this._x + xOffset); + }; + + + /** + * Add yOffset to the y parameter. + * @param {number} yOffset + */ + FlatView.prototype.offsetY = function(yOffset) + { + this.setY(this._y + yOffset); + }; + + + /** + * Add zoomOffset to the zoom value. + * @param {number} zoomOffset + */ + FlatView.prototype.offsetZoom = function(zoomOffset) { + this.setZoom(this._zoom + zoomOffset); + }; + + + /** + * Set the media aspect ratio. + * @param {number} mediaAspectRatio + */ + FlatView.prototype.setMediaAspectRatio = function(mediaAspectRatio) { + this._resetParams(); + this._params.mediaAspectRatio = mediaAspectRatio; + this._update(this._params); + }; + + + /** + * Set the viewport dimensions. + * @param {Size} size + */ + FlatView.prototype.setSize = function(size) { + this._resetParams(); + this._params.width = size.width; + this._params.height = size.height; + this._update(this._params); + }; + + + /** + * Set the view parameters. Unspecified parameters are left unchanged. + * @param {FlatViewParameters} params + */ + FlatView.prototype.setParameters = function(params) { + this._resetParams(); + this._params.x = params.x; + this._params.y = params.y; + this._params.zoom = params.zoom; + this._params.mediaAspectRatio = params.mediaAspectRatio; + this._update(this._params); + }; + + + /** + * Set the view limiter. + * @param {?FlatViewLimiter} limiter The new limiter, or null to unset. + */ + FlatView.prototype.setLimiter = function(limiter) { + this._limiter = limiter || null; + this._update(); + }; + + + FlatView.prototype._resetParams = function() { + var params = this._params; + params.x = null; + params.y = null; + params.zoom = null; + params.mediaAspectRatio = null; + params.width = null; + params.height = null; + }; + + + FlatView.prototype._update = function(params) { + + // Avoid object allocation when no parameters are supplied. + if (params == null) { + this._resetParams(); + params = this._params; + } + + // Save old parameters for later comparison. + var oldX = this._x; + var oldY = this._y; + var oldZoom = this._zoom; + var oldMediaAspectRatio = this._mediaAspectRatio; + var oldWidth = this._width; + var oldHeight = this._height; + + // Fill in object with the new set of parameters to pass into the limiter. + params.x = params.x != null ? params.x : oldX; + params.y = params.y != null ? params.y : oldY; + params.zoom = params.zoom != null ? params.zoom : oldZoom; + params.mediaAspectRatio = params.mediaAspectRatio != null ? + params.mediaAspectRatio : oldMediaAspectRatio; + params.width = params.width != null ? params.width : oldWidth; + params.height = params.height != null ? params.height : oldHeight; + + // Apply view limiting when defined. + if (this._limiter) { + params = this._limiter(params); + if (!params) { + throw new Error('Bad view limiter'); + } + } + + // Grab the limited parameters. + var newX = params.x; + var newY = params.y; + var newZoom = params.zoom; + var newMediaAspectRatio = params.mediaAspectRatio; + var newWidth = params.width; + var newHeight = params.height; + + // Consistency check. + if (!real_1(newX) || !real_1(newY) || !real_1(newZoom) || + !real_1(newMediaAspectRatio) || !real_1(newWidth) || !real_1(newHeight)) { + throw new Error('Bad view - suspect a broken limiter'); + } + + // Constrain zoom. + newZoom = clamp_1(newZoom, zoomLimitEpsilon, Infinity); + + // Update parameters. + this._x = newX; + this._y = newY; + this._zoom = newZoom; + this._mediaAspectRatio = newMediaAspectRatio; + this._width = newWidth; + this._height = newHeight; + + // Check whether the parameters changed and emit the corresponding events. + if (newX !== oldX || newY !== oldY || newZoom !== oldZoom || + newMediaAspectRatio !== oldMediaAspectRatio || + newWidth !== oldWidth || newHeight !== oldHeight) { + this._projectionChanged = true; + this.emit('change'); + } + if (newWidth !== oldWidth || newHeight !== oldHeight) { + this.emit('resize'); + } + + }; + + + FlatView.prototype._zoomX = function() { + return this._zoom; + }; + + + FlatView.prototype._zoomY = function() { + var mediaAspectRatio = this._mediaAspectRatio; + var aspect = this._width / this._height; + var zoomX = this._zoom; + var zoomY = zoomX * mediaAspectRatio / aspect; + if (isNaN(zoomY)) { + zoomY = zoomX; + } + return zoomY; + }; + + + FlatView.prototype.updateWithControlParameters = function(parameters) { + var scale = this.zoom(); + var zoomX = this._zoomX(); + var zoomY = this._zoomY(); + + // TODO: should the scale be the same for both axes? + this.offsetX(parameters.axisScaledX * zoomX + parameters.x * scale); + this.offsetY(parameters.axisScaledY * zoomY + parameters.y * scale); + this.offsetZoom(parameters.zoom * scale); + }; + + + FlatView.prototype._updateProjection = function() { + var projMatrix = this._projMatrix; + var invProjMatrix = this._invProjMatrix; + var frustum = this._frustum; + + // Recalculate projection matrix when required. + if (this._projectionChanged) { + var x = this._x; + var y = this._y; + var zoomX = this._zoomX(); + var zoomY = this._zoomY(); + + // Recalculate view frustum. + var top = frustum[0] = (0.5 - y) + 0.5 * zoomY; + var right = frustum[1] = (x - 0.5) + 0.5 * zoomX; + var bottom = frustum[2] = (0.5 - y) - 0.5 * zoomY; + var left = frustum[3] = (x - 0.5) - 0.5 * zoomX; + + // Recalculate projection matrix and its inverse. + mat4$5.ortho(projMatrix, left, right, bottom, top, -1, 1); + mat4$5.invert(invProjMatrix, projMatrix); + + this._projectionChanged = false; + } + }; + + + /** + * Returns the projection matrix for the current view. + * @returns {mat4} + */ + FlatView.prototype.projection = function() { + this._updateProjection(); + return this._projMatrix; + }; + + + /** + * Returns the inverse projection matrix for the current view. + * @returns {mat4} + */ + FlatView.prototype.inverseProjection = function() { + this._updateProjection(); + return this._invProjMatrix; + }; + + + /** + * Return whether the view frustum intersects the given rectangle. + * + * This function may return false positives, but never false negatives. + * It is used for frustum culling, i.e., excluding invisible tiles from the + * rendering process. + * + * @param {vec3[]} rectangle The vertices of the rectangle. + */ + FlatView.prototype.intersects = function(rectangle) { + this._updateProjection(); + + var frustum = this._frustum; + + // Check whether the rectangle is on the outer side of any of the frustum + // planes. This is a sufficient condition, though not necessary, for the + // rectangle to be completely outside the fruouter + for (var i = 0; i < frustum.length; i++) { + var limit = frustum[i]; + var axis = planeAxes[i]; + var cmp = planeCmp[i]; + var inside = false; + for (var j = 0; j < rectangle.length; j++) { + var vertex = rectangle[j]; + if (cmp < 0 && vertex[axis] < limit || cmp > 0 && vertex[axis] > limit) { + inside = true; + break; + } + } + if (!inside) { + return false; + } + } + return true; + }; + + + /** + * Select the level that should be used to render the view. + * @param {Level[]} levelList the list of levels from which to select. + * @return {Level} the selected level. + */ + FlatView.prototype.selectLevel = function(levels) { + + // Multiply the viewport width by the device pixel ratio to get the required + // horizontal resolution in pixels. + // + // Calculate the fraction of the image that would be visible at the current + // zoom value. Then, for each level, multiply by the level width to get the + // width in pixels of the portion that would be visible. + // + // Search for the smallest level that satifies the the required width, + // falling back on the largest level if none do. + + var requiredPixels = pixelRatio_1() * this.width(); + var zoomFactor = this._zoom; + + for (var i = 0; i < levels.length; i++) { + var level = levels[i]; + if (zoomFactor * level.width() >= requiredPixels) { + return level; + } + } + + return levels[levels.length - 1]; + + }; + + + /** + * Convert view coordinates into screen coordinates. If a result argument is + * provided, it is filled in and returned. Otherwise, a fresh object is filled + * in and returned. + * + * @param {FlatViewCoords} coords The view coordinates. + * @param {Coords=} result The result argument for the screen coordinates. + * @return {Coords} + */ + FlatView.prototype.coordinatesToScreen = function(coords, result) { + var ray = this._vec; + + if (!result) { + result = {}; + } + + var width = this._width; + var height = this._height; + + // Undefined on a null viewport. + if (width <= 0 || height <= 0) { + result.x = null; + result.y = null; + return null; + } + + // Extract coordinates from argument, filling in default values. + var x = coords && coords.x != null ? coords.x : defaultX; + var y = coords && coords.y != null ? coords.y : defaultY; + + // Project view ray onto clip space. + vec4$5.set(ray, x - 0.5, 0.5 - y, -1, 1); + vec4$5.transformMat4(ray, ray, this.projection()); + + // Calculate perspective divide. + for (var i = 0; i < 3; i++) { + ray[i] /= ray[3]; + } + + // Convert to viewport coordinates and return. + result.x = width * (ray[0] + 1) / 2; + result.y = height * (1 - ray[1]) / 2; + + return result; + }; + + + /** + * Convert screen coordinates into view coordinates. If a result argument is + * provided, it is filled in with the result and returned. Otherwise, a fresh + * object is filled in and returned. + * + * @param {Coords} coords The screen coordinates. + * @param {FlatViewCoords=} result The result argument for the view coordinates. + * @return {FlatViewCoords} + */ + FlatView.prototype.screenToCoordinates = function(coords, result) { + var ray = this._vec; + + if (!result) { + result = {}; + } + + var width = this._width; + var height = this._height; + + // Convert viewport coordinates to clip space. + var vecx = 2 * coords.x / width - 1; + var vecy = 1 - 2 * coords.y / height; + vec4$5.set(ray, vecx, vecy, 1, 1); + + // Project back to world space. + vec4$5.transformMat4(ray, ray, this.inverseProjection()); + + // Convert to flat coordinates. + result.x = 0.5 + ray[0]; + result.y = 0.5 - ray[1]; + + return result; + }; + + + /** + * Factory functions for view limiters. See {@link FlatViewLimiter}. + * @namespace + */ + FlatView.limit = { + + /** + * Returns a view limiter that constrains the x parameter. + * @param {number} min The minimum x value. + * @param {number} max The maximum y value. + * @return {FlatViewLimiter} + */ + x: function(min, max) { + return function limitX(params) { + params.x = clamp_1(params.x, min, max); + return params; + }; + }, + + /** + * Return a view limiter that constrains the y parameter. + * @param {number} min The minimum y value. + * @param {number} max The maximum y value. + * @return {FlatViewLimiter} + */ + y: function(min, max) { + return function limitY(params) { + params.y = clamp_1(params.y, min, max); + return params; + }; + }, + + /** + * Returns a view limiter than constrains the zoom parameter. + * @param {number} min The minimum zoom value. + * @param {number} max The maximum zoom value. + * @return {FlatViewLimiter} + */ + zoom: function(min, max) { + return function limitZoom(params) { + params.zoom = clamp_1(params.zoom, min, max); + return params; + }; + }, + + /** + * Returns a view limiter that prevents zooming in beyond the given + * resolution. + * @param {number} size The image width in pixels. + * @return {FlatViewLimiter} + */ + resolution: function(size) { + return function limitResolution(params) { + if (params.width <= 0 || params.height <= 0) { + return params; + } + var width = params.width; + var minZoom = pixelRatio_1() * width / size; + params.zoom = clamp_1(params.zoom, minZoom, Infinity); + return params; + }; + }, + + /** + * Returns a view limiter that constrains the values of the x parameter that + * are inside the viewport. + * @param {number} min The minimum x value. + * @param {number} max The maximum x value. + * @return {FlatViewLimiter} + */ + visibleX: function(min, max) { + return function limitVisibleX(params) { + // Calculate the zoom value that makes the specified range fully visible. + var maxZoom = max - min; + + // Clamp zoom to the maximum value. + if (params.zoom > maxZoom) { + params.zoom = maxZoom; + } + + // Bound X such that the image is visible up to the range edges. + var minX = min + 0.5 * params.zoom; + var maxX = max - 0.5 * params.zoom; + params.x = clamp_1(params.x, minX, maxX); + + return params; + }; + }, + + /** + * Returns a view limiter that constrains the values of the y parameter that + * are inside the viewport. + * @param {number} min The minimum y value. + * @param {number} max The maximum y value. + * @return {FlatViewLimiter} + */ + visibleY: function(min, max) { + return function limitVisibleY(params) { + + // Do nothing for a null viewport. + if (params.width <= 0 || params.height <= 0) { + return params; + } + + // Calculate the X to Y conversion factor. + var viewportAspectRatio = params.width / params.height; + var factor = viewportAspectRatio / params.mediaAspectRatio; + + // Calculate the zoom value that makes the specified range fully visible. + var maxZoom = (max - min) * factor; + + // Clamp zoom to the maximum value. + if (params.zoom > maxZoom) { + params.zoom = maxZoom; + } + + // Bound Y such that the image is visible up to the range edges. + var minY = min + 0.5 * params.zoom / factor; + var maxY = max - 0.5 * params.zoom / factor; + params.y = clamp_1(params.y, minY, maxY); + + return params; + }; + }, + + + /** + * Returns a view limiter that constrains the zoom parameter such that + * zooming out is prevented beyond the point at which the image is fully + * visible. Unless the image and the viewport have the same aspect ratio, + * this will cause bands to appear around the image. + * @return {FlatViewLimiter} + */ + letterbox: function() { + return function limitLetterbox(params) { + if(params.width <= 0 || params.height <= 0) { + return params; + } + var viewportAspectRatio = params.width / params.height; + + var fullWidthZoom = 1.0; + var fullHeightZoom = viewportAspectRatio / params.mediaAspectRatio; + + // If the image is wider than the viewport, limit the horizontal zoom to + // the image width. + if (params.mediaAspectRatio >= viewportAspectRatio) { + params.zoom = Math.min(params.zoom, fullWidthZoom); + } + + // If the image is narrower than the viewport, limit the vertical zoom to + // the image height. + if (params.mediaAspectRatio <= viewportAspectRatio) { + params.zoom = Math.min(params.zoom, fullHeightZoom); + } + + // If the full image width is visible, limit x to the central point. + // Else, bound x such that image is visible up to the horizontal edges. + var minX, maxX; + if (params.zoom > fullWidthZoom) { + minX = maxX = 0.5; + } else { + minX = 0.0 + 0.5 * params.zoom / fullWidthZoom; + maxX = 1.0 - 0.5 * params.zoom / fullWidthZoom; + } + + // If the full image height is visible, limit y to the central point. + // Else, bound y such that image is visible up to the vertical edges. + var minY, maxY; + if (params.zoom > fullHeightZoom) { + minY = maxY = 0.5; + } else { + minY = 0.0 + 0.5 * params.zoom / fullHeightZoom; + maxY = 1.0 - 0.5 * params.zoom / fullHeightZoom; + } + + // Clamp x and y into the calculated bounds. + params.x = clamp_1(params.x, minX, maxX); + params.y = clamp_1(params.y, minY, maxY); + + return params; + }; + } + + }; + + + FlatView.type = FlatView.prototype.type = 'flat'; + + + var Flat$1 = FlatView; + + function WorkPool(opts) { + this._concurrency = opts && opts.concurrency || 1; + this._paused = opts && !!opts.paused || false; + + this._pool = []; + for (var i = 0; i < this._concurrency; i++) { + this._pool.push(new WorkQueue_1(opts)); + } + + this._next = 0; + } + + + WorkPool.prototype.length = function() { + var len = 0; + for (var i = 0; i < this._pool.length; i++) { + len += this._pool[i].length(); + } + return len; + }; + + + WorkPool.prototype.push = function(fn, cb) { + var i = this._next; + var cancel = this._pool[i].push(fn, cb); + this._next = mod_1(this._next + 1, this._concurrency); + return cancel; + }; + + + WorkPool.prototype.pause = function() { + if (!this._paused) { + this._paused = true; + for (var i = 0; i < this._concurrency; i++) { + this._pool[i].pause(); + } + } + }; + + + WorkPool.prototype.resume = function() { + if (this._paused) { + this._paused = false; + for (var i = 0; i < this._concurrency; i++) { + this._pool[i].resume(); + } + } + }; + + + var WorkPool_1 = WorkPool; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function noop$1() {} + + var noop_1 = noop$1; + + // Return a function that executes its arguments (which should be cancelables) + // in sequence, so that each of them passes its return values to the next. + // Execution is aborted if one of the functions returns an error; in that case + // the last function in the sequence is called with the error. + // See util/cancelize.js for an explanation of what cancelables are. + function chain() { + + // The list of functions to chain together. + var argList = Array.prototype.slice.call(arguments, 0); + + return function chained() { + + // List of remaining functions to be executed. + // Make a copy of the original list so we can mutate the former while + // preserving the latter intact for future invocations of the chain. + var fnList = argList.slice(0); + + // Currently executing function. + var fn = null; + + // Cancel method for the currently executing function. + var cfn = null; + + // Arguments for the first function. + var args = arguments.length ? Array.prototype.slice.call(arguments, 0, arguments.length - 1) : []; + + // Callback for the chain. + var done = arguments.length ? arguments[arguments.length - 1] : noop_1; + + // Execute the next function in the chain. + // Receives the error and return values from the previous function. + function exec() { + + // Extract error from arguments. + var err = arguments[0]; + + // Abort chain on error. + if (err) { + fn = cfn = null; + done.apply(null, arguments); + return; + } + + // Terminate if there are no functions left in the chain. + if (!fnList.length) { + fn = cfn = null; + done.apply(null, arguments); + return; + } + + // Advance to the next function in the chain. + fn = fnList.shift(); + var _fn = fn; + + // Extract arguments to pass into the next function. + var ret = Array.prototype.slice.call(arguments, 1); + + // Call next function with previous return value and call back exec. + ret.push(exec); + var _cfn = fn.apply(null, ret); // fn(null, ret..., exec) + + // Detect when fn has completed synchronously and do not clobber the + // internal state in that case. You're not expected to understand this. + if (_fn !== fn) { + return; + } + + // Remember the cancel method for the currently executing function. + // Detect chaining on non-cancellable function. + if (typeof _cfn !== 'function') { + throw new Error('chain: chaining on non-cancellable function'); + } else { + cfn = _cfn; + } + + } + + // Cancel chain execution. + function cancel() { + if (cfn) { + cfn.apply(null, arguments); + } + } + + // Start chain execution. + // We call exec as if linking from a previous function in the chain, + // except that the error is always null. As a consequence, chaining on an + // empty list yields the identity function. + args.unshift(null); + exec.apply(null, args); // exec(null, args...) + + return cancel; + + }; + + } + + var chain_1 = chain; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Perform a cancelable delay. + // See util/cancelize.js for an explanation of what cancelables are. + function delay$1(ms, done) { + + // Work around IE8 bug whereby a setTimeout callback may still be called + // after the corresponding clearTimeout is invoked. + var timer = null; + + function finish() { + if (timer != null) { + timer = null; + done(null); + } + } + + function cancel() { + if (timer != null) { + clearTimeout(timer); + timer = null; + done.apply(null, arguments); + } + } + + timer = setTimeout(finish, ms); + + return cancel; + + } + + var delay_1 = delay$1; + + // Map template properties to their corresponding tile properties. + var templateProperties = { + x: 'x', + y: 'y', + z: 'z', + f: 'face' + }; + + // Default face order for cube maps. + var defaultCubeMapFaceOrder = 'bdflru'; + + // Default maximum number of concurrent requests. + var defaultConcurrency = 4; + + // Default milliseconds to wait before retrying failed requests. + var defaultRetryDelay = 10000; + + + /** + * @class ImageUrlSource + * @implements Source + * @classdesc + * + * A {@link Source} that loads {@link Asset assets} from images given a URL and + * a crop rectangle. + * + * @param {Function} sourceFromTile Function that receives a tile and returns + * a `{ url, rect }` object, where `url` is an image URL and `rect`, when + * present, is an `{ x, y, width, height }` object in normalized coordinates + * denoting the portion of the image to use. + * @param {Object} opts + * @param {number} [opts.concurrency=4] Maximum number of tiles to request at + * the same time. The limit is per {@link ImageSourceUrl} instance. + * @param {number} [opts.retryDelay=10000] Time in milliseconds to wait before + * retrying a failed request. + */ + function ImageUrlSource(sourceFromTile, opts) { + + opts = opts ? opts : {}; + + this._loadPool = new WorkPool_1({ + concurrency: opts.concurrency || defaultConcurrency + }); + + this._retryDelay = opts.retryDelay || defaultRetryDelay; + this._retryMap = {}; + + this._sourceFromTile = sourceFromTile; + } + + minimalEventEmitter(ImageUrlSource); + + + ImageUrlSource.prototype.loadAsset = function(stage, tile, done) { + + var self = this; + + var retryDelay = this._retryDelay; + var retryMap = this._retryMap; + + var tileSource = this._sourceFromTile(tile); + var url = tileSource.url; + var rect = tileSource.rect; + + var loadImage = stage.loadImage.bind(stage, url, rect); + + var loadFn = function(done) { + // TODO: Deduplicate load requests for the same URL. Although the browser + // might be smart enough to avoid duplicate requests, they are still unduly + // impacted by the concurrency parameter. + return self._loadPool.push(loadImage, function(err, asset) { + if (err) { + if (err instanceof NetworkError_1) { + // If a network error occurred, wait before retrying. + retryMap[url] = now(); + self.emit('networkError', asset, err); + } + done(err, tile); + } else { + // On a successful fetch, forget the previous timeout. + delete retryMap[url]; + done(null, tile, asset); + } + }); + }; + + // Check whether we are retrying a failed request. + var delayAmount; + var lastTime = retryMap[url]; + if (lastTime != null) { + var currentTime = now(); + var elapsed = currentTime - lastTime; + if (elapsed < retryDelay) { + // Wait before retrying. + delayAmount = retryDelay - elapsed; + } else { + // Retry timeout expired; perform the request at once. + delayAmount = 0; + delete retryMap[url]; + } + } + + var delayFn = delay_1.bind(null, delayAmount); + + return chain_1(delayFn, loadFn)(done); + }; + + + /** + * Creates an ImageUrlSource from a string template. + * + * @param {String} url Tile URL template, which may contain the following + * placeholders: + * - `{f}` : tile face (one of `b`, `d`, `f`, `l`, `r`, `u`) + * - `{z}` : tile level index (0 is the smallest level) + * - `{x}` : tile horizontal index + * - `{y}` : tile vertical index + * @param {Object} opts In addition to the options already supported by the + * {@link ImageUrlSource} constructor. + * @param {String} opts.cubeMapPreviewUrl URL to use as the preview level. + * This must be a single image containing six cube faces laid out + * vertically according to the face order parameter. + * @param {String} [opts.cubeMapPreviewFaceOrder='bdflru'] Face order within + * the preview image. + */ + ImageUrlSource.fromString = function(url, opts) { + opts = opts || {}; + + var faceOrder = opts && opts.cubeMapPreviewFaceOrder || defaultCubeMapFaceOrder; + + var urlFn = opts.cubeMapPreviewUrl ? withPreview : withoutPreview; + + return new ImageUrlSource(urlFn, opts); + + function withoutPreview(tile) { + var tileUrl = url; + + for (var property in templateProperties) { + var templateProperty = templateProperties[property]; + var regExp = propertyRegExp(property); + var valueFromTile = tile.hasOwnProperty(templateProperty) ? tile[templateProperty] : ''; + tileUrl = tileUrl.replace(regExp, valueFromTile); + } + + return { url: tileUrl }; + } + + function withPreview(tile) { + if (tile.z === 0) { + return cubeMapUrl(tile); + } + else { + return withoutPreview(tile); + } + } + + function cubeMapUrl(tile) { + var y = faceOrder.indexOf(tile.face) / 6; + return { + url: opts.cubeMapPreviewUrl, + rect: { x: 0, y: y, width: 1, height: 1/6 } + }; + } + }; + + function propertyRegExp(property) { + var regExpStr = '\\{(' + property + ')\\}'; + return new RegExp(regExpStr, 'g'); + } + + var ImageUrl = ImageUrlSource; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @class SingleAssetSource + * @implements Source + * @classdesc + * + * A {@link Source} that always provides the same {@link Asset}. + * + * @param {Asset} asset The asset. + */ + function SingleAssetSource(asset) { + this._asset = asset; + } + + SingleAssetSource.prototype.asset = function() { + return this._asset; + }; + + SingleAssetSource.prototype.loadAsset = function(stage, tile, done) { + var self = this; + + var timeout = setTimeout(function() { + done(null, tile, self._asset); + }, 0); + + function cancel() { + clearTimeout(timeout); + done.apply(null, arguments); + } + + return cancel; + }; + + var SingleAsset = SingleAssetSource; + + /** + * @class DynamicAsset + * @implements Asset + * @extends StaticAsset + * @classdesc + * + * A mutable {@link Asset} compatible with {@link WebGlStage} and + * {@link CssStage}. + * + * @param {HTMLImageElement|HTMLCanvasElement|ImageBitmap} element The + * underlying pixel source. + * @throws If the pixel source is unsupported. + */ + function DynamicAsset(element) { + this.constructor.super_.call(this, element); + this._timestamp = 0; + } + + inherits_1(DynamicAsset, Static); + minimalEventEmitter(DynamicAsset); + + /** + * Destructor. + */ + DynamicAsset.prototype.destroy = function() { + clearOwnProperties_1(this); + }; + + DynamicAsset.prototype.timestamp = function() { + return this._timestamp; + }; + + DynamicAsset.prototype.isDynamic = function() { + return true; + }; + + /** + * Marks the asset dirty, signaling that the contents of the underlying pixel + * source have changed. + * + * @throws If the asset is not dynamic. + */ + DynamicAsset.prototype.markDirty = function() { + this._timestamp++; + this.emit('change'); + }; + + var Dynamic = DynamicAsset; + + // An LruSet holds up to a maximum number of elements, ordered by their time of + // insertion. When the addition of an element would cause the capacity to be + // exceeded, the oldest element in the set is evicted. As a special case, an + // LruSet with zero capacity always rejects the insertion of an element. + // + // Elements must implement hash() and equals(). Note that the implementation + // doesn't currently use hash(), but a future version might. + function LruSet(capacity) { + if (!isFinite(capacity) || Math.floor(capacity) !== capacity || capacity < 0) { + throw new Error('LruSet: invalid capacity'); + } + this._capacity = capacity; + + // Elements are stored in a circular array ordered by decreasing age. + // Start is the index of the oldest element and size is the number of valid + // elements; the region containing valid elements may wrap around. + this._elements = new Array(this._capacity); + this._start = 0; + this._size = 0; + } + + LruSet.prototype._index = function(i) { + return mod_1(this._start + i, this._capacity); + }; + + // Adds an element into the set, possibly replacing an equal element already in + // the set. The element becomes the newest. If the set is at capacity, the + // oldest element is removed. Returns the removed element if it does not equal + // the inserted element, or null otherwise. If the capacity is zero, does + // nothing and returns the element. + LruSet.prototype.add = function(element) { + if (this._capacity === 0) { + return element; + } + this.remove(element); + var evictedElement = + this._size === this._capacity ? this._elements[this._index(0)] : null; + this._elements[this._index(this._size)] = element; + if (this._size < this._capacity) { + this._size++; + } else { + this._start = this._index(1); + } + return evictedElement; + }; + + // Removes an element from the set. + // Returns the removed element, or null if the element was not found. + LruSet.prototype.remove = function(element) { + for (var i = 0; i < this._size; i++) { + var existingElement = this._elements[this._index(i)]; + if (element.equals(existingElement)) { + for (var j = i; j < this._size - 1; j++) { + this._elements[this._index(j)] = this._elements[this._index(j + 1)]; + } + this._size--; + return existingElement; + } + } + return null; + }; + + // Returns whether an element is in the set. + LruSet.prototype.has = function(element) { + for (var i = 0; i < this._size; i++) { + if (element.equals(this._elements[this._index(i)])) { + return true; + } + } + return false; + }; + + // Returns the number of elements in the set. + LruSet.prototype.size = function() { + return this._size; + }; + + // Removes all elements from the set. + LruSet.prototype.clear = function() { + this._elements.length = 0; + this._start = 0; + this._size = 0; + }; + + // Calls fn(element) for each element in the set, in an unspecified order. + // Returns the number of times fn was called. + // The result is unspecified if the set is mutated during iteration. + LruSet.prototype.forEach = function(fn) { + var count = 0; + for (var i = 0; i < this._size; i++) { + fn(this._elements[this._index(i)]); + count += 1; + } + return count; + }; + + var LruSet_1 = LruSet; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function defaults(obj, defaultsObj) { + for (var key in defaultsObj) { + if (!(key in obj)) { + obj[key] = defaultsObj[key]; + } + } + return obj; + } + + var defaults_1 = defaults; + + // Return a cancelable function that executes fn in a loop until it returns + // successfully. + function retry(fn) { + + return function retried() { + + var args = arguments.length ? Array.prototype.slice.call(arguments, 0, arguments.length - 1) : []; + var done = arguments.length ? arguments[arguments.length - 1] : noop_1; + + var cfn = null; + var canceled = false; + + function exec() { + var err = arguments[0]; + if (!err || canceled) { + done.apply(null, arguments); + } else { + cfn = fn.apply(null, args); + } + } + + args.push(exec); + exec(true); + + return function cancel() { + canceled = true; + cfn.apply(null, arguments); + }; + + }; + + } + + var retry_1 = retry; + + var debug$2 = typeof MARZIPANODEBUG !== 'undefined' && MARZIPANODEBUG.textureStore; + + + // A Stage informs the TextureStore about the set of visible tiles during a + // frame by calling startFrame, markTile and endFrame. In a particular frame, + // TextureStore expects one or more calls to startFrame, followed by zero or + // more calls to markTile, followed by one or more calls to endFrame. The + // number of calls to startFrame and endFrame must match. Calls to other + // TextureStore methods may be freely interleaved with this sequence. + // + // At any given time, TextureStore is in one of four states. The START state + // corresponds to the interval between the first startFrame and the first + // markTile of a frame. The MARK state corresponds to the interval between the + // first markTile and the first endFrame. The END state corresponds to the + // interval between the first and the last endFrame. At any other time, the + // TextureStore is in the IDLE state. + var State = { + IDLE: 0, + START: 1, + MARK: 2, + END: 3 + }; + + + var defaultOptions = { + // Maximum number of cached textures for previously visible tiles. + previouslyVisibleCacheSize: 512 + }; + + + // Assign an id to each operation so we can track its state. + // We actually only need this in debug mode, but the code is less convoluted + // if we track unconditionally, and the performance hit is minimal anyway. + var nextId = 0; + + + // Distinguishes a cancellation from other kinds of errors. + function CancelError() {} + inherits_1(CancelError, Error); + + + /** + * @class TextureStoreItem + * @classdesc + * + * An item saved in a {@link TextureStore}. + * + * Clients do not need to instantiate this. It is automatically instantiated by + * a {@link TextureStore} to manage the lifetime of a stored item: loading, + * refreshing, unloading and emitting associated events. + * + * @param {TextureStore} store The underlying {@link TextureStore}. + * @param {Tile} tile The underlying tile. + */ + function TextureStoreItem(store, tile) { + + var self = this; + + var id = nextId++; + + self._id = id; + self._store = store; + self._tile = tile; + + self._asset = null; + self._texture = null; + + self._changeHandler = function() { + store.emit('textureInvalid', tile); + }; + + var source = store.source(); + var stage = store.stage(); + + var loadAsset = source.loadAsset.bind(source); + var createTexture = stage.createTexture.bind(stage); + + // Retry loading the asset until it succeeds, then create the texture from it. + // This process may be canceled at any point by calling the destroy() method. + var fn = chain_1(retry_1(loadAsset), createTexture); + + store.emit('textureStartLoad', tile); + if (debug$2) { + console.log('loading', id, tile); + } + + self._cancel = fn(stage, tile, function(err, _tile, asset, texture) { + + // Make sure we do not call cancel after the operation is complete. + self._cancel = null; + + if (err) { + // The loading process was interrupted by an error. + // This could either be because the texture creation failed, or because + // the operation was canceled before the loading was complete. + + // Destroy the asset and texture, if they exist. + if (asset) { + asset.destroy(); + } + if (texture) { + texture.destroy(); + } + + // Emit events. + if (err instanceof CancelError) { + store.emit('textureCancel', tile); + if (debug$2) { + console.log('cancel', id, tile); + } + } else { + store.emit('textureError', tile, err); + if (debug$2) { + console.log('error', id, tile); + } + } + + return; + } + + // Save a local reference to the texture. + self._texture = texture; + + // If the asset is dynamic, save a local reference to it and set up a + // handler to be called whenever it changes. Otherwise, destroy the asset + // as we won't be needing it any longer. + if (asset.isDynamic()) { + self._asset = asset; + asset.addEventListener('change', self._changeHandler); + } else { + asset.destroy(); + } + + // Emit event. + store.emit('textureLoad', tile); + if (debug$2) { + console.log('load', id, tile); + } + }); + + } + + + TextureStoreItem.prototype.asset = function() { + return this._asset; + }; + + + TextureStoreItem.prototype.texture = function() { + return this._texture; + }; + + + TextureStoreItem.prototype.destroy = function() { + var id = this._id; + var store = this._store; + var tile = this._tile; + var asset = this._asset; + var texture = this._texture; + var cancel = this._cancel; + + if (cancel) { + // The texture is still loading, so cancel it. + cancel(new CancelError('Texture load cancelled')); + return; + } + + // Destroy asset. + if (asset) { + asset.removeEventListener('change', this._changeHandler); + asset.destroy(); + } + + // Destroy texture. + if (texture) { + texture.destroy(); + } + + // Emit event. + store.emit('textureUnload', tile); + if (debug$2) { + console.log('unload', id, tile); + } + + clearOwnProperties_1(this); + }; + + minimalEventEmitter(TextureStoreItem); + + /** + * Signals that a texture has started to load. + * + * This event is followed by either {@link TextureStore#textureLoad}, + * {@link TextureStore#textureError} or {@link TextureStore#textureCancel}. + * + * @event TextureStore#textureStartLoad + * @param {Tile} tile The tile for which the texture has started to load. + */ + + /** + * Signals that a texture has been loaded. + * + * @event TextureStore#textureLoad + * @param {Tile} tile The tile for which the texture was loaded. + */ + + /** + * Signals that a texture has been unloaded. + * + * @event TextureStore#textureUnload + * @param {Tile} tile The tile for which the texture was unloaded. + */ + + /** + * Signals that a texture has been invalidated. + * + * This event may be raised for a texture with an underlying dynamic asset. It + * may only occur while the texture is loaded, i.e., in between + * {@link TextureStore#textureLoad} and {@link TextureStore#textureUnload}. + * + * @event TextureStore#textureInvalid + * @param {Tile} tile The tile for which the texture was invalidated. + */ + + /** + * Signals that loading a texture has been cancelled. + * + * This event may follow {@link TextureStore#textureStartLoad} if the texture + * becomes unnecessary before it finishes loading. + * + * @event TextureStore#textureCancel + * @param {Tile} tile The tile for which the texture loading was cancelled. + */ + + /** + * Signals that loading a texture has failed. + * + * This event may follow {@link TextureStore#textureStartLoad} if the texture + * fails to load. + * + * @event TextureStore#textureError + * @param {Tile} tile The tile for which the texture loading has failed. + */ + + /** + * @class TextureStore + * @classdesc + * + * A TextureStore maintains a cache of textures used to render a {@link Layer}. + * + * A {@link Stage} communicates with the TextureStore through the startFrame(), + * markTile() and endFrame() methods, which indicate the tiles that are visible + * in the current frame. Textures for visible tiles are loaded and retained + * as long as the tiles remain visible. A limited amount of textures whose + * tiles were previously visible are cached according to an LRU policy. Tiles + * may be pinned to keep their respective textures cached even when they are + * invisible; these textures do not count towards the previously visible limit. + * + * Multiple layers belonging to the same underlying {@link WebGlStage} may + * share the same TextureStore. Layers belonging to distinct {@link WebGlStage} + * instances, or belonging to a {@link CssStage} or a {@link FlashStage}, + * may not do so due to restrictions on the use of textures across stages. + * + * @param {Source} source The underlying source. + * @param {Stage} stage The underlying stage. + * @param {Object} opts Options. + * @param {Number} [opts.previouslyVisibleCacheSize=32] The maximum number of + * previously visible textures to cache according to an LRU policy. + */ + function TextureStore(source, stage, opts) { + opts = defaults_1(opts || {}, defaultOptions); + + this._source = source; + this._stage = stage; + + // The current state. + this._state = State.IDLE; + + // The number of startFrame calls yet to be matched by endFrame calls during + // the current frame. + this._delimCount = 0; + + // The cache proper: map cached tiles to their respective textures/assets. + this._itemMap = new _Map(); + + // The subset of cached tiles that are currently visible. + this._visible = new _Set(); + + // The subset of cached tiles that were visible recently, but are not + // visible right now. Newly inserted tiles replace older ones. + this._previouslyVisible = new LruSet_1(opts.previouslyVisibleCacheSize); + + // The subset of cached tiles that should never be evicted from the cache. + // A tile may be pinned more than once; map each tile into a reference count. + this._pinMap = new _Map(); + + // Temporary variables. + this._newVisible = new _Set(); + this._noLongerVisible = []; + this._visibleAgain = []; + this._evicted = []; + } + + minimalEventEmitter(TextureStore); + + + /** + * Destructor. + */ + TextureStore.prototype.destroy = function() { + this.clear(); + clearOwnProperties_1(this); + }; + + + /** + * Return the underlying {@link Stage}. + * @return {Stage} + */ + TextureStore.prototype.stage = function() { + return this._stage; + }; + + + /** + * Return the underlying {@link Source}. + * @return {Source} + */ + TextureStore.prototype.source = function() { + return this._source; + }; + + + /** + * Remove all textures from the TextureStore, including pinned textures. + */ + TextureStore.prototype.clear = function() { + var self = this; + + // Collect list of tiles to be evicted. + self._evicted.length = 0; + self._itemMap.forEach(function(tile) { + self._evicted.push(tile); + }); + + // Evict tiles. + self._evicted.forEach(function(tile) { + self._unloadTile(tile); + }); + + // Clear all internal state. + self._itemMap.clear(); + self._visible.clear(); + self._previouslyVisible.clear(); + self._pinMap.clear(); + self._newVisible.clear(); + self._noLongerVisible.length = 0; + self._visibleAgain.length = 0; + self._evicted.length = 0; + }; + + + /** + * Remove all textures in the TextureStore, excluding unpinned textures. + */ + TextureStore.prototype.clearNotPinned = function() { + var self = this; + + // Collect list of tiles to be evicted. + self._evicted.length = 0; + self._itemMap.forEach(function(tile) { + if (!self._pinMap.has(tile)) { + self._evicted.push(tile); + } + }); + + // Evict tiles. + self._evicted.forEach(function(tile) { + self._unloadTile(tile); + }); + + // Clear all caches except the pinned set. + self._visible.clear(); + self._previouslyVisible.clear(); + + // Clear temporary variables. + self._evicted.length = 0; + }; + + + /** + * Signal the beginning of a frame. Called from {@link Stage}. + */ + TextureStore.prototype.startFrame = function() { + // Check that we are in an appropriate state. + if (this._state !== State.IDLE && this._state !== State.START) { + throw new Error('TextureStore: startFrame called out of sequence'); + } + + // Enter the START state, if not already there. + this._state = State.START; + + // Expect one more endFrame call. + this._delimCount++; + }; + + + /** + * Mark a tile as visible within the current frame. Called from {@link Stage}. + * @param {Tile} tile The tile to mark. + */ + TextureStore.prototype.markTile = function(tile) { + // Check that we are in an appropriate state. + if (this._state !== State.START && this._state !== State.MARK) { + throw new Error('TextureStore: markTile called out of sequence'); + } + + // Enter the MARK state, if not already there. + this._state = State.MARK; + + // Refresh texture for dynamic assets. + var item = this._itemMap.get(tile); + var texture = item && item.texture(); + var asset = item && item.asset(); + if (texture && asset) { + texture.refresh(tile, asset); + } + + // Add tile to the visible set. + this._newVisible.add(tile); + }; + + + /** + * Signal the end of a frame. Called from {@link Stage}. + */ + TextureStore.prototype.endFrame = function() { + // Check that we are in an appropriate state. + if (this._state !== State.START && this._state !== State.MARK && this._state !== State.END) { + throw new Error('TextureStore: endFrame called out of sequence'); + } + + // Enter the END state, if not already there. + this._state = State.END; + + // Expect one less call to endFrame. + this._delimCount--; + + // If no further calls are expected, process frame and enter the IDLE state. + if (!this._delimCount) { + this._update(); + this._state = State.IDLE; + } + }; + + + TextureStore.prototype._update = function() { + var self = this; + + // Calculate the set of tiles that used to be visible but no longer are. + self._noLongerVisible.length = 0; + self._visible.forEach(function(tile) { + if (!self._newVisible.has(tile)) { + self._noLongerVisible.push(tile); + } + }); + + // Calculate the set of tiles that were visible recently and have become + // visible again. + self._visibleAgain.length = 0; + self._newVisible.forEach(function(tile) { + if (self._previouslyVisible.has(tile)) { + self._visibleAgain.push(tile); + } + }); + + // Remove tiles that have become visible again from the list of previously + // visible tiles. + self._visibleAgain.forEach(function(tile) { + self._previouslyVisible.remove(tile); + }); + + // Cancel loading of tiles that are no longer visible. + // Move no longer visible tiles with a loaded texture into the previously + // visible set, and collect the tiles evicted from the latter. + self._evicted.length = 0; + self._noLongerVisible.forEach(function(tile) { + var item = self._itemMap.get(tile); + var texture = item && item.texture(); + if (texture) { + var otherTile = self._previouslyVisible.add(tile); + if (otherTile != null) { + self._evicted.push(otherTile); + } + } else if (item) { + self._unloadTile(tile); + } + }); + + // Unload evicted tiles, unless they are pinned. + self._evicted.forEach(function(tile) { + if (!self._pinMap.has(tile)) { + self._unloadTile(tile); + } + }); + + // Load visible tiles that are not already in the store. + // Refresh texture on visible tiles for dynamic assets. + self._newVisible.forEach(function(tile) { + var item = self._itemMap.get(tile); + if (!item) { + self._loadTile(tile); + } + }); + + // Swap the old visible set with the new one. + var tmp = self._visible; + self._visible = self._newVisible; + self._newVisible = tmp; + + // Clear the new visible set. + self._newVisible.clear(); + + // Clear temporary variables. + self._noLongerVisible.length = 0; + self._visibleAgain.length = 0; + self._evicted.length = 0; + }; + + + TextureStore.prototype._loadTile = function(tile) { + if (this._itemMap.has(tile)) { + throw new Error('TextureStore: loading texture already in cache'); + } + var item = new TextureStoreItem(this, tile); + this._itemMap.set(tile, item); + }; + + + TextureStore.prototype._unloadTile = function(tile) { + var item = this._itemMap.del(tile); + if (!item) { + throw new Error('TextureStore: unloading texture not in cache'); + } + item.destroy(); + }; + + + TextureStore.prototype.asset = function(tile) { + var item = this._itemMap.get(tile); + if (item) { + return item.asset(); + } + return null; + }; + + + TextureStore.prototype.texture = function(tile) { + var item = this._itemMap.get(tile); + if (item) { + return item.texture(); + } + return null; + }; + + + /** + * Pin a tile. Textures for pinned tiles are never evicted from the store. + * Upon pinning, the texture is created if not already present. Pins are + * reference-counted; a tile may be pinned multiple times and must be unpinned + * the corresponding number of times. Pinning is useful e.g. to ensure that + * the lowest-resolution level of an image is always available to fall back + * onto. + * @param {Tile} tile the tile to pin + * @returns {number} the pin reference count. + */ + TextureStore.prototype.pin = function(tile) { + // Increment reference count. + var count = (this._pinMap.get(tile) || 0) + 1; + this._pinMap.set(tile, count); + // If the texture for the tile is not present, load it now. + if (!this._itemMap.has(tile)) { + this._loadTile(tile); + } + return count; + }; + + + /** + * Unpin a tile. Pins are reference-counted; a tile may be pinned multiple + * times and must be unpinned the corresponding number of times. + * @param {Tile} tile the tile to unpin + * @returns {number} the pin reference count. + */ + TextureStore.prototype.unpin = function(tile) { + var count = this._pinMap.get(tile); + // Consistency check. + if (!count) { + throw new Error('TextureStore: unpin when not pinned'); + } else { + // Decrement reference count. + count--; + if (count > 0) { + this._pinMap.set(tile, count); + } else { + this._pinMap.del(tile); + // If the tile does not belong to either the visible or previously + // visible sets, evict it from the cache. + if (!this._visible.has(tile) && !this._previouslyVisible.has(tile)) { + this._unloadTile(tile); + } + } + } + return count; + }; + + + /** + * Return type for {@link TextureStore#query}. + * @typedef {Object} TileState + * @property {boolean} visible Whether the tile is in the visible set. + * @property {boolean} previouslyVisible Whether the tile is in the previously + * visible set. + * @property {boolean} hasAsset Whether the asset for the tile is present. + * @property {boolean} hasTexture Whether the texture for the tile is present. + * @property {boolean} pinned Whether the tile is in the pinned set. + * @property {number} pinCount The pin reference count for the tile. + */ + + + /** + * Return the state of a tile. + * @param {Tile} tile The tile to query. + * @return {TileState} + */ + TextureStore.prototype.query = function(tile) { + var item = this._itemMap.get(tile); + var pinCount = this._pinMap.get(tile) || 0; + return { + visible: this._visible.has(tile), + previouslyVisible: this._previouslyVisible.has(tile), + hasAsset: item != null && item.asset() != null, + hasTexture: item != null && item.texture() != null, + pinned: pinCount !== 0, + pinCount: pinCount + }; + }; + + + var TextureStore_1 = TextureStore; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function extend(obj, sourceObj) { + for (var key in sourceObj) { + obj[key] = sourceObj[key]; + } + return obj; + } + + var extend_1 = extend; + + /** + * Signals that the layer has been rendered. + * + * @param {boolean} stable Whether all tiles were successfully rendered without + * missing textures or resorting to fallbacks. + * @event Layer#renderComplete + */ + + /** + * @class Layer + * @classdesc + * + * A Layer is a combination of {@link Source}, {@link Geometry}, {@link View} + * and {@link TextureStore} that may be added into a {@link Stage} and rendered + * with {@link Effects}. + * + * @param {Source} source + * @param {Geometry} geometry + * @param {View} view + * @param {TextureStore} textureStore + * @param {Object} opts + * @param {Effects} opts.effects + */ + function Layer(source, geometry, view, textureStore, opts) { + opts = opts || {}; + + var self = this; + + this._source = source; + this._geometry = geometry; + this._view = view; + this._textureStore = textureStore; + + this._effects = opts.effects || {}; + + this._fixedLevelIndex = null; + + this._viewChangeHandler = function() { + self.emit('viewChange', self.view()); + }; + + this._view.addEventListener('change', this._viewChangeHandler); + + this._textureStoreChangeHandler = function() { + self.emit('textureStoreChange', self.textureStore()); + }; + + this._textureStore.addEventListener('textureLoad', + this._textureStoreChangeHandler); + this._textureStore.addEventListener('textureError', + this._textureStoreChangeHandler); + this._textureStore.addEventListener('textureInvalid', + this._textureStoreChangeHandler); + } + + minimalEventEmitter(Layer); + + + /** + * Destructor. + */ + Layer.prototype.destroy = function() { + this._view.removeEventListener('change', this._viewChangeHandler); + this._textureStore.removeEventListener('textureLoad', + this._textureStoreChangeHandler); + this._textureStore.removeEventListener('textureError', + this._textureStoreChangeHandler); + this._textureStore.removeEventListener('textureInvalid', + this._textureStoreChangeHandler); + clearOwnProperties_1(this); + }; + + + /** + * Returns the underlying {@link Source source}. + * @return {Source} + */ + Layer.prototype.source = function() { + return this._source; + }; + + + /** + * Returns the underlying {@link Geometry geometry}. + * @return {Geometry} + */ + Layer.prototype.geometry = function() { + return this._geometry; + }; + + + /** + * Returns the underlying {@link View view}. + * @return {View} + */ + Layer.prototype.view = function() { + return this._view; + }; + + + /** + * Returns the underlying {@link TextureStore texture store}. + * @return {TextureStore} + */ + Layer.prototype.textureStore = function() { + return this._textureStore; + }; + + + /** + * Returns the currently set {@link Effects effects}. + * @return {Effects} + */ + Layer.prototype.effects = function() { + return this._effects; + }; + + + /** + * Sets the {@link Effects effects}. + * @param {Effects} effects + */ + Layer.prototype.setEffects = function(effects) { + this._effects = effects; + this.emit('effectsChange', this._effects); + }; + + + /** + * Merges effects into the currently set ones. The merge is non-recursive; for + * instance, if current effects are `{ rect: { relativeWidth: 0.5 } }`, + * calling this method with `{ rect: { relativeX: 0.5 }}` will reset + * `rect.relativeWidth`. + * + * @param {Effects} effects + */ + Layer.prototype.mergeEffects = function(effects) { + extend_1(this._effects, effects); + this.emit('effectsChange', this._effects); + }; + + + /** + * Returns the fixed level index. + * @return {(number|null)} + */ + Layer.prototype.fixedLevel = function() { + return this._fixedLevelIndex; + }; + + + /** + * Sets the fixed level index. When set, the corresponding level will be + * used regardless of the view parameters. Unset with a null argument. + * + * @param {(number|null)} levelIndex + * @throws An error if the level index is out of range. + */ + Layer.prototype.setFixedLevel = function(levelIndex) { + if (levelIndex !== this._fixedLevelIndex) { + if (levelIndex != null && (levelIndex >= this._geometry.levelList.length || + levelIndex < 0)) { + throw new Error("Level index out of range: " + levelIndex); + } + this._fixedLevelIndex = levelIndex; + this.emit('fixedLevelChange', this._fixedLevelIndex); + } + }; + + + Layer.prototype._selectLevel = function() { + var level; + if (this._fixedLevelIndex != null) { + level = this._geometry.levelList[this._fixedLevelIndex]; + } else { + level = this._view.selectLevel(this._geometry.selectableLevelList); + } + return level; + }; + + + Layer.prototype.visibleTiles = function(result) { + var level = this._selectLevel(); + return this._geometry.visibleTiles(this._view, level, result); + }; + + + /** + * Pin a whole level into the texture store. + * @param {Number} levelIndex + */ + Layer.prototype.pinLevel = function(levelIndex) { + var level = this._geometry.levelList[levelIndex]; + var tiles = this._geometry.levelTiles(level); + for (var i = 0; i < tiles.length; i++) { + this._textureStore.pin(tiles[i]); + } + }; + + + /** + * Unpin a whole level from the texture store. + * @param {Number} levelIndex + */ + Layer.prototype.unpinLevel = function(levelIndex) { + var level = this._geometry.levelList[levelIndex]; + var tiles = this._geometry.levelTiles(level); + for (var i = 0; i < tiles.length; i++) { + this._textureStore.unpin(tiles[i]); + } + }; + + + /** + * Pin the first level. Equivalent to `pinLevel(0)`. + */ + Layer.prototype.pinFirstLevel = function() { + return this.pinLevel(0); + }; + + + /** + * Unpin the first level. Equivalent to `unpinLevel(0)`. + */ + Layer.prototype.unpinFirstLevel = function() { + return this.unpinLevel(0); + }; + + + var Layer_1 = Layer; + + /** + * Signals that {@link Stage#render} is about to be called. + * @event RenderLoop#beforeRender + */ + + /** + * Signals that {@link Stage#render} has just been called. + * @event RenderLoop#afterRender + */ + + /** + * @class RenderLoop + * @classdesc + * + * A RenderLoop wraps a {@link Stage} and calls {@link Stage#render} on the next + * frame whenever it fires {@link Stage#renderInvalid}. It may be started and + * stopped, and is initially in the stopped state, in which no call to + * {@link Stage#render} occurs. + * + * @listens Stage#renderInvalid + * + * @param {Stage} stage + */ + function RenderLoop(stage) { + + var self = this; + + // The stage wrapped by the loop. + this._stage = stage; + + // Whether the loop is running. + this._running = false; + + // Whether the loop is currently rendering. + this._rendering = false; + + // The current requestAnimationFrame handle. + this._requestHandle = null; + + // The callback passed into requestAnimationFrame. + this._boundLoop = this._loop.bind(this); + + // Handler for renderInvalid events emitted by the stage. + this._renderInvalidHandler = function() { + // If we are already rendering, there's no need to schedule a new render + // on the next frame. + if (!self._rendering) { + self.renderOnNextFrame(); + } + }; + + // Handle renderInvalid events emitted by the stage. + this._stage.addEventListener('renderInvalid', this._renderInvalidHandler); + + } + + minimalEventEmitter(RenderLoop); + + + /** + * Destructor. + */ + RenderLoop.prototype.destroy = function() { + this.stop(); + this._stage.removeEventListener('renderInvalid', this._renderInvalidHandler); + clearOwnProperties_1(this); + }; + + + /** + * Returns the underlying stage. + * @return {Stage} + */ + RenderLoop.prototype.stage = function() { + return this._stage; + }; + + + /** + * Starts the render loop. + */ + RenderLoop.prototype.start = function() { + this._running = true; + this.renderOnNextFrame(); + }; + + + /** + * Stops the render loop. + */ + RenderLoop.prototype.stop = function() { + if (this._requestHandle) { + window.cancelAnimationFrame(this._requestHandle); + this._requestHandle = null; + } + this._running = false; + }; + + + /** + * Forces the stage to render on the next frame, even if its contents remain + * valid. Does nothing if the loop is stopped. + */ + RenderLoop.prototype.renderOnNextFrame = function() { + if (this._running && !this._requestHandle) { + this._requestHandle = window.requestAnimationFrame(this._boundLoop); + } + }; + + + RenderLoop.prototype._loop = function() { + if (!this._running) { + throw new Error('Render loop running while in stopped state'); + } + this._requestHandle = null; + this._rendering = true; + this.emit('beforeRender'); + this._rendering = false; + this._stage.render(); + this.emit('afterRender'); + }; + + + var RenderLoop_1 = RenderLoop; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @class Dynamics + * @classdesc + * + * Represents how a control parameter changes. Used in the events emitted by + * {@link ControlMethod}. + * + * @property {number} offset Parameter changed by a fixed value + * @property {number} velocity Parameter is changing at this velocity + * @property {number} friction The velocity will decrease at this rate + */ + function Dynamics() { + this.velocity = null; + this.friction = null; + this.offset = null; + } + + Dynamics.equals = function(d1, d2) { + return d1.velocity === d2.velocity && d1.friction === d2.friction && d1.offset === d2.offset; + }; + + Dynamics.prototype.equals = function(other) { + return Dynamics.equals(this, other); + }; + + Dynamics.prototype.update = function(other, elapsed) { + if (other.offset) { + // If other has an offset, make this.offset a number instead of null + this.offset = this.offset || 0; + this.offset += other.offset; + } + + var offsetFromVelocity = this.offsetFromVelocity(elapsed); + if (offsetFromVelocity) { + // If there is an offset to add from the velocity, make this offset a number instead of null + this.offset = this.offset || 0; + this.offset += offsetFromVelocity; + } + + this.velocity = other.velocity; + this.friction = other.friction; + }; + + Dynamics.prototype.reset = function() { + this.velocity = null; + this.friction = null; + this.offset = null; + }; + + + Dynamics.prototype.velocityAfter = function(elapsed) { + if (!this.velocity) { + return null; + } + if (this.friction) { + return decreaseAbs(this.velocity, this.friction *elapsed); + } + return this.velocity; + }; + + Dynamics.prototype.offsetFromVelocity = function(elapsed) { + elapsed = Math.min(elapsed, this.nullVelocityTime()); + + var velocityEnd = this.velocityAfter(elapsed); + var averageVelocity = (this.velocity + velocityEnd) / 2; + + return averageVelocity * elapsed; + }; + + + Dynamics.prototype.nullVelocityTime = function() { + if (this.velocity == null) { + return 0; + } + if (this.velocity && !this.friction) { + return Infinity; + } + return Math.abs(this.velocity / this.friction); + }; + + function decreaseAbs(num, dec) { + if (num < 0) { + return Math.min(0, num + dec); + } + if (num > 0) { + return Math.max(0, num - dec); + } + return 0; + } + + var Dynamics_1 = Dynamics; + + /** + * @class KeyControlMethod + * @implements ControlMethod + * @classdesc + * + * Sets the velocity and friction of a single parameter by pressing and + * unpressing a key. + * + * @param {number} keyCode Key which activates the method when pressed + * @param {string} parameter The parameter to be controlled (e.g. `x`, `y` or `zoom`) + * @param {number} velocity Velocity at which the parameter changes. Use a + * negative number for opposite direction + * @param {number} friction Friction at which the parameter stops + * @param {Element} [element=document] DOM element where the key events are listened to + */ + function KeyControlMethod(keyCode, parameter, velocity, friction, element) { + if(!keyCode) { + throw new Error("KeyControlMethod: keyCode must be defined"); + } + if(!parameter) { + throw new Error("KeyControlMethod: parameter must be defined"); + } + if(!velocity) { + throw new Error("KeyControlMethod: velocity must be defined"); + } + if(!friction) { + throw new Error("KeyControlMethod: friction must be defined"); + } + + element = element || document; + + this._keyCode = keyCode; + this._parameter = parameter; + this._velocity = velocity; + this._friction = friction; + this._element = element; + + this._keydownHandler = this._handlePress.bind(this); + this._keyupHandler = this._handleRelease.bind(this); + this._blurHandler = this._handleBlur.bind(this); + + this._element.addEventListener('keydown', this._keydownHandler); + this._element.addEventListener('keyup', this._keyupHandler); + window.addEventListener('blur', this._blurHandler); + + this._dynamics = new Dynamics_1(); + this._pressing = false; + } + minimalEventEmitter(KeyControlMethod); + + /** + * Destructor. + */ + KeyControlMethod.prototype.destroy = function() { + this._element.removeEventListener('keydown', this._keydownHandler); + this._element.removeEventListener('keyup', this._keyupHandler); + window.removeEventListener('blur', this._blurHandler); + clearOwnProperties_1(this); + }; + + KeyControlMethod.prototype._handlePress = function(e) { + if(e.keyCode !== this._keyCode) { return; } + + this._pressing = true; + + this._dynamics.velocity = this._velocity; + this._dynamics.friction = 0; + this.emit('parameterDynamics', this._parameter, this._dynamics); + this.emit('active'); + }; + + KeyControlMethod.prototype._handleRelease = function(e) { + if(e.keyCode !== this._keyCode) { return; } + + if(this._pressing) { + this._dynamics.friction = this._friction; + this.emit('parameterDynamics', this._parameter, this._dynamics); + this.emit('inactive'); + } + + this._pressing = false; + }; + + KeyControlMethod.prototype._handleBlur = function() { + this._dynamics.velocity = 0; + this.emit('parameterDynamics', this._parameter, this._dynamics); + this.emit('inactive'); + + this._pressing = false; + }; + + var Key = KeyControlMethod; + + var hammer = createCommonjsModule(function (module) { + /*! Hammer.JS - v2.0.4 - 2014-09-28 + * http://hammerjs.github.io/ + * + * Copyright (c) 2014 Jorik Tangelder; + * Licensed under the MIT license */ + (function(window, document, exportName, undefined$1) { + + var VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o']; + var TEST_ELEMENT = document.createElement('div'); + + var TYPE_FUNCTION = 'function'; + + var round = Math.round; + var abs = Math.abs; + var now = Date.now; + + /** + * set a timeout with a given scope + * @param {Function} fn + * @param {Number} timeout + * @param {Object} context + * @returns {number} + */ + function setTimeoutContext(fn, timeout, context) { + return setTimeout(bindFn(fn, context), timeout); + } + + /** + * if the argument is an array, we want to execute the fn on each entry + * if it aint an array we don't want to do a thing. + * this is used by all the methods that accept a single and array argument. + * @param {*|Array} arg + * @param {String} fn + * @param {Object} [context] + * @returns {Boolean} + */ + function invokeArrayArg(arg, fn, context) { + if (Array.isArray(arg)) { + each(arg, context[fn], context); + return true; + } + return false; + } + + /** + * walk objects and arrays + * @param {Object} obj + * @param {Function} iterator + * @param {Object} context + */ + function each(obj, iterator, context) { + var i; + + if (!obj) { + return; + } + + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length !== undefined$1) { + i = 0; + while (i < obj.length) { + iterator.call(context, obj[i], i, obj); + i++; + } + } else { + for (i in obj) { + obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj); + } + } + } + + /** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge] + * @returns {Object} dest + */ + function extend(dest, src, merge) { + var keys = Object.keys(src); + var i = 0; + while (i < keys.length) { + if (!merge || (merge && dest[keys[i]] === undefined$1)) { + dest[keys[i]] = src[keys[i]]; + } + i++; + } + return dest; + } + + /** + * merge the values from src in the dest. + * means that properties that exist in dest will not be overwritten by src + * @param {Object} dest + * @param {Object} src + * @returns {Object} dest + */ + function merge(dest, src) { + return extend(dest, src, true); + } + + /** + * simple class inheritance + * @param {Function} child + * @param {Function} base + * @param {Object} [properties] + */ + function inherit(child, base, properties) { + var baseP = base.prototype, + childP; + + childP = child.prototype = Object.create(baseP); + childP.constructor = child; + childP._super = baseP; + + if (properties) { + extend(childP, properties); + } + } + + /** + * simple function bind + * @param {Function} fn + * @param {Object} context + * @returns {Function} + */ + function bindFn(fn, context) { + return function boundFn() { + return fn.apply(context, arguments); + }; + } + + /** + * let a boolean value also be a function that must return a boolean + * this first item in args will be used as the context + * @param {Boolean|Function} val + * @param {Array} [args] + * @returns {Boolean} + */ + function boolOrFn(val, args) { + if (typeof val == TYPE_FUNCTION) { + return val.apply(args ? args[0] || undefined$1 : undefined$1, args); + } + return val; + } + + /** + * use the val2 when val1 is undefined + * @param {*} val1 + * @param {*} val2 + * @returns {*} + */ + function ifUndefined(val1, val2) { + return (val1 === undefined$1) ? val2 : val1; + } + + /** + * addEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ + function addEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.addEventListener(type, handler, false); + }); + } + + /** + * removeEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ + function removeEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.removeEventListener(type, handler, false); + }); + } + + /** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ + function hasParent(node, parent) { + while (node) { + if (node == parent) { + return true; + } + node = node.parentNode; + } + return false; + } + + /** + * small indexOf wrapper + * @param {String} str + * @param {String} find + * @returns {Boolean} found + */ + function inStr(str, find) { + return str.indexOf(find) > -1; + } + + /** + * split string on whitespace + * @param {String} str + * @returns {Array} words + */ + function splitStr(str) { + return str.trim().split(/\s+/g); + } + + /** + * find if a array contains the object using indexOf or a simple polyFill + * @param {Array} src + * @param {String} find + * @param {String} [findByKey] + * @return {Boolean|Number} false when not found, or the index + */ + function inArray(src, find, findByKey) { + if (src.indexOf && !findByKey) { + return src.indexOf(find); + } else { + var i = 0; + while (i < src.length) { + if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) { + return i; + } + i++; + } + return -1; + } + } + + /** + * convert array-like objects to real arrays + * @param {Object} obj + * @returns {Array} + */ + function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + } + + /** + * unique array with objects based on a key (like 'id') or just by the array's value + * @param {Array} src [{id:1},{id:2},{id:1}] + * @param {String} [key] + * @param {Boolean} [sort=False] + * @returns {Array} [{id:1},{id:2}] + */ + function uniqueArray(src, key, sort) { + var results = []; + var values = []; + var i = 0; + + while (i < src.length) { + var val = key ? src[i][key] : src[i]; + if (inArray(values, val) < 0) { + results.push(src[i]); + } + values[i] = val; + i++; + } + + if (sort) { + if (!key) { + results = results.sort(); + } else { + results = results.sort(function sortUniqueArray(a, b) { + return a[key] > b[key]; + }); + } + } + + return results; + } + + /** + * get the prefixed property + * @param {Object} obj + * @param {String} property + * @returns {String|Undefined} prefixed + */ + function prefixed(obj, property) { + var prefix, prop; + var camelProp = property[0].toUpperCase() + property.slice(1); + + var i = 0; + while (i < VENDOR_PREFIXES.length) { + prefix = VENDOR_PREFIXES[i]; + prop = (prefix) ? prefix + camelProp : property; + + if (prop in obj) { + return prop; + } + i++; + } + return undefined$1; + } + + /** + * get a unique id + * @returns {number} uniqueId + */ + var _uniqueId = 1; + function uniqueId() { + return _uniqueId++; + } + + /** + * get the window object of an element + * @param {HTMLElement} element + * @returns {DocumentView|Window} + */ + function getWindowForElement(element) { + var doc = element.ownerDocument; + return (doc.defaultView || doc.parentWindow); + } + + var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; + + var SUPPORT_TOUCH = ('ontouchstart' in window); + var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined$1; + var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent); + + var INPUT_TYPE_TOUCH = 'touch'; + var INPUT_TYPE_PEN = 'pen'; + var INPUT_TYPE_MOUSE = 'mouse'; + var INPUT_TYPE_KINECT = 'kinect'; + + var COMPUTE_INTERVAL = 25; + + var INPUT_START = 1; + var INPUT_MOVE = 2; + var INPUT_END = 4; + var INPUT_CANCEL = 8; + + var DIRECTION_NONE = 1; + var DIRECTION_LEFT = 2; + var DIRECTION_RIGHT = 4; + var DIRECTION_UP = 8; + var DIRECTION_DOWN = 16; + + var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT; + var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN; + var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + + var PROPS_XY = ['x', 'y']; + var PROPS_CLIENT_XY = ['clientX', 'clientY']; + + /** + * create new input type manager + * @param {Manager} manager + * @param {Function} callback + * @returns {Input} + * @constructor + */ + function Input(manager, callback) { + var self = this; + this.manager = manager; + this.callback = callback; + this.element = manager.element; + this.target = manager.options.inputTarget; + + // smaller wrapper around the handler, for the scope and the enabled state of the manager, + // so when disabled the input events are completely bypassed. + this.domHandler = function(ev) { + if (boolOrFn(manager.options.enable, [manager])) { + self.handler(ev); + } + }; + + this.init(); + + } + + Input.prototype = { + /** + * should handle the inputEvent data and trigger the callback + * @virtual + */ + handler: function() { }, + + /** + * bind the events + */ + init: function() { + this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + }, + + /** + * unbind the events + */ + destroy: function() { + this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + } + }; + + /** + * create new input type manager + * called by the Manager constructor + * @param {Hammer} manager + * @returns {Input} + */ + function createInputInstance(manager) { + var Type; + var inputClass = manager.options.inputClass; + + if (inputClass) { + Type = inputClass; + } else if (SUPPORT_POINTER_EVENTS) { + Type = PointerEventInput; + } else if (SUPPORT_ONLY_TOUCH) { + Type = TouchInput; + } else if (!SUPPORT_TOUCH) { + Type = MouseInput; + } else { + Type = TouchMouseInput; + } + return new (Type)(manager, inputHandler); + } + + /** + * handle input events + * @param {Manager} manager + * @param {String} eventType + * @param {Object} input + */ + function inputHandler(manager, eventType, input) { + var pointersLen = input.pointers.length; + var changedPointersLen = input.changedPointers.length; + var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0)); + var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0)); + + input.isFirst = !!isFirst; + input.isFinal = !!isFinal; + + if (isFirst) { + manager.session = {}; + } + + // source event is the normalized value of the domEvents + // like 'touchstart, mouseup, pointerdown' + input.eventType = eventType; + + // compute scale, rotation etc + computeInputData(manager, input); + + // emit secret event + manager.emit('hammer.input', input); + + manager.recognize(input); + manager.session.prevInput = input; + } + + /** + * extend the data with some usable properties like scale, rotate, velocity etc + * @param {Object} manager + * @param {Object} input + */ + function computeInputData(manager, input) { + var session = manager.session; + var pointers = input.pointers; + var pointersLength = pointers.length; + + // store the first input to calculate the distance and direction + if (!session.firstInput) { + session.firstInput = simpleCloneInputData(input); + } + + // to compute scale and rotation we need to store the multiple touches + if (pointersLength > 1 && !session.firstMultiple) { + session.firstMultiple = simpleCloneInputData(input); + } else if (pointersLength === 1) { + session.firstMultiple = false; + } + + var firstInput = session.firstInput; + var firstMultiple = session.firstMultiple; + var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center; + + var center = input.center = getCenter(pointers); + input.timeStamp = now(); + input.deltaTime = input.timeStamp - firstInput.timeStamp; + + input.angle = getAngle(offsetCenter, center); + input.distance = getDistance(offsetCenter, center); + + computeDeltaXY(session, input); + input.offsetDirection = getDirection(input.deltaX, input.deltaY); + + input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1; + input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0; + + computeIntervalInputData(session, input); + + // find the correct target + var target = manager.element; + if (hasParent(input.srcEvent.target, target)) { + target = input.srcEvent.target; + } + input.target = target; + } + + function computeDeltaXY(session, input) { + var center = input.center; + var offset = session.offsetDelta || {}; + var prevDelta = session.prevDelta || {}; + var prevInput = session.prevInput || {}; + + if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) { + prevDelta = session.prevDelta = { + x: prevInput.deltaX || 0, + y: prevInput.deltaY || 0 + }; + + offset = session.offsetDelta = { + x: center.x, + y: center.y + }; + } + + input.deltaX = prevDelta.x + (center.x - offset.x); + input.deltaY = prevDelta.y + (center.y - offset.y); + } + + /** + * velocity is calculated every x ms + * @param {Object} session + * @param {Object} input + */ + function computeIntervalInputData(session, input) { + var last = session.lastInterval || input, + deltaTime = input.timeStamp - last.timeStamp, + velocity, velocityX, velocityY, direction; + + if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined$1)) { + var deltaX = last.deltaX - input.deltaX; + var deltaY = last.deltaY - input.deltaY; + + var v = getVelocity(deltaTime, deltaX, deltaY); + velocityX = v.x; + velocityY = v.y; + velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; + direction = getDirection(deltaX, deltaY); + + session.lastInterval = input; + } else { + // use latest velocity info if it doesn't overtake a minimum period + velocity = last.velocity; + velocityX = last.velocityX; + velocityY = last.velocityY; + direction = last.direction; + } + + input.velocity = velocity; + input.velocityX = velocityX; + input.velocityY = velocityY; + input.direction = direction; + } + + /** + * create a simple clone from the input used for storage of firstInput and firstMultiple + * @param {Object} input + * @returns {Object} clonedInputData + */ + function simpleCloneInputData(input) { + // make a simple copy of the pointers because we will get a reference if we don't + // we only need clientXY for the calculations + var pointers = []; + var i = 0; + while (i < input.pointers.length) { + pointers[i] = { + clientX: round(input.pointers[i].clientX), + clientY: round(input.pointers[i].clientY) + }; + i++; + } + + return { + timeStamp: now(), + pointers: pointers, + center: getCenter(pointers), + deltaX: input.deltaX, + deltaY: input.deltaY + }; + } + + /** + * get the center of all the pointers + * @param {Array} pointers + * @return {Object} center contains `x` and `y` properties + */ + function getCenter(pointers) { + var pointersLength = pointers.length; + + // no need to loop when only one touch + if (pointersLength === 1) { + return { + x: round(pointers[0].clientX), + y: round(pointers[0].clientY) + }; + } + + var x = 0, y = 0, i = 0; + while (i < pointersLength) { + x += pointers[i].clientX; + y += pointers[i].clientY; + i++; + } + + return { + x: round(x / pointersLength), + y: round(y / pointersLength) + }; + } + + /** + * calculate the velocity between two points. unit is in px per ms. + * @param {Number} deltaTime + * @param {Number} x + * @param {Number} y + * @return {Object} velocity `x` and `y` + */ + function getVelocity(deltaTime, x, y) { + return { + x: x / deltaTime || 0, + y: y / deltaTime || 0 + }; + } + + /** + * get the direction between two points + * @param {Number} x + * @param {Number} y + * @return {Number} direction + */ + function getDirection(x, y) { + if (x === y) { + return DIRECTION_NONE; + } + + if (abs(x) >= abs(y)) { + return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return y > 0 ? DIRECTION_UP : DIRECTION_DOWN; + } + + /** + * calculate the absolute distance between two points + * @param {Object} p1 {x, y} + * @param {Object} p2 {x, y} + * @param {Array} [props] containing x and y keys + * @return {Number} distance + */ + function getDistance(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + + return Math.sqrt((x * x) + (y * y)); + } + + /** + * calculate the angle between two coordinates + * @param {Object} p1 + * @param {Object} p2 + * @param {Array} [props] containing x and y keys + * @return {Number} angle + */ + function getAngle(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.atan2(y, x) * 180 / Math.PI; + } + + /** + * calculate the rotation degrees between two pointersets + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} rotation + */ + function getRotation(start, end) { + return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY); + } + + /** + * calculate the scale factor between two pointersets + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} scale + */ + function getScale(start, end) { + return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY); + } + + var MOUSE_INPUT_MAP = { + mousedown: INPUT_START, + mousemove: INPUT_MOVE, + mouseup: INPUT_END + }; + + var MOUSE_ELEMENT_EVENTS = 'mousedown'; + var MOUSE_WINDOW_EVENTS = 'mousemove mouseup'; + + /** + * Mouse events input + * @constructor + * @extends Input + */ + function MouseInput() { + this.evEl = MOUSE_ELEMENT_EVENTS; + this.evWin = MOUSE_WINDOW_EVENTS; + + this.allow = true; // used by Input.TouchMouse to disable mouse events + this.pressed = false; // mousedown state + + Input.apply(this, arguments); + } + + inherit(MouseInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function MEhandler(ev) { + var eventType = MOUSE_INPUT_MAP[ev.type]; + + // on start we want to have the left mouse button down + if (eventType & INPUT_START && ev.button === 0) { + this.pressed = true; + } + + if (eventType & INPUT_MOVE && ev.which !== 1) { + eventType = INPUT_END; + } + + // mouse must be down, and mouse events are allowed (see the TouchMouse input) + if (!this.pressed || !this.allow) { + return; + } + + if (eventType & INPUT_END) { + this.pressed = false; + } + + this.callback(this.manager, eventType, { + pointers: [ev], + changedPointers: [ev], + pointerType: INPUT_TYPE_MOUSE, + srcEvent: ev + }); + } + }); + + var POINTER_INPUT_MAP = { + pointerdown: INPUT_START, + pointermove: INPUT_MOVE, + pointerup: INPUT_END, + pointercancel: INPUT_CANCEL, + pointerout: INPUT_CANCEL + }; + + // in IE10 the pointer types is defined as an enum + var IE10_POINTER_TYPE_ENUM = { + 2: INPUT_TYPE_TOUCH, + 3: INPUT_TYPE_PEN, + 4: INPUT_TYPE_MOUSE, + 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816 + }; + + var POINTER_ELEMENT_EVENTS = 'pointerdown'; + var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; + + // IE10 has prefixed support, and case-sensitive + if (window.MSPointerEvent) { + POINTER_ELEMENT_EVENTS = 'MSPointerDown'; + POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel'; + } + + /** + * Pointer events input + * @constructor + * @extends Input + */ + function PointerEventInput() { + this.evEl = POINTER_ELEMENT_EVENTS; + this.evWin = POINTER_WINDOW_EVENTS; + + Input.apply(this, arguments); + + this.store = (this.manager.session.pointerEvents = []); + } + + inherit(PointerEventInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function PEhandler(ev) { + var store = this.store; + var removePointer = false; + + var eventTypeNormalized = ev.type.toLowerCase().replace('ms', ''); + var eventType = POINTER_INPUT_MAP[eventTypeNormalized]; + var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType; + + var isTouch = (pointerType == INPUT_TYPE_TOUCH); + + // get index of the event in the store + var storeIndex = inArray(store, ev.pointerId, 'pointerId'); + + // start and mouse must be down + if (eventType & INPUT_START && (ev.button === 0 || isTouch)) { + if (storeIndex < 0) { + store.push(ev); + storeIndex = store.length - 1; + } + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + removePointer = true; + } + + // it not found, so the pointer hasn't been down (so it's probably a hover) + if (storeIndex < 0) { + return; + } + + // update the event in the store + store[storeIndex] = ev; + + this.callback(this.manager, eventType, { + pointers: store, + changedPointers: [ev], + pointerType: pointerType, + srcEvent: ev + }); + + if (removePointer) { + // remove from the store + store.splice(storeIndex, 1); + } + } + }); + + var SINGLE_TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart'; + var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Touch events input + * @constructor + * @extends Input + */ + function SingleTouchInput() { + this.evTarget = SINGLE_TOUCH_TARGET_EVENTS; + this.evWin = SINGLE_TOUCH_WINDOW_EVENTS; + this.started = false; + + Input.apply(this, arguments); + } + + inherit(SingleTouchInput, Input, { + handler: function TEhandler(ev) { + var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; + + // should we handle the touch events? + if (type === INPUT_START) { + this.started = true; + } + + if (!this.started) { + return; + } + + var touches = normalizeSingleTouches.call(this, ev, type); + + // when done, reset the started state + if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) { + this.started = false; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); + + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function normalizeSingleTouches(ev, type) { + var all = toArray(ev.touches); + var changed = toArray(ev.changedTouches); + + if (type & (INPUT_END | INPUT_CANCEL)) { + all = uniqueArray(all.concat(changed), 'identifier', true); + } + + return [all, changed]; + } + + var TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Multi-user touch events input + * @constructor + * @extends Input + */ + function TouchInput() { + this.evTarget = TOUCH_TARGET_EVENTS; + this.targetIds = {}; + + Input.apply(this, arguments); + } + + inherit(TouchInput, Input, { + handler: function MTEhandler(ev) { + var type = TOUCH_INPUT_MAP[ev.type]; + var touches = getTouches.call(this, ev, type); + if (!touches) { + return; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); + + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function getTouches(ev, type) { + var allTouches = toArray(ev.touches); + var targetIds = this.targetIds; + + // when there is only one touch, the process can be simplified + if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) { + targetIds[allTouches[0].identifier] = true; + return [allTouches, allTouches]; + } + + var i, + targetTouches, + changedTouches = toArray(ev.changedTouches), + changedTargetTouches = [], + target = this.target; + + // get target touches from touches + targetTouches = allTouches.filter(function(touch) { + return hasParent(touch.target, target); + }); + + // collect touches + if (type === INPUT_START) { + i = 0; + while (i < targetTouches.length) { + targetIds[targetTouches[i].identifier] = true; + i++; + } + } + + // filter changed touches to only contain touches that exist in the collected target ids + i = 0; + while (i < changedTouches.length) { + if (targetIds[changedTouches[i].identifier]) { + changedTargetTouches.push(changedTouches[i]); + } + + // cleanup removed touches + if (type & (INPUT_END | INPUT_CANCEL)) { + delete targetIds[changedTouches[i].identifier]; + } + i++; + } + + if (!changedTargetTouches.length) { + return; + } + + return [ + // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel' + uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), + changedTargetTouches + ]; + } + + /** + * Combined touch and mouse input + * + * Touch has a higher priority then mouse, and while touching no mouse events are allowed. + * This because touch devices also emit mouse events while doing a touch. + * + * @constructor + * @extends Input + */ + function TouchMouseInput() { + Input.apply(this, arguments); + + var handler = bindFn(this.handler, this); + this.touch = new TouchInput(this.manager, handler); + this.mouse = new MouseInput(this.manager, handler); + } + + inherit(TouchMouseInput, Input, { + /** + * handle mouse and touch events + * @param {Hammer} manager + * @param {String} inputEvent + * @param {Object} inputData + */ + handler: function TMEhandler(manager, inputEvent, inputData) { + var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), + isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE); + + // when we're in a touch event, so block all upcoming mouse events + // most mobile browser also emit mouseevents, right after touchstart + if (isTouch) { + this.mouse.allow = false; + } else if (isMouse && !this.mouse.allow) { + return; + } + + // reset the allowMouse when we're done + if (inputEvent & (INPUT_END | INPUT_CANCEL)) { + this.mouse.allow = true; + } + + this.callback(manager, inputEvent, inputData); + }, + + /** + * remove the event listeners + */ + destroy: function destroy() { + this.touch.destroy(); + this.mouse.destroy(); + } + }); + + var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction'); + var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined$1; + + // magical touchAction value + var TOUCH_ACTION_COMPUTE = 'compute'; + var TOUCH_ACTION_AUTO = 'auto'; + var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented + var TOUCH_ACTION_NONE = 'none'; + var TOUCH_ACTION_PAN_X = 'pan-x'; + var TOUCH_ACTION_PAN_Y = 'pan-y'; + + /** + * Touch Action + * sets the touchAction property or uses the js alternative + * @param {Manager} manager + * @param {String} value + * @constructor + */ + function TouchAction(manager, value) { + this.manager = manager; + this.set(value); + } + + TouchAction.prototype = { + /** + * set the touchAction value on the element or enable the polyfill + * @param {String} value + */ + set: function(value) { + // find out the touch-action by the event handlers + if (value == TOUCH_ACTION_COMPUTE) { + value = this.compute(); + } + + if (NATIVE_TOUCH_ACTION) { + this.manager.element.style[PREFIXED_TOUCH_ACTION] = value; + } + this.actions = value.toLowerCase().trim(); + }, + + /** + * just re-set the touchAction value + */ + update: function() { + this.set(this.manager.options.touchAction); + }, + + /** + * compute the value for the touchAction property based on the recognizer's settings + * @returns {String} value + */ + compute: function() { + var actions = []; + each(this.manager.recognizers, function(recognizer) { + if (boolOrFn(recognizer.options.enable, [recognizer])) { + actions = actions.concat(recognizer.getTouchAction()); + } + }); + return cleanTouchActions(actions.join(' ')); + }, + + /** + * this method is called on each input cycle and provides the preventing of the browser behavior + * @param {Object} input + */ + preventDefaults: function(input) { + // not needed with native support for the touchAction property + if (NATIVE_TOUCH_ACTION) { + return; + } + + var srcEvent = input.srcEvent; + var direction = input.offsetDirection; + + // if the touch action did prevented once this session + if (this.manager.session.prevented) { + srcEvent.preventDefault(); + return; + } + + var actions = this.actions; + var hasNone = inStr(actions, TOUCH_ACTION_NONE); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + + if (hasNone || + (hasPanY && direction & DIRECTION_HORIZONTAL) || + (hasPanX && direction & DIRECTION_VERTICAL)) { + return this.preventSrc(srcEvent); + } + }, + + /** + * call preventDefault to prevent the browser's default behavior (scrolling in most cases) + * @param {Object} srcEvent + */ + preventSrc: function(srcEvent) { + this.manager.session.prevented = true; + srcEvent.preventDefault(); + } + }; + + /** + * when the touchActions are collected they are not a valid value, so we need to clean things up. * + * @param {String} actions + * @returns {*} + */ + function cleanTouchActions(actions) { + // none + if (inStr(actions, TOUCH_ACTION_NONE)) { + return TOUCH_ACTION_NONE; + } + + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + + // pan-x and pan-y can be combined + if (hasPanX && hasPanY) { + return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y; + } + + // pan-x OR pan-y + if (hasPanX || hasPanY) { + return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y; + } + + // manipulation + if (inStr(actions, TOUCH_ACTION_MANIPULATION)) { + return TOUCH_ACTION_MANIPULATION; + } + + return TOUCH_ACTION_AUTO; + } + + /** + * Recognizer flow explained; * + * All recognizers have the initial state of POSSIBLE when a input session starts. + * The definition of a input session is from the first input until the last input, with all it's movement in it. * + * Example session for mouse-input: mousedown -> mousemove -> mouseup + * + * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed + * which determines with state it should be. + * + * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to + * POSSIBLE to give it another change on the next cycle. + * + * Possible + * | + * +-----+---------------+ + * | | + * +-----+-----+ | + * | | | + * Failed Cancelled | + * +-------+------+ + * | | + * Recognized Began + * | + * Changed + * | + * Ended/Recognized + */ + var STATE_POSSIBLE = 1; + var STATE_BEGAN = 2; + var STATE_CHANGED = 4; + var STATE_ENDED = 8; + var STATE_RECOGNIZED = STATE_ENDED; + var STATE_CANCELLED = 16; + var STATE_FAILED = 32; + + /** + * Recognizer + * Every recognizer needs to extend from this class. + * @constructor + * @param {Object} options + */ + function Recognizer(options) { + this.id = uniqueId(); + + this.manager = null; + this.options = merge(options || {}, this.defaults); + + // default is enable true + this.options.enable = ifUndefined(this.options.enable, true); + + this.state = STATE_POSSIBLE; + + this.simultaneous = {}; + this.requireFail = []; + } + + Recognizer.prototype = { + /** + * @virtual + * @type {Object} + */ + defaults: {}, + + /** + * set options + * @param {Object} options + * @return {Recognizer} + */ + set: function(options) { + extend(this.options, options); + + // also update the touchAction, in case something changed about the directions/enabled state + this.manager && this.manager.touchAction.update(); + return this; + }, + + /** + * recognize simultaneous with an other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + recognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) { + return this; + } + + var simultaneous = this.simultaneous; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (!simultaneous[otherRecognizer.id]) { + simultaneous[otherRecognizer.id] = otherRecognizer; + otherRecognizer.recognizeWith(this); + } + return this; + }, + + /** + * drop the simultaneous link. it doesnt remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRecognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + delete this.simultaneous[otherRecognizer.id]; + return this; + }, + + /** + * recognizer can only run when an other is failing + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + requireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) { + return this; + } + + var requireFail = this.requireFail; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (inArray(requireFail, otherRecognizer) === -1) { + requireFail.push(otherRecognizer); + otherRecognizer.requireFailure(this); + } + return this; + }, + + /** + * drop the requireFailure link. it does not remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRequireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + var index = inArray(this.requireFail, otherRecognizer); + if (index > -1) { + this.requireFail.splice(index, 1); + } + return this; + }, + + /** + * has require failures boolean + * @returns {boolean} + */ + hasRequireFailures: function() { + return this.requireFail.length > 0; + }, + + /** + * if the recognizer can recognize simultaneous with an other recognizer + * @param {Recognizer} otherRecognizer + * @returns {Boolean} + */ + canRecognizeWith: function(otherRecognizer) { + return !!this.simultaneous[otherRecognizer.id]; + }, + + /** + * You should use `tryEmit` instead of `emit` directly to check + * that all the needed recognizers has failed before emitting. + * @param {Object} input + */ + emit: function(input) { + var self = this; + var state = this.state; + + function emit(withState) { + self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input); + } + + // 'panstart' and 'panmove' + if (state < STATE_ENDED) { + emit(true); + } + + emit(); // simple 'eventName' events + + // panend and pancancel + if (state >= STATE_ENDED) { + emit(true); + } + }, + + /** + * Check that all the require failure recognizers has failed, + * if true, it emits a gesture event, + * otherwise, setup the state to FAILED. + * @param {Object} input + */ + tryEmit: function(input) { + if (this.canEmit()) { + return this.emit(input); + } + // it's failing anyway + this.state = STATE_FAILED; + }, + + /** + * can we emit? + * @returns {boolean} + */ + canEmit: function() { + var i = 0; + while (i < this.requireFail.length) { + if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) { + return false; + } + i++; + } + return true; + }, + + /** + * update the recognizer + * @param {Object} inputData + */ + recognize: function(inputData) { + // make a new copy of the inputData + // so we can change the inputData without messing up the other recognizers + var inputDataClone = extend({}, inputData); + + // is is enabled and allow recognizing? + if (!boolOrFn(this.options.enable, [this, inputDataClone])) { + this.reset(); + this.state = STATE_FAILED; + return; + } + + // reset when we've reached the end + if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) { + this.state = STATE_POSSIBLE; + } + + this.state = this.process(inputDataClone); + + // the recognizer has recognized a gesture + // so trigger an event + if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) { + this.tryEmit(inputDataClone); + } + }, + + /** + * return the state of the recognizer + * the actual recognizing happens in this method + * @virtual + * @param {Object} inputData + * @returns {Const} STATE + */ + process: function(inputData) { }, // jshint ignore:line + + /** + * return the preferred touch-action + * @virtual + * @returns {Array} + */ + getTouchAction: function() { }, + + /** + * called when the gesture isn't allowed to recognize + * like when another is being recognized or it is disabled + * @virtual + */ + reset: function() { } + }; + + /** + * get a usable string, used as event postfix + * @param {Const} state + * @returns {String} state + */ + function stateStr(state) { + if (state & STATE_CANCELLED) { + return 'cancel'; + } else if (state & STATE_ENDED) { + return 'end'; + } else if (state & STATE_CHANGED) { + return 'move'; + } else if (state & STATE_BEGAN) { + return 'start'; + } + return ''; + } + + /** + * direction cons to string + * @param {Const} direction + * @returns {String} + */ + function directionStr(direction) { + if (direction == DIRECTION_DOWN) { + return 'down'; + } else if (direction == DIRECTION_UP) { + return 'up'; + } else if (direction == DIRECTION_LEFT) { + return 'left'; + } else if (direction == DIRECTION_RIGHT) { + return 'right'; + } + return ''; + } + + /** + * get a recognizer by name if it is bound to a manager + * @param {Recognizer|String} otherRecognizer + * @param {Recognizer} recognizer + * @returns {Recognizer} + */ + function getRecognizerByNameIfManager(otherRecognizer, recognizer) { + var manager = recognizer.manager; + if (manager) { + return manager.get(otherRecognizer); + } + return otherRecognizer; + } + + /** + * This recognizer is just used as a base for the simple attribute recognizers. + * @constructor + * @extends Recognizer + */ + function AttrRecognizer() { + Recognizer.apply(this, arguments); + } + + inherit(AttrRecognizer, Recognizer, { + /** + * @namespace + * @memberof AttrRecognizer + */ + defaults: { + /** + * @type {Number} + * @default 1 + */ + pointers: 1 + }, + + /** + * Used to check if it the recognizer receives valid input, like input.distance > 10. + * @memberof AttrRecognizer + * @param {Object} input + * @returns {Boolean} recognized + */ + attrTest: function(input) { + var optionPointers = this.options.pointers; + return optionPointers === 0 || input.pointers.length === optionPointers; + }, + + /** + * Process the input and return the state for the recognizer + * @memberof AttrRecognizer + * @param {Object} input + * @returns {*} State + */ + process: function(input) { + var state = this.state; + var eventType = input.eventType; + + var isRecognized = state & (STATE_BEGAN | STATE_CHANGED); + var isValid = this.attrTest(input); + + // on cancel input and we've recognized before, return STATE_CANCELLED + if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) { + return state | STATE_CANCELLED; + } else if (isRecognized || isValid) { + if (eventType & INPUT_END) { + return state | STATE_ENDED; + } else if (!(state & STATE_BEGAN)) { + return STATE_BEGAN; + } + return state | STATE_CHANGED; + } + return STATE_FAILED; + } + }); + + /** + * Pan + * Recognized when the pointer is down and moved in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function PanRecognizer() { + AttrRecognizer.apply(this, arguments); + + this.pX = null; + this.pY = null; + } + + inherit(PanRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PanRecognizer + */ + defaults: { + event: 'pan', + threshold: 10, + pointers: 1, + direction: DIRECTION_ALL + }, + + getTouchAction: function() { + var direction = this.options.direction; + var actions = []; + if (direction & DIRECTION_HORIZONTAL) { + actions.push(TOUCH_ACTION_PAN_Y); + } + if (direction & DIRECTION_VERTICAL) { + actions.push(TOUCH_ACTION_PAN_X); + } + return actions; + }, + + directionTest: function(input) { + var options = this.options; + var hasMoved = true; + var distance = input.distance; + var direction = input.direction; + var x = input.deltaX; + var y = input.deltaY; + + // lock to axis? + if (!(direction & options.direction)) { + if (options.direction & DIRECTION_HORIZONTAL) { + direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + hasMoved = x != this.pX; + distance = Math.abs(input.deltaX); + } else { + direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN; + hasMoved = y != this.pY; + distance = Math.abs(input.deltaY); + } + } + input.direction = direction; + return hasMoved && distance > options.threshold && direction & options.direction; + }, + + attrTest: function(input) { + return AttrRecognizer.prototype.attrTest.call(this, input) && + (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input))); + }, + + emit: function(input) { + this.pX = input.deltaX; + this.pY = input.deltaY; + + var direction = directionStr(input.direction); + if (direction) { + this.manager.emit(this.options.event + direction, input); + } + + this._super.emit.call(this, input); + } + }); + + /** + * Pinch + * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out). + * @constructor + * @extends AttrRecognizer + */ + function PinchRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(PinchRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'pinch', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN); + }, + + emit: function(input) { + this._super.emit.call(this, input); + if (input.scale !== 1) { + var inOut = input.scale < 1 ? 'in' : 'out'; + this.manager.emit(this.options.event + inOut, input); + } + } + }); + + /** + * Press + * Recognized when the pointer is down for x ms without any movement. + * @constructor + * @extends Recognizer + */ + function PressRecognizer() { + Recognizer.apply(this, arguments); + + this._timer = null; + this._input = null; + } + + inherit(PressRecognizer, Recognizer, { + /** + * @namespace + * @memberof PressRecognizer + */ + defaults: { + event: 'press', + pointers: 1, + time: 500, // minimal time of the pointer to be pressed + threshold: 5 // a minimal movement is ok, but keep it low + }, + + getTouchAction: function() { + return [TOUCH_ACTION_AUTO]; + }, + + process: function(input) { + var options = this.options; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTime = input.deltaTime > options.time; + + this._input = input; + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) { + this.reset(); + } else if (input.eventType & INPUT_START) { + this.reset(); + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.time, this); + } else if (input.eventType & INPUT_END) { + return STATE_RECOGNIZED; + } + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function(input) { + if (this.state !== STATE_RECOGNIZED) { + return; + } + + if (input && (input.eventType & INPUT_END)) { + this.manager.emit(this.options.event + 'up', input); + } else { + this._input.timeStamp = now(); + this.manager.emit(this.options.event, this._input); + } + } + }); + + /** + * Rotate + * Recognized when two or more pointer are moving in a circular motion. + * @constructor + * @extends AttrRecognizer + */ + function RotateRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(RotateRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof RotateRecognizer + */ + defaults: { + event: 'rotate', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN); + } + }); + + /** + * Swipe + * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function SwipeRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(SwipeRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof SwipeRecognizer + */ + defaults: { + event: 'swipe', + threshold: 10, + velocity: 0.65, + direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL, + pointers: 1 + }, + + getTouchAction: function() { + return PanRecognizer.prototype.getTouchAction.call(this); + }, + + attrTest: function(input) { + var direction = this.options.direction; + var velocity; + + if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) { + velocity = input.velocity; + } else if (direction & DIRECTION_HORIZONTAL) { + velocity = input.velocityX; + } else if (direction & DIRECTION_VERTICAL) { + velocity = input.velocityY; + } + + return this._super.attrTest.call(this, input) && + direction & input.direction && + input.distance > this.options.threshold && + abs(velocity) > this.options.velocity && input.eventType & INPUT_END; + }, + + emit: function(input) { + var direction = directionStr(input.direction); + if (direction) { + this.manager.emit(this.options.event + direction, input); + } + + this.manager.emit(this.options.event, input); + } + }); + + /** + * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur + * between the given interval and position. The delay option can be used to recognize multi-taps without firing + * a single tap. + * + * The eventData from the emitted event contains the property `tapCount`, which contains the amount of + * multi-taps being recognized. + * @constructor + * @extends Recognizer + */ + function TapRecognizer() { + Recognizer.apply(this, arguments); + + // previous time and center, + // used for tap counting + this.pTime = false; + this.pCenter = false; + + this._timer = null; + this._input = null; + this.count = 0; + } + + inherit(TapRecognizer, Recognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'tap', + pointers: 1, + taps: 1, + interval: 300, // max time between the multi-tap taps + time: 250, // max time of the pointer to be down (like finger on the screen) + threshold: 2, // a minimal movement is ok, but keep it low + posThreshold: 10 // a multi-tap can be a bit off the initial position + }, + + getTouchAction: function() { + return [TOUCH_ACTION_MANIPULATION]; + }, + + process: function(input) { + var options = this.options; + + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTouchTime = input.deltaTime < options.time; + + this.reset(); + + if ((input.eventType & INPUT_START) && (this.count === 0)) { + return this.failTimeout(); + } + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (validMovement && validTouchTime && validPointers) { + if (input.eventType != INPUT_END) { + return this.failTimeout(); + } + + var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true; + var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold; + + this.pTime = input.timeStamp; + this.pCenter = input.center; + + if (!validMultiTap || !validInterval) { + this.count = 1; + } else { + this.count += 1; + } + + this._input = input; + + // if tap count matches we have recognized it, + // else it has began recognizing... + var tapCount = this.count % options.taps; + if (tapCount === 0) { + // no failing requirements, immediately trigger the tap event + // or wait as long as the multitap interval to trigger + if (!this.hasRequireFailures()) { + return STATE_RECOGNIZED; + } else { + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.interval, this); + return STATE_BEGAN; + } + } + } + return STATE_FAILED; + }, + + failTimeout: function() { + this._timer = setTimeoutContext(function() { + this.state = STATE_FAILED; + }, this.options.interval, this); + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function() { + if (this.state == STATE_RECOGNIZED ) { + this._input.tapCount = this.count; + this.manager.emit(this.options.event, this._input); + } + } + }); + + /** + * Simple way to create an manager with a default set of recognizers. + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ + function Hammer(element, options) { + options = options || {}; + options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset); + return new Manager(element, options); + } + + /** + * @const {string} + */ + Hammer.VERSION = '2.0.4'; + + /** + * default settings + * @namespace + */ + Hammer.defaults = { + /** + * set if DOM events are being triggered. + * But this is slower and unused by simple implementations, so disabled by default. + * @type {Boolean} + * @default false + */ + domEvents: false, + + /** + * The value for the touchAction property/fallback. + * When set to `compute` it will magically set the correct value based on the added recognizers. + * @type {String} + * @default compute + */ + touchAction: TOUCH_ACTION_COMPUTE, + + /** + * @type {Boolean} + * @default true + */ + enable: true, + + /** + * EXPERIMENTAL FEATURE -- can be removed/changed + * Change the parent input target element. + * If Null, then it is being set the to main element. + * @type {Null|EventTarget} + * @default null + */ + inputTarget: null, + + /** + * force an input class + * @type {Null|Function} + * @default null + */ + inputClass: null, + + /** + * Default recognizer setup when calling `Hammer()` + * When creating a new Manager these will be skipped. + * @type {Array} + */ + preset: [ + // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...] + [RotateRecognizer, { enable: false }], + [PinchRecognizer, { enable: false }, ['rotate']], + [SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }], + [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']], + [TapRecognizer], + [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']], + [PressRecognizer] + ], + + /** + * Some CSS properties can be used to improve the working of Hammer. + * Add them to this method and they will be set when creating a new Manager. + * @namespace + */ + cssProps: { + /** + * Disables text selection to improve the dragging gesture. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userSelect: 'none', + + /** + * Disable the Windows Phone grippers when pressing an element. + * @type {String} + * @default 'none' + */ + touchSelect: 'none', + + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @type {String} + * @default 'none' + */ + touchCallout: 'none', + + /** + * Specifies whether zooming is enabled. Used by IE10> + * @type {String} + * @default 'none' + */ + contentZooming: 'none', + + /** + * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userDrag: 'none', + + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in iOS. This property obeys the alpha value, if specified. + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } + }; + + var STOP = 1; + var FORCED_STOP = 2; + + /** + * Manager + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ + function Manager(element, options) { + options = options || {}; + + this.options = merge(options, Hammer.defaults); + this.options.inputTarget = this.options.inputTarget || element; + + this.handlers = {}; + this.session = {}; + this.recognizers = []; + + this.element = element; + this.input = createInputInstance(this); + this.touchAction = new TouchAction(this, this.options.touchAction); + + toggleCssProps(this, true); + + each(options.recognizers, function(item) { + var recognizer = this.add(new (item[0])(item[1])); + item[2] && recognizer.recognizeWith(item[2]); + item[3] && recognizer.requireFailure(item[3]); + }, this); + } + + Manager.prototype = { + /** + * set options + * @param {Object} options + * @returns {Manager} + */ + set: function(options) { + extend(this.options, options); + + // Options that need a little more setup + if (options.touchAction) { + this.touchAction.update(); + } + if (options.inputTarget) { + // Clean up existing event listeners and reinitialize + this.input.destroy(); + this.input.target = options.inputTarget; + this.input.init(); + } + return this; + }, + + /** + * stop recognizing for this session. + * This session will be discarded, when a new [input]start event is fired. + * When forced, the recognizer cycle is stopped immediately. + * @param {Boolean} [force] + */ + stop: function(force) { + this.session.stopped = force ? FORCED_STOP : STOP; + }, + + /** + * run the recognizers! + * called by the inputHandler function on every movement of the pointers (touches) + * it walks through all the recognizers and tries to detect the gesture that is being made + * @param {Object} inputData + */ + recognize: function(inputData) { + var session = this.session; + if (session.stopped) { + return; + } + + // run the touch-action polyfill + this.touchAction.preventDefaults(inputData); + + var recognizer; + var recognizers = this.recognizers; + + // this holds the recognizer that is being recognized. + // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED + // if no recognizer is detecting a thing, it is set to `null` + var curRecognizer = session.curRecognizer; + + // reset when the last recognizer is recognized + // or when we're in a new session + if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) { + curRecognizer = session.curRecognizer = null; + } + + var i = 0; + while (i < recognizers.length) { + recognizer = recognizers[i]; + + // find out if we are allowed try to recognize the input for this one. + // 1. allow if the session is NOT forced stopped (see the .stop() method) + // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one + // that is being recognized. + // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer. + // this can be setup with the `recognizeWith()` method on the recognizer. + if (session.stopped !== FORCED_STOP && ( // 1 + !curRecognizer || recognizer == curRecognizer || // 2 + recognizer.canRecognizeWith(curRecognizer))) { // 3 + recognizer.recognize(inputData); + } else { + recognizer.reset(); + } + + // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the + // current active recognizer. but only if we don't already have an active recognizer + if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) { + curRecognizer = session.curRecognizer = recognizer; + } + i++; + } + }, + + /** + * get a recognizer by its event name. + * @param {Recognizer|String} recognizer + * @returns {Recognizer|Null} + */ + get: function(recognizer) { + if (recognizer instanceof Recognizer) { + return recognizer; + } + + var recognizers = this.recognizers; + for (var i = 0; i < recognizers.length; i++) { + if (recognizers[i].options.event == recognizer) { + return recognizers[i]; + } + } + return null; + }, + + /** + * add a recognizer to the manager + * existing recognizers with the same event name will be removed + * @param {Recognizer} recognizer + * @returns {Recognizer|Manager} + */ + add: function(recognizer) { + if (invokeArrayArg(recognizer, 'add', this)) { + return this; + } + + // remove existing + var existing = this.get(recognizer.options.event); + if (existing) { + this.remove(existing); + } + + this.recognizers.push(recognizer); + recognizer.manager = this; + + this.touchAction.update(); + return recognizer; + }, + + /** + * remove a recognizer by name or instance + * @param {Recognizer|String} recognizer + * @returns {Manager} + */ + remove: function(recognizer) { + if (invokeArrayArg(recognizer, 'remove', this)) { + return this; + } + + var recognizers = this.recognizers; + recognizer = this.get(recognizer); + recognizers.splice(inArray(recognizers, recognizer), 1); + + this.touchAction.update(); + return this; + }, + + /** + * bind event + * @param {String} events + * @param {Function} handler + * @returns {EventEmitter} this + */ + on: function(events, handler) { + var handlers = this.handlers; + each(splitStr(events), function(event) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + }); + return this; + }, + + /** + * unbind event, leave emit blank to remove all handlers + * @param {String} events + * @param {Function} [handler] + * @returns {EventEmitter} this + */ + off: function(events, handler) { + var handlers = this.handlers; + each(splitStr(events), function(event) { + if (!handler) { + delete handlers[event]; + } else { + handlers[event].splice(inArray(handlers[event], handler), 1); + } + }); + return this; + }, + + /** + * emit event to the listeners + * @param {String} event + * @param {Object} data + */ + emit: function(event, data) { + // we also want to trigger dom events + if (this.options.domEvents) { + triggerDomEvent(event, data); + } + + // no handlers, so skip it all + var handlers = this.handlers[event] && this.handlers[event].slice(); + if (!handlers || !handlers.length) { + return; + } + + data.type = event; + data.preventDefault = function() { + data.srcEvent.preventDefault(); + }; + + var i = 0; + while (i < handlers.length) { + handlers[i](data); + i++; + } + }, + + /** + * destroy the manager and unbinds all events + * it doesn't unbind dom events, that is the user own responsibility + */ + destroy: function() { + this.element && toggleCssProps(this, false); + + this.handlers = {}; + this.session = {}; + this.input.destroy(); + this.element = null; + } + }; + + /** + * add/remove the css properties as defined in manager.options.cssProps + * @param {Manager} manager + * @param {Boolean} add + */ + function toggleCssProps(manager, add) { + var element = manager.element; + each(manager.options.cssProps, function(value, name) { + element.style[prefixed(element.style, name)] = add ? value : ''; + }); + } + + /** + * trigger dom event + * @param {String} event + * @param {Object} data + */ + function triggerDomEvent(event, data) { + var gestureEvent = document.createEvent('Event'); + gestureEvent.initEvent(event, true, true); + gestureEvent.gesture = data; + data.target.dispatchEvent(gestureEvent); + } + + extend(Hammer, { + INPUT_START: INPUT_START, + INPUT_MOVE: INPUT_MOVE, + INPUT_END: INPUT_END, + INPUT_CANCEL: INPUT_CANCEL, + + STATE_POSSIBLE: STATE_POSSIBLE, + STATE_BEGAN: STATE_BEGAN, + STATE_CHANGED: STATE_CHANGED, + STATE_ENDED: STATE_ENDED, + STATE_RECOGNIZED: STATE_RECOGNIZED, + STATE_CANCELLED: STATE_CANCELLED, + STATE_FAILED: STATE_FAILED, + + DIRECTION_NONE: DIRECTION_NONE, + DIRECTION_LEFT: DIRECTION_LEFT, + DIRECTION_RIGHT: DIRECTION_RIGHT, + DIRECTION_UP: DIRECTION_UP, + DIRECTION_DOWN: DIRECTION_DOWN, + DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL: DIRECTION_VERTICAL, + DIRECTION_ALL: DIRECTION_ALL, + + Manager: Manager, + Input: Input, + TouchAction: TouchAction, + + TouchInput: TouchInput, + MouseInput: MouseInput, + PointerEventInput: PointerEventInput, + TouchMouseInput: TouchMouseInput, + SingleTouchInput: SingleTouchInput, + + Recognizer: Recognizer, + AttrRecognizer: AttrRecognizer, + Tap: TapRecognizer, + Pan: PanRecognizer, + Swipe: SwipeRecognizer, + Pinch: PinchRecognizer, + Rotate: RotateRecognizer, + Press: PressRecognizer, + + on: addEventListeners, + off: removeEventListeners, + each: each, + merge: merge, + extend: extend, + inherit: inherit, + bindFn: bindFn, + prefixed: prefixed + }); + + if (typeof undefined$1 == TYPE_FUNCTION && undefined$1.amd) { + undefined$1(function() { + return Hammer; + }); + } else if ( module.exports) { + module.exports = Hammer; + } else { + window[exportName] = Hammer; + } + + })(window, document, 'Hammer'); + }); + + var nextId$1 = 1; + var idProperty = 'MarzipanoHammerElementId'; + function getKeyForElementAndType(element, type) { + if (!element[idProperty]) { + element[idProperty] = nextId$1++; + } + return type + element[idProperty]; + } + + + /** + * @class HammerGestures + * @classdesc + * + * Manages Hammer.js instances. One instance is created for each combination of + * DOM element and pointer type. + */ + function HammerGestures() { + this._managers = {}; + this._refCount = {}; + } + + + HammerGestures.prototype.get = function(element, type) { + var key = getKeyForElementAndType(element, type); + if (!this._managers[key]) { + this._managers[key] = this._createManager(element, type); + this._refCount[key] = 0; + } + this._refCount[key]++; + return new HammerGesturesHandle(this, this._managers[key], element, type); + }; + + + HammerGestures.prototype._createManager = function(element, type) { + var manager = new hammer.Manager(element); + + // Managers are created with different parameters for different pointer + // types. + if (type === 'mouse') { + manager.add(new hammer.Pan({ direction: hammer.DIRECTION_ALL, threshold: 0 })); + } + else if (type === 'touch' || type === 'pen' || type === 'kinect') { + // On touch one wants to have both panning and pinching. The panning + // recognizer needs a threshold to allow the pinch to be recognized. + manager.add(new hammer.Pan({ direction: hammer.DIRECTION_ALL, threshold: 20, pointers: 1 })); + if (!(es5.msie && parseFloat(es5.version) < 10)) { + // Do not add pinch to IE8-9 to prevent focus issues which prevent wheel scrolling from + // working. + manager.add(new hammer.Pinch()); + } + } + + return manager; + }; + + + HammerGestures.prototype._releaseHandle = function(element, type) { + var key = getKeyForElementAndType(element, type); + if (this._refCount[key]) { + this._refCount[key]--; + if (!this._refCount[key]) { + this._managers[key].destroy(); + delete this._managers[key]; + delete this._refCount[key]; + } + } + }; + + + function HammerGesturesHandle(hammerGestures, manager, element, type) { + this._manager = manager; + this._element = element; + this._type = type; + this._hammerGestures = hammerGestures; + this._eventHandlers = []; + } + + + HammerGesturesHandle.prototype.on = function(events, handler) { + var type = this._type; + var handlerFilteredEvents = function(e) { + if (type === e.pointerType) { + handler(e); + } + }; + + this._eventHandlers.push({ events: events, handler: handlerFilteredEvents }); + this._manager.on(events, handlerFilteredEvents); + }; + + + HammerGesturesHandle.prototype.release = function() { + for (var i = 0; i < this._eventHandlers.length; i++) { + var eventHandler = this._eventHandlers[i]; + this._manager.off(eventHandler.events, eventHandler.handler); + } + + this._hammerGestures._releaseHandle(this._element, this._type); + this._manager = null; + this._element = null; + this._type = null; + this._hammerGestures = null; + }; + + + HammerGesturesHandle.prototype.manager = function() { + return this._manager; + }; + + + var HammerGestures_1 = new HammerGestures(); + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function maxFriction(friction, velocityX, velocityY, maxFrictionTime, result) { + var velocity = Math.sqrt(Math.pow(velocityX,2) + Math.pow(velocityY,2)); + friction = Math.max(friction, velocity/maxFrictionTime); + changeVectorNorm(velocityX, velocityY, friction, result); + result[0] = Math.abs(result[0]); + result[1] = Math.abs(result[1]); + } + + function changeVectorNorm(x, y, n, result) { + var theta = Math.atan(y/x); + result[0] = n * Math.cos(theta); + result[1] = n * Math.sin(theta); + } + + var util = { + maxFriction: maxFriction, + changeVectorNorm: changeVectorNorm + }; + + var maxFriction$1 = util.maxFriction; + + + var defaultOptions$1 = { + friction: 6, + maxFrictionTime: 0.3 + }; + + var debug$3 = typeof MARZIPANODEBUG !== 'undefined' && MARZIPANODEBUG.controls; + + /** + * @class DragControlMethod + * @implements ControlMethod + * @classdesc + * + * Controls the view by clicking/tapping and dragging. + * + * @param {Element} element Element to listen for events. + * @param {string} pointerType Which Hammer.js pointer type to use (e.g. + * `mouse` or `touch`). + * @param {Object} opts + * @param {number} opts.friction + * @param {number} opts.maxFrictionTime + */ + function DragControlMethod(element, pointerType, opts) { + this._element = element; + + this._opts = defaults_1(opts || {}, defaultOptions$1); + + this._startEvent = null; + this._lastEvent = null; + + this._active = false; + + this._dynamics = { + x: new Dynamics_1(), + y: new Dynamics_1() + }; + + this._hammer = HammerGestures_1.get(element, pointerType); + + this._hammer.on("hammer.input", this._handleHammerEvent.bind(this)); + + this._hammer.on('panstart', this._handleStart.bind(this)); + this._hammer.on('panmove', this._handleMove.bind(this)); + this._hammer.on('panend', this._handleEnd.bind(this)); + this._hammer.on('pancancel', this._handleEnd.bind(this)); + + } + + minimalEventEmitter(DragControlMethod); + + /** + * Destructor. + */ + DragControlMethod.prototype.destroy = function() { + this._hammer.release(); + clearOwnProperties_1(this); + }; + + DragControlMethod.prototype._handleHammerEvent = function(e) { + if (e.isFirst) { + if (debug$3 && this._active) { + throw new Error('DragControlMethod active detected when already active'); + } + this._active = true; + this.emit('active'); + } + if (e.isFinal) { + if (debug$3 && !this._active) { + throw new Error('DragControlMethod inactive detected when already inactive'); + } + this._active = false; + this.emit('inactive'); + } + }; + + DragControlMethod.prototype._handleStart = function(e) { + // Prevent this event from dragging other DOM elements, causing + // unexpected behavior on Chrome. + e.preventDefault(); + + this._startEvent = e; + }; + + + DragControlMethod.prototype._handleMove = function(e) { + // Prevent this event from dragging other DOM elements, causing + // unexpected behavior on Chrome. + e.preventDefault(); + + if (this._startEvent) { + this._updateDynamicsMove(e); + this.emit('parameterDynamics', 'axisScaledX', this._dynamics.x); + this.emit('parameterDynamics', 'axisScaledY', this._dynamics.y); + } + }; + + + DragControlMethod.prototype._handleEnd = function(e) { + // Prevent this event from dragging other DOM elements, causing + // unexpected behavior on Chrome. + e.preventDefault(); + + if (this._startEvent) { + this._updateDynamicsRelease(e); + this.emit('parameterDynamics', 'axisScaledX', this._dynamics.x); + this.emit('parameterDynamics', 'axisScaledY', this._dynamics.y); + } + + this._startEvent = false; + this._lastEvent = false; + }; + + + DragControlMethod.prototype._updateDynamicsMove = function(e) { + var x = e.deltaX; + var y = e.deltaY; + + // When a second finger touches the screen, panstart sometimes has a large + // offset at start; subtract that offset to prevent a sudden jump. + var eventToSubtract = this._lastEvent || this._startEvent; + + if (eventToSubtract) { + x -= eventToSubtract.deltaX; + y -= eventToSubtract.deltaY; + } + + var elementRect = this._element.getBoundingClientRect(); + var width = elementRect.right - elementRect.left; + var height = elementRect.bottom - elementRect.top; + + x /= width; + y /= height; + + this._dynamics.x.reset(); + this._dynamics.y.reset(); + this._dynamics.x.offset = -x; + this._dynamics.y.offset = -y; + + this._lastEvent = e; + }; + + + var tmpReleaseFriction = [ null, null ]; + DragControlMethod.prototype._updateDynamicsRelease = function(e) { + var elementRect = this._element.getBoundingClientRect(); + var width = elementRect.right - elementRect.left; + var height = elementRect.bottom - elementRect.top; + + var x = 1000 * e.velocityX / width; + var y = 1000 * e.velocityY / height; + + this._dynamics.x.reset(); + this._dynamics.y.reset(); + this._dynamics.x.velocity = x; + this._dynamics.y.velocity = y; + + maxFriction$1(this._opts.friction, this._dynamics.x.velocity, this._dynamics.y.velocity, this._opts.maxFrictionTime, tmpReleaseFriction); + this._dynamics.x.friction = tmpReleaseFriction[0]; + this._dynamics.y.friction = tmpReleaseFriction[1]; + }; + + + var Drag = DragControlMethod; + + var maxFriction$2 = util.maxFriction; + + + + var defaultOptions$2 = { + speed: 8, + friction: 6, + maxFrictionTime: 0.3 + }; + + + /** + * @class QtvrControlMethod + * @implements ControlMethod + * @classdesc + * + * Controls the view by holding the mouse button down and moving it. + * Also known as "QTVR" control mode. + * + * @param {Element} element Element to listen for events. + * @param {string} pointerType Which Hammer.js pointer type to use (e.g. + * `mouse` or `touch`). + * @param {Object} opts + * @param {number} opts.speed + * @param {number} opts.friction + * @param {number} opts.maxFrictionTime + */ + // TODO: allow speed not change linearly with distance to click spot. + // Quadratic or other would allow a larger speed range. + function QtvrControlMethod(element, pointerType, opts) { + this._element = element; + + this._opts = defaults_1(opts || {}, defaultOptions$2); + + this._active = false; + + this._hammer = HammerGestures_1.get(element, pointerType); + + this._dynamics = { + x: new Dynamics_1(), + y: new Dynamics_1() + }; + + this._hammer.on('panstart', this._handleStart.bind(this)); + this._hammer.on('panmove', this._handleMove.bind(this)); + this._hammer.on('panend', this._handleRelease.bind(this)); + this._hammer.on('pancancel', this._handleRelease.bind(this)); + } + + minimalEventEmitter(QtvrControlMethod); + + /** + * Destructor. + */ + QtvrControlMethod.prototype.destroy = function() { + this._hammer.release(); + clearOwnProperties_1(this); + }; + + + QtvrControlMethod.prototype._handleStart = function(e) { + // Prevent event dragging other DOM elements and causing strange behavior on Chrome + e.preventDefault(); + + if (!this._active) { + this._active = true; + this.emit('active'); + } + }; + + + QtvrControlMethod.prototype._handleMove = function(e) { + // Prevent event dragging other DOM elements and causing strange behavior on Chrome + e.preventDefault(); + + this._updateDynamics(e, false); + }; + + + QtvrControlMethod.prototype._handleRelease = function(e) { + // Prevent event dragging other DOM elements and causing strange behavior on Chrome + e.preventDefault(); + + this._updateDynamics(e, true); + + if (this._active) { + this._active = false; + this.emit('inactive'); + } + }; + + + var tmpReleaseFriction$1 = [ null, null ]; + QtvrControlMethod.prototype._updateDynamics = function(e, release) { + var elementRect = this._element.getBoundingClientRect(); + var width = elementRect.right - elementRect.left; + var height = elementRect.bottom - elementRect.top; + var maxDim = Math.max(width, height); + + var x = e.deltaX / maxDim * this._opts.speed; + var y = e.deltaY / maxDim * this._opts.speed; + + this._dynamics.x.reset(); + this._dynamics.y.reset(); + this._dynamics.x.velocity = x; + this._dynamics.y.velocity = y; + + if (release) { + maxFriction$2(this._opts.friction, this._dynamics.x.velocity, this._dynamics.y.velocity, this._opts.maxFrictionTime, tmpReleaseFriction$1); + this._dynamics.x.friction = tmpReleaseFriction$1[0]; + this._dynamics.y.friction = tmpReleaseFriction$1[1]; + } + + this.emit('parameterDynamics', 'x', this._dynamics.x); + this.emit('parameterDynamics', 'y', this._dynamics.y); + }; + + + var Qtvr = QtvrControlMethod; + + // Cross-browser mouse wheel event listener. + // Adapted from: https://developer.mozilla.org/en-US/docs/Web/Events/wheel + // This version requires eventShim. + function WheelListener(elem, callback, useCapture) { + var eventName = getEventName(); + + if (eventName === 'wheel') { + this._fun = callback; + this._elem = elem; + this._elem.addEventListener('wheel', this._fun, useCapture); + } else if (eventName === 'mousewheel') { + this._fun = fallbackHandler(callback); + this._elem = elem; + this._elem.addEventListener('mousewheel', this._fun, useCapture); + } else { + throw new Error('Browser does not support mouse wheel events'); + } + } + + /** + * Destructor. + */ + WheelListener.prototype.destroy = function() { + this._elem.removeEventListener(getEventName(), this._fun); + clearOwnProperties_1(this); + }; + + function fallbackHandler(callback) { + return function handleWheelEvent(originalEvent) { + if (!originalEvent) { + originalEvent = window.event; + } + + // Create a normalized event object. + var event = { + originalEvent: originalEvent, + target: originalEvent.target || originalEvent.srcElement, + type: "wheel", + deltaMode: 1, + deltaX: 0, + deltaZ: 0, + timeStamp: originalEvent.timeStamp || Date.now(), + preventDefault: originalEvent.preventDefault.bind(originalEvent) + }; + + // Calculate deltaY. + event.deltaY = - 1/40 * originalEvent.wheelDelta; + if (originalEvent.wheelDeltaX) { + // Calculate deltaX. + event.deltaX = - 1/40 * originalEvent.wheelDeltaX; + } + + // Fire the callback. + return callback(event); + }; + } + + // Detect the supported wheel event name and cache the result. + var eventName; + function getEventName() { + if (eventName !== undefined) { + return eventName; + } + if ('onwheel' in document.createElement('div')) { + // Modern browsers support 'wheel'. + return (eventName = 'wheel'); + } else if (document.onmousewheel !== undefined) { + // Webkit and IE support at least 'mousewheel'. + return (eventName = 'mousewheel'); + } else { + return (eventName = null); + } + } + + var WheelListener_1 = WheelListener; + + var defaultOptions$3 = { + frictionTime: 0.2, + zoomDelta: 0.001 + }; + + /** + * @class ScrollZoomControlMethod + * @implements ControlMethod + * @classdesc + * + * Controls the fov/zoom through the mouse wheel. + * + * @param {Element} element Element to listen for events. + * @param {Object} opts + * @param {number} [opts.frictionTime=0.2] + * @param {number} [opts.zoomDelta=0.001] + */ + function ScrollZoomControlMethod(element, opts) { + this._opts = defaults_1(opts || {}, defaultOptions$3); + + this._dynamics = new Dynamics_1(); + + this._eventList = []; + + var fn = this._opts.frictionTime ? this.withSmoothing : this.withoutSmoothing; + this._wheelListener = new WheelListener_1(element, fn.bind(this)); + } + + minimalEventEmitter(ScrollZoomControlMethod); + + /** + * Destructor. + */ + ScrollZoomControlMethod.prototype.destroy = function() { + this._wheelListener.destroy(); + clearOwnProperties_1(this); + }; + + + ScrollZoomControlMethod.prototype.withoutSmoothing = function(e) { + this._dynamics.offset = wheelEventDelta(e) * this._opts.zoomDelta; + this.emit('parameterDynamics', 'zoom', this._dynamics); + + e.preventDefault(); + + this.emit('active'); + this.emit('inactive'); + }; + + + ScrollZoomControlMethod.prototype.withSmoothing = function(e) { + var currentTime = e.timeStamp; + + // Record event. + this._eventList.push(e); + + // Remove events whose smoothing has already expired. + while (this._eventList[0].timeStamp < currentTime - this._opts.frictionTime*1000) { + this._eventList.shift(0); + } + + // Get the current velocity from the recorded events. + // Each wheel movement causes a velocity of change/frictionTime during frictionTime. + var velocity = 0; + for (var i = 0; i < this._eventList.length; i++) { + var zoomChangeFromEvent = wheelEventDelta(this._eventList[i]) * this._opts.zoomDelta; + velocity += zoomChangeFromEvent / this._opts.frictionTime; + } + + this._dynamics.velocity = velocity; + this._dynamics.friction = Math.abs(velocity) / this._opts.frictionTime; + + this.emit('parameterDynamics', 'zoom', this._dynamics); + + e.preventDefault(); + + this.emit('active'); + this.emit('inactive'); + }; + + + function wheelEventDelta(e) { + var multiplier = e.deltaMode == 1 ? 20 : 1; + return e.deltaY * multiplier; + } + + + var ScrollZoom = ScrollZoomControlMethod; + + /** + * @class PinchZoomControlMethod + * @implements ControlMethod + * @classdesc + * + * Control the view fov/zoom by pinching with two fingers. + * + * @param {Element} element Element to listen for events. + * @param {string} pointerType Which Hammer.js pointer type to use + * @param {Object} opts + */ + function PinchZoomControlMethod(element, pointerType, opts) { + this._hammer = HammerGestures_1.get(element, pointerType); + + this._lastEvent = null; + + this._active = false; + + this._dynamics = new Dynamics_1(); + + this._hammer.on('pinchstart', this._handleStart.bind(this)); + this._hammer.on('pinch', this._handleEvent.bind(this)); + this._hammer.on('pinchend', this._handleEnd.bind(this)); + this._hammer.on('pinchcancel', this._handleEnd.bind(this)); + } + + minimalEventEmitter(PinchZoomControlMethod); + + /** + * Destructor. + */ + PinchZoomControlMethod.prototype.destroy = function() { + this._hammer.release(); + clearOwnProperties_1(this); + }; + + + PinchZoomControlMethod.prototype._handleStart = function() { + if (!this._active) { + this._active = true; + this.emit('active'); + } + }; + + + PinchZoomControlMethod.prototype._handleEnd = function() { + this._lastEvent = null; + + if (this._active) { + this._active = false; + this.emit('inactive'); + } + }; + + + PinchZoomControlMethod.prototype._handleEvent = function(e) { + var scale = e.scale; + + if (this._lastEvent) { + scale /= this._lastEvent.scale; + } + + this._dynamics.offset = (scale - 1) * -1; + this.emit('parameterDynamics', 'zoom', this._dynamics); + + this._lastEvent = e; + }; + + + var PinchZoom = PinchZoomControlMethod; + + /** + * @class VelocityControlMethod + * @implements ControlMethod + * @classdesc + * + * Sets the velocity and friction of a single parameter. + * + * The user should emit 'active' and 'inactive' events if required. + * + * @param {String} parameter The parameter to be controlled (e.g. `x`, `y` or `zoom`) + */ + function VelocityControlMethod(parameter) { + if(!parameter) { + throw new Error("VelocityControlMethod: parameter must be defined"); + } + + this._parameter = parameter; + this._dynamics = new Dynamics_1(); + } + minimalEventEmitter(VelocityControlMethod); + + /** + * Destructor. + */ + VelocityControlMethod.prototype.destroy = function() { + clearOwnProperties_1(this); + }; + + /** + * Set the parameter's velocity. + * @param {Number} velocity + */ + VelocityControlMethod.prototype.setVelocity = function(velocity) { + this._dynamics.velocity = velocity; + this.emit('parameterDynamics', this._parameter, this._dynamics); + }; + + /** + * Set the parameter's friction. + * @param {Number} friction + */ + VelocityControlMethod.prototype.setFriction = function(friction) { + this._dynamics.friction = friction; + this.emit('parameterDynamics', this._parameter, this._dynamics); + }; + + var Velocity = VelocityControlMethod; + + /** + * @class ElementPressControlMethod + * @implements ControlMethod + * @classdesc + * + * Sets the velocity and friction of a single parameter by pressing and + * unpressing a DOM element. + * + * @param {Element} element Element which activates the method when pressed + * @param {string} parameter The parameter to be controlled (e.g. `x`, `y` or `zoom`) + * @param {number} velocity Velocity at which the parameter changes. Use a + * negative number for opposite direction + * @param {number} friction Friction at which the parameter stops + */ + function ElementPressControlMethod(element, parameter, velocity, friction) { + if(!element) { + throw new Error("ElementPressControlMethod: element must be defined"); + } + if(!parameter) { + throw new Error("ElementPressControlMethod: parameter must be defined"); + } + if(!velocity) { + throw new Error("ElementPressControlMethod: velocity must be defined"); + } + if(!friction) { + throw new Error("ElementPressControlMethod: friction must be defined"); + } + + this._element = element; + + this._pressHandler = this._handlePress.bind(this); + this._releaseHandler = this._handleRelease.bind(this); + + element.addEventListener('mousedown', this._pressHandler); + element.addEventListener('mouseup', this._releaseHandler); + element.addEventListener('mouseleave', this._releaseHandler); + element.addEventListener('touchstart', this._pressHandler); + element.addEventListener('touchmove', this._releaseHandler); + element.addEventListener('touchend', this._releaseHandler); + + this._parameter = parameter; + this._velocity = velocity; + this._friction = friction; + this._dynamics = new Dynamics_1(); + + this._pressing = false; + } + minimalEventEmitter(ElementPressControlMethod); + + /** + * Destructor. + */ + ElementPressControlMethod.prototype.destroy = function() { + this._element.removeEventListener('mousedown', this._pressHandler); + this._element.removeEventListener('mouseup', this._releaseHandler); + this._element.removeEventListener('mouseleave', this._releaseHandler); + this._element.removeEventListener('touchstart', this._pressHandler); + this._element.removeEventListener('touchmove', this._releaseHandler); + this._element.removeEventListener('touchend', this._releaseHandler); + clearOwnProperties_1(this); + }; + + ElementPressControlMethod.prototype._handlePress = function() { + this._pressing = true; + + this._dynamics.velocity = this._velocity; + this._dynamics.friction = 0; + this.emit('parameterDynamics', this._parameter, this._dynamics); + this.emit('active'); + }; + + ElementPressControlMethod.prototype._handleRelease = function() { + if(this._pressing) { + this._dynamics.friction = this._friction; + this.emit('parameterDynamics', this._parameter, this._dynamics); + this.emit('inactive'); + } + + this._pressing = false; + }; + + var ElementPress = ElementPressControlMethod; + + /** + * @class ControlComposer + * @classdesc + * + * Combines changes in parameters triggered by multiple {@link ControlMethod} + * instances. + * + * @listens ControlMethod#parameterDynamics + */ + function ControlComposer(opts) { + opts = opts || {}; + + this._methods = []; + + this._parameters = [ 'x' ,'y', 'axisScaledX', 'axisScaledY', 'zoom', 'yaw', 'pitch', 'roll' ]; + + this._now = opts.nowForTesting || now; + + this._composedOffsets = { }; + + this._composeReturn = { offsets: this._composedOffsets, changing: null }; + } + + minimalEventEmitter(ControlComposer); + + + ControlComposer.prototype.add = function(instance) { + if (this.has(instance)) { + return; + } + + var dynamics = {}; + this._parameters.forEach(function(parameter) { + dynamics[parameter] = { + dynamics: new Dynamics_1(), + time: null + }; + }); + + var parameterDynamicsHandler = this._updateDynamics.bind(this, dynamics); + + var method = { + instance: instance, + dynamics: dynamics, + parameterDynamicsHandler: parameterDynamicsHandler + }; + + instance.addEventListener('parameterDynamics', parameterDynamicsHandler); + + this._methods.push(method); + }; + + + ControlComposer.prototype.remove = function(instance) { + var index = this._indexOfInstance(instance); + if (index >= 0) { + var method = this._methods.splice(index, 1)[0]; + method.instance.removeEventListener('parameterDynamics', method.parameterDynamicsHandler); + } + }; + + + ControlComposer.prototype.has = function(instance) { + return this._indexOfInstance(instance) >= 0; + }; + + + ControlComposer.prototype._indexOfInstance = function(instance) { + for (var i = 0; i < this._methods.length; i++) { + if (this._methods[i].instance === instance) { + return i; + } + } + return -1; + }; + + + ControlComposer.prototype.list = function() { + var instances = []; + for (var i = 0; i < this._methods.length; i++) { + instances.push(this._methods[i].instance); + } + return instances; + }; + + + ControlComposer.prototype._updateDynamics = function(storedDynamics, parameter, dynamics) { + var parameterDynamics = storedDynamics[parameter]; + + if (!parameterDynamics) { + throw new Error("Unknown control parameter " + parameter); + } + + var newTime = this._now(); + parameterDynamics.dynamics.update(dynamics, (newTime - parameterDynamics.time)/1000); + parameterDynamics.time = newTime; + + this.emit('change'); + }; + + + ControlComposer.prototype._resetComposedOffsets = function() { + for (var i = 0; i < this._parameters.length; i++) { + this._composedOffsets[this._parameters[i]] = 0; + } + }; + + + ControlComposer.prototype.offsets = function() { + var parameter; + var changing = false; + + var currentTime = this._now(); + + this._resetComposedOffsets(); + + for (var i = 0; i < this._methods.length; i++) { + var methodDynamics = this._methods[i].dynamics; + + for (var p = 0; p < this._parameters.length; p++) { + parameter = this._parameters[p]; + var parameterDynamics = methodDynamics[parameter]; + var dynamics = parameterDynamics.dynamics; + + + // Add offset to composed offset + if (dynamics.offset != null) { + this._composedOffsets[parameter] += dynamics.offset; + // Reset offset + dynamics.offset = null; + } + + // Calculate offset from velocity and add it + var elapsed = (currentTime - parameterDynamics.time)/1000; + var offsetFromVelocity = dynamics.offsetFromVelocity(elapsed); + + if(offsetFromVelocity) { + this._composedOffsets[parameter] += offsetFromVelocity; + } + + // Update velocity on dynamics + var currentVelocity = dynamics.velocityAfter(elapsed); + dynamics.velocity = currentVelocity; + + // If there is still a velocity, set changing + if(currentVelocity) { + changing = true; + } + + parameterDynamics.time = currentTime; + } + } + + this._composeReturn.changing = changing; + return this._composeReturn; + }; + + + ControlComposer.prototype.destroy = function() { + var instances = this.list(); + for (var i = 0; i < instances.length; i++) { + this.remove(instances[i]); + } + + clearOwnProperties_1(this); + }; + + + var Composer = ControlComposer; + + var debug$4 = typeof MARZIPANODEBUG !== 'undefined' && MARZIPANODEBUG.controls; + + /** + * @class Controls + * @classdesc + * + * Set of controls which affect a view (e.g. keyboard, touch) + * + * {@link ControlMethod} instances can be registered on this class. The methods + * are then combined to calculate the final parameters to change the {@link View}. + * + * Controls is attached to a {@link RenderLoop}. Currently it affects the + * {@link view} of all {@link Layer} on the {@link Stage} of the + * {@link RenderLoop} it is attached to. A more flexible API may be provided + * in the future. + * + * The ControlMethod instances are registered with an id and may be enabled, + * disabled and unregistered using that id. The whole Control can also be + * enabled or disabled. + * + */ + function Controls(opts) { + opts = opts || {}; + + this._methods = {}; + this._methodGroups = {}; + this._composer = new Composer(); + + // Whether the controls are enabled. + this._enabled = (opts && opts.enabled) ? !!opts.enabled : true; + + // How many control methods are enabled and in the active state. + this._activeCount = 0; + + this.updatedViews_ = []; + + this._attachedRenderLoop = null; + } + + minimalEventEmitter(Controls); + + /** + * Destructor. + */ + Controls.prototype.destroy = function() { + this.detach(); + this._composer.destroy(); + clearOwnProperties_1(this); + }; + + + /** + * @return {ControlMethod[]} List of registered @{link ControlMethod instances} + */ + Controls.prototype.methods = function() { + var obj = {}; + for (var id in this._methods) { + obj[id] = this._methods[id]; + } + return obj; + }; + + /** + * @param {String} id + * @return {ControlMethod} + */ + Controls.prototype.method = function(id) { + return this._methods[id]; + }; + + /** + * @param {String} id + * @param {ControlMethod} instance + * @param {Boolean} [enable=false] + */ + Controls.prototype.registerMethod = function(id, instance, enable) { + if (this._methods[id]) { + throw new Error('Control method already registered with id ' + id); + } + + this._methods[id] = { + instance: instance, + enabled: false, + active: false, + activeHandler: this._handleActive.bind(this, id), + inactiveHandler: this._handleInactive.bind(this, id) + }; + + if(enable) { + this.enableMethod(id, instance); + } + }; + + + /** + * @param {String} id + */ + Controls.prototype.unregisterMethod = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('No control method registered with id ' + id); + } + if (method.enabled) { + this.disableMethod(id); + } + delete this._methods[id]; + }; + + /** + * @param {String} id + */ + Controls.prototype.enableMethod = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('No control method registered with id ' + id); + } + if (method.enabled) { + return; + } + method.enabled = true; + if (method.active) { + this._incrementActiveCount(); + } + this._listen(id); + this._updateComposer(); + this.emit('methodEnabled', id); + }; + + + /** + * @param {String} id + */ + Controls.prototype.disableMethod = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('No control method registered with id ' + id); + } + if (!method.enabled) { + return; + } + method.enabled = false; + if (method.active) { + this._decrementActiveCount(); + } + this._unlisten(id); + this._updateComposer(); + this.emit('methodDisabled', id); + }; + + + /** + * Create a method group, which can be used to more conveniently enable or + * disable several control methods at once + * @param {String} groupId + * @param {String[]} methodIds + */ + Controls.prototype.addMethodGroup = function(groupId, methodIds) { + this._methodGroups[groupId] = methodIds; + }; + + /** + * @param {String} groupId + */ + Controls.prototype.removeMethodGroup = function(id) { + delete this._methodGroups[id]; + }; + + /** + * @return {ControlMethodGroup[]} List of control method groups + */ + Controls.prototype.methodGroups = function() { + var obj = {}; + for (var id in this._methodGroups) { + obj[id] = this._methodGroups[id]; + } + return obj; + }; + + /** + * Enables all the control methods in the group + * @param {String} groupId + */ + Controls.prototype.enableMethodGroup = function(id) { + var self = this; + self._methodGroups[id].forEach(function(methodId) { + self.enableMethod(methodId); + }); + }; + + /** + * Disables all the control methods in the group + * @param {String} groupId + */ + Controls.prototype.disableMethodGroup = function(id) { + var self = this; + self._methodGroups[id].forEach(function(methodId) { + self.disableMethod(methodId); + }); + }; + + /** + * @returns {Boolean} + */ + Controls.prototype.enabled = function() { + return this._enabled; + }; + + /** + * Enables the controls + */ + Controls.prototype.enable = function() { + if (this._enabled) { + return; + } + this._enabled = true; + if (this._activeCount > 0) { + this.emit('active'); + } + this.emit('enabled'); + this._updateComposer(); + }; + + + /** + * Disables the controls + */ + Controls.prototype.disable = function() { + if (!this._enabled) { + return; + } + this._enabled = false; + if (this._activeCount > 0) { + this.emit('inactive'); + } + this.emit('disabled'); + this._updateComposer(); + }; + + + + /** + * Attaches the controls to a {@link RenderLoop}. The RenderLoop will be woken + * up when the controls are activated + * + * @param {RenderLoop} + */ + Controls.prototype.attach = function(renderLoop) { + if (this._attachedRenderLoop) { + this.detach(); + } + + this._attachedRenderLoop = renderLoop; + this._beforeRenderHandler = this._updateViewsWithControls.bind(this); + this._changeHandler = renderLoop.renderOnNextFrame.bind(renderLoop); + + this._attachedRenderLoop.addEventListener('beforeRender', this._beforeRenderHandler); + this._composer.addEventListener('change', this._changeHandler); + }; + + /** + * Detaches the controls + */ + Controls.prototype.detach = function() { + if (!this._attachedRenderLoop) { + return; + } + + this._attachedRenderLoop.removeEventListener('beforeRender', this._beforeRenderHandler); + this._composer.removeEventListener('change', this._changeHandler); + + this._beforeRenderHandler = null; + this._changeHandler = null; + this._attachedRenderLoop = null; + }; + + /** + * @param {Boolean} + */ + Controls.prototype.attached = function() { + return this._attachedRenderLoop != null; + }; + + + Controls.prototype._listen = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('Bad method id'); + } + method.instance.addEventListener('active', method.activeHandler); + method.instance.addEventListener('inactive', method.inactiveHandler); + }; + + + Controls.prototype._unlisten = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('Bad method id'); + } + method.instance.removeEventListener('active', method.activeHandler); + method.instance.removeEventListener('inactive', method.inactiveHandler); + }; + + + Controls.prototype._handleActive = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('Bad method id'); + } + if (!method.enabled) { + throw new Error('Should not receive event from disabled control method'); + } + if (!method.active) { + method.active = true; + this._incrementActiveCount(); + } + }; + + + Controls.prototype._handleInactive = function(id) { + var method = this._methods[id]; + if (!method) { + throw new Error('Bad method id'); + } + if (!method.enabled) { + throw new Error('Should not receive event from disabled control method'); + } + if (method.active) { + method.active = false; + this._decrementActiveCount(); + } + }; + + + Controls.prototype._incrementActiveCount = function() { + this._activeCount++; + if (debug$4) { + this._checkActiveCount(); + } + if (this._enabled && this._activeCount === 1) { + this.emit('active'); + } + }; + + + Controls.prototype._decrementActiveCount = function() { + this._activeCount--; + if (debug$4) { + this._checkActiveCount(); + } + if (this._enabled && this._activeCount === 0) { + this.emit('inactive'); + } + }; + + + Controls.prototype._checkActiveCount = function() { + var count = 0; + for (var id in this._methods) { + var method = this._methods[id]; + if (method.enabled && method.active) { + count++; + } + } + if (count != this._activeCount) { + throw new Error('Bad control state'); + } + }; + + + Controls.prototype._updateComposer = function() { + var composer = this._composer; + + for (var id in this._methods) { + var method = this._methods[id]; + var enabled = this._enabled && method.enabled; + + if (enabled && !composer.has(method.instance)) { + composer.add(method.instance); + } + if (!enabled && composer.has(method.instance)) { + composer.remove(method.instance); + } + } + }; + + + Controls.prototype._updateViewsWithControls = function() { + var controlData = this._composer.offsets(); + if (controlData.changing) { + this._attachedRenderLoop.renderOnNextFrame(); + } + + // Update each view at most once, even when shared by multiple layers. + // The number of views is expected to be small, so use an array to keep track. + this.updatedViews_.length = 0; + + var layers = this._attachedRenderLoop.stage().listLayers(); + for (var i = 0; i < layers.length; i++) { + var view = layers[i].view(); + if (this.updatedViews_.indexOf(view) < 0) { + layers[i].view().updateWithControlParameters(controlData.offsets); + this.updatedViews_.push(view); + } + } + }; + + + var Controls_1 = Controls; + + var setTransform$2 = dom.setTransform; + var setPixelPosition$1 = dom.setPixelPosition; + + + // This cannot belong in util/dom.js because support/Css also depends on it + // and it would cause a circular dependency. + + function positionAbsolutely(element, x, y, extraTransforms) { + extraTransforms = extraTransforms || ''; + if (Css()) { + // Use CSS 3D transforms when the browser supports them. + // A translateZ(0) transform improves performance on Chrome by creating a + // new layer for the element, which prevents unnecessary repaints. + var transform = 'translateX(' + decimal_1(x) + 'px) translateY(' + decimal_1(y) + 'px) translateZ(0) ' + extraTransforms; + setTransform$2(element, transform); + } else { + // Fall back to absolute positioning. + setPixelPosition$1(element, x, y); + } + } + + var positionAbsolutely_1 = positionAbsolutely; + + var setTransform$3 = dom.setTransform; + + + /** + * @class Hotspot + * @classdesc + * + * A Hotspot allows a DOM element to be placed at a fixed position in the + * image. The position is updated automatically when the {@link View view} + * changes. + * + * Positioning is performed with the `transform` CSS property when available, + * falling back to the `position`, `left` and `top` properties when not. + * In both cases, the top left corner of the element is placed in the requested + * position; clients are expected to use additional children elements or other + * CSS properties to achieve more sophisticated layouts. + * + * There are two kinds of hotspots: regular and embedded. A regular hotspot + * does not change size depending on the zoom level. An embedded hotspot is + * displayed at a fixed size relative to the panorama, always covering the + * same portion of the image. Embedded hotspots require CSS 3D transform + * support. + * + * Clients should call {@link HotspotContainer#createHotspot} instead of + * invoking the constructor directly. + * + * @param {Element} domElement The DOM element. + * @param {View} view The view. + * @param {Object} coords The hotspot coordinates. + * Use {@link RectilinearViewCoords} for a {@link RectilinearView} or + * {@link FlatViewCoords} for a {@link FlatView}. + * @param {Object} opts Additional options. + * @param {Object} opts.perspective Perspective options for embedded hotspots. + * @param {number} [opts.perspective.radius=null] If set, embed the hotspot + * into the image by transforming it into the surface of a sphere with this + * radius. + * @param {string} [opts.perspective.extraTransforms=null] If set, append this + * value to the CSS `transform` property used to position the hotspot. This + * may be used to rotate an embedded hotspot. + */ + function Hotspot(domElement, parentDomElement, view, coords, opts) { + + opts = opts || {}; + opts.perspective = opts.perspective || {}; + opts.perspective.extraTransforms = + opts.perspective.extraTransforms != null ? opts.perspective.extraTransforms : ""; + + if ((opts.perspective.radius || opts.perspective.extraTransforms) && !Css()) { + throw new Error('CSS transforms on hotspots are not supported on this browser'); + } + + this._domElement = domElement; + this._parentDomElement = parentDomElement; + this._view = view; + this._coords = {}; + this._perspective = {}; + + this.setPosition(coords); + + // Add hotspot into the DOM. + this._parentDomElement.appendChild(this._domElement); + + this.setPerspective(opts.perspective); + + // Whether the hotspot is visible. + // The hotspot may still be hidden if it's inside a hidden HotspotContainer. + this._visible = true; + + // The current calculated screen position. + this._position = { x: 0, y: 0 }; + } + + minimalEventEmitter(Hotspot); + + + /** + * Destructor. + * Clients should call {@link HotspotContainer#destroyHotspot} instead. + */ + Hotspot.prototype.destroy = function() { + this._parentDomElement.removeChild(this._domElement); + clearOwnProperties_1(this); + }; + + + /** + * @return {Element} + */ + Hotspot.prototype.domElement = function() { + return this._domElement; + }; + + + /** + * @return {Object} + */ + Hotspot.prototype.position = function() { + return this._coords; + }; + + + /** + * @param {Object} coords + */ + Hotspot.prototype.setPosition = function(coords) { + for (var key in coords) { + this._coords[key] = coords[key]; + } + this._update(); + // TODO: We should probably emit a hotspotsChange event on the parent + // HotspotContainer. What's the best way to do so? + }; + + + /** + * @return {Object} + */ + Hotspot.prototype.perspective = function() { + return this._perspective; + }; + + + /** + * @param {Object} + */ + Hotspot.prototype.setPerspective = function(perspective) { + for (var key in perspective) { + this._perspective[key] = perspective[key]; + } + this._update(); + }; + + + /** + * Show the hotspot + */ + Hotspot.prototype.show = function() { + if (!this._visible) { + this._visible = true; + this._update(); + } + }; + + + /** + * Hide the hotspot + */ + Hotspot.prototype.hide = function() { + if (this._visible) { + this._visible = false; + this._update(); + } + }; + + + Hotspot.prototype._update = function() { + var element = this._domElement; + + var params = this._coords; + var position = this._position; + var x, y; + + var isVisible = false; + + if (this._visible) { + var view = this._view; + + if (this._perspective.radius) { + // Hotspots that are embedded in the panorama may be visible even when + // positioned behind the camera. + isVisible = true; + this._setEmbeddedPosition(view, params); + } else { + // Regular hotspots are only visible when positioned in front of the + // camera. Note that they may be partially visible when positioned outside + // the viewport. + view.coordinatesToScreen(params, position); + x = position.x; + y = position.y; + + if (x != null && y != null) { + isVisible = true; + this._setPosition(x, y); + } + } + } + + // Show if visible, hide if not. + if (isVisible) { + element.style.display = 'block'; + element.style.position = 'absolute'; + } + else { + element.style.display = 'none'; + element.style.position = ''; + } + + }; + + + Hotspot.prototype._setEmbeddedPosition = function(view, params) { + var transform = view.coordinatesToPerspectiveTransform( + params, this._perspective.radius, this._perspective.extraTransforms); + setTransform$3(this._domElement, transform); + }; + + + Hotspot.prototype._setPosition = function(x, y) { + positionAbsolutely_1(this._domElement, x, y, this._perspective.extraTransforms); + }; + + + var Hotspot_1 = Hotspot; + + // Detect CSS pointer-events support. + function checkCssPointerEventsSupported() { + + // Check for existence of CSS property. + var style = document.createElement('a').style; + style.cssText = 'pointer-events:auto'; + var hasCssProperty = style.pointerEvents === 'auto'; + + // The above result is spurious on emulation mode for IE 8-10. + var isOldIE = es5.msie && parseFloat(es5.version) < 11; + + return hasCssProperty && !isOldIE; + } + + // Cache result. + var supported$3; + function cssPointerEventsSupported() { + if (supported$3 !== undefined) { + return supported$3; + } + return (supported$3 = checkCssPointerEventsSupported()); + } + + var cssPointerEvents = cssPointerEventsSupported; + + var setAbsolute$4 = dom.setAbsolute; + var setOverflowHidden$2 = dom.setOverflowHidden; + var setOverflowVisible$1 = dom.setOverflowVisible; + var setNullSize$1 = dom.setNullSize; + var setPixelSize$1 = dom.setPixelSize; + var setPointerEvents = dom.setWithVendorPrefix('pointer-events'); + + + /** + * Signals that a hotspot has been created or destroyed on the container. + * @event HotspotContainer#hotspotsChange + */ + + /** + * @class HotspotContainer + * @classdesc + * + * Creates a DOM element to hold {@link Hotspot hotspots} and updates their + * position when necessary. + * + * @param {Element} parentDomElement The DOM element inside which the container + * should be created. + * @param {Stage} stage The underlying stage. + * @param {View} view The view according to which the hotspots are positioned. + * @param {RenderLoop} renderLoop The render loop indicating when the hotspots + * must be rendered. + * @param {Object} opts + * @param {RectSpec} opts.rect Rectangular region covered by the container. See + * {@link Effects#rect}. + */ + function HotspotContainer(parentDomElement, stage, view, renderLoop, opts) { + opts = opts || {}; + + this._parentDomElement = parentDomElement; + this._stage = stage; + this._view = view; + this._renderLoop = renderLoop; + + // Hotspot list. + this._hotspots = []; + + // Whether the hotspot container should be visible. + // It may still be hidden if a rect effect is set on a browser without + // pointer-events support. + this._visible = true; + + // The current rect. + this._rect = opts.rect; + + // Whether the visibility or the rect have changed since the last DOM update. + this._visibilityOrRectChanged = true; + + // The last seen stage dimensions. + this._stageWidth = null; + this._stageHeight = null; + + // Temporary variable to hold the calculated position and size. + this._tmpRect = {}; + + // Wrapper element. When the rect effect is set, the wrapper will have nonzero + // dimensions and `pointer-events: none` so that hotspots outside the rect are + // hidden, but no mouse events are hijacked. The exception is browsers without + // pointer-events support, where we refuse to show the hotspots when a rect is + // set as it would prevent the controls from receiving mouse events. + this._hotspotContainerWrapper = document.createElement('div'); + setAbsolute$4(this._hotspotContainerWrapper); + setPointerEvents(this._hotspotContainerWrapper, 'none'); + this._parentDomElement.appendChild(this._hotspotContainerWrapper); + + // Hotspot container element. It has zero dimensions and `pointer-events: all` + // to override the `pointer-events: none` on the wrapper and allow hotspots to + // be interacted with. + this._hotspotContainer = document.createElement('div'); + setAbsolute$4(this._hotspotContainer); + setPointerEvents(this._hotspotContainer, 'all'); + this._hotspotContainerWrapper.appendChild(this._hotspotContainer); + + // Update when the hotspots change or scene is re-rendered. + this._updateHandler = this._update.bind(this); + this._renderLoop.addEventListener('afterRender', this._updateHandler); + } + + minimalEventEmitter(HotspotContainer); + + + /** + * Destructor. + */ + HotspotContainer.prototype.destroy = function() { + while (this._hotspots.length) { + this.destroyHotspot(this._hotspots[0]); + } + + this._parentDomElement.removeChild(this._hotspotContainerWrapper); + + this._renderLoop.removeEventListener('afterRender', this._updateHandler); + + clearOwnProperties_1(this); + }; + + + /** + * @return {Element} + */ + HotspotContainer.prototype.domElement = function() { + return this._hotspotContainer; + }; + + + /** + * @param {Rect} rect + */ + HotspotContainer.prototype.setRect = function(rect) { + if (rect && !cssPointerEvents() && typeof console !== 'undefined') { + console.warn( + "Using a rect effect is not fully supported on this browser. " + + "Hotspots may not be shown."); + } + this._rect = rect; + this._visibilityOrRectChanged = true; + }; + + + /** + * @return {Rect} + */ + HotspotContainer.prototype.rect = function() { + return this._rect; + }; + + + /** + * Creates a new hotspot in this container. + * + * @param {Element} domElement DOM element to use for the hotspot + * @param {Object} coords The hotspot coordinates. + * Use {@link RectilinearViewCoords}` for a {@link RectilinearView} or + * {@link FlatViewCoords} for a {@link FlatView}. + * @param {Object} opts Options in the same format as the `opts` argument to + * the {@link Hotspot} constructor. + * @return {Hotspot} + */ + HotspotContainer.prototype.createHotspot = function(domElement, coords, opts) { + coords = coords || {}; + + var hotspot = new Hotspot_1( + domElement, this._hotspotContainer, this._view, coords, opts); + this._hotspots.push(hotspot); + hotspot._update(); + + this.emit('hotspotsChange'); + + return hotspot; + }; + + + /** + * @param {Hotspot} hotspot + * @return {boolean} + */ + HotspotContainer.prototype.hasHotspot = function(hotspot) { + return this._hotspots.indexOf(hotspot) >= 0; + }; + + + /** + * @return {Hotspot[]} + */ + HotspotContainer.prototype.listHotspots = function() { + return [].concat(this._hotspots); + }; + + + /** + * Removes a hotspot from the container. + * + * @param {Hotspot} hotspot + */ + HotspotContainer.prototype.destroyHotspot = function(hotspot) { + var i = this._hotspots.indexOf(hotspot); + if (i < 0) { + throw new Error('No such hotspot'); + } + this._hotspots.splice(i, 1); + + hotspot.destroy(); + this.emit('hotspotsChange'); + }; + + + /** + * Hide the container's DOM element, causing every contained {@link Hotspot} to + * be hidden. + */ + HotspotContainer.prototype.hide = function() { + if (this._visible) { + this._visible = false; + this._visibilityOrRectChanged = true; + this._update(); + } + }; + + + /** + * Show the container's DOM element, causing every contained {@link Hotspot} to + * be shown. + */ + HotspotContainer.prototype.show = function() { + if (!this._visible) { + this._visible = true; + this._visibilityOrRectChanged = true; + this._update(); + } + }; + + + HotspotContainer.prototype._update = function() { + var wrapper = this._hotspotContainerWrapper; + var width = this._stage.width(); + var height = this._stage.height(); + var tmpRect = this._tmpRect; + + // Avoid updating the wrapper DOM unless necessary. + if (this._visibilityOrRectChanged || + (this._rect && (width !== this._stageWidth || height !== this._stageHeight))) { + var visible = this._visible && !(this._rect && !cssPointerEvents()); + wrapper.style.display = visible ? 'block' : 'none'; + + if (visible) { + if (this._rect) { + calcRect_1(width, height, this._rect, tmpRect); + positionAbsolutely_1(wrapper, width * tmpRect.x, height * tmpRect.y); + setPixelSize$1(wrapper, width * tmpRect.width, height * tmpRect.height); + setOverflowHidden$2(wrapper); + } else { + positionAbsolutely_1(wrapper, 0, 0); + setNullSize$1(wrapper); + setOverflowVisible$1(wrapper); + } + } + + this._stageWidth = width; + this._stageHeight = height; + this._visibilityOrRectChanged = false; + } + + // Update hotspots unconditionally, as the view parameters may have changed. + for (var i = 0; i < this._hotspots.length; i++) { + this._hotspots[i]._update(); + } + }; + + + var HotspotContainer_1 = HotspotContainer; + + /** + * Signals that the scene's view has changed. See {@link View#event:change}. + * @event Scene#viewChange + */ + + /** + * Signals that the scene's layers have changed. + * @event Scene#layerChange + */ + + /** + * @class Scene + * @classdesc + * + * A Scene is a stack of {@link Layer layers} sharing the same {@link View view} + * and {@link HotspotContainer hotspot container}. It belongs to the + * {@link Viewer viewer} inside which it is displayed. + * + * Clients should call {@link Viewer#createScene} instead of invoking the + * constructor directly. + * + * @param {Viewer} viewer The viewer this scene belongs to. + * @param {View} view The scene's underlying view. + */ + function Scene(viewer, view) { + this._viewer = viewer; + this._view = view; + this._layers = []; + + // Hotspot container. Assume it occupies a full rect. + this._hotspotContainer = new HotspotContainer_1( + viewer._controlContainer, + viewer.stage(), + this._view, + viewer.renderLoop()); + + // The current movement. + this._movement = null; + this._movementStartTime = null; + this._movementStep = null; + this._movementParams = null; + this._movementCallback = null; + + // Event listener for updating the view according to the current movement. + // The listener is set/unset on the render loop when a movement starts/stops. + this._updateMovementHandler = this._updateMovement.bind(this); + + // Show or hide hotspots when scene changes. + this._updateHotspotContainerHandler = this._updateHotspotContainer.bind(this); + this._viewer.addEventListener('sceneChange', this._updateHotspotContainerHandler); + + // Emit event when view changes. + this._viewChangeHandler = this.emit.bind(this, 'viewChange'); + this._view.addEventListener('change', this._viewChangeHandler); + + // Update the hotspot container. + this._updateHotspotContainer(); + } + + minimalEventEmitter(Scene); + + + /** + * Destructor. Clients should call {@link Viewer#destroyScene} instead. + */ + Scene.prototype.destroy = function() { + this._view.removeEventListener('change', this._viewChangeHandler); + this._viewer.removeEventListener('sceneChange', this._updateHotspotContainerHandler); + + if (this._movement) { + this.stopMovement(); + } + + this._hotspotContainer.destroy(); + + this.destroyAllLayers(); + + clearOwnProperties_1(this); + }; + + + + /** + * Returns the {@link HotspotContainer hotspot container} for the scene. + * @return {Layer} + */ + Scene.prototype.hotspotContainer = function() { + return this._hotspotContainer; + }; + + /** + * Returns the first of the {@link Layer layers} belonging to the scene, or + * null if the scene has no layers. + * + * This method is equivalent to `Scene#listLayers[0]`. It may be removed in the + * future. + * + * @return {Layer} + */ + Scene.prototype.layer = function() { + return this._layers[0]; + }; + + /** + * Returns a list of all {@link Layer layers} belonging to the scene. The + * returned list is in display order, background to foreground. + * @return {Layer[]} + */ + Scene.prototype.listLayers = function() { + return [].concat(this._layers); + }; + + + /** + * Returns the scene's underlying {@link View view}. + * @return {View} + */ + Scene.prototype.view = function() { + return this._view; + }; + + + /** + * Returns the {@link Viewer viewer} the scene belongs to. + * @return {Viewer} + */ + Scene.prototype.viewer = function() { + return this._viewer; + }; + + + /** + * Returns whether the scene is currently visible. + * @return {boolean} + */ + Scene.prototype.visible = function() { + return this._viewer.scene() === this; + }; + + + /** + * Creates a new {@link Layer layer} and adds it into the scene in the + * foreground position. + * + * @param {Object} opts Layer creation options. + * @param {Source} opts.source The layer's underlying {@link Source}. + * @param {Source} opts.geometry The layer's underlying {@link Geometry}. + * @param {boolean} [opts.pinFirstLevel=false] Whether to pin the first level to + * provide a fallback of last resort, at the cost of memory consumption. + * @param {Object} [opts.textureStoreOpts={}] Options to pass to the + * {@link TextureStore} constructor. + * @param {Object} [opts.layerOpts={}] Options to pass to the {@link Layer} + * constructor. + * @return {Layer} + */ + Scene.prototype.createLayer = function(opts) { + opts = opts || {}; + + var textureStoreOpts = opts.textureStoreOpts || {}; + var layerOpts = opts.layerOpts || {}; + + var source = opts.source; + var geometry = opts.geometry; + var view = this._view; + var stage = this._viewer.stage(); + var textureStore = new TextureStore_1(source, stage, textureStoreOpts); + var layer = new Layer_1(source, geometry, view, textureStore, layerOpts); + + this._layers.push(layer); + + if (opts.pinFirstLevel) { + layer.pinFirstLevel(); + } + + // Signal that the layers have changed. + this.emit('layerChange'); + + return layer; + }; + + + /** + * Destroys a {@link Layer layer} and removes it from the scene. + * @param {Layer} layer + * @throws An error if the layer does not belong to the scene. + */ + Scene.prototype.destroyLayer = function(layer) { + var i = this._layers.indexOf(layer); + if (i < 0) { + throw new Error('No such layer in scene'); + } + + this._layers.splice(i, 1); + + // Signal that the layers have changed. + this.emit('layerChange'); + + layer.textureStore().destroy(); + layer.destroy(); + }; + + + /** + * Destroys all {@link Layer layers} and removes them from the scene. + */ + Scene.prototype.destroyAllLayers = function() { + while (this._layers.length > 0) { + this.destroyLayer(this._layers[0]); + } + }; + + + /** + * Switches to the scene. + * + * This is equivalent to calling {@link Viewer#switchScene} on this scene. + * + * @param {Object} opts Options to pass into {@link Viewer#switchScene}. + * @param {function} done Function to call when the switch is complete. + */ + Scene.prototype.switchTo = function(opts, done) { + return this._viewer.switchScene(this, opts, done); + }; + + + /** + * Tweens the scene's underlying {@link View view}. + * + * @param {Object} params Target view parameters. + * @param {Object} opts Transition options. + * @param {function} [opts.ease=easeInOutQuad] Tween easing function + * @param {number} [opts.controlsInterrupt=false] allow controls to interrupt + * an ongoing tween. + * @param {number} [opts.transitionDuration=1000] Tween duration, in + * milliseconds. + * @param {number} [opts.closest=true] Whether to tween through the shortest + * path between the initial and final view parameters. This requires + * {@link View#normalizeToClosest} to be implemented, and does nothing + * otherwise. + * @param {function} done Function to call when the tween finishes or is + * interrupted. + */ + Scene.prototype.lookTo = function(params, opts, done) { + opts = opts || {}; + done = done || noop_1; + + if (type_1(params) !== 'object') { + throw new Error("Target view parameters must be an object"); + } + + // Quadratic in/out easing. + var easeInOutQuad = function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k; + } + return -0.5 * (--k * (k - 2) - 1); + }; + + var ease = opts.ease != null ? opts.ease : easeInOutQuad; + var controlsInterrupt = opts.controlsInterrupt != null ? opts.controlsInterrupt : false; + var duration = opts.transitionDuration != null ? opts.transitionDuration : 1000; + var shortest = opts.shortest != null ? opts.shortest : true; + + var view = this._view; + + var initialParams = view.parameters(); + + var finalParams = {}; + defaults_1(finalParams, params); + defaults_1(finalParams, initialParams); + + // Tween through the shortest path if requested. + // The view must implement the normalizeToClosest() method. + if (shortest && view.normalizeToClosest) { + view.normalizeToClosest(finalParams, finalParams); + } + + var movement = function() { + + var finalUpdate = false; + + return function(params, elapsed) { + + if (elapsed >= duration && finalUpdate) { + return null; + } + + var delta = Math.min(elapsed / duration, 1); + + for (var param in params) { + var start = initialParams[param]; + var end = finalParams[param]; + params[param] = start + ease(delta) * (end - start); + } + + finalUpdate = elapsed >= duration; + + return params; + + }; + }; + + var reenableControls = this._viewer.controls().enabled(); + + if (!controlsInterrupt) { + this._viewer.controls().disable(); + } + + this.startMovement(movement, function() { + if (reenableControls) { + this._viewer.controls().enable(); + } + done(); + }); + + }; + + + /** + * Starts a movement, possibly replacing the current movement. + * + * @param {function} fn The movement function. + * @param {function} done Function to be called when the movement finishes or is + * interrupted. + */ + Scene.prototype.startMovement = function(fn, done) { + + var renderLoop = this._viewer.renderLoop(); + + if (this._movement) { + this.stopMovement(); + } + + var step = fn(); + if (typeof step !== 'function') { + throw new Error('Bad movement'); + } + + this._movement = fn; + this._movementStep = step; + this._movementStartTime = now(); + this._movementParams = {}; + this._movementCallback = done; + + renderLoop.addEventListener('beforeRender', this._updateMovementHandler); + renderLoop.renderOnNextFrame(); + }; + + + /** + * Stops the current movement. + */ + Scene.prototype.stopMovement = function() { + + var renderLoop = this._viewer.renderLoop(); + + if (!this._movement) { + return; + } + + if (this._movementCallback) { + this._movementCallback(); + } + + renderLoop.removeEventListener('beforeRender', this._updateMovementHandler); + + this._movement = null; + this._movementStep = null; + this._movementStartTime = null; + this._movementParams = null; + this._movementCallback = null; + }; + + + /** + * Returns the current movement. + * @return {function} + */ + Scene.prototype.movement = function() { + return this._movement; + }; + + + Scene.prototype._updateMovement = function() { + + if (!this._movement) { + throw new Error('Should not call update'); + } + + var renderLoop = this._viewer.renderLoop(); + var view = this._view; + + var elapsed = now() - this._movementStartTime; + var step = this._movementStep; + var params = this._movementParams; + + params = view.parameters(params); + params = step(params, elapsed); + if (params == null) { + this.stopMovement(); + } else { + view.setParameters(params); + renderLoop.renderOnNextFrame(); + } + + }; + + + Scene.prototype._updateHotspotContainer = function() { + if (this.visible()) { + this._hotspotContainer.show(); + } else { + this._hotspotContainer.hide(); + } + }; + + + var Scene_1 = Scene; + + var defaultOptions$4 = { + duration: Infinity + }; + + + /** + * Signals a timeout. + * @event Timer#timeout + */ + + + /** + * @class Timer + * @classdesc + * + * A Timer provides a mechanism to receive an event after a timeout. + * + * A timer has a set duration, and is either started or stopped at a given time. + * The timer is initially stopped. When the timer is started, a timeout event is + * scheduled to fire once the set duration elapses. When the timer is stopped, + * the scheduled timeout event is cancelled. When a timeout event fires, the + * timer returns to the stopped state. + * + * @param {number} [opts.duration=Infinity] Timeout in milliseconds. + */ + function Timer(opts) { + + opts = defaults_1(opts || {}, defaultOptions$4); + + this._duration = opts.duration; + + this._startTime = null; + + this._handle = null; + + this._check = this._check.bind(this); + + } + + minimalEventEmitter(Timer); + + + /** + * Starts the timer. If the timer is already started, this has the effect of + * stopping and starting again (i.e. resetting the timer). + */ + Timer.prototype.start = function() { + this._startTime = now(); + if (this._handle == null && this._duration < Infinity) { + this._setup(this._duration); + } + }; + + + /** + * Returns whether the timer is in the started state. + * @return {boolean} + */ + Timer.prototype.started = function() { + return this._startTime != null; + }; + + + /** + * Stops the timer. + */ + Timer.prototype.stop = function() { + this._startTime = null; + if (this._handle != null) { + clearTimeout(this._handle); + this._handle = null; + } + }; + + + Timer.prototype._setup = function(interval) { + this._handle = setTimeout(this._check, interval); + }; + + + Timer.prototype._teardown = function() { + clearTimeout(this._handle); + this._handle = null; + }; + + + Timer.prototype._check = function() { + var currentTime = now(); + var elapsed = currentTime - this._startTime; + var remaining = this._duration - elapsed; + + this._teardown(); + + if (remaining <= 0) { + this.emit('timeout'); + this._startTime = null; + } else if (remaining < Infinity) { + this._setup(remaining); + } + }; + + + /** + * Returns the currently set duration. + */ + Timer.prototype.duration = function() { + return this._duration; + }; + + + /** + * Sets the duration. If the timer is already started, the timeout event is + * rescheduled to occur once the new duration has elapsed since the last call + * to start. In particular, if an amount of time larger than the new duration + * has already elapsed, the timeout event fires immediately. + * @param {number} + */ + Timer.prototype.setDuration = function(duration) { + this._duration = duration; + if (this._startTime != null) { + this._check(); + } + }; + + + var Timer_1 = Timer; + + var defaultOpts = { + active: 'move', + inactive: 'default', + disabled: 'default' + }; + + /** + * @class ControlCursor + * @classdesc + * + * Sets the CSS cursor on a DOM element according to the state of a + * {@link ControlMethod}. + * + * @param {Controls} controls Controls instance containing the control method. + * @param {string} id ID of the control method. + * @param {Element} element DOM element where the cursor should be set. + * @param {Object} opts The control cursors. Each field must be a valid value + * for the `cursor` CSS property. + * @param {string} [opts.active='move'] Cursor to set when the control method + * is enabled and active. + * @param {string} [opts.inactive='default'] Cursor to set when the control + * method is enabled and inactive. + * @param {string} [opts.disabled='default'] Cursor to set when the control + * method is disabled. + */ + function ControlCursor(controls, id, element, opts) { + opts = defaults_1(opts || {}, defaultOpts); + + // TODO: This class may misbehave if the control method is unregistered and a + // different control method is registered under the same id. + + this._element = element; + this._controls = controls; + this._id = id; + + this._attached = false; + + this._setActiveCursor = this._setCursor.bind(this, opts.active); + this._setInactiveCursor = this._setCursor.bind(this, opts.inactive); + this._setDisabledCursor = this._setCursor.bind(this, opts.disabled); + this._setOriginalCursor = this._setCursor.bind(this, this._element.style.cursor); + + this._updateAttachmentHandler = this._updateAttachment.bind(this); + + controls.addEventListener('methodEnabled', this._updateAttachmentHandler); + controls.addEventListener('methodDisabled', this._updateAttachmentHandler); + controls.addEventListener('enabled', this._updateAttachmentHandler); + controls.addEventListener('disabled', this._updateAttachmentHandler); + + this._updateAttachment(); + } + + /** + * Destructor. + */ + ControlCursor.prototype.destroy = function() { + this._detachFromControlMethod(this._controls.method(this._id)); + this._setOriginalCursor(); + + this._controls.removeEventListener('methodEnabled', + this._updateAttachmentHandler); + this._controls.removeEventListener('methodDisabled', + this._updateAttachmentHandler); + this._controls.removeEventListener('enabled', + this._updateAttachmentHandler); + this._controls.removeEventListener('disabled', + this._updateAttachmentHandler); + + clearOwnProperties_1(this); + }; + + ControlCursor.prototype._updateAttachment = function() { + var controls = this._controls; + var id = this._id; + if (controls.enabled() && controls.method(id).enabled) { + this._attachToControlMethod(controls.method(id)); + } else { + this._detachFromControlMethod(controls.method(id)); + } + }; + + ControlCursor.prototype._attachToControlMethod = function(controlMethod) { + if (!this._attached) { + controlMethod.instance.addEventListener('active', this._setActiveCursor); + controlMethod.instance.addEventListener('inactive', this._setInactiveCursor); + + if (controlMethod.active) { + this._setActiveCursor(); + } else { + this._setInactiveCursor(); + } + + this._attached = true; + } + }; + + ControlCursor.prototype._detachFromControlMethod = function(controlMethod) { + if (this._attached) { + controlMethod.instance.removeEventListener('active', this._setActiveCursor); + controlMethod.instance.removeEventListener('inactive', this._setInactiveCursor); + + this._setDisabledCursor(); + + this._attached = false; + } + }; + + ControlCursor.prototype._setCursor = function(cursor) { + this._element.style.cursor = cursor; + }; + + var ControlCursor_1 = ControlCursor; + + var defaultOptions$5 = { + mouseViewMode: 'drag' + }; + + /** + * Instantiate and register some commonly used {@link ControlMethod} instances. + * + * The following instances are registered: + * - mouseViewDrag + * - mouseViewQtvr + * - touchView + * - pinch + * - arrowKeys + * - plusMinusKeys + * - wasdKeys + * - qeKeys + * + * @param {Controls} controls Where to register the instances. + * @param {Element} element Element to listen for events. + * @param {Object} opts + * @param {'drag'|'qtvr'} mouseViewMode + */ + function registerDefaultControls(controls, element, opts) { + opts = defaults_1(opts || {}, defaultOptions$5); + + var controlMethods = { + mouseViewDrag: new Drag(element, 'mouse'), + mouseViewQtvr: new Qtvr(element, 'mouse'), + touchView: new Drag(element, 'touch'), + pinch: new PinchZoom(element, 'touch'), + + leftArrowKey: new Key(37, 'x', -0.7, 3), + rightArrowKey: new Key(39, 'x', 0.7, 3), + upArrowKey: new Key(38, 'y', -0.7, 3), + downArrowKey: new Key(40, 'y', 0.7, 3), + plusKey: new Key(107, 'zoom', -0.7, 3), + minusKey: new Key(109, 'zoom', 0.7, 3), + + wKey: new Key(87, 'y', -0.7, 3), + aKey: new Key(65, 'x', -0.7, 3), + sKey: new Key(83, 'y', 0.7, 3), + dKey: new Key(68, 'x', 0.7, 3), + qKey: new Key(81, 'roll', 0.7, 3), + eKey: new Key(69, 'roll', -0.7, 3) + }; + + if(opts.scrollZoom !== false) { + controlMethods.scrollZoom = new ScrollZoom(element); //{ frictionTime: 0 } + } + + var controlMethodGroups = { + arrowKeys: [ 'leftArrowKey', 'rightArrowKey', 'upArrowKey', 'downArrowKey' ], + plusMinusKeys: [ 'plusKey', 'minusKey' ], + wasdKeys: [ 'wKey', 'aKey', 'sKey', 'dKey' ], + qeKeys: [ 'qKey', 'eKey' ] + }; + + + var enabledControls = [ 'scrollZoom', 'touchView', 'pinch' ]; + switch (opts.mouseViewMode) { + case 'drag': + enabledControls.push('mouseViewDrag'); + break; + case 'qtvr': + enabledControls.push('mouseViewQtvr'); + break; + default: + throw new Error("Unknown mouse view mode: " + opts.mouseViewMode); + } + + for (var id in controlMethods) { + var method = controlMethods[id]; + controls.registerMethod(id, method); + if (enabledControls.indexOf(id) >= 0) { + controls.enableMethod(id); + } + } + + for (var groupId in controlMethodGroups) { + var methodGroup = controlMethodGroups[groupId]; + controls.addMethodGroup(groupId, methodGroup); + } + + return controlMethods; + } + + var registerDefaultControls_1 = registerDefaultControls; + + function tween(duration, update, done) { + var cancelled = false; + + var startTime = now(); + + function runUpdate() { + if(cancelled) { return; } + var tweenVal = (now() - startTime)/duration; + if(tweenVal < 1) { + update(tweenVal); + requestAnimationFrame(runUpdate); + } + else { + update(1); + done(); + } + } + + update(0); + requestAnimationFrame(runUpdate); + + return function cancel() { + cancelled = true; + done.apply(null, arguments); + } + } + + var tween_1 = tween; + + var setOverflowHidden$3 = dom.setOverflowHidden; + var setAbsolute$5 = dom.setAbsolute; + var setFullSize$4 = dom.setFullSize; + var setBlocking$2 = dom.setBlocking; + + + + + + var stageMap = { + webgl: WebGl$1, + css: Css$1, + flash: Flash$2 + }; + + var stagePrefList = [ + WebGl$1, + Css$1, + Flash$2 + ]; + + /** + * Signals that the current scene has changed. + * @event Viewer#sceneChange + */ + + /** + * Signals that the view of the current scene has changed. See + * {@link View#event:change}. + * @event Viewer#viewChange + */ + + /** + * @class Viewer + * @classdesc + * + * A Viewer is a container for multiple {@link Scene scenes} to be displayed + * inside a {@link Stage stage} contained in the DOM. + * + * Scenes may be created by calling {@link Viewer#createScene}. Except during a + * scene switch, a single one of them, called the current scene, is visible. + * Calling {@link Viewer#switchScene} sets the current scene and switches to it. + * + * @param {Element} domElement The DOM element to contain the stage. + * @param {Object} opts Viewer creation options. + * @param {(null|'webgl'|'css'|'flash')} [opts.stageType=null] The type of stage + * to create. The default is to choose the most appropriate type depending + * on the browser capabilities. + * @param {Object} opts.controls Options to be passed to + * {@link registerDefaultControls}. + * @param {Object} opts.stage Options to be passed to the {@link Stage} + * constructor. + * @param {Object} opts.cursors Cursor options. + * @param {Object} opts.cursors.drag Drag cursor options to be passed to the + * {@link ControlCursor} constructor. + */ + function Viewer(domElement, opts) { + opts = opts || {}; + + this._domElement = domElement; + + // Add `overflow: hidden` to the domElement. + setOverflowHidden$3(domElement); + + // Select the stage type to use. + var Stage; + if (opts.stageType) { + // If a specific stage type was specified, use that one. + Stage = stageMap[opts.stageType]; + if (!Stage) { + throw new Error('Unknown stage type: ' + opts.stageType); + } + } else { + // Choose the best supported stage according to the default preference + // order. Note that this may yield an unsupported stage for some + // geometry/view combinations. Client code is expected to pass in a + // specific stage type in those cases. + for (var i = 0; i < stagePrefList.length; i++) { + if (stagePrefList[i].supported()) { + Stage = stagePrefList[i]; + break; + } + } + if (!Stage) { + throw new Error('None of the stage types are supported'); + } + } + + // Create stage. + this._stage = new Stage(opts.stage); + + // Register the default renderers for the selected stage. + registerDefaultRenderers_1(this._stage); + + // Add the stage element into the DOM. + this._domElement.appendChild(this._stage.domElement()); + + // Create control container. + // Controls cannot be placed directly on the root DOM element because + // Hammer.js will prevent click events from reaching the elements beneath. + + // The hotspot containers will be added inside the controls container. + this._controlContainer = document.createElement('div'); + setAbsolute$5(this._controlContainer); + setFullSize$4(this._controlContainer); + + // Prevent bounce scroll effect on iOS. + // Applied only for iOS, as Android's events must have the default action to allow interaction with hotspots. + if (es5.ios) { + this._controlContainer.addEventListener('touchmove', function(event) { + event.preventDefault(); + }); + } + + + // Old IE does not detect mouse events on elements without background + // Add a child element to the controls with full width, a background color + // and opacity 0 + var controlCapture = document.createElement('div'); + setAbsolute$5(controlCapture); + setFullSize$4(controlCapture); + setBlocking$2(controlCapture); + + this._controlContainer.appendChild(controlCapture); + domElement.appendChild(this._controlContainer); + + // Respond to window size changes. + this._size = {}; + this.updateSize(); + this._updateSizeListener = this.updateSize.bind(this); + window.addEventListener('resize', this._updateSizeListener); + + // Create render loop. + this._renderLoop = new RenderLoop_1(this._stage); + + // Create the controls and register them with the render loop. + this._controls = new Controls_1(); + this._controlMethods = registerDefaultControls_1(this._controls, this._controlContainer, opts.controls); + this._controls.attach(this._renderLoop); + + // Expose HammerJS. + this._hammerManagerTouch = HammerGestures_1.get(this._controlContainer, 'touch'); + this._hammerManagerMouse = HammerGestures_1.get(this._controlContainer, 'mouse'); + + // Initialize drag cursor. + this._dragCursor = new ControlCursor_1(this._controls, 'mouseViewDrag', domElement, opts.cursors && opts.cursors.drag || {}); + + // Start the render loop. + this._renderLoop.start(); + + // Scene list. + this._scenes = []; + + // The currently visible scene. + // During a scene transition, this is the scene being switched to. + this._currentScene = null; + + // The scene being switched from during a scene transition. + // This is necessary to update the layers correctly when they are added or + // removed during a transition. + this._replacedScene = null; + + // The current transition. + this._cancelCurrentTween = null; + + // The event listener fired when the current scene layers change. + // This is attached to the correct scene whenever the current scene changes. + this._layerChangeHandler = this._updateSceneLayers.bind(this); + + // The event listener fired when the current scene view changes. + // This is attached to the correct scene whenever the current scene changes. + this._viewChangeHandler = this.emit.bind(this, 'viewChange'); + + // Setup the idle timer. + // By default, the timer has an infinite duration so it does nothing. + this._idleTimer = new Timer_1(); + this._idleTimer.start(); + + // Reset the timer whenever the view changes. + this._resetIdleTimerHandler = this._resetIdleTimer.bind(this); + this.addEventListener('viewChange', this._resetIdleTimerHandler); + + // Start the idle movement when the idle timer fires. + this._triggerIdleTimerHandler = this._triggerIdleTimer.bind(this); + this._idleTimer.addEventListener('timeout', this._triggerIdleTimerHandler); + + // Stop an ongoing movement when the controls are activated or when the + // scene changes. + this._stopMovementHandler = this.stopMovement.bind(this); + this._controls.addEventListener('active', this._stopMovementHandler); + this.addEventListener('sceneChange', this._stopMovementHandler); + + // The currently programmed idle movement. + this._idleMovement = null; + } + + minimalEventEmitter(Viewer); + + + /** + * Destructor. + */ + Viewer.prototype.destroy = function() { + + window.removeEventListener('resize', this._updateSizeListener); + + if (this._currentScene) { + this._removeSceneEventListeners(this._currentScene); + } + + if (this._replacedScene) { + this._removeSceneEventListeners(this._replacedScene); + } + + this._dragCursor.destroy(); + + for (var methodName in this._controlMethods) { + this._controlMethods[methodName].destroy(); + } + + while (this._scenes.length) { + this.destroyScene(this._scenes[0]); + } + + // The Flash renderer must be torn down before the element is removed from + // the DOM, so all scenes must have been destroyed before this point. + this._domElement.removeChild(this._stage.domElement()); + + this._stage.destroy(); + this._renderLoop.destroy(); + this._controls.destroy(); + this._controls = null; + + if (this._cancelCurrentTween) { + this._cancelCurrentTween(); + } + + clearOwnProperties_1(this); + }; + + + /** + * Updates the stage size to fill the containing element. + * + * This method is automatically called when the browser window is resized. + * Most clients won't need to explicitly call it to keep the size up to date. + */ + Viewer.prototype.updateSize = function() { + var size = this._size; + size.width = this._domElement.clientWidth; + size.height = this._domElement.clientHeight; + this._stage.setSize(size); + }; + + + /** + * Returns the underlying {@link Stage stage}. + * @return {Stage} + */ + Viewer.prototype.stage = function() { + return this._stage; + }; + + + /** + * Returns the underlying {@link RenderLoop render loop}. + * @return {RenderLoop} + */ + Viewer.prototype.renderLoop = function() { + return this._renderLoop; + }; + + + /** + * Returns the underlying {@link Controls controls}. + * @return {Controls} + */ + Viewer.prototype.controls = function() { + return this._controls; + }; + + + /** + * Returns the underlying DOM element. + * @return {Element} + */ + Viewer.prototype.domElement = function() { + return this._domElement; + }; + + + /** + * Creates a new {@link Scene scene} with a single layer and adds it to the + * viewer. + * + * The current scene does not change. To switch to the scene, call + * {@link Viewer#switchScene}. + * + * @param {Object} opts Scene creation options. + * @param {View} opts.view The scene's underlying {@link View}. + * @param {Source} opts.source The layer's underlying {@link Source}. + * @param {Geometry} opts.geometry The layer's underlying {@link Geometry}. + * @param {boolean} [opts.pinFirstLevel=false] Whether to pin the first level to + * provide a fallback of last resort, at the cost of memory consumption. + * @param {Object} [opts.textureStoreOpts={}] Options to pass to the + * {@link TextureStore} constructor. + * @param {Object} [opts.layerOpts={}] Options to pass to the {@link Layer} + * constructor. + * @return {Scene} + */ + Viewer.prototype.createScene = function(opts) { + opts = opts || {}; + + var scene = this.createEmptyScene({ view: opts.view }); + + scene.createLayer({ + source: opts.source, + geometry: opts.geometry, + pinFirstLevel: opts.pinFirstLevel, + textureStoreOpts: opts.textureStoreOpts, + layerOpts: opts.layerOpts + }); + + return scene; + }; + + + /** + * Creates a new {@link Scene scene} with no layers and adds it to the viewer. + * + * Layers may be added to the scene by calling {@link Scene#createLayer}. + * However, if the scene has a single layer, it is simpler to call + * {@link Viewer#createScene} instead of this method. + * + * The current scene does not change. To switch to the scene, call + * {@link Viewer#switchScene}. + * + * @param {Object} opts Scene creation options. + * @param {View} opts.view The scene's underlying {@link View}. + * @return {Scene} + */ + Viewer.prototype.createEmptyScene = function(opts) { + opts = opts || {}; + + var scene = new Scene_1(this, opts.view); + this._scenes.push(scene); + + return scene; + }; + + + Viewer.prototype._updateSceneLayers = function() { + var i; + var layer; + + var stage = this._stage; + var currentScene = this._currentScene; + var replacedScene = this._replacedScene; + + var oldLayers = stage.listLayers(); + + // The stage contains layers from at most two scenes: the current one, on top, + // and the one currently being switched away from, on the bottom. + var newLayers = []; + if (replacedScene) { + newLayers = newLayers.concat(replacedScene.listLayers()); + } + if (currentScene) { + newLayers = newLayers.concat(currentScene.listLayers()); + } + + // A single layer can be added or removed from the scene at a time. + if (Math.abs(oldLayers.length - newLayers.length) !== 1) { + throw new Error('Stage and scene out of sync'); + } + + if (newLayers.length < oldLayers.length) { + // A layer was removed. + for (i = 0; i < oldLayers.length; i++) { + layer = oldLayers[i]; + if (newLayers.indexOf(layer) < 0) { + this._removeLayerFromStage(layer); + break; + } + } + } + if (newLayers.length > oldLayers.length) { + // A layer was added. + for (i = 0; i < newLayers.length; i++) { + layer = newLayers[i]; + if (oldLayers.indexOf(layer) < 0) { + this._addLayerToStage(layer, i); + } + } + } + + // TODO: When in the middle of a scene transition, call the transition update + // function immediately to prevent an added layer from flashing with the wrong + // opacity. + }; + + + Viewer.prototype._addLayerToStage = function(layer, i) { + // Pin the first level to ensure a fallback while the layer is visible. + // Note that this is distinct from the `pinFirstLevel` option passed to + // createScene(), which pins the layer even when it's not visible. + layer.pinFirstLevel(); + this._stage.addLayer(layer, i); + }; + + + Viewer.prototype._removeLayerFromStage = function(layer) { + this._stage.removeLayer(layer); + layer.unpinFirstLevel(); + layer.textureStore().clearNotPinned(); + }; + + + Viewer.prototype._addSceneEventListeners = function(scene) { + scene.addEventListener('layerChange', this._layerChangeHandler); + scene.addEventListener('viewChange', this._viewChangeHandler); + }; + + + Viewer.prototype._removeSceneEventListeners = function(scene) { + scene.removeEventListener('layerChange', this._layerChangeHandler); + scene.removeEventListener('viewChange', this._viewChangeHandler); + }; + + + /** + * Destroys a {@link Scene scene} and removes it from the viewer. + * @param {Scene} scene + */ + Viewer.prototype.destroyScene = function(scene) { + var i = this._scenes.indexOf(scene); + if (i < 0) { + throw new Error('No such scene in viewer'); + } + + var j; + var layers; + + if (this._currentScene === scene) { + // The destroyed scene is the current scene. + // Remove event listeners, remove layers from stage and cancel transition. + this._removeSceneEventListeners(scene); + layers = scene.listLayers(); + for (j = 0; j < layers.length; j++) { + this._removeLayerFromStage(layers[j]); + } + if (this._cancelCurrentTween) { + this._cancelCurrentTween(); + this._cancelCurrentTween = null; + } + this._currentScene = null; + this.emit('sceneChange'); + } + + if (this._replacedScene === scene) { + // The destroyed scene is being switched away from. + // Remove event listeners and remove layers from stage. + this._removeSceneEventListeners(scene); + layers = scene.listLayers(); + for (j = 0; j < layers.length; j++) { + this._removeLayerFromStage(layers[j]); + } + this._replacedScene = null; + } + + this._scenes.splice(i, 1); + + scene.destroy(); + }; + + + /** + * Destroys all {@link Scene scenes} and removes them from the viewer. + */ + Viewer.prototype.destroyAllScenes = function() { + while (this._scenes.length > 0) { + this.destroyScene(this._scenes[0]); + } + }; + + + /** + * Returns whether the viewer contains a {@link Scene scene}. + * @param {Scene} scene + * @return {boolean} + */ + Viewer.prototype.hasScene = function(scene) { + return this._scenes.indexOf(scene) >= 0; + }; + + + /** + * Returns a list of all {@link Scene scenes}. + * @return {Scene[]} + */ + Viewer.prototype.listScenes = function() { + return [].concat(this._scenes); + }; + + + /** + * Returns the current {@link Scene scene}, or null if there isn't one. + * + * To change the current scene, call {@link Viewer#switchScene}. + * + * @return {Scene} + */ + Viewer.prototype.scene = function() { + return this._currentScene; + }; + + + /** + * Returns the {@link View view} for the current {@link Scene scene}, or null + * if there isn't one. + * @return {View} + */ + Viewer.prototype.view = function() { + var scene = this._currentScene; + if (scene) { + return scene.view(); + } + return null; + }; + + + /** + * Tweens the {@link View view} for the current {@link Scene scene}. + * + * This method is equivalent to calling {@link Scene#lookTo} on the current + * scene. + * + * @param {Object} opts Options to pass into {@link Scene#lookTo}. + * @param {function} done Function to call when the tween is complete. + */ + Viewer.prototype.lookTo = function(params, opts, done) { + // TODO: is it an error to call lookTo when no scene is displayed? + var scene = this._currentScene; + if (scene) { + scene.lookTo(params, opts, done); + } + }; + + + /** + * Starts a movement, possibly replacing the current movement. + * + * This method is equivalent to calling {@link Scene#startMovement} on the + * current scene. If there is no current scene, this is a no-op. + * + * @param {function} fn The movement function. + * @param {function} done Function to be called when the movement finishes or is + * interrupted. + */ + Viewer.prototype.startMovement = function(fn, done) { + var scene = this._currentScene; + if (!scene) { + return; + } + scene.startMovement(fn, done); + }; + + + /** + * Stops the current movement. + * + * This method is equivalent to calling {@link Scene#stopMovement} on the + * current scene. If there is no current scene, this is a no-op. + */ + Viewer.prototype.stopMovement = function() { + var scene = this._currentScene; + if (!scene) { + return; + } + scene.stopMovement(); + }; + + + /** + * Returns the current movement. + * + * This method is equivalent to calling {@link Scene#movement} on the + * current scene. If there is no current scene, this is a no-op. + * + * @return {function} + */ + Viewer.prototype.movement = function() { + var scene = this._currentScene; + if (!scene) { + return; + } + return scene.movement(); + }; + + + /** + * Schedules an idle movement to be automatically started when the view remains + * unchanged for the given timeout period. + * + * Changing the view while the idle movement is active stops the movement and + * schedules it to start again after the same timeout period. To disable it + * permanently, call with a null movement or an infinite timeout. + * + * @param {number} timeout Timeout period in milliseconds. + * @param {function} movement Automatic movement function, or null to disable. + */ + Viewer.prototype.setIdleMovement = function(timeout, movement) { + this._idleTimer.setDuration(timeout); + this._idleMovement = movement; + }; + + + /** + * Stops the idle movement. It will be started again after the timeout set by + * {@link Viewer#setIdleMovement}. + */ + Viewer.prototype.breakIdleMovement = function() { + this.stopMovement(); + this._resetIdleTimer(); + }; + + + Viewer.prototype._resetIdleTimer = function() { + this._idleTimer.start(); + }; + + + Viewer.prototype._triggerIdleTimer = function() { + var idleMovement = this._idleMovement; + if (!idleMovement) { + return; + } + this.startMovement(idleMovement); + }; + + + var defaultSwitchDuration = 1000; + + function defaultTransitionUpdate(val, newScene, oldScene) { + var layers = newScene.listLayers(); + layers.forEach(function(layer) { + layer.mergeEffects({ opacity: val }); + }); + + newScene._hotspotContainer.domElement().style.opacity = val; + } + + + /** + * Switches to another {@link Scene scene} with a fade transition. This scene + * becomes the current one. + * + * If a transition is already taking place, it is interrupted before the new one + * starts. + * + * @param {Scene} newScene The scene to switch to. + * @param {Object} opts Transition options. + * @param {number} [opts.transitionDuration=1000] Transition duration, in + * milliseconds. + * @param {number} [opts.transitionUpdate=defaultTransitionUpdate] + * Transition update function, with signature `f(t, newScene, oldScene)`. + * This function is called on each frame with `t` increasing from 0 to 1. + * An initial call with `t=0` and a final call with `t=1` are guaranteed. + * The default function sets the opacity of the new scene to `t`. + * @param {function} done Function to call when the transition finishes or is + * interrupted. If the new scene is equal to the old one, no transition + * takes place, but this function is still called. + */ + Viewer.prototype.switchScene = function(newScene, opts, done) { + var self = this; + + opts = opts || {}; + done = done || noop_1; + + var stage = this._stage; + + var oldScene = this._currentScene; + + // Do nothing if the target scene is the current one. + if (oldScene === newScene) { + done(); + return; + } + + if (this._scenes.indexOf(newScene) < 0) { + throw new Error('No such scene in viewer'); + } + + // Cancel an already ongoing transition. This ensures that the stage contains + // layers from exactly one scene before the transition begins. + if (this._cancelCurrentTween) { + this._cancelCurrentTween(); + this._cancelCurrentTween = null; + } + + var oldSceneLayers = oldScene ? oldScene.listLayers() : []; + var newSceneLayers = newScene.listLayers(); + var stageLayers = stage.listLayers(); + + // Check that the stage contains exactly as many layers as the current scene, + // and that the top layer is the right one. If this test fails, either there + // is a bug or the user tried to modify the stage concurrently. + if (oldScene && ((stageLayers.length !== oldSceneLayers.length) || + (stageLayers.length > 1 && stageLayers[0] != oldSceneLayers[0]))) { + throw new Error('Stage not in sync with viewer'); + } + + // Get the transition parameters. + var duration = opts.transitionDuration != null ? + opts.transitionDuration : defaultSwitchDuration; + var update = opts.transitionUpdate != null ? + opts.transitionUpdate : defaultTransitionUpdate; + + // Add new scene layers into the stage before starting the transition. + for (var i = 0; i < newSceneLayers.length; i++) { + this._addLayerToStage(newSceneLayers[i]); + } + + // Update function to be called on every frame. + function tweenUpdate(val) { + update(val, newScene, oldScene); + } + + // Once the transition is complete, remove old scene layers from the stage and + // remove the event listeners. If the old scene was destroyed during the + // transition, this has already been taken care of. Otherwise, we still need + // to get a fresh copy of the scene's layers, since they might have changed + // during the transition. + function tweenDone() { + if (self._replacedScene) { + self._removeSceneEventListeners(self._replacedScene); + oldSceneLayers = self._replacedScene.listLayers(); + for (var i = 0; i < oldSceneLayers.length; i++) { + self._removeLayerFromStage(oldSceneLayers[i]); + } + self._replacedScene = null; + } + self._cancelCurrentTween = null; + done(); + } + + // Store the cancelable for the transition. + this._cancelCurrentTween = tween_1(duration, tweenUpdate, tweenDone); + + // Update the current and replaced scene. + this._currentScene = newScene; + this._replacedScene = oldScene; + + // Emit scene and view change events. + this.emit('sceneChange'); + this.emit('viewChange'); + + // Add event listeners to the new scene. + // Note that event listeners can only be removed from the old scene once the + // transition is complete, since layers might get added or removed in the + // interim. + this._addSceneEventListeners(newScene); + }; + + + var Viewer_1 = Viewer; + + var vec4$6 = require$$67.vec4; + var mat4$6 = require$$67.mat4; + + /** + * Helper functions for color transformation {@link Effects}. + * + * References: + * + * - [ColorMatrix Guide](http://docs.rainmeter.net/tips/colormatrix-guide) + * - [Matrix Operations for Image Processing](http://www.graficaobscura.com/matrix/index.html) + * - [WebGLImageFilter](https://github.com/phoboslab/WebGLImageFilter) + * - [glfx.js](https://github.com/evanw/glfx.js) + * + * @namespace colorEffects + */ + + /** + * A vector and matrix corresponding to an identity transformation. + * + * @param {Object} result Object to store result + * @param {vec4} result.colorOffset Array with zeroes. + * @param {mat4} result.colorMatrix Identity matrix. + * + * @memberof colorEffects + */ + function identity$7(resultArg) { + var result = resultArg || {}; + result.colorOffset = result.colorOffset || vec4$6.create(); + result.colorMatrix = result.colorMatrix || mat4$6.create(); + return result; + } + + /** + * Apply color effects to a single pixel + * + * @param {vec4} pixel Values in range [0,1] + * @param {Object} effect + * @param {vec4} effect.colorOffset + * @param {mat4} effect.colorMatrix + * @param {vec4} result Object to store result + * + * @memberof colorEffects + */ + function applyToPixel(pixel, effect, result) { + vec4TransformMat4Transposed(result, pixel, effect.colorMatrix); + vec4$6.add(result, result, effect.colorOffset); + } + + // Oddly, the colorTransform matrix needs to be transposed to be used with + // vec4.transformMat4. It is strange that transformMat4 dosn't work the same + // way as multiplying on the shader. + // TODO: investigate this further + function vec4TransformMat4Transposed(out, a, m) { + var x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[1] * y + m[2] * z + m[3] * w; + out[1] = m[4] * x + m[5] * y + m[6] * z + m[7] * w; + out[2] = m[8] * x + m[9] * y + m[10] * z + m[11] * w; + out[3] = m[12] * x + m[13] * y + m[14] * z + m[15] * w; + return out; + } + + /** + * Apply color effects to an ImageData + * + * @param {ImageData} imageData This object will be mutated + * @param {Object} effect + * @param {vec4} effect.colorOffset + * @param {mat4} effect.colorMatrix + * + * @memberof colorEffects + */ + var tmpPixel = vec4$6.create(); + function applyToImageData(imageData, effect) { + var width = imageData.width; + var height = imageData.height; + var data = imageData.data; + + for(var i = 0; i < width * height; i++) { + vec4$6.set(tmpPixel, data[i*4+0]/255, data[i*4+1]/255, data[i*4+2]/255, data[i*4+3]/255); + applyToPixel(tmpPixel, effect, tmpPixel); + data[i*4+0] = tmpPixel[0]*255; + data[i*4+1] = tmpPixel[1]*255; + data[i*4+2] = tmpPixel[2]*255; + data[i*4+3] = tmpPixel[3]*255; + } + } + + var colorEffects = { + identity: identity$7, + applyToPixel: applyToPixel, + applyToImageData: applyToImageData + }; + + var defaultSpeed = 0.1; + var defaultAccel = 0.01; + + var defaultOptions$6 = { + yawSpeed: defaultSpeed, + pitchSpeed: defaultSpeed, + fovSpeed: defaultSpeed, + yawAccel: defaultAccel, + pitchAccel: defaultAccel, + fovAccel: defaultAccel, + targetPitch: 0, + targetFov: null + }; + + /** + * @param {Object} opts + * @param {Number} [opts.yawSpeed=0.1] Yaw maximum speed + * @param {Number} [opts.pitchSpeed=0.1] Pitch maximum speed + * @param {Number} [opts.fovSpeed=0.1] Fov maximum speed + * @param {Number} [opts.yawAccel=0.01] Yaw acceleration + * @param {Number} [opts.pitchAccel=0.01] Pitch acceleration + * @param {Number} [opts.fovAccel=0.01] Fov acceleration + * @param {Number} [opts.targetPitch=0] Value that pitch converges to. `null` means that the pitch will not change. + * @param {Number} [opts.targetFov=null] Value that fov converges to. `null` means that the fov will not change. + * @returns Movement function that can be passed to {@link Viewer#setIdleMovement} or {@link Scene#startMovement} + */ + function autorotate(opts) { + + opts = defaults_1(opts || {}, defaultOptions$6); + + var yawSpeed = opts.yawSpeed; + var pitchSpeed = opts.pitchSpeed; + var fovSpeed = opts.fovSpeed; + var yawAccel = opts.yawAccel; + var pitchAccel = opts.pitchAccel; + var fovAccel = opts.fovAccel; + var targetPitch = opts.targetPitch; + var targetFov = opts.targetFov; + + return function start() { + + var lastTime = 0; + var lastYawSpeed = 0; + var lastPitchSpeed = 0; + var lastFovSpeed = 0; + + var currentYawSpeed = 0; + var currentPitchSpeed = 0; + var currentFovSpeed = 0; + + var timeDelta; + var yawDelta; + var pitchDelta; + var fovDelta; + + return function step(params, currentTime) { + + timeDelta = (currentTime - lastTime) / 1000; + currentYawSpeed = Math.min(lastYawSpeed + timeDelta * yawAccel, yawSpeed); + yawDelta = currentYawSpeed * timeDelta; + params.yaw = params.yaw + yawDelta; + + if (targetPitch != null && params.pitch !== targetPitch) { + var pitchThresh = 0.5 * lastPitchSpeed * lastPitchSpeed / pitchAccel; + if (Math.abs(targetPitch - params.pitch) > pitchThresh) { + // Acceleration phase + currentPitchSpeed = Math.min(lastPitchSpeed + timeDelta * pitchAccel, pitchSpeed); + } else { + // Deceleration phase + currentPitchSpeed = Math.max(lastPitchSpeed - timeDelta * pitchAccel, 0); + } + // currentPitchSpeed is the absolute value (>= 0) + pitchDelta = currentPitchSpeed * timeDelta; + if (targetPitch < params.pitch) { + params.pitch = Math.max(targetPitch, params.pitch - pitchDelta); + } + if (targetPitch > params.pitch) { + params.pitch = Math.min(targetPitch, params.pitch + pitchDelta); + } + } + + if (targetFov != null && params.fov !== targetPitch) { + var fovThresh = 0.5 * lastFovSpeed * lastFovSpeed / fovAccel; + if (Math.abs(targetFov - params.fov) > fovThresh) { + // Acceleration phase + currentFovSpeed = Math.min(lastFovSpeed + timeDelta * fovAccel, fovSpeed); + } else { + // Deceleration phase + currentFovSpeed = Math.max(lastFovSpeed - timeDelta * fovAccel, 0); + } + // currentFovSpeed is the absolute value (>= 0) + fovDelta = currentFovSpeed * timeDelta; + if (targetFov < params.fov) { + params.fov = Math.max(targetFov, params.fov - fovDelta); + } + if (targetFov > params.fov) { + params.fov = Math.min(targetFov, params.fov + fovDelta); + } + } + + lastTime = currentTime; + lastYawSpeed = currentYawSpeed; + lastPitchSpeed = currentPitchSpeed; + lastFovSpeed = currentFovSpeed; + + return params; + + }; + + }; + + } + + var autorotate_1 = autorotate; + + /* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @memberof util + * @param {number} deg + * @return {number} + */ + function degToRad(deg) { + return deg * Math.PI / 180; + } + + var degToRad_1 = degToRad; + + var src = { + + // Stages. + WebGlStage: WebGl$1, + CssStage: Css$1, + FlashStage: Flash$2, + + // Renderers. + WebGlCubeRenderer: WebGlCube, + WebGlFlatRenderer: WebGlFlat, + WebGlEquirectRenderer: WebGlEquirect, + CssCubeRenderer: CssCube, + CssFlatRenderer: CssFlat, + FlashCubeRenderer: FlashCube, + FlashFlatRenderer: FlashFlat, + registerDefaultRenderers: registerDefaultRenderers_1, + + // Geometries. + CubeGeometry: Cube, + FlatGeometry: Flat, + EquirectGeometry: Equirect, + + // Views. + RectilinearView: Rectilinear, + FlatView: Flat$1, + + // Sources. + ImageUrlSource: ImageUrl, + SingleAssetSource: SingleAsset, + + // Assets. + StaticAsset: Static, + DynamicAsset: Dynamic, + + // Texture store. + TextureStore: TextureStore_1, + + // Layer. + Layer: Layer_1, + + // Render loop. + RenderLoop: RenderLoop_1, + + // Controls. + KeyControlMethod: Key, + DragControlMethod: Drag, + QtvrControlMethod: Qtvr, + ScrollZoomControlMethod: ScrollZoom, + PinchZoomControlMethod: PinchZoom, + VelocityControlMethod: Velocity, + ElementPressControlMethod: ElementPress, + Controls: Controls_1, + Dynamics: Dynamics_1, + + // High-level API. + Viewer: Viewer_1, + Scene: Scene_1, + + // Hotspots. + Hotspot: Hotspot_1, + HotspotContainer: HotspotContainer_1, + + // Effects. + colorEffects: colorEffects, + + // Miscellaneous functions. + registerDefaultControls: registerDefaultControls_1, + autorotate: autorotate_1, + + // Utility functions. + util: { + async: async_1, + cancelize: cancelize_1, + chain: chain_1, + clamp: clamp_1, + clearOwnProperties: clearOwnProperties_1, + cmp: cmp_1, + compose: compose_1, + convertFov: convertFov, + decimal: decimal_1, + defaults: defaults_1, + defer: defer_1, + degToRad: degToRad_1, + delay: delay_1, + dom: dom, + extend: extend_1, + hash: hash_1, + inherits: inherits_1, + mod: mod_1, + noop: noop_1, + now: now, + once: once_1, + pixelRatio: pixelRatio_1, + radToDeg: radToDeg_1, + real: real_1, + retry: retry_1, + tween: tween_1, + type: type_1 + }, + + // Expose dependencies for clients to use. + dependencies: { + bowser: es5, + glMatrix: require$$67, + eventEmitter: minimalEventEmitter, + hammerjs: hammer + } + }; + + var initialFov = function (aspectRatio) { + var fovMax = 2 * Math.atan(Math.tan((120 * Math.PI) / 180 / 2) / aspectRatio); + return Math.min((100 * Math.PI) / 180, fovMax); + }; + var createView = function (aspectRatio, viewParams, viewLimit) { + var _a, _b; + if (viewParams === void 0) { viewParams = { yaw: 0, pitch: 0 }; } + var initialViewParams = __assign({ fov: initialFov(aspectRatio), roll: Math.PI * 0 }, viewParams); + var limiter = (viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.minVFov) ? src.util.compose(src.RectilinearView.limit.vfov(viewLimit.minVFov, viewLimit.maxVFov), src.RectilinearView.limit.hfov(0, viewLimit.maxHFov), src.RectilinearView.limit.pitch(-Math.PI * 0.5, Math.PI * 0.5)) + : src.RectilinearView.limit.traditional(4096, (_a = viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.maxVFov) !== null && _a !== void 0 ? _a : (100 * Math.PI) / 180, (_b = viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.maxHFov) !== null && _b !== void 0 ? _b : (150 * Math.PI) / 180); + return new src.RectilinearView(initialViewParams, limiter); + }; + + // @ts-ignore + var EquiImage = /** @class */ (function () { + function EquiImage(_a, aspectRatio, viewLimit) { + var url = _a.url, type = _a.type, viewParams = _a.viewParams; + this.url = url; + this.type = type; + this.viewParams = viewParams; + this.aspectRatio = aspectRatio; + this.viewLimit = viewLimit; + } + EquiImage.createGeometry = function () { + return new src.EquirectGeometry([{ width: 4096 }]); + }; + EquiImage.prototype.createSource = function () { + return src.ImageUrlSource.fromString(this.url); + }; + EquiImage.prototype.createScene = function (viewer) { + return viewer.createScene({ + geometry: EquiImage.createGeometry(), + pinFirstLevel: true, + source: this.createSource(), + view: createView(this.aspectRatio, this.viewParams, this.viewLimit), + }); + }; + return EquiImage; + }()); + + // @ts-ignore + var CubeImage = /** @class */ (function () { + function CubeImage(_a, aspectRatio, viewLimit) { + var urls = _a.urls, type = _a.type, viewParams = _a.viewParams; + this.urls = urls; + this.type = type; + this.viewParams = viewParams; + this.aspectRatio = aspectRatio; + this.viewLimit = viewLimit; + } + CubeImage.createGeometry = function () { + return new src.CubeGeometry([{ size: 1536, tileSize: 1536 }]); + }; + CubeImage.prototype.createSource = function () { + var _this = this; + var sourceFromTile = function (tile) { + var valueFromTile = tile.face; + return { url: _this.urls[valueFromTile] }; + }; + return new src.ImageUrlSource(sourceFromTile, {}); + }; + CubeImage.prototype.createScene = function (viewer) { + return viewer.createScene({ + geometry: CubeImage.createGeometry(), + pinFirstLevel: true, + source: this.createSource(), + view: createView(this.aspectRatio, this.viewParams, this.viewLimit), + }); + }; + return CubeImage; + }()); + + // @ts-ignore + var createView$1 = function (size, viewLimit) { + var width = size.width, height = size.height; + var maxZoom = 2; + var aspectRatio = width / height || 1; + var initialViewParams = { + mediaAspectRatio: aspectRatio, + zoom: maxZoom, + }; + var minZoom = (viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.minZoom) || 0; + var limiter = src.util.compose(src.FlatView.limit.zoom(minZoom, maxZoom), src.FlatView.limit.letterbox()); + return new src.FlatView(initialViewParams, limiter); + }; + + var FlatImage = /** @class */ (function () { + function FlatImage(_a, canvas, viewLimit) { + var url = _a.url, type = _a.type; + this.url = url; + this.type = type; + this.canvas = canvas; + this.viewLimit = viewLimit; + } + FlatImage.init = function (_a, viewLimit) { + var url = _a.url, type = _a.type; + return __awaiter(this, void 0, void 0, function () { + var canvas, ctx, img; + return __generator(this, function (_b) { + canvas = document.createElement('canvas'); + ctx = canvas.getContext('2d'); + img = new Image(); + img.crossOrigin = 'anonymous'; + img.src = url; + return [2 /*return*/, new Promise(function (resolve, reject) { + img.onload = function () { + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + ctx.drawImage(img, 0, 0); + resolve(new FlatImage({ url: url, type: type }, canvas, viewLimit)); + }; + img.onerror = reject; + img.src = url; + })]; + }); + }); + }; + FlatImage.prototype.createGeometry = function () { + var _a = this.canvas, width = _a.width, height = _a.height; + var tileWidth = Math.max(width, height); + var tileHeight = tileWidth; + return new src.FlatGeometry([ + { + width: width, + height: height, + tileWidth: tileWidth, + tileHeight: tileHeight, + }, + ]); + }; + FlatImage.prototype.createSource = function () { + var asset = new src.DynamicAsset(this.canvas); + return new src.SingleAssetSource(asset); + }; + FlatImage.prototype.createScene = function (viewer) { + return viewer.createScene({ + geometry: this.createGeometry(), + pinFirstLevel: true, + source: this.createSource(), + view: createView$1(this.canvas, this.viewLimit), + }); + }; + return FlatImage; + }()); + + function newImage(x, aspectRatio, viewLimit) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (x.type === 'cube') { + return [2 /*return*/, new CubeImage(x, aspectRatio, viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.rectilinear)]; + } + if (x.type === 'equirect') { + return [2 /*return*/, new EquiImage(x, aspectRatio, viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.rectilinear)]; + } + return [2 /*return*/, FlatImage.init(x, viewLimit === null || viewLimit === void 0 ? void 0 : viewLimit.flat)]; + }); + }); + } + + // Unique ID creation requires a high quality random # generator. In the browser we therefore + // require the crypto API and do not support built-in fallback to lower quality random number + // generators (like Math.random()). + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, + // find the complete implementation of crypto (msCrypto) on IE11. + var getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); + var rnds8 = new Uint8Array(16); + function rng() { + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); + } + + return getRandomValues(rnds8); + } + + var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + + function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); + } + + /** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ + + var byteToHex = []; + + for (var i$1 = 0; i$1 < 256; ++i$1) { + byteToHex.push((i$1 + 0x100).toString(16).substr(1)); + } + + function stringify(arr) { + var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!validate(uuid)) { + throw TypeError('Stringified UUID is invalid'); + } + + return uuid; + } + + function v4(options, buf, offset) { + options = options || {}; + var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (var i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return stringify(rnds); + } + + var StyleSheet = /** @class */ (function () { + function StyleSheet() { + var styleEl = document.createElement('style'); + document.head.appendChild(styleEl); + var sheet = styleEl.sheet; + if (!sheet) { + throw new Error('Failed to create a stylesheet.'); + } + this.sheet = sheet; + } + StyleSheet.prototype.insertRule = function (selector, css) { + this.sheet.insertRule(selector + " " + css, 0); + }; + return StyleSheet; + }()); + + // eslint-disable-next-line import/prefer-default-export + var hotspotEvents = function (div, outerDiv, options) { + var draggable = (options === null || options === void 0 ? void 0 : options.draggable) || false; + var stopPropagation = pipe(tap(function (e) { + e.stopPropagation(); + })); + var mouseEnter$ = fromEvent(div, 'mouseenter').pipe(stopPropagation); + var mouseLeave$ = fromEvent(div, 'mouseleave').pipe(stopPropagation); + var mouseDown$ = fromEvent(div, 'mousedown').pipe(stopPropagation); + var mouseUp$ = fromEvent(window, 'mouseup').pipe(stopPropagation); + var mouseMove$ = fromEvent(window, 'mousemove').pipe(stopPropagation); + var touchStart$ = fromEvent(div, 'touchstart').pipe(stopPropagation); + var touchEnd$ = fromEvent(window, 'touchend').pipe(stopPropagation); + var touchMove$ = fromEvent(window, 'touchmove').pipe(stopPropagation); + var blur$ = fromEvent(window, 'blur'); + var pointerDown$ = merge(mouseDown$, touchStart$); + var pointerUpGlobal$ = merge(mouseUp$, touchEnd$, blur$); + var pointerUp$ = pointerDown$.pipe(switchMapTo(pointerUpGlobal$.pipe(first()))); + var pointerMove$ = merge(mouseMove$, touchMove$.pipe(filter(function (e) { return e.touches.length > 0; }), map(function (e) { return e.touches[0]; }))); + var browserClick$ = fromEvent(div, 'click').pipe(stopPropagation); + var customClick$ = pointerDown$.pipe(mergeMap(function (e) { + return pointerMove$.pipe(takeUntil(pointerUpGlobal$), count(), filter(function (n) { return n === 0; }), map(function () { return e; })); + })); + var clicked$ = draggable ? customClick$ : browserClick$; + var dragPosition$ = pointerMove$.pipe(observeOn(animationFrameScheduler), windowToggle(pointerDown$, function () { return pointerUpGlobal$; }), map(function (o$) { + var rect = outerDiv.getBoundingClientRect(); + return o$.pipe(first(), map(function (e) { return ({ x: rect.x - e.clientX, y: rect.y - e.clientY }); }), switchMap(function (_a) { + var x = _a.x, y = _a.y; + return o$.pipe(map(function (e) { return ({ x: e.clientX + x, y: e.clientY + y }); })); + })); + }), map(catchError(function () { return EMPTY; }))); + // Note: Prevents mouse down and touch start events from bubbling even when there is no listener. + pointerDown$.subscribe(); + return { + clicked$: clicked$, + mouseEnter$: mouseEnter$, + mouseLeave$: mouseLeave$, + dragPosition$: draggable ? dragPosition$ : EMPTY, + pointerDown$: pointerDown$, + pointerUp$: pointerUp$, + }; + }; + + // eslint-disable-next-line import/prefer-default-export + function escape(str) { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/ /g, ' '); + } + + var SCENE_LINK_BACKGROUND_COLOR = '#ea5851'; + var SCENE_LINK_BACKGROUND_COLOR_HOVER = '#2c2828'; + var SCENE_LINK_BORDER_COLOR = '#ffffff'; + var generateId = function () { return "x" + v4(); }; + // Note: Firefox will not display SVGs correctly if the filter IDs are duplicated. + var focusAnnotationSvg = function () { + var id = generateId(); + return ""; + }; + var imageAnnotationSvg = ""; + var textAnnotationSvg = ""; + var shareLinkAnnotationSvg = ""; + var HotspotFactory = /** @class */ (function () { + function HotspotFactory() { + this.stylesheet = new StyleSheet(); + } + HotspotFactory.prototype.css = function (tag, css) { + this.stylesheet.insertRule(tag, css); + }; + HotspotFactory.prototype.createAnnotation = function (annotation) { + var _a; + var opacity = (_a = annotation.opacity) !== null && _a !== void 0 ? _a : (annotation.draggable === false ? 0.5 : 1); + var disable = annotation.draggable === false; + var isProjects = annotation.type === 'shareLink'; + var outerDiv = document.createElement('div'); + var containerDiv = document.createElement('div'); + var div = document.createElement('div'); + var containerDivId = generateId(); + var divId = generateId(); + var bigger = generateId(); + if (annotation.zIndex != null) { + outerDiv.style.zIndex = "" + annotation.zIndex; + } + outerDiv.appendChild(containerDiv); + containerDiv.appendChild(div); + containerDiv.id = containerDivId; + div.id = divId; + if (annotation.draggable) { + div.draggable = true; + } + div.innerHTML = (function () { + switch (annotation.type) { + case 'text': + return textAnnotationSvg; + case 'image': + return imageAnnotationSvg; + case 'shareLink': + return shareLinkAnnotationSvg; + default: + return ''; + } + })(); + this.css("@keyframes " + bigger, "{\n 0% {\n transform: scale(0.9);\n }\n 100% {\n transform: scale(1.1);\n }\n }"); + this.css("#" + containerDivId, "{\n align-items: center;\n width: 36px;\n height: 36px;\n display: flex;\n justify-content: center;\n position: relative;\n transform: translateX(-50%) translateY(-50%);\n }"); + this.css("#" + divId, "{\n align-items: center;\n width: 36px;\n height: 36px;\n background-color: " + (isProjects + ? '#0093bb' + : "rgba(255, 255, 255, " + (annotation.opacity === 1 ? 1 : 0.8) + ")") + ";\n box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.5);\n border-radius: 100%;\n box-sizing: border-box;\n color: white;\n " + (disable ? '' : 'cursor: pointer;') + "\n display: flex;\n justify-content: center;\n position: relative;\n animation-duration: 0.3s;\n animation-name: none;\n opacity: " + opacity + ";\n }"); + this.css("#" + divId + ".hover", "{\n animation-name: " + bigger + ";\n transform: scale(1.1);\n }"); + return __assign({ div: outerDiv }, hotspotEvents(div, outerDiv, annotation)); + }; + HotspotFactory.prototype.createEmbeddedAnnotation = function (annotation) { + var outerDiv = document.createElement('div'); + var containerDiv = document.createElement('div'); + var div = document.createElement('div'); + var containerDivId = generateId(); + var divId = generateId(); + outerDiv.appendChild(containerDiv); + containerDiv.appendChild(div); + containerDiv.id = containerDivId; + div.id = divId; + div.innerHTML = (function () { + switch (annotation.type) { + case 'focus': + return focusAnnotationSvg(); + default: + return ''; + } + })(); + this.css("#" + containerDivId, "{\n align-items: center;\n width: 200px;\n height: 200px;\n display: flex;\n justify-content: center;\n position: relative;\n }"); + this.css("#" + divId, "{\n align-items: center;\n width: 200px;\n height: 200px;\n display: flex;\n justify-content: center;\n position: relative;\n cursor: pointer;\n }"); + return __assign({ div: outerDiv }, hotspotEvents(div, outerDiv, annotation)); + }; + HotspotFactory.prototype.createFlatEmbeddedAnnotation = function (annotation, size$) { + var outerDiv = document.createElement('div'); + var containerDiv = document.createElement('div'); + var div = document.createElement('div'); + var containerDivId = generateId(); + var divId = generateId(); + outerDiv.appendChild(containerDiv); + containerDiv.appendChild(div); + containerDiv.id = containerDivId; + div.id = divId; + div.innerHTML = (function () { + switch (annotation.type) { + case 'focus': + return focusAnnotationSvg(); + default: + return ''; + } + })(); + this.css("#" + containerDivId, "{\n align-items: center;\n display: flex;\n justify-content: center;\n position: relative;\n width: 0px;\n height: 0px;\n overflow: show;\n }"); + this.css("#" + divId, "{\n align-items: center;\n width: 200px;\n height: 200px;\n display: flex;\n justify-content: center;\n position: relative;\n cursor: pointer;\n }"); + size$.pipe(distinctUntilChanged()).subscribe(function (x) { + div.style.transform = "scale(" + x / 200 + ")"; + }); + return __assign({ div: outerDiv }, hotspotEvents(div, outerDiv, annotation)); + }; + // eslint-disable-next-line no-unused-vars + HotspotFactory.prototype.createSceneLink = function (sceneLink, hasDeleteButton) { + if (hasDeleteButton === void 0) { hasDeleteButton = false; } + var _a = sceneLink.withImage + ? this.createSceneLinkWithImage(sceneLink) + : this.createSceneLinkWithoutImage(sceneLink, hasDeleteButton), outerDiv = _a.outerDiv, div = _a.div, deleteButtonClicked$ = _a.deleteButtonClicked$; + return __assign({ div: outerDiv, deleteButtonClicked$: deleteButtonClicked$ }, hotspotEvents(div, outerDiv, sceneLink)); + }; + HotspotFactory.prototype.createSceneLinkWithImage = function (sceneLink) { + var imageUrl = sceneLink.imageUrl, label = sceneLink.label, isLocked = sceneLink.isLocked; + var containerId = generateId(); + var arrowContainerId = generateId(); + var imageContainerId = generateId(); + var imgId = generateId(); + var imgMaskId = generateId(); + var spanId = generateId(); + var pulsateId = generateId(); + var outerDiv = document.createElement('div'); + var div = document.createElement('div'); + outerDiv.appendChild(div); + div.id = containerId; + var lock = ''; + if (isLocked) { + var lockIconFilterId = imgMaskId + "-shadow-filter"; + lock = "\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n "; + } + div.innerHTML = "\n
\n \n \n \n \n \n \n
\n
\n " + (imageUrl + ? "\""" + : '') + "\n " + lock + "\n " + escape(label) + "\n
\n "; + this.css("@keyframes " + pulsateId, "{\n 0% {\n transform: scale(1.0);\n }\n 100% {\n transform: scale(1.2);\n }\n }"); + this.css("#" + containerId, "{\n align-items: center;\n cursor: pointer;\n display: flex;\n justify-content: center;\n position: relative;\n transform: translateX(-50%) translateY(-50%);\n animation-direction: alternate;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n animation-name: " + pulsateId + ";\n }"); + this.css("#" + containerId + ":hover", "{\n animation-name: none;\n }"); + this.css("#" + arrowContainerId, "{\n position: absolute;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n }"); + this.css("#" + imageContainerId, "{\n align-items: center;\n border-radius: 100%;\n border: 2px solid white;\n box-shadow: 0px 0px 4px 0px black;\n display: flex;\n height: 32px;\n justify-content: center;\n overflow: hidden;\n position: absolute;\n transition-duration: 300ms;\n transition-property: height, width;\n width: 32px;\n z-index: -1;\n }"); + this.css("#" + imageContainerId + ":hover", "{\n border: 1px solid gray;\n box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.3);\n height: 150px;\n width: 150px;\n z-index: 0;\n }"); + this.css("#" + imgId, "{\n border-radius: 100%;\n position: absolute;\n opacity: 0;\n object-fit: cover;\n width: 100%;\n height: 100%;\n transition-property: opacity;\n transition-duration: 300ms;\n }"); + this.css("#" + imgMaskId, "{\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: rgba(255, 255, 255, 0.45);\n visibility: hidden;\n display: flex;\n justify-content: center;\n }"); + this.css("#" + imageContainerId + ":hover #" + imgMaskId, "{\n visibility: visible;\n }"); + this.css("#" + imgMaskId + " .lockIcon", "{\n margin-top: 22px;\n }"); + this.css("#" + spanId, "{\n color: #ffffff;\n line-height: 22px;\n opacity: 0;\n padding: 15px;\n position: absolute;\n text-align: center;\n transition-duration: 300ms;\n transition-property: opacity;\n visibility: hidden;\n text-shadow: 0px 1px 5px rgba(0, 0, 0, 0.9);\n width: 100%;\n word-break: break-all;\n font-size: 14px;\n }"); + this.css("#" + imageContainerId + ":hover #" + imgId, "{\n opacity: 1;\n }"); + this.css("#" + imageContainerId + ":hover #" + spanId, "{\n visibility: visible;\n transition-delay: 300ms;\n opacity: 1;\n }"); + return { outerDiv: outerDiv, div: div, deleteButtonClicked$: EMPTY }; + }; + HotspotFactory.prototype.createSceneLinkWithoutImage = function (sceneLink, hasDeleteButton) { + return typeof sceneLink.draggable === 'undefined' + ? this.createSceneLinkOld(sceneLink, hasDeleteButton) + : this.createSceneLink2(sceneLink); + }; + HotspotFactory.prototype.createSceneLink2 = function (sceneLink) { + var disable = !sceneLink.draggable; + var label = sceneLink.label, opacity = sceneLink.opacity; + var containerId = generateId(); + var arrowContainerId = generateId(); + var labelId = generateId(); + var outerDiv = document.createElement('div'); + var div = document.createElement('div'); + outerDiv.appendChild(div); + div.id = containerId; + if (sceneLink.draggable) { + div.draggable = true; + } + div.innerHTML = "\n " + (label ? "" + escape(label) + "" : '') + "\n
\n \n \n \n \n \n \n
\n "; + this.css("#" + containerId, "{\n align-items: center;\n width: 34px;\n height: 34px;\n border: 2px solid white;\n border-radius: 100%;\n box-shadow: black 0px 0px 4px 0px;\n box-sizing: border-box;\n " + (disable ? '' : 'cursor: pointer;') + "\n display: flex;\n justify-content: center;\n position: relative;\n transform: translateX(-50%) translateY(-50%);\n opacity: " + (opacity || (disable ? 0.5 : 1.0)) + ";\n }"); + this.css("#" + labelId, "{\n position: absolute;\n top: -26px;\n line-height: 14px;\n background-color: rgba(0, 0, 0, 0.4);\n color: white;\n text-height: 12px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 2px;\n max-width: 160px;\n transition-duration: 300ms;\n transition-property: max-width;\n transition-timing-function: ease-in-out;\n }"); + this.css("#" + containerId + ":hover>span", "{\n max-width: 300px;\n }"); + this.css("#" + arrowContainerId, "{\n position: absolute;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n }"); + return { outerDiv: outerDiv, div: div, deleteButtonClicked$: EMPTY }; + }; + HotspotFactory.prototype.createSceneLinkOld = function (sceneLink, hasDeleteButton) { + var label = sceneLink.label; + var divId = generateId(); + var spanId = generateId(); + var outerDiv = document.createElement('div'); + var div = document.createElement('div'); + outerDiv.appendChild(div); + div.id = divId; + div.innerHTML = "\n " + escape(label) + "\n "; + var deleteButtonClicked$ = EMPTY; + if (hasDeleteButton) { + var button = document.createElement('button'); + button.id = generateId(); + button.innerHTML = "\n \n \n \n \n \n \n \n \n "; + deleteButtonClicked$ = fromEvent(button, 'click').pipe(tap(function (e) { + e.stopPropagation(); + outerDiv.style.visibility = 'hidden'; + })); + outerDiv.children[0].appendChild(button); + this.css("#" + button.id, "{\n background-color: " + SCENE_LINK_BORDER_COLOR + ";\n border-radius: 100%;\n border: 0;\n color: " + SCENE_LINK_BACKGROUND_COLOR + ";\n cursor: pointer;\n height: 16px;\n line-height: 16px;\n margin: 0;\n margin-left: 8px;\n padding: 0;\n text-align: center;\n width: 16px;\n }"); + } + this.css("#" + divId, "{\n align-items: center;\n background-color: " + SCENE_LINK_BACKGROUND_COLOR + ";\n border: 2px solid " + SCENE_LINK_BORDER_COLOR + ";\n border-radius: 16px;\n box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);\n cursor: pointer;\n display: flex;\n max-width: 160px;\n padding: 0px " + (hasDeleteButton ? '8px' : '16px') + " 0px 16px;\n position: relative;\n transform: translateX(-50%) translateY(-38px);\n transition-duration: 300ms;\n transition-property: max-width;\n transition-timing-function: ease-in-out;\n }"); + this.css("#" + divId + "::before", "{\n border-radius: 4px;\n content: '';\n width: 0;\n height: 0;\n border-left: 12px solid transparent;\n border-right: 12px solid transparent;\n border-top: 12px solid " + SCENE_LINK_BORDER_COLOR + ";\n position: absolute;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%) translateY(12px);\n }"); + this.css("#" + divId + "::after", "{\n border-radius: 4px;\n content: '';\n width: 0;\n height: 0;\n border-left: 10px solid transparent;\n border-right: 10px solid transparent;\n border-top: 10px solid " + SCENE_LINK_BACKGROUND_COLOR + ";\n position: absolute;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%) translateY(9px);\n }"); + this.css("#" + divId + ":hover", "{\n max-width: 300px;\n background-color: " + SCENE_LINK_BACKGROUND_COLOR_HOVER + ";\n }"); + this.css("#" + divId + ":hover::after", "{\n border-top: 10px solid " + SCENE_LINK_BACKGROUND_COLOR_HOVER + ";\n }"); + this.css("#" + divId + ":hover>button", "{\n color: " + SCENE_LINK_BACKGROUND_COLOR_HOVER + ";\n }"); + this.css("#" + spanId, "{\n color: " + SCENE_LINK_BORDER_COLOR + ";\n display: block;\n font-size: 14px;\n line-height: 30px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }"); + return { outerDiv: outerDiv, div: div, deleteButtonClicked$: deleteButtonClicked$ }; + }; + HotspotFactory.prototype.createTripodCover = function (tripodCover) { + var id = generateId(); + var outerDiv = document.createElement('div'); + outerDiv.innerHTML = ""; + outerDiv.onclick = function (e) { return e.stopPropagation(); }; + outerDiv.onmousedown = function (e) { return e.stopPropagation(); }; + outerDiv.onmouseup = function (e) { return e.stopPropagation(); }; + outerDiv.ontouchstart = function (e) { return e.stopPropagation(); }; + outerDiv.ontouchend = function (e) { return e.stopPropagation(); }; + this.css("#" + id, "{\n border-radius: 100%;\n object-fit: cover;\n height: 250px;\n width: 250px;\n }"); + return outerDiv; + }; + return HotspotFactory; + }()); + + function isFlatViewCoords(coords) { + if (!coords) + return false; + var c = coords; + return typeof c.x === 'number' && typeof c.y === 'number'; + } + function isRectilinearViewCoords(coords) { + if (!coords) + return false; + var c = coords; + return typeof c.yaw === 'number' && typeof c.pitch === 'number'; + } + + // const TRANSITION_DURATION = 300; + var TRANSITION_DURATION = 1000; + var Scene$1 = /** @class */ (function () { + function Scene(rawScene, viewer, rViewer, scene, isEditMode) { + this.willDestroy$s = new Subject(); + this.annotationEvent$$ = new ReplaySubject(); + this.annotationEvent$ = this.annotationEvent$$.pipe(mergeAll(), takeUntil(this.willDestroy$s)); + this.embeddedAnnotationEvent$$ = new ReplaySubject(); + this.embeddedAnnotationEvent$ = this.embeddedAnnotationEvent$$.pipe(mergeAll(), takeUntil(this.willDestroy$s)); + this.sceneLinkEvent$$ = new ReplaySubject(); + this.sceneLinkEvent$ = this.sceneLinkEvent$$.pipe(mergeAll(), takeUntil(this.willDestroy$s)); + var id = rawScene.id, image = rawScene.image, sceneLinks = rawScene.sceneLinks; + this.id = id; + this.image = image; + this.viewer = viewer; + this.rViewer = rViewer; + this.scene = scene; + this.sceneLinks = sceneLinks || []; + var events = this.scene + .listLayers() + .map(function (layer) { return fromEvent(layer.textureStore(), 'textureLoad'); }); + this.textureLoaded$ = from(events).pipe(mergeAll(), takeUntil(this.willDestroy$s)); + this.hotspotFactory = new HotspotFactory(); + this.addHotspots(rawScene, isEditMode); + } + Object.defineProperty(Scene.prototype, "willDestroy$", { + get: function () { + return this.willDestroy$s.pipe(take(1)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Scene.prototype, "initialView", { + get: function () { + if (this.image.type === 'flat') + return undefined; + var viewParams = this.image.viewParams || { yaw: 0, pitch: 0 }; + return __assign({ fov: initialFov(this.aspectRatio) }, viewParams); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Scene.prototype, "aspectRatio", { + get: function () { + return this.viewer.stage().width() / this.viewer.stage().height() || 1; + }, + enumerable: false, + configurable: true + }); + Scene.prototype.addHotspots = function (tscene, isEditMode) { + var _this = this; + var image = tscene.image, annotations = tscene.annotations, embeddedAnnotations = tscene.embeddedAnnotations, sceneLinks = tscene.sceneLinks, tripodCover = tscene.tripodCover; + if (annotations) { + annotations.forEach(function (annotation) { return _this.addAnnotation(annotation); }); + } + if (embeddedAnnotations) { + embeddedAnnotations.forEach(function (annotation) { + return _this.addEmbeddedAnnotation(annotation); + }); + } + if (sceneLinks) { + sceneLinks === null || sceneLinks === void 0 ? void 0 : sceneLinks.forEach(function (sceneLink) { + return _this.addSceneLink(sceneLink, isEditMode); + }); + } + if (tripodCover && image.type !== 'flat') { + var dom = this.hotspotFactory.createTripodCover(tripodCover); + this.createHotspot({ + dom: dom, + position: { yaw: 0, pitch: Math.PI * 0.5, type: 'rectilinear' }, + perspective: { radius: 500 }, + }); + } + }; + Scene.prototype.processDragPosition = function (dragPosition$, div) { + var _this = this; + var node = div.firstChild; + var dragStart$ = dragPosition$.pipe(map(pipe(first(), catchError(function () { return EMPTY; }))), mergeAll(), first()); + var dragEnd$ = dragPosition$.pipe(map(pipe(last(), catchError(function () { return EMPTY; }))), mergeAll(), first(), map(function (_a) { + var clientX = _a.x, clientY = _a.y; + var rect = _this.viewer.domElement().getBoundingClientRect(); + var x = clientX - rect.x; + var y = clientY - rect.y; + var view = _this.view(); + var position = __assign(__assign({}, view.screenToCoordinates({ x: x, y: y })), { type: view.type }); + return { position: position, xy: { x: x, y: y } }; + })); + dragStart$.subscribe(function () { + _this.viewer.controls().disable(); + document.body.appendChild(node); + node.style.position = 'fixed'; + node.style.zIndex = '10'; + }); + dragEnd$.subscribe(function () { + _this.viewer.controls().enable(); + node.style.display = 'none'; + }); + dragPosition$ + .pipe(mergeAll(), observeOn(animationFrameScheduler)) + .subscribe(function (_a) { + var x = _a.x, y = _a.y; + node.style.left = x + "px"; + node.style.top = y + "px"; + }); + dragPosition$ + .pipe(map(function (p$) { + return p$.pipe(map(function (_a) { + var x = _a.x, y = _a.y; + var rect = _this.viewer.domElement().getBoundingClientRect(); + var ths = 18; + if (x - rect.x < ths) { + return 'left'; + } + if (x - rect.x > rect.width - ths) { + return 'right'; + } + if (y - rect.y < ths) { + return 'top'; + } + if (y - rect.y > rect.height - ths) { + return 'bottom'; + } + return null; + }), endWith(null)); + }), mergeAll(), switchMap(function (b) { return (b ? interval(10).pipe(mapTo(b)) : EMPTY); }), observeOn(animationFrameScheduler)) + .subscribe(function (edge) { + var coords = _this.rViewer.getRectilinearViewCoords(); + switch (edge) { + case 'left': + _this.rViewer.setRectilinearViewCoords(__assign(__assign({}, coords), { yaw: coords.yaw - 0.01 })); + break; + case 'right': + _this.rViewer.setRectilinearViewCoords(__assign(__assign({}, coords), { yaw: coords.yaw + 0.01 })); + break; + } + }); + return { + dragStart$: dragStart$, + dragEnd$: dragEnd$, + }; + }; + Scene.prototype.processEmbeddedDragPosition = function (dragPosition$, marzipanoHotspot) { + var _this = this; + var position$$ = dragPosition$.pipe(map(function (o$) { + var baseCoords = marzipanoHotspot.position(); + var baseXY = (function () { + var view = _this.view(); + if (isFlatViewCoords(baseCoords) && view.type === 'flat') { + return view.coordinatesToScreen(baseCoords); + } + if (isRectilinearViewCoords(baseCoords) && + view.type === 'rectilinear') { + return view.coordinatesToScreen(baseCoords); + } + return undefined; + })(); + return baseXY + ? o$.pipe(pairwise(), scan(function (_a, _b) { + var x = _a.x, y = _a.y; + var _c = _b[0], x0 = _c.x, y0 = _c.y, _d = _b[1], x1 = _d.x, y1 = _d.y; + return ({ + x: x + x1 - x0, + y: y + y1 - y0, + }); + }, baseXY), map(function (xy) { + var position = __assign(__assign({}, _this.view().screenToCoordinates(xy)), { type: _this.view().type }); + return { position: position, xy: xy }; + })) + : EMPTY; + })); + var dragStart$ = position$$.pipe(map(pipe(first(), catchError(function () { return EMPTY; }))), switchAll()); + var dragEnd$ = position$$.pipe(map(pipe(last(), catchError(function () { return EMPTY; }))), switchAll()); + dragStart$.subscribe(function () { return _this.viewer.controls().disable(); }); + dragEnd$.subscribe(function () { return _this.viewer.controls().enable(); }); + position$$.pipe(switchAll()).subscribe(function (_a) { + var position = _a.position; + marzipanoHotspot.setPosition(position); + }); + return { + dragStart$: dragStart$, + dragEnd$: dragEnd$, + }; + }; + Scene.prototype.addAnnotation = function (annotation) { + var _this = this; + var _a = this.hotspotFactory.createAnnotation(annotation), div = _a.div, clicked$ = _a.clicked$, mouseEnter$ = _a.mouseEnter$, mouseLeave$ = _a.mouseLeave$, dragPosition$ = _a.dragPosition$; + var deleteHotspot = this.createHotspot(__assign({ dom: div }, annotation)).deleteHotspot; + var res = function () { + var _a = div.getBoundingClientRect(), divX = _a.x, divY = _a.y; + var _b = _this.viewer.domElement().getBoundingClientRect(), viewerX = _b.x, viewerY = _b.y; + return __assign(__assign({}, annotation), { div: div, xy: { x: divX - viewerX, y: divY - viewerY } }); + }; + this.annotationEvent$$.next(clicked$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'clicked' })); }))); + this.annotationEvent$$.next(mouseEnter$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'mouseEnter' })); }))); + this.annotationEvent$$.next(mouseLeave$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'mouseLeave' })); }))); + if (annotation.draggable) { + var _b = this.processDragPosition(dragPosition$, div), dragStart$ = _b.dragStart$, dragEnd$ = _b.dragEnd$; + this.annotationEvent$$.next(dragStart$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'dragStart' })); }))); + this.annotationEvent$$.next(dragEnd$.pipe(map(function (_a) { + var position = _a.position, xy = _a.xy; + return (__assign(__assign({}, res()), { position: position, + xy: xy, eventType: 'dragEnd' })); + }))); + dragEnd$.pipe(take(1)).subscribe(function (_a) { + var position = _a.position; + try { + deleteHotspot(); + _this.addAnnotation(__assign(__assign({}, annotation), { position: position })); + } + catch (_b) { + // TODO: + } + }); + } + }; + Scene.prototype.addEmbeddedAnnotation = function (annotation) { + var _this = this; + var view = this.view(); + var _a = (function () { + if (view.type === 'rectilinear') { + return _this.hotspotFactory.createEmbeddedAnnotation(annotation); + } + var size$ = fromEvent(view, 'change').pipe(startWith(null), map(function () { + var rect = _this.viewer.domElement().getBoundingClientRect(); + var _a = view.parameters(), zoom = _a.zoom, mediaAspectRatio = _a.mediaAspectRatio; + var viewerWidthPx = rect.width; + var imgWidthPx = viewerWidthPx / zoom; + var imgHeightPx = imgWidthPx / mediaAspectRatio; + return imgHeightPx * annotation.height; + })); + return _this.hotspotFactory.createFlatEmbeddedAnnotation(annotation, size$); + })(), div = _a.div, clicked$ = _a.clicked$, mouseEnter$ = _a.mouseEnter$, mouseLeave$ = _a.mouseLeave$, dragPosition$ = _a.dragPosition$; + var marzipanoHotspot = this.createHotspot(__assign({ dom: div, perspective: view.type === 'rectilinear' + ? { radius: 100 / Math.tan(annotation.height / 2) } + : undefined }, annotation)).marzipanoHotspot; + var res = function () { + var position = marzipanoHotspot.position(); + var xy = (function () { + if (isFlatViewCoords(position) && view.type === 'flat') { + return view.coordinatesToScreen(position); + } + if (isRectilinearViewCoords(position) && view.type === 'rectilinear') { + return view.coordinatesToScreen(position); + } + return undefined; + })() || { x: 0, y: 0 }; + return __assign(__assign({}, annotation), { div: div, + xy: xy }); + }; + this.embeddedAnnotationEvent$$.next(clicked$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'clicked' })); }))); + this.embeddedAnnotationEvent$$.next(mouseEnter$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'mouseEnter' })); }))); + this.embeddedAnnotationEvent$$.next(mouseLeave$.pipe(map(function () { return (__assign(__assign({}, res()), { eventType: 'mouseLeave' })); }))); + if (annotation.draggable) { + var _b = this.processEmbeddedDragPosition(dragPosition$, marzipanoHotspot), dragStart$ = _b.dragStart$, dragEnd$ = _b.dragEnd$; + this.embeddedAnnotationEvent$$.next(dragStart$.pipe(map(function (_a) { + var position = _a.position, xy = _a.xy; + return (__assign(__assign({}, res()), { position: position, + xy: xy, eventType: 'dragStart' })); + }))); + this.embeddedAnnotationEvent$$.next(dragEnd$.pipe(map(function (_a) { + var position = _a.position, xy = _a.xy; + return (__assign(__assign({}, res()), { position: position, + xy: xy, eventType: 'dragEnd' })); + }))); + } + }; + Scene.prototype.addSceneLink = function (sceneLink, isEditMode) { + var _this = this; + var _a = this.hotspotFactory.createSceneLink(sceneLink, isEditMode), div = _a.div, clicked$ = _a.clicked$, deleteButtonClicked$ = _a.deleteButtonClicked$, mouseEnter$ = _a.mouseEnter$, mouseLeave$ = _a.mouseLeave$, dragPosition$ = _a.dragPosition$, pointerDown$ = _a.pointerDown$, pointerUp$ = _a.pointerUp$; + var deleteHotspot = this.createHotspot(__assign({ dom: div }, sceneLink)).deleteHotspot; + var fromTo = { + from: this.id, + to: sceneLink.sceneId, + position: sceneLink.position, + draggable: sceneLink.draggable || false, + }; + this.sceneLinkEvent$$.next(clicked$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'clicked' })))); + this.sceneLinkEvent$$.next(deleteButtonClicked$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'deleted' })))); + this.sceneLinkEvent$$.next(mouseEnter$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'mouseEnter' })))); + this.sceneLinkEvent$$.next(mouseLeave$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'mouseLeave' })))); + this.sceneLinkEvent$$.next(pointerDown$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'pointerDown' })))); + this.sceneLinkEvent$$.next(pointerUp$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'pointerUp' })))); + if (sceneLink.draggable) { + var _b = this.processDragPosition(dragPosition$, div), dragStart$ = _b.dragStart$, dragEnd$ = _b.dragEnd$; + this.sceneLinkEvent$$.next(dragStart$.pipe(mapTo(__assign(__assign({}, fromTo), { eventType: 'dragStart' })))); + this.sceneLinkEvent$$.next(dragEnd$.pipe(map(function (_a) { + var position = _a.position, xy = _a.xy; + return (__assign(__assign({}, fromTo), { position: position, + xy: xy, eventType: 'dragEnd' })); + }))); + dragEnd$.pipe(take(1)).subscribe(function (_a) { + var position = _a.position; + try { + deleteHotspot(); + _this.addSceneLink(__assign(__assign({}, sceneLink), { position: position }), isEditMode); + } + catch (_b) { + // TODO: + } + }); + } + }; + Scene.prototype.directionTo = function (sceneId, walkthrough) { + if (walkthrough === void 0) { walkthrough = true; } + if (!walkthrough) + return undefined; + var sceneLink = this.sceneLinks.find(function (x) { return x.sceneId === sceneId; }); + if (!sceneLink) + return undefined; + if (sceneLink.position.type === 'rectilinear') { + return sceneLink.position; + } + return undefined; + }; + Scene.prototype.updateHotspots = function (rawScene, isEditMode) { + var hotspotContainer = this.scene.hotspotContainer(); + hotspotContainer + .listHotspots() + .forEach(function (hotspot) { return hotspotContainer.destroyHotspot(hotspot); }); + this.addHotspots(rawScene, isEditMode); + }; + Scene.init = function (_a) { + var props = _a.props, viewer = _a.viewer, rViewer = _a.rViewer, isEditMode = _a.isEditMode, viewLimit = _a.viewLimit; + return __awaiter(this, void 0, void 0, function () { + var stage, aspectRatio, image, scene; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + stage = viewer.stage(); + aspectRatio = stage.width() / stage.height() || 1; + return [4 /*yield*/, newImage(props.image, aspectRatio, viewLimit)]; + case 1: + image = _b.sent(); + scene = image.createScene(viewer); + return [2 /*return*/, new Scene(props, viewer, rViewer, scene, isEditMode)]; + } + }); + }); + }; + Scene.prototype.switchTo = function (options) { + var _a; + var defaultTransitionDuration = (_a = options.transitionDuration) !== null && _a !== void 0 ? _a : TRANSITION_DURATION; + var _b = (function () { + if (options.sceneLinkTransition) { + var _a = options.sceneLinkTransition, + // eslint-disable-next-line no-shadow + rotationDuration_1 = _a.rotationDuration, + // eslint-disable-next-line no-shadow + zoomInDuration_1 = _a.zoomInDuration; + // eslint-disable-next-line no-shadow + var transitionDuration_1 = Math.max(rotationDuration_1 + zoomInDuration_1, defaultTransitionDuration); + return { transitionDuration: transitionDuration_1, rotationDuration: rotationDuration_1, zoomInDuration: zoomInDuration_1 }; + // eslint-disable-next-line no-else-return + } + else { + // eslint-disable-next-line no-shadow + var transitionDuration_2 = defaultTransitionDuration; + // eslint-disable-next-line no-shadow + var rotationDuration_2 = 0.5 * defaultTransitionDuration; + // eslint-disable-next-line no-shadow + var zoomInDuration_2 = 0.5 * defaultTransitionDuration; + return { transitionDuration: transitionDuration_2, rotationDuration: rotationDuration_2, zoomInDuration: zoomInDuration_2 }; + } + })(), transitionDuration = _b.transitionDuration, rotationDuration = _b.rotationDuration, zoomInDuration = _b.zoomInDuration; + var currentYaw = 0; + var currentPitch = 0; + var dYaw = 0; + var dPitch = 0; + var rotate = false; + this.scene.switchTo({ + transitionDuration: transitionDuration, + transitionUpdate: function (t, newScene, oldScene) { + var _a, _b; + if (newScene) { + var view = newScene.view(); + if (t === 0 && view.type === 'rectilinear') { + if (options.initialView) { + view.setParameters(options.initialView); + } + if (!oldScene && options.target) { + view.setParameters(options.target); + } + } + } + var walkthrough = (_b = (_a = options.sceneLinkTransition) === null || _a === void 0 ? void 0 : _a.walkthrough) !== null && _b !== void 0 ? _b : true; + if (oldScene && walkthrough) { + var view = oldScene.view(); + if (view.type === 'rectilinear' && options.target) { + rotate = true; + if (t === 0) { + var yaw = options.target.yaw; + var pitch = 0; + currentYaw = view.yaw(); + currentPitch = view.pitch(); + var dYawRaw_1 = (yaw !== null && yaw !== void 0 ? yaw : currentYaw) - currentYaw; + dYaw = (function () { + if (dYawRaw_1 > Math.PI) + return dYawRaw_1 - 2 * Math.PI; + if (dYawRaw_1 < -Math.PI) + return dYawRaw_1 + 2 * Math.PI; + return dYawRaw_1; + })(); + dPitch = (pitch !== null && pitch !== void 0 ? pitch : currentPitch) - currentPitch; + } + var t1 = Math.min((t * transitionDuration) / rotationDuration, 1); + var ease = function (x) { return x * (2 - x); }; + var s = ease(t1); + view.setYaw(currentYaw + s * dYaw); + view.setPitch(currentPitch + s * dPitch); + if (t * transitionDuration > rotationDuration) { + view.setFov(view.fov() * 0.99); + } + } + } + (function () { + var s = Math.max((t * transitionDuration - rotationDuration) / zoomInDuration, 0); + var opacity = Math.min(rotate + ? s * s + : (t * transitionDuration) / defaultTransitionDuration, 1); + newScene + .listLayers() + .forEach(function (layer) { return layer.mergeEffects({ opacity: opacity }); }); + // eslint-disable-next-line no-param-reassign + newScene + .hotspotContainer() + .domElement().style.opacity = opacity.toString(); + if (oldScene && opacity > 0.99) { + oldScene + .listLayers() + .forEach(function (layer) { return layer.mergeEffects({ opacity: 0 }); }); + } + })(); + }, + }); + }; + Scene.prototype.view = function () { + return this.scene.view(); + }; + Scene.prototype.createLayer = function (x) { + return this.scene.createLayer(x); + }; + Scene.prototype.getPaintCanvas = function () { + return this.paintCanvas; + }; + Scene.prototype.setPaintCanvas = function (canvas) { + this.paintCanvas = canvas; + }; + Scene.prototype.startMovement = function (movement) { + try { + this.scene.startMovement(movement); + } + catch (_a) { + return false; + } + return true; + }; + Scene.prototype.stopMovement = function () { + try { + this.scene.stopMovement(); + } + catch (_a) { + return false; + } + return true; + }; + Scene.prototype.movement = function () { + return this.scene.movement(); + }; + Scene.prototype.createHotspot = function (hotspot) { + var hotspotContainer = this.scene.hotspotContainer(); + var opts = hotspot.perspective + ? { perspective: hotspot.perspective } + : undefined; + var marzipanoHotspot = hotspotContainer.createHotspot(hotspot.dom, hotspot.position, opts); + var deleteHotspot = function () { + return hotspotContainer.destroyHotspot(marzipanoHotspot); + }; + return { deleteHotspot: deleteHotspot, marzipanoHotspot: marzipanoHotspot }; + }; + Scene.prototype.destroy = function () { + this.willDestroy$s.next(); + this.viewer.destroyScene(this.scene); + }; + return Scene; + }()); + + var getDragPositionsFrom = function (div) { + var mouseup$ = fromEvent(window, 'mouseup'); + var mousedown$ = fromEvent(div, 'mousedown'); + var mousemove$ = fromEvent(div, 'mousemove'); + var touchend$ = fromEvent(window, 'touchend'); + var touchstart$ = fromEvent(div, 'touchstart'); + var touchmove$ = fromEvent(div, 'touchmove'); + var blur$ = fromEvent(window, 'blur'); + var rect = function () { return div.getBoundingClientRect(); }; + var mousePosition$ = merge(mousemove$, mousedown$).pipe(filter(function (event) { return !!event; }), map(function (event) { + var x = event.clientX - rect().x; + var y = event.clientY - rect().y; + return { x: x, y: y }; + }), windowToggle(mousedown$, function () { return merge(mouseup$, blur$); })); + var touchPosition$ = merge(touchmove$, touchstart$).pipe(filter(function (event) { return !!event; }), map(function (event) { + var x = event.touches[0].clientX - rect().x; + var y = event.touches[0].clientY - rect().y; + return { x: x, y: y }; + }), windowToggle(touchstart$, function () { return merge(touchend$, blur$); })); + return merge(mousePosition$, touchPosition$); + }; + var getClickPositionsFrom = function (div) { + var mouseup$ = fromEvent(window, 'mouseup'); + var mousedown$ = fromEvent(div, 'mousedown'); + var mousemove$ = fromEvent(div, 'mousemove'); + var touchend$ = fromEvent(window, 'touchend'); + var touchstart$ = fromEvent(div, 'touchstart'); + var touchmove$ = fromEvent(div, 'touchmove'); + var rect = function () { return div.getBoundingClientRect(); }; + var mousePosition$ = mousedown$.pipe(map(function () { return race(mouseup$, mousemove$.pipe(map(function () { return null; }))).pipe(first()); }), switchAll(), filter(function (event) { return !!event; }), map(function (event) { + var x = event.clientX - rect().x; + var y = event.clientY - rect().y; + return { x: x, y: y }; + })); + var touchPosition$ = touchstart$.pipe(map(function () { return race(touchend$, touchmove$.pipe(map(function () { return null; }))).pipe(first()); }), switchAll(), filter(function (event) { return !!event; }), map(function (event) { return event.touches[0]; }), filter(function (x) { return !!x; }), map(function (touch) { + var x = touch.clientX - rect().x; + var y = touch.clientY - rect().y; + return { x: x, y: y }; + })); + return merge(mousePosition$, touchPosition$); + }; + var filterByLatestFrom = function (b$) { + return pipe(withLatestFrom(b$), filter(function (_a) { + var b = _a[1]; + return b; + }), map(function (_a) { + var x = _a[0]; + return x; + })); + }; + // eslint-disable-next-line arrow-body-style + var observeOnResize = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return new Observable(function (observer) { + // @ts-ignore + var mutation = new ResizeObserver(function (mutations) { + observer.next(mutations); + }); + mutation.observe.apply(mutation, args); + return function () { return mutation.disconnect(); }; + }); + }; + + var Cached = /** @class */ (function () { + function Cached(f, destructor, numOfCache) { + this.cache = new Map(); + this.clear$ = new Subject(); + this.f = f; + this.destructor = destructor || noop; + this.numOfCache = Math.max(1, numOfCache !== null && numOfCache !== void 0 ? numOfCache : Infinity); + } + Cached.prototype.updateCache = function (id) { + var _this = this; + if (this.cache.has(id)) { + // Refresh order + var val = this.cache.get(id); + this.cache.delete(id); + this.cache.set(id, val); + return; + } + if (this.cache.size === this.numOfCache) { + var oldestKey = this.cache.keys().next().value; + this.clear$.next(oldestKey); + this.cache.delete(oldestKey); + } + var ctor = new Observable(function (subscriber) { + var res = { x: undefined }; + _this.f(id).then(function (x) { + res.x = x; + subscriber.next(x); + }, subscriber.error); + return function () { return res.x && _this.destructor(res.x); }; + }).pipe(takeUntil(this.clear$.pipe(filter(function (targetId) { return targetId === id; }))), shareReplay(1)); + this.cache.set(id, ctor); + }; + Cached.prototype.get = function (id) { + return __awaiter(this, void 0, void 0, function () { + var res; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + this.updateCache(id); + return [4 /*yield*/, this.cache.get(id).pipe(first()).toPromise()]; + case 1: + res = _a.sent(); + if (!res) { + this.cache.delete(id); + } + return [2 /*return*/, res]; + } + }); + }); + }; + Cached.prototype.clear = function () { + var _this = this; + Array.from(this.cache.keys()).forEach(function (id) { + _this.clear$.next(id); + _this.cache.delete(id); + }); + }; + return Cached; + }()); + + // Hack to clear memory for Safari + // See: https://qiita.com/minimo/items/b724c6793f45aca5e6f5 + function clearCanvasMemory(dom) { + dom.querySelectorAll('canvas').forEach(function (c) { + var canvas = c; + canvas.width = 0; + canvas.height = 0; + }); + } + + // @ts-ignore + var Viewer$1 = /** @class */ (function () { + function Viewer(props) { + this.zoomInButton = document.createElement('button'); + this.zoomOutButton = document.createElement('button'); + this.viewer = new src.Viewer(props.div, props.opts); + this.isActive$ = merge(fromEvent(this.viewer.controls(), 'active').pipe(mapTo(true)), fromEvent(this.viewer.controls(), 'inactive').pipe(mapTo(false))).pipe(distinctUntilChanged(), takeUntil(props.destroy$)); + this.viewChange$ = fromEvent(this.viewer, 'viewChange').pipe(takeUntil(props.destroy$)); + this.destroy$ = props.destroy$; + this.initialize(props); + } + Viewer.prototype.initialize = function (props) { + var _this = this; + var zoomIn$ = props.zoomIn$.pipe(map(pipe(startWith(true), endWith(false))), switchAll(), distinctUntilChanged()); + var zoomOut$ = props.zoomOut$.pipe(map(pipe(startWith(true), endWith(false))), switchAll(), distinctUntilChanged()); + merge(zoomIn$.pipe(tap(function (b) { + if (b) { + _this.zoomInButton.dispatchEvent(new MouseEvent('mousedown')); + } + else { + _this.zoomInButton.dispatchEvent(new MouseEvent('mouseup')); + } + })), zoomOut$.pipe(tap(function (b) { + if (b) { + _this.zoomOutButton.dispatchEvent(new MouseEvent('mousedown')); + } + else { + _this.zoomOutButton.dispatchEvent(new MouseEvent('mouseup')); + } + })), props.controls$.pipe(tap(function (b) { + if (b) { + _this.viewer.controls().enable(); + } + else { + _this.viewer.controls().disable(); + } + })), props.updateSize$.pipe(tap(function () { return _this.viewer.updateSize(); }))) + .pipe(takeUntil(this.destroy$)) + .subscribe(); + this.destroy$.subscribe(function () { + var _a; + clearCanvasMemory(_this.viewer.domElement()); + var parent = _this.viewer.domElement().parentNode; + _this.viewer.destroy(); + (_a = parent === null || parent === void 0 ? void 0 : parent.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(parent); + }); + var velocity = 0.7; + var friction = 3; + this.viewer + .controls() + .registerMethod('inElement', new src.ElementPressControlMethod(this.zoomInButton, 'zoom', -velocity, friction), true); + this.viewer + .controls() + .registerMethod('outElement', new src.ElementPressControlMethod(this.zoomOutButton, 'zoom', velocity, friction), true); + }; + return Viewer; + }()); + + var ignoreError = function () { return catchError(function () { return EMPTY; }); }; + var isNonNulled = function (value) { return value != null; }; + var Viewer$2 = /** @class */ (function () { + function Viewer(_a) { + var _this = this; + var getScene = _a.getScene, refetch$ = _a.refetch$, config = _a.config; + var _b, _c, _d; + this.mouseenter$s = new Subject(); + this.mouseleave$s = new Subject(); + this.isStopAutoTransition$s = new BehaviorSubject(false); + this.willSceneSwitched$s = new BehaviorSubject({ sceneId: '' }); + this.calcSwitchingInitialView = function (newScene, oldSceneId, transition, walkthrough) { return __awaiter(_this, void 0, void 0, function () { + var directionTo, directionFrom; + var _a, _b; + return __generator(this, function (_c) { + if (newScene.view().type !== 'rectilinear') { + return [2 /*return*/, undefined]; + } + if (oldSceneId.length > 0 && ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.keepCoords)) { + return [2 /*return*/, this.view.parameters()]; + } + if (transition !== 'sceneLink') { + return [2 /*return*/, newScene.initialView]; + } + directionTo = newScene.directionTo(oldSceneId, walkthrough); + directionFrom = directionTo && { + yaw: directionTo.yaw > 0 + ? directionTo.yaw - Math.PI + : directionTo.yaw + Math.PI, + pitch: 0, + }; + return [2 /*return*/, __assign(__assign({}, newScene.initialView), directionFrom)]; + }); + }); }; + this.scene$ = this.willSceneSwitched$s.pipe(distinctUntilKeyChanged('sceneId'), pairwise(), + // eslint-disable-next-line consistent-return + switchMap(function (_a) { + var oldSceneId = _a[0].sceneId, _b = _a[1], sceneId = _b.sceneId, config = _b.config; + return __awaiter(_this, void 0, void 0, function () { + var scene, _c, _d, _e, view; + var _f; + var _g, _h, _j, _k; + return __generator(this, function (_l) { + switch (_l.label) { + case 0: return [4 /*yield*/, this.scenes.get(sceneId)]; + case 1: + scene = _l.sent(); + if (!scene) { + return [2 /*return*/, undefined]; + } + _d = (_c = scene).switchTo; + _e = [__assign({}, config)]; + _f = {}; + return [4 /*yield*/, this.calcSwitchingInitialView(scene, oldSceneId, config === null || config === void 0 ? void 0 : config.transition, (_h = (_g = this.config) === null || _g === void 0 ? void 0 : _g.sceneLinkTransition) === null || _h === void 0 ? void 0 : _h.walkthrough)]; + case 2: + _d.apply(_c, [__assign.apply(void 0, _e.concat([(_f.initialView = _l.sent(), _f.target = config === null || config === void 0 ? void 0 : config.target, _f.transitionDuration = (_j = this.config) === null || _j === void 0 ? void 0 : _j.transitionDuration, _f.sceneLinkTransition = (_k = this.config) === null || _k === void 0 ? void 0 : _k.sceneLinkTransition, _f)]))]); + this.currentView = scene.view(); + view = scene.view(); + if (view.type === 'rectilinear') { + this.view$.next(view); + } + if (view.type === 'flat') { + this.flatView$.next(view); + } + return [2 /*return*/, { scene: scene, config: config }]; + } + }); + }); + }), filter(function (x) { return !!x; }), shareReplay(1)); + this.sceneLinkDragStart$s = new Subject(); + this.sceneLinkDragEnd$s = new Subject(); + this.sceneLinkClicked$s = new Subject(); + this.sceneLinkDeleted$s = new Subject(); + this.sceneLinkEvent$$ = new ReplaySubject(); + this.annotationEvent$$ = new ReplaySubject(); + this.embeddedAnnotationEvent$$ = new ReplaySubject(); + this.textureLoaded$$ = new ReplaySubject(); + this.editMode$b = new BehaviorSubject('paint'); + this.edit$b = new BehaviorSubject(false); + this.show$b = new BehaviorSubject(true); + this.zoomInStart$ = new Subject(); + this.zoomInEnd$ = new Subject(); + this.zoomOutStart$ = new Subject(); + this.zoomOutEnd$ = new Subject(); + this.updateSize$ = new Subject(); + this.destroy$ = new Subject(); + this.switchScene = function (id, config) { return __awaiter(_this, void 0, void 0, function () { + return __generator(this, function (_a) { + this.willSceneSwitched$s.next({ sceneId: id, config: config }); + return [2 /*return*/]; + }); + }); }; + /** + * @deprecated Use getRectilinearViewCoords instead + */ + this.currentRectilinearView = function () { return _this.getRectilinearViewCoords(); }; + this.getRectilinearViewCoords = function () { return _this.view.parameters(); }; + this.setRectilinearViewCoords = function (params) { + _this.view.setParameters(params); + }; + this.getViewParams = function () { + var view = _this.currentView; + if (!view) + return undefined; + var width = _this.width || 1; + var height = _this.height || 1; + if (view.type === 'flat') { + var parameters = view.parameters(); + var viewportAspectRatio = width / height; + var hzoom = (parameters.zoom * parameters.mediaAspectRatio) / viewportAspectRatio; + return __assign(__assign({ type: 'flat' }, parameters), { hzoom: hzoom }); + } + if (view.type === 'rectilinear') { + var parameters = view.parameters(); + var hfov = src.util.convertFov.vtoh(parameters.fov, width, height); + return __assign(__assign({ type: 'rectilinear' }, parameters), { hfov: hfov }); + } + return undefined; + }; + this.currentSceneId = function () { return _this.sceneId$.pipe(first()).toPromise(); }; + this.updateSize = function () { return _this.updateSize$.next(); }; + this.setEditMode = function (mode) { + _this.editMode$b.next(mode); + }; + this.setEdit = function (edit) { + _this.edit$b.next(edit); + }; + this.setShow = function (show) { + _this.show$b.next(show); + }; + this.setIndex = function (index) { + var childContainter = _this.div.parentElement; + childContainter.style.order = index.toString(); + return childContainter; + }; + this.getPaintCanvas = function () { return __awaiter(_this, void 0, void 0, function () { + var scene; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.scene$.pipe(first()).toPromise()]; + case 1: + scene = (_a.sent()).scene; + return [2 /*return*/, scene.getPaintCanvas()]; + } + }); + }); }; + this.zoomIn = function () { + _this.zoomInStart(); + _this.zoomInEnd(); + }; + this.zoomInStart = function () { + _this.zoomInStart$.next(); + }; + this.zoomInEnd = function () { + _this.zoomInEnd$.next(); + }; + this.zoomOut = function () { + _this.zoomOutStart(); + _this.zoomOutEnd(); + }; + this.zoomOutStart = function () { + _this.zoomOutStart$.next(); + }; + this.zoomOutEnd = function () { + _this.zoomOutEnd$.next(); + }; + this.initialize = function () { + var _a, _b, _c; + if (!((_b = (_a = _this.config) === null || _a === void 0 ? void 0 : _a.sceneLink) === null || _b === void 0 ? void 0 : _b.disableSwitchScene)) { + _this.sceneLinkClicked$.subscribe(function (_a) { + var to = _a.to, position = _a.position; + return _this.switchScene(to, { target: position, transition: 'sceneLink' }); + }); + } + var autorotate = (_c = _this.config) === null || _c === void 0 ? void 0 : _c.autorotate; + if (autorotate) { + _this.setupAutoRotate(); + } + }; + var limit = (function () { + var _a, _b; + if ((_a = config === null || config === void 0 ? void 0 : config.view) === null || _a === void 0 ? void 0 : _a.limit3D) { + return config.view.limit3D; + } + if ((_b = config === null || config === void 0 ? void 0 : config.view) === null || _b === void 0 ? void 0 : _b.limit) { + // DEPRECATED PATH + return { + maxVFov: config.view.limit.minFov, + maxHFov: config.view.limit.maxFov, + }; + } + return undefined; + })(); + var child = Viewer.createChildDiv(((_b = config === null || config === void 0 ? void 0 : config.color) === null || _b === void 0 ? void 0 : _b.background) || 'black'); + this.viewerComponent = new Viewer$1({ + div: child, + opts: { + controls: config === null || config === void 0 ? void 0 : config.controls, + }, + zoomIn$: this.zoomIn$, + zoomOut$: this.zoomOut$, + controls$: this.edit$.pipe(map(function (b) { return !b; })), + updateSize$: this.updateSize$, + destroy$: this.destroy$, + }); + this.scenes = new Cached(function (id) { return __awaiter(_this, void 0, void 0, function () { + var rawScene, isEditMode_1, scene_1, _a; + var _this = this; + var _b, _c; + return __generator(this, function (_d) { + switch (_d.label) { + case 0: return [4 /*yield*/, getScene(id)]; + case 1: + rawScene = _d.sent(); + if (!rawScene) + return [2 /*return*/, undefined]; + _d.label = 2; + case 2: + _d.trys.push([2, 4, , 5]); + isEditMode_1 = !!((_b = config === null || config === void 0 ? void 0 : config.sceneLink) === null || _b === void 0 ? void 0 : _b.isEditMode); + return [4 /*yield*/, Scene$1.init({ + props: rawScene, + viewer: this.viewerComponent.viewer, + rViewer: this, + isEditMode: isEditMode_1, + viewLimit: { + rectilinear: limit, + flat: (_c = config === null || config === void 0 ? void 0 : config.view) === null || _c === void 0 ? void 0 : _c.limit2D, + }, + })]; + case 3: + scene_1 = _d.sent(); + refetch$ + .pipe(filter(function (x) { return x === id; }), switchMap(function (sceneId) { return getScene(sceneId); }), takeUntil(scene_1.willDestroy$)) + .subscribe(function (rawScene2) { + return rawScene2 && scene_1.updateHotspots(rawScene2, isEditMode_1); + }); + scene_1.sceneLinkEvent$.subscribe(function (e) { + switch (e.eventType) { + case 'dragStart': + _this.sceneLinkDragStart$s.next(e); + break; + case 'dragEnd': + _this.sceneLinkDragEnd$s.next(e); + break; + case 'clicked': + _this.sceneLinkClicked$s.next(__assign(__assign({}, e), { position: e.position.type === 'rectilinear' ? e.position : undefined })); + break; + case 'deleted': + _this.sceneLinkDeleted$s.next(e); + break; + case 'mouseEnter': + _this.mouseenter$s.next(); + break; + case 'mouseLeave': + _this.mouseleave$s.next(); + break; + } + }); + this.sceneLinkEvent$$.next(scene_1.sceneLinkEvent$.pipe(map(function (x) { return (__assign(__assign({}, x), { sceneId: scene_1.id })); }))); + this.annotationEvent$$.next(scene_1.annotationEvent$.pipe(map(function (x) { return (__assign(__assign({}, x), { sceneId: scene_1.id })); }))); + this.embeddedAnnotationEvent$$.next(scene_1.embeddedAnnotationEvent$.pipe(map(function (x) { return (__assign(__assign({}, x), { sceneId: scene_1.id })); }))); + this.textureLoaded$$.next(scene_1.textureLoaded$); + return [2 /*return*/, scene_1]; + case 4: + _a = _d.sent(); + return [2 /*return*/, undefined]; + case 5: return [2 /*return*/]; + } + }); + }); }, function (scene) { return scene.destroy(); }, Math.floor(Math.max(3, (_d = (_c = config === null || config === void 0 ? void 0 : config.scene) === null || _c === void 0 ? void 0 : _c.numOfCache) !== null && _d !== void 0 ? _d : 6))); + var aspectRatio = this.width / this.height || 1; + this.view$ = new BehaviorSubject(createView(aspectRatio, undefined, limit)); + var _e = this, width = _e.width, height = _e.height; + this.flatView$ = new BehaviorSubject(createView$1({ width: width, height: height })); + this.config = config; + this.initialize(); + } + Object.defineProperty(Viewer.prototype, "viewer", { + /** + * @deprecated Do not use marzipano API directly. + */ + get: function () { + return this.viewerComponent.viewer; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "view", { + get: function () { + return this.view$.getValue(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "flatView", { + get: function () { + return this.flatView$.getValue(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "currentRectilinearViewCoords$", { + get: function () { + var _this = this; + return this.view$.pipe(map(function (v) { + return fromEvent(v, 'change'); + }), switchAll(), map(function () { return _this.view.parameters(); })); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "div", { + get: function () { + return this.viewerComponent.viewer.domElement(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "canvas", { + get: function () { + return this.div.firstChild; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "width", { + get: function () { + return this.viewerComponent.viewer.stage().width(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "height", { + get: function () { + return this.viewerComponent.viewer.stage().height(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "xy$$", { + get: function () { + return getDragPositionsFrom(this.div).pipe(withLatestFrom(this.edit$, this.show$), filter(function (_a) { + var b1 = _a[1], b2 = _a[2]; + return b1 && b2; + }), map(function (_a) { + var xys$ = _a[0]; + return xys$; + })); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "point$$", { + get: function () { + var _this = this; + return this.scene$.pipe(switchMap(function (_a) { + var scene = _a.scene; + return scene.image.type === 'flat' ? EMPTY : _this.xy$$; + }), map(pipe(map(function (xy) { return _this.screenToRectilinearCoordinates(xy); }), ignoreError()))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "pointFlat$$", { + get: function () { + var _this = this; + return this.scene$.pipe(switchMap(function (_a) { + var scene = _a.scene; + return scene.image.type === 'flat' ? _this.xy$$ : EMPTY; + }), map(pipe(map(function (xy) { return _this.screenToFlatCoordinates(xy); }), ignoreError()))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "clicked$", { + get: function () { + var _this = this; + return getClickPositionsFrom(this.div).pipe(map(function (xy) { return (__assign({ screenX: xy.x, screenY: xy.y }, _this.screenToCoordinates(xy))); })); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "isStopAutoTransition", { + get: function () { + return this.isStopAutoTransition$s.getValue(); + }, + set: function (b) { + this.isStopAutoTransition$s.next(b); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "active$", { + get: function () { + return merge(this.viewerComponent.isActive$.pipe(filter(function (b) { return b; })), this.mouseenter$s, this.annotationEvent$.pipe(filter(function (x) { return x.eventType === 'mouseEnter'; })), this.embeddedAnnotationEvent$.pipe(filter(function (x) { return x.eventType === 'mouseEnter'; })), + // HACK: + this.isStopAutoTransition$s.pipe(switchMap(function (b) { return (b ? timer(0, 1000) : EMPTY); }))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "inactive$", { + get: function () { + return merge(this.viewerComponent.isActive$.pipe(filter(function (b) { return !b; })), this.mouseleave$s, this.annotationEvent$.pipe(filter(function (x) { return x.eventType === 'mouseLeave'; })), this.embeddedAnnotationEvent$.pipe(filter(function (x) { return x.eventType === 'mouseLeave'; })), this.isStopAutoTransition$s.pipe(filter(function (b) { return !b; }))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "isActive$", { + get: function () { + return merge(this.active$.pipe(mapTo(true)), this.inactive$.pipe(mapTo(false))).pipe(distinctUntilChanged(), shareReplay(1)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "viewChanged$", { + get: function () { + return this.viewerComponent.viewChange$; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "viewCoords$", { + get: function () { + var _this = this; + return this.viewChanged$.pipe(observeOn(animationFrameScheduler), map(function () { return _this.getViewParams(); }), filter(isNonNulled)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "noInteractForAWhile$", { + get: function () { + var _a; + var autorotate = (_a = this.config) === null || _a === void 0 ? void 0 : _a.autorotate; + return autorotate + ? merge(this.isActive$.pipe(debounceTime(autorotate.inactiveDuration), filter(function (isActive) { return !isActive; }), mapTo(true)), this.active$.pipe(mapTo(false))).pipe(startWith(true)) + : EMPTY; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "shouldSwitchNextScene$", { + get: function () { + var _this = this; + var _a; + var autorotate = (_a = this.config) === null || _a === void 0 ? void 0 : _a.autorotate; + if (!autorotate) + return EMPTY; + var equi$ = this.scene$.pipe(switchMap(function (_a) { + var scene = _a.scene; + return _this.noInteractForAWhile$.pipe(map(function (noInteract) { return scene.image.type !== 'flat' && noInteract; })); + }), switchMap(function (trigger) { + if (!trigger) + return of(false); + var initialYaw = _this.view.yaw(); + var isFullRotate$ = _this.viewChanged$.pipe(map(function () { + var dYaw = initialYaw - _this.view.yaw(); + return dYaw < 0.02 && dYaw > 0.01; + })); + return isFullRotate$; + }), distinctUntilChanged(), filter(function (x) { return x; })); + var flat$ = this.scene$.pipe(switchMap(function (_a) { + var config = _a.config, scene = _a.scene; + return scene.image.type === 'flat' + ? of(true).pipe(delay((config === null || config === void 0 ? void 0 : config.auto) ? autorotate.flatImageDuration + : autorotate.flatImageDuration + autorotate.inactiveDuration)) + : EMPTY; + })); + return merge(equi$, flat$).pipe(mapTo(true)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneId$", { + get: function () { + return this.scene$.pipe(map(function (_a) { + var scene = _a.scene; + return scene.id; + })); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneLinkDragStart$", { + /** + * @deprecated Use sceneLinkEvent$ instead + */ + get: function () { + return this.sceneLinkDragStart$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneLinkDragEnd$", { + /** + * @deprecated Use sceneLinkEvent$ instead + */ + get: function () { + return this.sceneLinkDragEnd$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneLinkClicked$", { + /** + * @deprecated Use sceneLinkEvent$ instead + */ + get: function () { + return this.sceneLinkClicked$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneLinkDeleted$", { + /** + * @deprecated Use sceneLinkEvent$ instead + */ + get: function () { + return this.sceneLinkDeleted$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "sceneLinkEvent$", { + get: function () { + return this.sceneLinkEvent$$.pipe(mergeAll()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "annotationEvent$", { + get: function () { + return this.annotationEvent$$.pipe(mergeAll()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "embeddedAnnotationEvent$", { + get: function () { + return this.embeddedAnnotationEvent$$.pipe(mergeAll()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "textureLoaded$", { + get: function () { + return this.textureLoaded$$.pipe(mergeAll()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "editMode$", { + get: function () { + return this.editMode$b.asObservable().pipe(distinctUntilChanged()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "edit$", { + get: function () { + return this.edit$b.asObservable().pipe(distinctUntilChanged()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "show$", { + get: function () { + return this.show$b.asObservable().pipe(distinctUntilChanged()); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "zoomIn$", { + get: function () { + return this.zoomInStart$.pipe(mapTo(NEVER.pipe(takeUntil(this.zoomInEnd$)))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Viewer.prototype, "zoomOut$", { + get: function () { + return this.zoomOutStart$.pipe(mapTo(NEVER.pipe(takeUntil(this.zoomOutEnd$)))); + }, + enumerable: false, + configurable: true + }); + Viewer.prototype.destroy = function () { + this.destroy$.next(); + }; + Viewer.prototype.px2rad = function (px) { + var _a; + var fovPx = ((_a = this.div) === null || _a === void 0 ? void 0 : _a.clientHeight) || 500; + var fovRad = this.view.fov(); + var radPerPx = fovRad / fovPx; + return px * radPerPx; + }; + Viewer.prototype.px2flatPx = function (px) { + var zoom = this.flatView.parameters().zoom; + return px * zoom * 2; + }; + Viewer.prototype.coordinatesToScreen = function (point) { + var _this = this; + return this.viewChanged$.pipe(startWith(true), map(function () { return _this.view.coordinatesToScreen(point); })); + }; + Viewer.prototype.screenToRectilinearCoordinates = function (xy) { + return this.view.screenToCoordinates(xy); + }; + Viewer.prototype.screenToFlatCoordinates = function (xy) { + return this.flatView.screenToCoordinates(xy); + }; + Viewer.prototype.screenToCoordinates = function (xy) { + var _a; + return (_a = this.currentView) === null || _a === void 0 ? void 0 : _a.screenToCoordinates(xy); + }; + Viewer.prototype.setupAutoRotate = function () { + var _this = this; + var autorotateOpts = function () { return ({ + fovAccel: 0.01, + fovSpeed: 0.1, + pitchAccel: 0.01, + pitchSpeed: 0.1, + targetFov: initialFov(_this.width / _this.height || 1), + targetPitch: 0, + yawAccel: 0.01, + yawSpeed: 0.1, + }); }; + var initialMovement = function () { return src.autorotate(autorotateOpts()); }; + var continueMovement = function () { + return src.autorotate(__assign(__assign({}, autorotateOpts()), { fovAccel: 0.1, pitchAccel: 0.1, yawAccel: 0.1 })); + }; + this.scene$ + .pipe(startWith(null), pairwise()) + .subscribe(function (_a) { + var prev = _a[0], current = _a[1]; + if (prev) { + var prevScene = prev.scene; + prevScene.stopMovement(); + } + var _b = current, scene = _b.scene, config = _b.config; + if (!(scene === null || scene === void 0 ? void 0 : scene.movement())) { + scene.startMovement((config === null || config === void 0 ? void 0 : config.auto) ? continueMovement() : initialMovement()); + } + }); + this.noInteractForAWhile$ + .pipe(withLatestFrom(this.scene$)) + .subscribe(function (_a) { + var noInteract = _a[0], scene = _a[1].scene; + if (noInteract) { + if (!(scene === null || scene === void 0 ? void 0 : scene.movement())) { + scene === null || scene === void 0 ? void 0 : scene.startMovement(initialMovement()); + } + } + else { + scene === null || scene === void 0 ? void 0 : scene.stopMovement(); + } + }); + }; + Viewer.createChildDiv = function (backgroundColor) { + var childContainter = document.createElement('div'); + childContainter.style.flexGrow = '1'; + childContainter.style.position = 'relative'; + childContainter.style.boxSizing = 'border-box'; + childContainter.style.overflow = 'hidden'; + var child = document.createElement('div'); + childContainter.appendChild(child); + child.style.backgroundColor = backgroundColor; + child.style.top = '0px'; + child.style.left = '0px'; + child.style.width = '100%'; + child.style.height = '100%'; + child.style.overflow = 'hidden'; + return child; + }; + return Viewer; + }()); + + // @ts-ignore + var Canvas = /** @class */ (function () { + function Canvas(props) { + this.canvas = (function () { + var canvas = document.createElement('canvas'); + canvas.width = props.width; + canvas.height = props.height; + return canvas; + })(); + this.ctx = this.canvas.getContext('2d'); + this.changed$s = new Subject(); + this.destroy$ = props.destroy$; + this.initialize(props); + } + Object.defineProperty(Canvas.prototype, "changed$", { + get: function () { + return this.changed$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Canvas.prototype, "width", { + get: function () { + return this.canvas.width; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Canvas.prototype, "height", { + get: function () { + return this.canvas.height; + }, + enumerable: false, + configurable: true + }); + Canvas.prototype.initialize = function (props) { + var _this = this; + var _a; + merge(props.path$.pipe(tap(function (path) { return _this.draw(path); })), ((_a = props.img$) === null || _a === void 0 ? void 0 : _a.pipe(tap(function (img) { return _this.drawImage(img); }))) || EMPTY, props.clear$.pipe(tap(function () { return _this.clear(); }))) + .pipe(takeUntil(this.destroy$)) + .subscribe(); + this.destroy$.pipe(take(1)).subscribe(function () { return _this.destroy(); }); + }; + Canvas.prototype.draw = function (path) { + var _this = this; + var points = path.points, config = path.config; + if (points.length < 1) + return; + if (config.globalCompositeOperation) { + this.ctx.globalCompositeOperation = config.globalCompositeOperation; + } + if (config.lineCap) { + this.ctx.lineCap = config.lineCap; + } + if (config.lineWidth) { + this.ctx.lineWidth = config.lineWidth; + } + if (config.strokeStyle) { + this.ctx.strokeStyle = config.strokeStyle; + } + this.ctx.beginPath(); + if (points.length === 1) { + var _a = points[0], x = _a.x, y = _a.y; + // HACK: draw a dot. + points.push({ x: x + 0, y: y + 1 }); + points.push({ x: x + 1, y: y + 1 }); + points.push({ x: x + 1, y: y + 0 }); + points.push({ x: x + 0, y: y + 0 }); + } + from(points) + .pipe(pairwise()) + .subscribe({ + next: function (_a) { + var p1 = _a[0], p2 = _a[1]; + _this.ctx.moveTo(p1.x, p1.y); + _this.ctx.lineTo(p2.x, p2.y); + }, + complete: function () { + _this.ctx.stroke(); + _this.changed$s.next(); + }, + }); + }; + Canvas.prototype.drawImage = function (_a) { + var img = _a.img, config = _a.config; + if (config.globalCompositeOperation) { + this.ctx.globalCompositeOperation = config.globalCompositeOperation; + } + this.ctx.drawImage(img, 0, 0, this.width, this.height); + this.changed$s.next(); + }; + Canvas.prototype.clear = function () { + this.ctx.clearRect(0, 0, this.width, this.height); + this.changed$s.next(); + }; + Canvas.prototype.destroy = function () { + // Hack to clear memory for Safari + // See: https://qiita.com/minimo/items/b724c6793f45aca5e6f5 + this.canvas.width = 0; + this.canvas.height = 0; + }; + return Canvas; + }()); + + // @ts-ignore + var CanvasAsset = /** @class */ (function () { + function CanvasAsset(props) { + this.canvasAsset = new src.DynamicAsset(props.canvas); + this.destroy$ = props.destroy$; + this.initialize(props); + } + CanvasAsset.prototype.initialize = function (props) { + var _this = this; + props.refresh$ + .pipe(takeUntil(this.destroy$)) + .subscribe(function () { return _this.canvasAsset.markDirty(); }); + }; + return CanvasAsset; + }()); + + function mod$1(x, y) { + return ((x % y) + y) % y; + } + function clamp$1(x, min, max) { + return Math.min(Math.max(x, min), max); + } + + /* eslint-disable no-unused-vars */ + function getPointToXY(width, height) { + return function (p) { + var theta = mod$1(p.yaw - Math.PI, 2 * Math.PI); + var phi = mod$1(p.pitch - Math.PI / 2, Math.PI); + var s = theta / (2 * Math.PI); + var t = phi / Math.PI; + var imageX = Math.floor(s * width); + var imageY = Math.floor(t * height); + return { x: imageX, y: imageY }; + }; + } + function getPointsToXYs(width, height) { + var pontToXY = getPointToXY(width, height); + return function (ps) { + var xysRaw = ps.map(pontToXY); + var xys = [xysRaw[0]]; + var result = []; + // eslint-disable-next-line no-plusplus + for (var i = 1; i < xysRaw.length; i++) { + var e1 = xysRaw[i - 1]; + var e2 = xysRaw[i]; + // If the line crosses the vertical edge of the canvas + if (Math.abs(e1.x - e2.x) > width * 0.5) { + var _a = e1.x < e2.x ? [e1, e2] : [e2, e1], eb = _a[0], ec = _a[1]; + var ea = { x: ec.x - width, y: ec.y }; + var y = (-ea.x * eb.y + eb.x * ea.y) / (-ea.x + eb.x); + var eab = { x: 0, y: y }; + var ecd = { x: width, y: y }; + if (e1.x < e2.x) { + xys.push(eab); + result.push(xys); + xys = [ecd]; + } + else { + xys.push(ecd); + result.push(xys); + xys = [eab]; + } + } + xys.push(xysRaw[i]); + } + result.push(xys); + return result; + }; + } + + var MAX_360_IMAGE_WIDTH = 4096; + var EquirectPaintLayer = /** @class */ (function () { + function EquirectPaintLayer(props) { + var _a, _b; + var width = Math.round((_b = (_a = props.config) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : MAX_360_IMAGE_WIDTH); + var height = Math.round(width / 2); + var pointsToXYs = getPointsToXYs(width, height); + var path$ = props.path$.pipe(mergeMap(function (_a) { + var points = _a.points, _b = _a.config, strokeStyle = _b.color, pathWidth = _b.width, globalCompositeOperation = _b.globalCompositeOperation; + var lineWidth = (pathWidth * width) / Math.PI; + return pointsToXYs(points).map(function (xys) { return ({ + points: xys, + config: { + globalCompositeOperation: globalCompositeOperation, + lineCap: 'round', + lineWidth: lineWidth, + strokeStyle: strokeStyle, + }, + }); }); + })); + var img$ = props.img$, clear$ = props.clear$, destroy$ = props.destroy$; + var canvas = new Canvas({ + width: width, + height: height, + path$: path$, + img$: img$, + clear$: clear$, + destroy$: destroy$, + }); + var canvasAsset = new CanvasAsset({ + canvas: canvas.canvas, + refresh$: canvas.changed$, + destroy$: destroy$, + }); + this.canvasAsset = canvasAsset.canvasAsset; + } + return EquirectPaintLayer; + }()); + + /* eslint-disable no-unused-vars */ + function getPointToXY$1(width, height) { + return function (p) { + var imageX = clamp$1(p.x, 0, 1) * width; + var imageY = clamp$1(p.y, 0, 1) * height; + return { x: imageX, y: imageY }; + }; + } + + var FlatPaintLayer = /** @class */ (function () { + function FlatPaintLayer(props) { + var width = props.width, height = props.height, img$ = props.img$, clear$ = props.clear$, destroy$ = props.destroy$; + var pointToXy = getPointToXY$1(width, height); + var path$ = props.path$.pipe(map(function (_a) { + var points = _a.points, _b = _a.config, strokeStyle = _b.color, lineWidth = _b.width, globalCompositeOperation = _b.globalCompositeOperation; + return ({ + points: points.map(pointToXy), + config: { + globalCompositeOperation: globalCompositeOperation, + lineCap: 'round', + lineWidth: lineWidth, + strokeStyle: strokeStyle, + }, + }); + })); + var canvas = new Canvas({ + width: width, + height: height, + path$: path$, + img$: img$, + clear$: clear$, + destroy$: destroy$, + }); + var canvasAsset = new CanvasAsset({ + canvas: canvas.canvas, + refresh$: canvas.changed$, + destroy$: destroy$, + }); + this.canvasAsset = canvasAsset.canvasAsset; + } + return FlatPaintLayer; + }()); + + function image(url) { + return new Observable(function (subscriber) { + var img = new Image(); + img.onload = function () { + img.width = img.naturalWidth; + img.height = img.naturalHeight; + subscriber.next(img); + subscriber.complete(); + }; + img.onerror = function (e) { return subscriber.error(e); }; + img.crossOrigin = 'Anonymous'; + img.src = url; + }); + } + function blurImage(radius) { + return function (img$) { + return new Observable(function (subscriber) { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + if (!ctx) + return subscriber.error(); + var subscription = img$.subscribe(function (img) { + var width = Math.round(img.width / radius); + var height = Math.round(img.height / radius); + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + subscriber.next(canvas); + }); + return function () { + subscription.unsubscribe(); + canvas.width = 0; + canvas.height = 0; + }; + }); + }; + } + + var RectilinearViewCoords = /** @class */ (function () { + function RectilinearViewCoords(props) { + var yaw = props.yaw, pitch = props.pitch; + this.yaw = mod$1(yaw + Math.PI, Math.PI * 2) - Math.PI; + this.pitch = clamp$1(pitch, -Math.PI * 0.5, Math.PI * 0.5); + } + RectilinearViewCoords.prototype.add = function (other) { + var _a = this, yaw1 = _a.yaw, pitch1 = _a.pitch; + var yaw2 = other.yaw, pitch2 = other.pitch; + return new RectilinearViewCoords({ + yaw: yaw1 + yaw2, + pitch: pitch1 + pitch2, + }); + }; + RectilinearViewCoords.prototype.sub = function (other) { + var _a = this, yaw1 = _a.yaw, pitch1 = _a.pitch; + var yaw2 = other.yaw, pitch2 = other.pitch; + return new RectilinearViewCoords({ + yaw: yaw1 - yaw2, + pitch: pitch1 - pitch2, + }); + }; + RectilinearViewCoords.prototype.l2 = function (other) { + var _a = this.sub(other), yaw = _a.yaw, pitch = _a.pitch; + return Math.sqrt(Math.pow(yaw, 2) + Math.pow(pitch, 2)); + }; + return RectilinearViewCoords; + }()); + + var isNonNulled$1 = function (value) { return value != null; }; + var l2 = function (line) { + var p1 = new RectilinearViewCoords(line.p1); + var p2 = new RectilinearViewCoords(line.p2); + return p1.l2(p2); + }; + var pointWithConfig2pathEntityWithSceneId = function (pointWithConfig$) { + return pointWithConfig$.pipe(map(function (_a) { + var point$ = _a.point$, color = _a.color, width = _a.width, sceneId = _a.sceneId; + return point$.pipe(toArray(), filter(function (x) { return x.length > 0; }), map(function (points) { + var path = { points: points, width: width, color: color }; + return { id: v4(), path: path, sceneId: sceneId }; + })); + }), mergeAll()); + }; + var pointWithConfig2erasorPath = function (pointWithConfig$) { + return pointWithConfig$.pipe(filter(function (_a) { + var color = _a.color; + return color === 'transparent'; + }), mergeMap(function (_a) { + var point$ = _a.point$, sceneId = _a.sceneId, width = _a.width; + return point$.pipe(pairwise(), map(function (_a) { + var p1 = _a[0], p2 = _a[1]; + return ({ points: [p1, p2], width: width, sceneId: sceneId }); + })); + })); + }; + var getPathEntitiesMap = function (pathEntityWithSceneId$, undo$, redo$) { + return merge(pathEntityWithSceneId$.pipe(map(function (data) { return ({ + command: 'new', + sceneId: data.sceneId, + data: data, + }); })), undo$.pipe(map(function (sceneId) { return ({ command: 'undo', sceneId: sceneId }); })), redo$.pipe(map(function (sceneId) { return ({ command: 'redo', sceneId: sceneId }); }))).pipe(scan(function (acc, x) { + var _a; + var sceneId = x.sceneId; + var prev = acc[sceneId]; + var next = (function () { + switch (x.command) { + case 'new': + // eslint-disable-next-line no-case-declarations + var data = __assign(__assign({}, x.data), { sceneId: undefined }); + delete data.sceneId; + return prev + ? { + paths: prev.paths.slice(0, prev.length).concat([data]), + length: prev.length + 1, + } + : { + paths: [data], + length: 1, + }; + case 'undo': + return prev + ? __assign(__assign({}, prev), { length: Math.max(prev.length - 1, 0) }) : { + paths: [], + length: 0, + }; + case 'redo': + return prev + ? __assign(__assign({}, prev), { length: Math.min(prev.length + 1, prev.paths.length) }) : { + paths: [], + length: 0, + }; + default: + throw new Error('Unreachable'); + } + })(); + return __assign(__assign({}, acc), (_a = {}, _a[sceneId] = next, _a)); + }, {}), map(function (data) { + return Object.entries(data) + .map(function (_a) { + var sceneId = _a[0], x = _a[1]; + return x ? { sceneId: sceneId, paths: x.paths.slice(0, x.length) } : undefined; + }) + .filter(isNonNulled$1) + .reduce(function (acc, _a) { + var _b; + var sceneId = _a.sceneId, paths = _a.paths; + return (__assign(__assign({}, acc), (_b = {}, _b[sceneId] = paths, _b))); + }, {}); + }), shareReplay(1)); + }; + var getPaintLayerProps = function (pathEntitiesMap$, pathEntitiesMapFromRepo$, erasorPathWithSceneId$, show$, blur$, sceneId, imageUrl) { + var erasorPath$ = erasorPathWithSceneId$.pipe(filter(function (x) { return x.sceneId === sceneId; }), map(function (_a) { + var points = _a.points, width = _a.width; + return ({ + points: points, + config: { + globalCompositeOperation: 'destination-out', + color: 'black', + width: width, + }, + }); + })); + var pathEntityFromDraw$ = pathEntitiesMap$.pipe(pluck(sceneId), filter(isNonNulled$1), distinctUntilChanged(function (x, y) { return x.length === y.length; }), shareReplay(1)); + var pathEntityFromRepo$ = pathEntitiesMapFromRepo$.pipe(pluck(sceneId), filter(isNonNulled$1), distinctUntilChanged(function (x, y) { return x.length === y.length; }), shareReplay(1)); + var pathEntity$ = pathEntityFromRepo$.pipe(switchMap(function (ps1) { + return merge(of(ps1), pathEntityFromDraw$.pipe(map(function (ps2) { return ps1.concat(ps2); }))); + })); + var pathToDraw$ = merge(pathEntity$.pipe(take(1)), pathEntity$.pipe(pairwise(), map(function (_a) { + var prev = _a[0], current = _a[1]; + return current.length > prev.length + ? current.slice(prev.length, current.length) + : current; + }))).pipe(mergeAll()); + var pathAll$ = show$.pipe(switchMap(function (show) { + if (show) { + return pathToDraw$.pipe(delay(1), map(function (x) { return x.path; })); + } + return EMPTY; + }), map(function (x) { + var points = x.points, width = x.width; + var color = x.color === 'transparent' ? 'black' : x.color; + var globalCompositeOperation = x.color === 'transparent' + ? 'destination-out' + : 'source-over'; + return { + points: points, + config: { + globalCompositeOperation: globalCompositeOperation, + color: color, + width: width, + }, + }; + })); + var path$ = merge(erasorPath$, pathAll$); + var img$ = (imageUrl ? image(imageUrl) : EMPTY).pipe(blurImage(10), map(function (img) { return ({ + img: img, + config: { globalCompositeOperation: 'source-in' }, + }); }), shareReplay()); + var clear$ = merge(show$.pipe(filter(function (show) { return !show; })), pathEntity$.pipe(pairwise(), filter(function (_a) { + var x = _a[0], y = _a[1]; + return x.length > y.length; + }))).pipe(map(function () { return undefined; })); + return { + path$: path$, + img$: path$.pipe(filterByLatestFrom(blur$), switchMapTo(img$)), + clear$: clear$, + }; + }; + + var ignoreError$1 = function () { return catchError(function () { return EMPTY; }); }; + var HandWrite = /** @class */ (function () { + function HandWrite(getPathEntities, getPathFlatEntities, getPainterParameters, viewer$, refetch$, undo$, redo$, config) { + var _this = this; + this.pointWithConfig$ = viewer$.pipe(mergeMap(function (viewer) { + return viewer.point$$.pipe(withLatestFrom(viewer.sceneId$), map(function (_a) { + var point$ = _a[0], sceneId = _a[1]; + var _b = getPainterParameters(), color = _b.color, widthPx = _b.width; + var width = viewer.px2rad(widthPx); + return { + point$: point$.pipe(distinctUntilChanged(function (p1, p2) { return l2({ p1: p1, p2: p2 }) < width; })), + sceneId: sceneId, + color: color, + width: width, + }; + })); + }), share()); + this.pointFlatWithConfig$ = viewer$.pipe(mergeMap(function (viewer) { + return viewer.pointFlat$$.pipe(withLatestFrom(viewer.sceneId$), map(function (_a) { + var point$ = _a[0], sceneId = _a[1]; + var _b = getPainterParameters(), color = _b.color, width = _b.width; + return { + point$: point$.pipe(distinctUntilChanged(function (p1, p2) { + return Math.pow((p1.x - p2.x), 2) + Math.pow((p1.y - p2.y), 2) < Math.pow(0.01, 2); + })), + sceneId: sceneId, + color: color, + width: viewer.px2flatPx(width), + }; + })); + }), share()); + this.pathEntity$ = this.pointWithConfig$.pipe(pointWithConfig2pathEntityWithSceneId); + this.pathFlatEntity$ = this.pointFlatWithConfig$.pipe(pointWithConfig2pathEntityWithSceneId); + var sceneIdToFetch$ = merge(viewer$.pipe(mergeMap(function (viewer) { return viewer.sceneId$; }), distinct()), refetch$); + this.pathEntityMapFromRepository$ = sceneIdToFetch$.pipe(mergeMap(function (sceneId) { return __awaiter(_this, void 0, void 0, function () { + var paths; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, getPathEntities(sceneId)]; + case 1: + paths = _a.sent(); + if (!paths) + throw new Error("Failed to get path entities: " + sceneId); + return [2 /*return*/, { sceneId: sceneId, paths: paths }]; + } + }); + }); }), scan(function (acc, _a) { + var _b; + var sceneId = _a.sceneId, paths = _a.paths; + return (__assign(__assign({}, acc), (_b = {}, _b[sceneId] = paths, _b))); + }, {}), shareReplay(1)); + this.pathEntityMap$ = getPathEntitiesMap(this.pathEntity$, undo$, redo$); + this.erasorPathWithSceneId$ = this.pointWithConfig$.pipe(pointWithConfig2erasorPath); + this.pathFlatEntityMapFromRepository$ = sceneIdToFetch$.pipe(mergeMap(function (sceneId) { return __awaiter(_this, void 0, void 0, function () { + var paths; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, getPathFlatEntities(sceneId)]; + case 1: + paths = _a.sent(); + if (!paths) + throw new Error("Failed to get path entities: " + sceneId); + return [2 /*return*/, { sceneId: sceneId, paths: paths }]; + } + }); + }); }), scan(function (acc, _a) { + var _b; + var sceneId = _a.sceneId, paths = _a.paths; + return (__assign(__assign({}, acc), (_b = {}, _b[sceneId] = paths, _b))); + }, {}), shareReplay(1)); + this.pathFlatEntityMap$ = getPathEntitiesMap(this.pathFlatEntity$, undo$, redo$); + this.erasorPathFlatWithSceneId$ = this.pointFlatWithConfig$.pipe(pointWithConfig2erasorPath); + viewer$.subscribe(function (viewer) { + return HandWrite.attachSurfaceCanvas(viewer, getPainterParameters); + }); + viewer$ + .pipe(mergeMap(function (viewer) { + return viewer.scene$.pipe(map(function (_a) { + var scene = _a.scene; + return ({ scene: scene, viewer: viewer }); + })); + }), distinct(function (x) { return x.scene; }), tap(function (_a) { + var scene = _a.scene, viewer = _a.viewer; + var paintLayer = scene.image.type === 'flat' + ? _this.createFlatPaintLayer(scene, viewer) + : _this.createEquirectPaintLayer(scene, viewer, (config === null || config === void 0 ? void 0 : config.equirectPaintLayerWidth) ? { width: config.equirectPaintLayerWidth } + : undefined); + var canvasAsset = paintLayer.canvasAsset; + var geometry = scene.image.type === 'flat' + ? new src.FlatGeometry([ + { + width: canvasAsset.element().width, + height: canvasAsset.element().height, + tileWidth: canvasAsset.element().width, + tileHeight: canvasAsset.element().height, + }, + ]) + : new src.EquirectGeometry([ + { width: canvasAsset.element().width }, + ]); + scene.createLayer({ + geometry: geometry, + pinFirstLevel: true, + source: new src.SingleAssetSource(canvasAsset), + }); + scene.setPaintCanvas(canvasAsset.element()); + })) + .subscribe(); + } + HandWrite.prototype.createEquirectPaintLayer = function (scene, viewer, config) { + var imageUrl = (function () { + switch (scene.image.type) { + case 'cube': + return scene.image.equirectUrl; + case 'equirect': + return scene.image.url; + } + return undefined; + })(); + var _a = getPaintLayerProps(this.pathEntityMap$, this.pathEntityMapFromRepository$, this.erasorPathWithSceneId$, viewer.show$, viewer.editMode$.pipe(map(function (mode) { return mode === 'blur'; })), scene.id, imageUrl), path$ = _a.path$, img$ = _a.img$, clear$ = _a.clear$; + var destroy$ = scene.willDestroy$; + var paintLayer = new EquirectPaintLayer({ + path$: path$, + img$: img$, + clear$: clear$, + destroy$: destroy$, + config: config, + }); + return paintLayer; + }; + HandWrite.prototype.createFlatPaintLayer = function (scene, viewer) { + var imageUrl = (function () { + switch (scene.image.type) { + case 'flat': + return scene.image.url; + } + return undefined; + })(); + var _a = getPaintLayerProps(this.pathFlatEntityMap$, this.pathFlatEntityMapFromRepository$, this.erasorPathFlatWithSceneId$, viewer.show$, viewer.editMode$.pipe(map(function (mode) { return mode === 'blur'; })), scene.id, imageUrl), path$ = _a.path$, img$ = _a.img$, clear$ = _a.clear$; + var destroy$ = scene.willDestroy$; + var width = viewer.width; + var height = (function () { + // HACK + var v = scene.view(); + var p = v.parameters(); + var aspectRatio = p.mediaAspectRatio || 1; + return width / aspectRatio; + })(); + var paintLayer = new FlatPaintLayer({ + width: width, + height: height, + path$: path$, + img$: img$, + clear$: clear$, + destroy$: destroy$, + }); + return paintLayer; + }; + HandWrite.createSurfaceCanvas = function (viewer) { + var div = viewer.div; + var surfaceCanvas = document.createElement('canvas'); + surfaceCanvas.style.position = 'absolute'; + surfaceCanvas.style.width = '100%'; + surfaceCanvas.style.height = '100%'; + div.insertBefore(surfaceCanvas, div.lastChild); + observeOnResize(div).subscribe(function (xs) { + return xs.forEach(function (x) { + var target = x.target; + if (target.clientWidth === 0) + return; + surfaceCanvas.width = target.clientWidth; + surfaceCanvas.height = target.clientHeight; + viewer.updateSize(); + }); + }); + return surfaceCanvas; + }; + HandWrite.attachSurfaceCanvas = function (viewer, getPainterParameters) { + var surfaceCanvas = HandWrite.createSurfaceCanvas(viewer); + var ctx = surfaceCanvas.getContext('2d'); + if (!ctx) + return; + viewer.xy$$ + .pipe(map(distinctUntilChanged(function (_a, _b) { + var x1 = _a.x, y1 = _a.y; + var x2 = _b.x, y2 = _b.y; + return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) < + getPainterParameters().width; + })), withLatestFrom(viewer.scene$), map(function (_a) { + var xy$ = _a[0], scene = _a[1].scene; + var _b = getPainterParameters(), color = _b.color, widthPx = _b.width; + ctx.strokeStyle = color; + ctx.lineCap = 'round'; + var width$ = scene.image.type === 'flat' + ? of(widthPx * 2) + : xy$.pipe(pairwise(), map(function (_a) { + var _b = _a[0], x3 = _b.x, y3 = _b.y, _c = _a[1], x4 = _c.x, y4 = _c.y; + var nx = y4 - y3; + var ny = x3 - x4; + var x1 = x3 + nx; + var y1 = y3 + ny; + var x2 = x3 - nx; + var y2 = y3 - ny; + var p1 = viewer.screenToRectilinearCoordinates({ + x: x1, + y: y1, + }); + var p2 = viewer.screenToRectilinearCoordinates({ + x: x2, + y: y2, + }); + var l2Px = Math.sqrt(Math.pow(nx, 2) + Math.pow(ny, 2)) * 2; + var l2Rad = l2({ p1: p1, p2: p2 }); + var r = (viewer.view.fov() * l2Px) / + (viewer.div.offsetHeight * l2Rad); + return widthPx * r * 2; + }), startWith(widthPx * 2), ignoreError$1()); + return merge(xy$.pipe(first(), map(function (_a) { + var x = _a.x, y = _a.y; + return ({ x: x + 1, y: y }); + }), ignoreError$1()), xy$).pipe(pairwise(), withLatestFrom(width$.pipe(map(Math.round))), tap(function (_a) { + var _b = _a[0], _c = _b[0], x1 = _c.x, y1 = _c.y, _d = _b[1], x2 = _d.x, y2 = _d.y, width = _a[1]; + ctx.lineWidth = width; + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + }), finalize(function () { + return ctx.clearRect(0, 0, surfaceCanvas.width, surfaceCanvas.height); + })); + }), mergeAll()) + .subscribe(); + }; + return HandWrite; + }()); + + var RectilinearViewParams = /** @class */ (function () { + function RectilinearViewParams(props) { + this.coords = new RectilinearViewCoords(props); + this.fov = props.fov; + } + Object.defineProperty(RectilinearViewParams.prototype, "yaw", { + get: function () { + return this.coords.yaw; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(RectilinearViewParams.prototype, "pitch", { + get: function () { + return this.coords.pitch; + }, + enumerable: false, + configurable: true + }); + RectilinearViewParams.prototype.add = function (other) { + return new RectilinearViewParams(__assign(__assign({}, this.coords.add(other.coords)), { fov: this.fov + other.fov })); + }; + RectilinearViewParams.prototype.sub = function (other) { + return new RectilinearViewParams(__assign(__assign({}, this.coords.sub(other.coords)), { fov: this.fov - other.fov })); + }; + return RectilinearViewParams; + }()); + + /* eslint-disable no-lone-blocks */ + var ViewerContainer = /** @class */ (function () { + function ViewerContainer(args) { + var _this = this; + this.splitDirection = 'horizontal'; + this.viewers = []; + this.refetch$ = new Subject(); + this.undo$ = new Subject(); + this.redo$ = new Subject(); + this.viewerCreated$s = new Subject(); + this.addNewViewer = function () { return __awaiter(_this, void 0, void 0, function () { + var index, viewer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + index = this.viewers.length; + return [4 /*yield*/, this.createViewer(index)]; + case 1: + viewer = _a.sent(); + return [2 /*return*/, viewer]; + } + }); + }); }; + /** + * @deprecated Viewer synchronization is no longer supported. + */ + this.addNewSyncedViewer = function () { return __awaiter(_this, void 0, void 0, function () { + var index, viewer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + index = this.viewers.length; + if (index < 1) + return [2 /*return*/, null]; + return [4 /*yield*/, this.syncViewer(index - 1, index)]; + case 1: + viewer = _a.sent(); + return [2 /*return*/, viewer]; + } + }); + }); }; + this.removeViewer = function () { + var viewer = _this.viewers.pop(); + if (viewer) { + if (_this.syncSubscription && + _this.syncSubscription.viewers.includes(viewer)) { + _this.asyncViewers(); + } + if (_this.lockSubscription && + _this.lockSubscription.viewers.includes(viewer)) { + _this.unlockViewers(); + } + viewer.destroy(); + } + _this.updateSize(); + }; + /** + * @deprecated Viewer synchronization is no longer supported. + */ + this.syncViewer = function (index1, index2) { return __awaiter(_this, void 0, void 0, function () { + var newViewer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.createViewer(index2)]; + case 1: + newViewer = _a.sent(); + this.syncViewers(index1, index2); + return [2 /*return*/, newViewer]; + } + }); + }); }; + /** + * @deprecated Viewer synchronization is no longer supported. + */ + this.asyncViewer = function (index) { + _this.asyncViewers(); + _this.createViewer(index); + }; + /** + * @deprecated Viewer synchronization is no longer supported. + */ + this.syncViewers = function (index1, index2) { + var viewer1 = _this.viewers[index1]; + var viewer2 = _this.viewers[index2]; + _this.asyncViewers(); + _this.syncSubscription = { + viewers: [viewer1, viewer2], + subscription: new Subscription(), + }; + _this.syncSubscription.subscription.add(viewer1.currentRectilinearViewCoords$.subscribe(function (params) { + return viewer2.setRectilinearViewCoords(params); + })); + _this.syncSubscription.subscription.add(viewer2.currentRectilinearViewCoords$.subscribe(function (params) { + return viewer1.setRectilinearViewCoords(params); + })); + viewer2.setRectilinearViewCoords(viewer1.getRectilinearViewCoords()); + }; + this.lockViewers = function (index1, index2) { + var viewer1 = _this.viewers[index1]; + var viewer2 = _this.viewers[index2]; + _this.unlockViewers(); + var params1$ = viewer1.scene$.pipe(first(), switchMapTo(viewer1.viewChanged$.pipe(startWith(null))), map(function () { return viewer1.getRectilinearViewCoords(); }), map(function (params) { return new RectilinearViewParams(params); }), shareReplay(1)); + var params2$ = viewer2.scene$.pipe(first(), switchMapTo(viewer2.viewChanged$.pipe(startWith(null))), map(function () { return viewer2.getRectilinearViewCoords(); }), map(function (params) { return new RectilinearViewParams(params); }), shareReplay(1)); + var paramsToRotate$ = combineLatest([params1$, params2$]).pipe(map(function (_a) { + var params1 = _a[0], params2 = _a[1]; + return params2.sub(params1); + }), pairwise(), map(function (_a) { + var params1 = _a[0], params2 = _a[1]; + return params2.sub(params1); + }), scan(function (params1, params2) { return params2.add(params1); })); + var viewerToRotate$ = merge(viewer1.active$.pipe(mapTo(viewer1.inactive$.pipe(first(), mapTo(viewer2)))), viewer2.active$.pipe(mapTo(viewer2.inactive$.pipe(first(), mapTo(viewer1))))).pipe(exhaust()); + var subscription = paramsToRotate$ + .pipe(withLatestFrom(viewerToRotate$, params1$, params2$)) + .subscribe(function (_a) { + var params = _a[0], viewer = _a[1], params1 = _a[2], params2 = _a[3]; + if (viewer === viewer1) { + viewer1.setRectilinearViewCoords(params1.add(params)); + } + if (viewer === viewer2) { + viewer2.setRectilinearViewCoords(params2.sub(params)); + } + }); + _this.lockSubscription = { + viewers: [viewer1, viewer2], + subscription: subscription, + }; + }; + /** + * @deprecated Viewer synchronization is no longer supported. + */ + this.asyncViewers = function () { + var _a; + (_a = _this.syncSubscription) === null || _a === void 0 ? void 0 : _a.subscription.unsubscribe(); + _this.syncSubscription = undefined; + }; + this.unlockViewers = function () { + var _a; + (_a = _this.lockSubscription) === null || _a === void 0 ? void 0 : _a.subscription.unsubscribe(); + _this.lockSubscription = undefined; + }; + this.setSplitDirection = function (direction) { + _this.splitDirection = direction; + var flexDirection = direction; + flexDirection = flexDirection.replace('vertical', 'column'); + flexDirection = flexDirection.replace('horizontal', 'row'); + _this.args.div.style.flexDirection = flexDirection; + _this.updateBorder(); + _this.updateSize(); + }; + this.styleRootDiv = function () { + _this.div.style.position = 'absolute'; + _this.div.style.display = 'flex'; + _this.div.style.flexWrap = 'nowrap'; + _this.div.style.overflow = 'auto'; + _this.div.style.top = '0px'; + _this.div.style.left = '0px'; + _this.div.style.width = '100%'; + _this.div.style.height = '100%'; + _this.div.style.overflow = 'hidden'; + }; + this.updateSize = function () { + _this.viewers.forEach(function (viewer) { return viewer.updateSize(); }); + }; + this.updateBorder = function () { + _this.viewers.forEach(function (viewer, i) { + /* eslint-disable no-param-reassign */ + var div = viewer.div.parentElement; + if (!div) + return; + div.style.borderLeft = + _this.splitDirection === 'horizontal' && i > 0 + ? '1px solid white' + : 'none'; + div.style.borderTop = + _this.splitDirection === 'vertical' && i > 0 + ? '1px solid white' + : 'none'; + div.style.borderRight = + _this.splitDirection === 'horizontal-reverse' && i > 0 + ? '1px solid white' + : 'none'; + div.style.borderBottom = + _this.splitDirection === 'vertical-reverse' && i > 0 + ? '1px solid white' + : 'none'; + /* eslint-enable no-param-reassign */ + }); + }; + this.div = args.div; + this.args = args; + var getPainterParameters = args.getPainterParameters; + if (getPainterParameters) { + var getPathEntities = function (id) { return __awaiter(_this, void 0, void 0, function () { + var rawScene; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, args.getScene(id)]; + case 1: + rawScene = _a.sent(); + return [2 /*return*/, (rawScene === null || rawScene === void 0 ? void 0 : rawScene.paths) || []]; + } + }); + }); }; + var getPathFlatEntities = function (id) { return __awaiter(_this, void 0, void 0, function () { + var rawScene; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, args.getScene(id)]; + case 1: + rawScene = _a.sent(); + return [2 /*return*/, (rawScene === null || rawScene === void 0 ? void 0 : rawScene.flatPaths) || []]; + } + }); + }); }; + this.handWrite = new HandWrite(getPathEntities, getPathFlatEntities, getPainterParameters, this.viewerCreated$.pipe(map(function (_a) { + var viewer = _a.viewer; + return viewer; + }), shareReplay()), this.refetch$, this.undo$, this.redo$, args.handWriteConfig); + } + this.initialize(); + } + Object.defineProperty(ViewerContainer.prototype, "pathEntity$", { + get: function () { + var _a; + return ((_a = this.handWrite) === null || _a === void 0 ? void 0 : _a.pathEntity$) || EMPTY; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewerContainer.prototype, "pathFlatEntity$", { + get: function () { + var _a; + return ((_a = this.handWrite) === null || _a === void 0 ? void 0 : _a.pathFlatEntity$) || EMPTY; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewerContainer.prototype, "viewerCreated$", { + get: function () { + return this.viewerCreated$s.asObservable(); + }, + enumerable: false, + configurable: true + }); + ViewerContainer.prototype.destroy = function () { + this.asyncViewers(); + this.unlockViewers(); + this.viewers.forEach(function (viewer) { return viewer.destroy(); }); + }; + ViewerContainer.prototype.refetch = function (sceneId) { + this.refetch$.next(sceneId); + }; + ViewerContainer.prototype.undo = function (sceneId) { + this.undo$.next(sceneId); + }; + ViewerContainer.prototype.redo = function (sceneId) { + this.redo$.next(sceneId); + }; + ViewerContainer.prototype.initialize = function () { + var _this = this; + this.styleRootDiv(); + this.viewerCreated$.pipe(tap(function () { return _this.updateSize(); })).subscribe(); + }; + ViewerContainer.prototype.createViewer = function (index) { + return __awaiter(this, void 0, void 0, function () { + var oldViewer, viewer; + return __generator(this, function (_a) { + oldViewer = this.viewers[index]; + if (oldViewer) { + oldViewer.destroy(); + } + viewer = new Viewer$2(__assign(__assign({}, this.args), { refetch$: this.refetch$ })); + this.setViewer(index, viewer); + this.viewerCreated$s.next({ index: index, viewer: viewer }); + this.updateBorder(); + this.updateSize(); + return [2 /*return*/, viewer]; + }); + }); + }; + ViewerContainer.prototype.setViewer = function (index, viewer) { + var child = viewer.setIndex(index); + this.div.appendChild(child); + this.viewers[index] = viewer; + }; + return ViewerContainer; + }()); + + exports.Viewer = Viewer$2; + exports.ViewerContainer = ViewerContainer; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/demos/demo-android/app/src/main/assets/index.html b/demos/demo-android/app/src/main/assets/index.html new file mode 100755 index 0000000..337761a --- /dev/null +++ b/demos/demo-android/app/src/main/assets/index.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + +

Preparing to display a photo.

+
+ + + + + + diff --git a/demos/demo-android/app/src/main/assets/index.js b/demos/demo-android/app/src/main/assets/index.js new file mode 100755 index 0000000..a9f23af --- /dev/null +++ b/demos/demo-android/app/src/main/assets/index.js @@ -0,0 +1,75 @@ +/* eslint-disable no-console */ +/* eslint-disable no-nested-ternary */ +const { ViewerContainer } = window.RICOH360Viewer; +const { rxjs } = window; +const { operators } = rxjs; + +const sceneId = 'sceneEqui'; +const getImageUrl = (id) => { + return injectedObject.getPhotoUrl() +}; + +const getScene = async (id) => { + return { + id, + image: { + type: 'equirect', + url: getImageUrl(id), + viewParams: { yaw: 0, pitch: 0, fov: 2.4 }, + } + } +}; + +const eventHandler = { + onSceneChange: (id) => { + console.log(`Change scene: ${id}`); + }, + onClick: (x) => console.log(`Click ${x}`), + onTextureLoad: () => console.log('Texture loaded'), + onViewChanged: (x) => console.log(`View changed: ${JSON.stringify(x)}`), +}; + +const divElement = document.getElementById('root'); +const viewer = new ViewerContainer({ + div: divElement, + config: { + color: { + background: 'navy', + }, + controls: { + scrollZoom: true, + }, + scene: { + numOfCache: 3, + }, + transitionDuration: 5, // millisecond + view: { + keepCoords: true, + limit3D: { + maxVFov: 2.8, // radian + minVFov: 0.8, + maxHFov: 2.8, + }, + }, + }, + getScene, +}); +viewer.viewerCreated$.subscribe(({ index }) => + console.log(`Viewer created: ${index}`), +); +viewer.viewerCreated$.subscribe(({ viewer: v, index }) => { + v.sceneId$.subscribe(eventHandler.onSceneChange); + v.viewCoords$ + .pipe(operators.throttleTime(500)) + .subscribe(eventHandler.onViewChanged); + v.clicked$.subscribe(eventHandler.onClick); + v.clicked$ + .pipe(operators.switchMap((x) => v.coordinatesToScreen(x))) + .subscribe(console.log); + v.textureLoaded$.subscribe(eventHandler.onTextureLoad); + v.isActive$.subscribe((x) => console.log(`isActive: ${x}`)); + + v.switchScene(sceneId); +}); + +viewer.addNewViewer(); \ No newline at end of file diff --git a/demos/demo-android/app/src/main/assets/rxjs.umd.js b/demos/demo-android/app/src/main/assets/rxjs.umd.js new file mode 100755 index 0000000..06b1e11 --- /dev/null +++ b/demos/demo-android/app/src/main/assets/rxjs.umd.js @@ -0,0 +1,9007 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define('rxjs', ['exports'], factory) : + (factory((global.rxjs = {}))); +}(this, (function (exports) { 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + var __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + + function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; + } + + function isFunction(x) { + return typeof x === 'function'; + } + + var _enable_super_gross_mode_that_will_cause_bad_things = false; + var config = { + Promise: undefined, + set useDeprecatedSynchronousErrorHandling(value) { + if (value) { + var error = new Error(); + console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack); + } + else if (_enable_super_gross_mode_that_will_cause_bad_things) { + console.log('RxJS: Back to a better error behavior. Thank you. <3'); + } + _enable_super_gross_mode_that_will_cause_bad_things = value; + }, + get useDeprecatedSynchronousErrorHandling() { + return _enable_super_gross_mode_that_will_cause_bad_things; + }, + }; + + function hostReportError(err) { + setTimeout(function () { throw err; }, 0); + } + + var empty = { + closed: true, + next: function (value) { }, + error: function (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + hostReportError(err); + } + }, + complete: function () { } + }; + + var isArray = (function () { return Array.isArray || (function (x) { return x && typeof x.length === 'number'; }); })(); + + function isObject(x) { + return x !== null && typeof x === 'object'; + } + + var UnsubscriptionErrorImpl = (function () { + function UnsubscriptionErrorImpl(errors) { + Error.call(this); + this.message = errors ? + errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n ') : ''; + this.name = 'UnsubscriptionError'; + this.errors = errors; + return this; + } + UnsubscriptionErrorImpl.prototype = Object.create(Error.prototype); + return UnsubscriptionErrorImpl; + })(); + var UnsubscriptionError = UnsubscriptionErrorImpl; + + var Subscription = (function () { + function Subscription(unsubscribe) { + this.closed = false; + this._parentOrParents = null; + this._subscriptions = null; + if (unsubscribe) { + this._ctorUnsubscribe = true; + this._unsubscribe = unsubscribe; + } + } + Subscription.prototype.unsubscribe = function () { + var errors; + if (this.closed) { + return; + } + var _a = this, _parentOrParents = _a._parentOrParents, _ctorUnsubscribe = _a._ctorUnsubscribe, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; + this.closed = true; + this._parentOrParents = null; + this._subscriptions = null; + if (_parentOrParents instanceof Subscription) { + _parentOrParents.remove(this); + } + else if (_parentOrParents !== null) { + for (var index = 0; index < _parentOrParents.length; ++index) { + var parent_1 = _parentOrParents[index]; + parent_1.remove(this); + } + } + if (isFunction(_unsubscribe)) { + if (_ctorUnsubscribe) { + this._unsubscribe = undefined; + } + try { + _unsubscribe.call(this); + } + catch (e) { + errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e]; + } + } + if (isArray(_subscriptions)) { + var index = -1; + var len = _subscriptions.length; + while (++index < len) { + var sub = _subscriptions[index]; + if (isObject(sub)) { + try { + sub.unsubscribe(); + } + catch (e) { + errors = errors || []; + if (e instanceof UnsubscriptionError) { + errors = errors.concat(flattenUnsubscriptionErrors(e.errors)); + } + else { + errors.push(e); + } + } + } + } + } + if (errors) { + throw new UnsubscriptionError(errors); + } + }; + Subscription.prototype.add = function (teardown) { + var subscription = teardown; + if (!teardown) { + return Subscription.EMPTY; + } + switch (typeof teardown) { + case 'function': + subscription = new Subscription(teardown); + case 'object': + if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') { + return subscription; + } + else if (this.closed) { + subscription.unsubscribe(); + return subscription; + } + else if (!(subscription instanceof Subscription)) { + var tmp = subscription; + subscription = new Subscription(); + subscription._subscriptions = [tmp]; + } + break; + default: { + throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); + } + } + var _parentOrParents = subscription._parentOrParents; + if (_parentOrParents === null) { + subscription._parentOrParents = this; + } + else if (_parentOrParents instanceof Subscription) { + if (_parentOrParents === this) { + return subscription; + } + subscription._parentOrParents = [_parentOrParents, this]; + } + else if (_parentOrParents.indexOf(this) === -1) { + _parentOrParents.push(this); + } + else { + return subscription; + } + var subscriptions = this._subscriptions; + if (subscriptions === null) { + this._subscriptions = [subscription]; + } + else { + subscriptions.push(subscription); + } + return subscription; + }; + Subscription.prototype.remove = function (subscription) { + var subscriptions = this._subscriptions; + if (subscriptions) { + var subscriptionIndex = subscriptions.indexOf(subscription); + if (subscriptionIndex !== -1) { + subscriptions.splice(subscriptionIndex, 1); + } + } + }; + Subscription.EMPTY = (function (empty) { + empty.closed = true; + return empty; + }(new Subscription())); + return Subscription; + }()); + function flattenUnsubscriptionErrors(errors) { + return errors.reduce(function (errs, err) { return errs.concat((err instanceof UnsubscriptionError) ? err.errors : err); }, []); + } + + var rxSubscriber = (function () { + return typeof Symbol === 'function' + ? Symbol('rxSubscriber') + : '@@rxSubscriber_' + Math.random(); + })(); + + var Subscriber = (function (_super) { + __extends(Subscriber, _super); + function Subscriber(destinationOrNext, error, complete) { + var _this = _super.call(this) || this; + _this.syncErrorValue = null; + _this.syncErrorThrown = false; + _this.syncErrorThrowable = false; + _this.isStopped = false; + switch (arguments.length) { + case 0: + _this.destination = empty; + break; + case 1: + if (!destinationOrNext) { + _this.destination = empty; + break; + } + if (typeof destinationOrNext === 'object') { + if (destinationOrNext instanceof Subscriber) { + _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; + _this.destination = destinationOrNext; + destinationOrNext.add(_this); + } + else { + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext); + } + break; + } + default: + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); + break; + } + return _this; + } + Subscriber.prototype[rxSubscriber] = function () { return this; }; + Subscriber.create = function (next, error, complete) { + var subscriber = new Subscriber(next, error, complete); + subscriber.syncErrorThrowable = false; + return subscriber; + }; + Subscriber.prototype.next = function (value) { + if (!this.isStopped) { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (!this.isStopped) { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (!this.isStopped) { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + this.destination.error(err); + this.unsubscribe(); + }; + Subscriber.prototype._complete = function () { + this.destination.complete(); + this.unsubscribe(); + }; + Subscriber.prototype._unsubscribeAndRecycle = function () { + var _parentOrParents = this._parentOrParents; + this._parentOrParents = null; + this.unsubscribe(); + this.closed = false; + this.isStopped = false; + this._parentOrParents = _parentOrParents; + return this; + }; + return Subscriber; + }(Subscription)); + var SafeSubscriber = (function (_super) { + __extends(SafeSubscriber, _super); + function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { + var _this = _super.call(this) || this; + _this._parentSubscriber = _parentSubscriber; + var next; + var context = _this; + if (isFunction(observerOrNext)) { + next = observerOrNext; + } + else if (observerOrNext) { + next = observerOrNext.next; + error = observerOrNext.error; + complete = observerOrNext.complete; + if (observerOrNext !== empty) { + context = Object.create(observerOrNext); + if (isFunction(context.unsubscribe)) { + _this.add(context.unsubscribe.bind(context)); + } + context.unsubscribe = _this.unsubscribe.bind(_this); + } + } + _this._context = context; + _this._next = next; + _this._error = error; + _this._complete = complete; + return _this; + } + SafeSubscriber.prototype.next = function (value) { + if (!this.isStopped && this._next) { + var _parentSubscriber = this._parentSubscriber; + if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._next, value); + } + else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + var useDeprecatedSynchronousErrorHandling = config.useDeprecatedSynchronousErrorHandling; + if (this._error) { + if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._error, err); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, this._error, err); + this.unsubscribe(); + } + } + else if (!_parentSubscriber.syncErrorThrowable) { + this.unsubscribe(); + if (useDeprecatedSynchronousErrorHandling) { + throw err; + } + hostReportError(err); + } + else { + if (useDeprecatedSynchronousErrorHandling) { + _parentSubscriber.syncErrorValue = err; + _parentSubscriber.syncErrorThrown = true; + } + else { + hostReportError(err); + } + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.complete = function () { + var _this = this; + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + if (this._complete) { + var wrappedComplete = function () { return _this._complete.call(_this._context); }; + if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(wrappedComplete); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, wrappedComplete); + this.unsubscribe(); + } + } + else { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { + try { + fn.call(this._context, value); + } + catch (err) { + this.unsubscribe(); + if (config.useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + hostReportError(err); + } + } + }; + SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { + if (!config.useDeprecatedSynchronousErrorHandling) { + throw new Error('bad call'); + } + try { + fn.call(this._context, value); + } + catch (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + parent.syncErrorValue = err; + parent.syncErrorThrown = true; + return true; + } + else { + hostReportError(err); + return true; + } + } + return false; + }; + SafeSubscriber.prototype._unsubscribe = function () { + var _parentSubscriber = this._parentSubscriber; + this._context = null; + this._parentSubscriber = null; + _parentSubscriber.unsubscribe(); + }; + return SafeSubscriber; + }(Subscriber)); + + function canReportError(observer) { + while (observer) { + var _a = observer, closed_1 = _a.closed, destination = _a.destination, isStopped = _a.isStopped; + if (closed_1 || isStopped) { + return false; + } + else if (destination && destination instanceof Subscriber) { + observer = destination; + } + else { + observer = null; + } + } + return true; + } + + function toSubscriber(nextOrObserver, error, complete) { + if (nextOrObserver) { + if (nextOrObserver instanceof Subscriber) { + return nextOrObserver; + } + if (nextOrObserver[rxSubscriber]) { + return nextOrObserver[rxSubscriber](); + } + } + if (!nextOrObserver && !error && !complete) { + return new Subscriber(empty); + } + return new Subscriber(nextOrObserver, error, complete); + } + + var observable = (function () { return typeof Symbol === 'function' && Symbol.observable || '@@observable'; })(); + + function identity(x) { + return x; + } + + function pipe() { + var fns = []; + for (var _i = 0; _i < arguments.length; _i++) { + fns[_i] = arguments[_i]; + } + return pipeFromArray(fns); + } + function pipeFromArray(fns) { + if (fns.length === 0) { + return identity; + } + if (fns.length === 1) { + return fns[0]; + } + return function piped(input) { + return fns.reduce(function (prev, fn) { return fn(prev); }, input); + }; + } + + var Observable = (function () { + function Observable(subscribe) { + this._isScalar = false; + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable$$1 = new Observable(); + observable$$1.source = this; + observable$$1.operator = operator; + return observable$$1; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var operator = this.operator; + var sink = toSubscriber(observerOrNext, error, complete); + if (operator) { + sink.add(operator.call(sink, this.source)); + } + else { + sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? + this._subscribe(sink) : + this._trySubscribe(sink)); + } + if (config.useDeprecatedSynchronousErrorHandling) { + if (sink.syncErrorThrowable) { + sink.syncErrorThrowable = false; + if (sink.syncErrorThrown) { + throw sink.syncErrorValue; + } + } + } + return sink; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } + catch (err) { + if (config.useDeprecatedSynchronousErrorHandling) { + sink.syncErrorThrown = true; + sink.syncErrorValue = err; + } + if (canReportError(sink)) { + sink.error(err); + } + else { + console.warn(err); + } + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscription; + subscription = _this.subscribe(function (value) { + try { + next(value); + } + catch (err) { + reject(err); + if (subscription) { + subscription.unsubscribe(); + } + } + }, reject, resolve); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var source = this.source; + return source && source.subscribe(subscriber); + }; + Observable.prototype[observable] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + if (operations.length === 0) { + return this; + } + return pipeFromArray(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; + }()); + function getPromiseCtor(promiseCtor) { + if (!promiseCtor) { + promiseCtor = config.Promise || Promise; + } + if (!promiseCtor) { + throw new Error('no Promise impl found'); + } + return promiseCtor; + } + + var ObjectUnsubscribedErrorImpl = (function () { + function ObjectUnsubscribedErrorImpl() { + Error.call(this); + this.message = 'object unsubscribed'; + this.name = 'ObjectUnsubscribedError'; + return this; + } + ObjectUnsubscribedErrorImpl.prototype = Object.create(Error.prototype); + return ObjectUnsubscribedErrorImpl; + })(); + var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl; + + var SubjectSubscription = (function (_super) { + __extends(SubjectSubscription, _super); + function SubjectSubscription(subject, subscriber) { + var _this = _super.call(this) || this; + _this.subject = subject; + _this.subscriber = subscriber; + _this.closed = false; + return _this; + } + SubjectSubscription.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.closed = true; + var subject = this.subject; + var observers = subject.observers; + this.subject = null; + if (!observers || observers.length === 0 || subject.isStopped || subject.closed) { + return; + } + var subscriberIndex = observers.indexOf(this.subscriber); + if (subscriberIndex !== -1) { + observers.splice(subscriberIndex, 1); + } + }; + return SubjectSubscription; + }(Subscription)); + + var SubjectSubscriber = (function (_super) { + __extends(SubjectSubscriber, _super); + function SubjectSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + return _this; + } + return SubjectSubscriber; + }(Subscriber)); + var Subject = (function (_super) { + __extends(Subject, _super); + function Subject() { + var _this = _super.call(this) || this; + _this.observers = []; + _this.closed = false; + _this.isStopped = false; + _this.hasError = false; + _this.thrownError = null; + return _this; + } + Subject.prototype[rxSubscriber] = function () { + return new SubjectSubscriber(this); + }; + Subject.prototype.lift = function (operator) { + var subject = new AnonymousSubject(this, this); + subject.operator = operator; + return subject; + }; + Subject.prototype.next = function (value) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + if (!this.isStopped) { + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].next(value); + } + } + }; + Subject.prototype.error = function (err) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + this.hasError = true; + this.thrownError = err; + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].error(err); + } + this.observers.length = 0; + }; + Subject.prototype.complete = function () { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].complete(); + } + this.observers.length = 0; + }; + Subject.prototype.unsubscribe = function () { + this.isStopped = true; + this.closed = true; + this.observers = null; + }; + Subject.prototype._trySubscribe = function (subscriber) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else { + return _super.prototype._trySubscribe.call(this, subscriber); + } + }; + Subject.prototype._subscribe = function (subscriber) { + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else if (this.hasError) { + subscriber.error(this.thrownError); + return Subscription.EMPTY; + } + else if (this.isStopped) { + subscriber.complete(); + return Subscription.EMPTY; + } + else { + this.observers.push(subscriber); + return new SubjectSubscription(this, subscriber); + } + }; + Subject.prototype.asObservable = function () { + var observable = new Observable(); + observable.source = this; + return observable; + }; + Subject.create = function (destination, source) { + return new AnonymousSubject(destination, source); + }; + return Subject; + }(Observable)); + var AnonymousSubject = (function (_super) { + __extends(AnonymousSubject, _super); + function AnonymousSubject(destination, source) { + var _this = _super.call(this) || this; + _this.destination = destination; + _this.source = source; + return _this; + } + AnonymousSubject.prototype.next = function (value) { + var destination = this.destination; + if (destination && destination.next) { + destination.next(value); + } + }; + AnonymousSubject.prototype.error = function (err) { + var destination = this.destination; + if (destination && destination.error) { + this.destination.error(err); + } + }; + AnonymousSubject.prototype.complete = function () { + var destination = this.destination; + if (destination && destination.complete) { + this.destination.complete(); + } + }; + AnonymousSubject.prototype._subscribe = function (subscriber) { + var source = this.source; + if (source) { + return this.source.subscribe(subscriber); + } + else { + return Subscription.EMPTY; + } + }; + return AnonymousSubject; + }(Subject)); + + function refCount() { + return function refCountOperatorFunction(source) { + return source.lift(new RefCountOperator(source)); + }; + } + var RefCountOperator = (function () { + function RefCountOperator(connectable) { + this.connectable = connectable; + } + RefCountOperator.prototype.call = function (subscriber, source) { + var connectable = this.connectable; + connectable._refCount++; + var refCounter = new RefCountSubscriber(subscriber, connectable); + var subscription = source.subscribe(refCounter); + if (!refCounter.closed) { + refCounter.connection = connectable.connect(); + } + return subscription; + }; + return RefCountOperator; + }()); + var RefCountSubscriber = (function (_super) { + __extends(RefCountSubscriber, _super); + function RefCountSubscriber(destination, connectable) { + var _this = _super.call(this, destination) || this; + _this.connectable = connectable; + return _this; + } + RefCountSubscriber.prototype._unsubscribe = function () { + var connectable = this.connectable; + if (!connectable) { + this.connection = null; + return; + } + this.connectable = null; + var refCount = connectable._refCount; + if (refCount <= 0) { + this.connection = null; + return; + } + connectable._refCount = refCount - 1; + if (refCount > 1) { + this.connection = null; + return; + } + var connection = this.connection; + var sharedConnection = connectable._connection; + this.connection = null; + if (sharedConnection && (!connection || sharedConnection === connection)) { + sharedConnection.unsubscribe(); + } + }; + return RefCountSubscriber; + }(Subscriber)); + + var ConnectableObservable = (function (_super) { + __extends(ConnectableObservable, _super); + function ConnectableObservable(source, subjectFactory) { + var _this = _super.call(this) || this; + _this.source = source; + _this.subjectFactory = subjectFactory; + _this._refCount = 0; + _this._isComplete = false; + return _this; + } + ConnectableObservable.prototype._subscribe = function (subscriber) { + return this.getSubject().subscribe(subscriber); + }; + ConnectableObservable.prototype.getSubject = function () { + var subject = this._subject; + if (!subject || subject.isStopped) { + this._subject = this.subjectFactory(); + } + return this._subject; + }; + ConnectableObservable.prototype.connect = function () { + var connection = this._connection; + if (!connection) { + this._isComplete = false; + connection = this._connection = new Subscription(); + connection.add(this.source + .subscribe(new ConnectableSubscriber(this.getSubject(), this))); + if (connection.closed) { + this._connection = null; + connection = Subscription.EMPTY; + } + } + return connection; + }; + ConnectableObservable.prototype.refCount = function () { + return refCount()(this); + }; + return ConnectableObservable; + }(Observable)); + var connectableObservableDescriptor = (function () { + var connectableProto = ConnectableObservable.prototype; + return { + operator: { value: null }, + _refCount: { value: 0, writable: true }, + _subject: { value: null, writable: true }, + _connection: { value: null, writable: true }, + _subscribe: { value: connectableProto._subscribe }, + _isComplete: { value: connectableProto._isComplete, writable: true }, + getSubject: { value: connectableProto.getSubject }, + connect: { value: connectableProto.connect }, + refCount: { value: connectableProto.refCount } + }; + })(); + var ConnectableSubscriber = (function (_super) { + __extends(ConnectableSubscriber, _super); + function ConnectableSubscriber(destination, connectable) { + var _this = _super.call(this, destination) || this; + _this.connectable = connectable; + return _this; + } + ConnectableSubscriber.prototype._error = function (err) { + this._unsubscribe(); + _super.prototype._error.call(this, err); + }; + ConnectableSubscriber.prototype._complete = function () { + this.connectable._isComplete = true; + this._unsubscribe(); + _super.prototype._complete.call(this); + }; + ConnectableSubscriber.prototype._unsubscribe = function () { + var connectable = this.connectable; + if (connectable) { + this.connectable = null; + var connection = connectable._connection; + connectable._refCount = 0; + connectable._subject = null; + connectable._connection = null; + if (connection) { + connection.unsubscribe(); + } + } + }; + return ConnectableSubscriber; + }(SubjectSubscriber)); + var RefCountSubscriber$1 = (function (_super) { + __extends(RefCountSubscriber, _super); + function RefCountSubscriber(destination, connectable) { + var _this = _super.call(this, destination) || this; + _this.connectable = connectable; + return _this; + } + RefCountSubscriber.prototype._unsubscribe = function () { + var connectable = this.connectable; + if (!connectable) { + this.connection = null; + return; + } + this.connectable = null; + var refCount$$1 = connectable._refCount; + if (refCount$$1 <= 0) { + this.connection = null; + return; + } + connectable._refCount = refCount$$1 - 1; + if (refCount$$1 > 1) { + this.connection = null; + return; + } + var connection = this.connection; + var sharedConnection = connectable._connection; + this.connection = null; + if (sharedConnection && (!connection || sharedConnection === connection)) { + sharedConnection.unsubscribe(); + } + }; + return RefCountSubscriber; + }(Subscriber)); + + function groupBy(keySelector, elementSelector, durationSelector, subjectSelector) { + return function (source) { + return source.lift(new GroupByOperator(keySelector, elementSelector, durationSelector, subjectSelector)); + }; + } + var GroupByOperator = (function () { + function GroupByOperator(keySelector, elementSelector, durationSelector, subjectSelector) { + this.keySelector = keySelector; + this.elementSelector = elementSelector; + this.durationSelector = durationSelector; + this.subjectSelector = subjectSelector; + } + GroupByOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new GroupBySubscriber(subscriber, this.keySelector, this.elementSelector, this.durationSelector, this.subjectSelector)); + }; + return GroupByOperator; + }()); + var GroupBySubscriber = (function (_super) { + __extends(GroupBySubscriber, _super); + function GroupBySubscriber(destination, keySelector, elementSelector, durationSelector, subjectSelector) { + var _this = _super.call(this, destination) || this; + _this.keySelector = keySelector; + _this.elementSelector = elementSelector; + _this.durationSelector = durationSelector; + _this.subjectSelector = subjectSelector; + _this.groups = null; + _this.attemptedToUnsubscribe = false; + _this.count = 0; + return _this; + } + GroupBySubscriber.prototype._next = function (value) { + var key; + try { + key = this.keySelector(value); + } + catch (err) { + this.error(err); + return; + } + this._group(value, key); + }; + GroupBySubscriber.prototype._group = function (value, key) { + var groups = this.groups; + if (!groups) { + groups = this.groups = new Map(); + } + var group = groups.get(key); + var element; + if (this.elementSelector) { + try { + element = this.elementSelector(value); + } + catch (err) { + this.error(err); + } + } + else { + element = value; + } + if (!group) { + group = (this.subjectSelector ? this.subjectSelector() : new Subject()); + groups.set(key, group); + var groupedObservable = new GroupedObservable(key, group, this); + this.destination.next(groupedObservable); + if (this.durationSelector) { + var duration = void 0; + try { + duration = this.durationSelector(new GroupedObservable(key, group)); + } + catch (err) { + this.error(err); + return; + } + this.add(duration.subscribe(new GroupDurationSubscriber(key, group, this))); + } + } + if (!group.closed) { + group.next(element); + } + }; + GroupBySubscriber.prototype._error = function (err) { + var groups = this.groups; + if (groups) { + groups.forEach(function (group, key) { + group.error(err); + }); + groups.clear(); + } + this.destination.error(err); + }; + GroupBySubscriber.prototype._complete = function () { + var groups = this.groups; + if (groups) { + groups.forEach(function (group, key) { + group.complete(); + }); + groups.clear(); + } + this.destination.complete(); + }; + GroupBySubscriber.prototype.removeGroup = function (key) { + this.groups.delete(key); + }; + GroupBySubscriber.prototype.unsubscribe = function () { + if (!this.closed) { + this.attemptedToUnsubscribe = true; + if (this.count === 0) { + _super.prototype.unsubscribe.call(this); + } + } + }; + return GroupBySubscriber; + }(Subscriber)); + var GroupDurationSubscriber = (function (_super) { + __extends(GroupDurationSubscriber, _super); + function GroupDurationSubscriber(key, group, parent) { + var _this = _super.call(this, group) || this; + _this.key = key; + _this.group = group; + _this.parent = parent; + return _this; + } + GroupDurationSubscriber.prototype._next = function (value) { + this.complete(); + }; + GroupDurationSubscriber.prototype._unsubscribe = function () { + var _a = this, parent = _a.parent, key = _a.key; + this.key = this.parent = null; + if (parent) { + parent.removeGroup(key); + } + }; + return GroupDurationSubscriber; + }(Subscriber)); + var GroupedObservable = (function (_super) { + __extends(GroupedObservable, _super); + function GroupedObservable(key, groupSubject, refCountSubscription) { + var _this = _super.call(this) || this; + _this.key = key; + _this.groupSubject = groupSubject; + _this.refCountSubscription = refCountSubscription; + return _this; + } + GroupedObservable.prototype._subscribe = function (subscriber) { + var subscription = new Subscription(); + var _a = this, refCountSubscription = _a.refCountSubscription, groupSubject = _a.groupSubject; + if (refCountSubscription && !refCountSubscription.closed) { + subscription.add(new InnerRefCountSubscription(refCountSubscription)); + } + subscription.add(groupSubject.subscribe(subscriber)); + return subscription; + }; + return GroupedObservable; + }(Observable)); + var InnerRefCountSubscription = (function (_super) { + __extends(InnerRefCountSubscription, _super); + function InnerRefCountSubscription(parent) { + var _this = _super.call(this) || this; + _this.parent = parent; + parent.count++; + return _this; + } + InnerRefCountSubscription.prototype.unsubscribe = function () { + var parent = this.parent; + if (!parent.closed && !this.closed) { + _super.prototype.unsubscribe.call(this); + parent.count -= 1; + if (parent.count === 0 && parent.attemptedToUnsubscribe) { + parent.unsubscribe(); + } + } + }; + return InnerRefCountSubscription; + }(Subscription)); + + var BehaviorSubject = (function (_super) { + __extends(BehaviorSubject, _super); + function BehaviorSubject(_value) { + var _this = _super.call(this) || this; + _this._value = _value; + return _this; + } + Object.defineProperty(BehaviorSubject.prototype, "value", { + get: function () { + return this.getValue(); + }, + enumerable: true, + configurable: true + }); + BehaviorSubject.prototype._subscribe = function (subscriber) { + var subscription = _super.prototype._subscribe.call(this, subscriber); + if (subscription && !subscription.closed) { + subscriber.next(this._value); + } + return subscription; + }; + BehaviorSubject.prototype.getValue = function () { + if (this.hasError) { + throw this.thrownError; + } + else if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else { + return this._value; + } + }; + BehaviorSubject.prototype.next = function (value) { + _super.prototype.next.call(this, this._value = value); + }; + return BehaviorSubject; + }(Subject)); + + var Action = (function (_super) { + __extends(Action, _super); + function Action(scheduler, work) { + return _super.call(this) || this; + } + Action.prototype.schedule = function (state, delay) { + if (delay === void 0) { delay = 0; } + return this; + }; + return Action; + }(Subscription)); + + var AsyncAction = (function (_super) { + __extends(AsyncAction, _super); + function AsyncAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + _this.pending = false; + return _this; + } + AsyncAction.prototype.schedule = function (state, delay) { + if (delay === void 0) { delay = 0; } + if (this.closed) { + return this; + } + this.state = state; + var id = this.id; + var scheduler = this.scheduler; + if (id != null) { + this.id = this.recycleAsyncId(scheduler, id, delay); + } + this.pending = true; + this.delay = delay; + this.id = this.id || this.requestAsyncId(scheduler, this.id, delay); + return this; + }; + AsyncAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + return setInterval(scheduler.flush.bind(scheduler, this), delay); + }; + AsyncAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if (delay !== null && this.delay === delay && this.pending === false) { + return id; + } + clearInterval(id); + return undefined; + }; + AsyncAction.prototype.execute = function (state, delay) { + if (this.closed) { + return new Error('executing a cancelled action'); + } + this.pending = false; + var error = this._execute(state, delay); + if (error) { + return error; + } + else if (this.pending === false && this.id != null) { + this.id = this.recycleAsyncId(this.scheduler, this.id, null); + } + }; + AsyncAction.prototype._execute = function (state, delay) { + var errored = false; + var errorValue = undefined; + try { + this.work(state); + } + catch (e) { + errored = true; + errorValue = !!e && e || new Error(e); + } + if (errored) { + this.unsubscribe(); + return errorValue; + } + }; + AsyncAction.prototype._unsubscribe = function () { + var id = this.id; + var scheduler = this.scheduler; + var actions = scheduler.actions; + var index = actions.indexOf(this); + this.work = null; + this.state = null; + this.pending = false; + this.scheduler = null; + if (index !== -1) { + actions.splice(index, 1); + } + if (id != null) { + this.id = this.recycleAsyncId(scheduler, id, null); + } + this.delay = null; + }; + return AsyncAction; + }(Action)); + + var QueueAction = (function (_super) { + __extends(QueueAction, _super); + function QueueAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + return _this; + } + QueueAction.prototype.schedule = function (state, delay) { + if (delay === void 0) { delay = 0; } + if (delay > 0) { + return _super.prototype.schedule.call(this, state, delay); + } + this.delay = delay; + this.state = state; + this.scheduler.flush(this); + return this; + }; + QueueAction.prototype.execute = function (state, delay) { + return (delay > 0 || this.closed) ? + _super.prototype.execute.call(this, state, delay) : + this._execute(state, delay); + }; + QueueAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) { + return _super.prototype.requestAsyncId.call(this, scheduler, id, delay); + } + return scheduler.flush(this); + }; + return QueueAction; + }(AsyncAction)); + + var Scheduler = (function () { + function Scheduler(SchedulerAction, now) { + if (now === void 0) { now = Scheduler.now; } + this.SchedulerAction = SchedulerAction; + this.now = now; + } + Scheduler.prototype.schedule = function (work, delay, state) { + if (delay === void 0) { delay = 0; } + return new this.SchedulerAction(this, work).schedule(state, delay); + }; + Scheduler.now = function () { return Date.now(); }; + return Scheduler; + }()); + + var AsyncScheduler = (function (_super) { + __extends(AsyncScheduler, _super); + function AsyncScheduler(SchedulerAction, now) { + if (now === void 0) { now = Scheduler.now; } + var _this = _super.call(this, SchedulerAction, function () { + if (AsyncScheduler.delegate && AsyncScheduler.delegate !== _this) { + return AsyncScheduler.delegate.now(); + } + else { + return now(); + } + }) || this; + _this.actions = []; + _this.active = false; + _this.scheduled = undefined; + return _this; + } + AsyncScheduler.prototype.schedule = function (work, delay, state) { + if (delay === void 0) { delay = 0; } + if (AsyncScheduler.delegate && AsyncScheduler.delegate !== this) { + return AsyncScheduler.delegate.schedule(work, delay, state); + } + else { + return _super.prototype.schedule.call(this, work, delay, state); + } + }; + AsyncScheduler.prototype.flush = function (action) { + var actions = this.actions; + if (this.active) { + actions.push(action); + return; + } + var error; + this.active = true; + do { + if (error = action.execute(action.state, action.delay)) { + break; + } + } while (action = actions.shift()); + this.active = false; + if (error) { + while (action = actions.shift()) { + action.unsubscribe(); + } + throw error; + } + }; + return AsyncScheduler; + }(Scheduler)); + + var QueueScheduler = (function (_super) { + __extends(QueueScheduler, _super); + function QueueScheduler() { + return _super !== null && _super.apply(this, arguments) || this; + } + return QueueScheduler; + }(AsyncScheduler)); + + var queueScheduler = new QueueScheduler(QueueAction); + var queue = queueScheduler; + + var EMPTY = new Observable(function (subscriber) { return subscriber.complete(); }); + function empty$1(scheduler) { + return scheduler ? emptyScheduled(scheduler) : EMPTY; + } + function emptyScheduled(scheduler) { + return new Observable(function (subscriber) { return scheduler.schedule(function () { return subscriber.complete(); }); }); + } + + function isScheduler(value) { + return value && typeof value.schedule === 'function'; + } + + var subscribeToArray = function (array) { return function (subscriber) { + for (var i = 0, len = array.length; i < len && !subscriber.closed; i++) { + subscriber.next(array[i]); + } + subscriber.complete(); + }; }; + + function scheduleArray(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + var i = 0; + sub.add(scheduler.schedule(function () { + if (i === input.length) { + subscriber.complete(); + return; + } + subscriber.next(input[i++]); + if (!subscriber.closed) { + sub.add(this.schedule()); + } + })); + return sub; + }); + } + + function fromArray(input, scheduler) { + if (!scheduler) { + return new Observable(subscribeToArray(input)); + } + else { + return scheduleArray(input, scheduler); + } + } + + function of() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var scheduler = args[args.length - 1]; + if (isScheduler(scheduler)) { + args.pop(); + return scheduleArray(args, scheduler); + } + else { + return fromArray(args); + } + } + + function throwError(error, scheduler) { + if (!scheduler) { + return new Observable(function (subscriber) { return subscriber.error(error); }); + } + else { + return new Observable(function (subscriber) { return scheduler.schedule(dispatch, 0, { error: error, subscriber: subscriber }); }); + } + } + function dispatch(_a) { + var error = _a.error, subscriber = _a.subscriber; + subscriber.error(error); + } + + (function (NotificationKind) { + NotificationKind["NEXT"] = "N"; + NotificationKind["ERROR"] = "E"; + NotificationKind["COMPLETE"] = "C"; + })(exports.NotificationKind || (exports.NotificationKind = {})); + var Notification = (function () { + function Notification(kind, value, error) { + this.kind = kind; + this.value = value; + this.error = error; + this.hasValue = kind === 'N'; + } + Notification.prototype.observe = function (observer) { + switch (this.kind) { + case 'N': + return observer.next && observer.next(this.value); + case 'E': + return observer.error && observer.error(this.error); + case 'C': + return observer.complete && observer.complete(); + } + }; + Notification.prototype.do = function (next, error, complete) { + var kind = this.kind; + switch (kind) { + case 'N': + return next && next(this.value); + case 'E': + return error && error(this.error); + case 'C': + return complete && complete(); + } + }; + Notification.prototype.accept = function (nextOrObserver, error, complete) { + if (nextOrObserver && typeof nextOrObserver.next === 'function') { + return this.observe(nextOrObserver); + } + else { + return this.do(nextOrObserver, error, complete); + } + }; + Notification.prototype.toObservable = function () { + var kind = this.kind; + switch (kind) { + case 'N': + return of(this.value); + case 'E': + return throwError(this.error); + case 'C': + return empty$1(); + } + throw new Error('unexpected notification kind value'); + }; + Notification.createNext = function (value) { + if (typeof value !== 'undefined') { + return new Notification('N', value); + } + return Notification.undefinedValueNotification; + }; + Notification.createError = function (err) { + return new Notification('E', undefined, err); + }; + Notification.createComplete = function () { + return Notification.completeNotification; + }; + Notification.completeNotification = new Notification('C'); + Notification.undefinedValueNotification = new Notification('N', undefined); + return Notification; + }()); + + function observeOn(scheduler, delay) { + if (delay === void 0) { delay = 0; } + return function observeOnOperatorFunction(source) { + return source.lift(new ObserveOnOperator(scheduler, delay)); + }; + } + var ObserveOnOperator = (function () { + function ObserveOnOperator(scheduler, delay) { + if (delay === void 0) { delay = 0; } + this.scheduler = scheduler; + this.delay = delay; + } + ObserveOnOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ObserveOnSubscriber(subscriber, this.scheduler, this.delay)); + }; + return ObserveOnOperator; + }()); + var ObserveOnSubscriber = (function (_super) { + __extends(ObserveOnSubscriber, _super); + function ObserveOnSubscriber(destination, scheduler, delay) { + if (delay === void 0) { delay = 0; } + var _this = _super.call(this, destination) || this; + _this.scheduler = scheduler; + _this.delay = delay; + return _this; + } + ObserveOnSubscriber.dispatch = function (arg) { + var notification = arg.notification, destination = arg.destination; + notification.observe(destination); + this.unsubscribe(); + }; + ObserveOnSubscriber.prototype.scheduleMessage = function (notification) { + var destination = this.destination; + destination.add(this.scheduler.schedule(ObserveOnSubscriber.dispatch, this.delay, new ObserveOnMessage(notification, this.destination))); + }; + ObserveOnSubscriber.prototype._next = function (value) { + this.scheduleMessage(Notification.createNext(value)); + }; + ObserveOnSubscriber.prototype._error = function (err) { + this.scheduleMessage(Notification.createError(err)); + this.unsubscribe(); + }; + ObserveOnSubscriber.prototype._complete = function () { + this.scheduleMessage(Notification.createComplete()); + this.unsubscribe(); + }; + return ObserveOnSubscriber; + }(Subscriber)); + var ObserveOnMessage = (function () { + function ObserveOnMessage(notification, destination) { + this.notification = notification; + this.destination = destination; + } + return ObserveOnMessage; + }()); + + var ReplaySubject = (function (_super) { + __extends(ReplaySubject, _super); + function ReplaySubject(bufferSize, windowTime, scheduler) { + if (bufferSize === void 0) { bufferSize = Number.POSITIVE_INFINITY; } + if (windowTime === void 0) { windowTime = Number.POSITIVE_INFINITY; } + var _this = _super.call(this) || this; + _this.scheduler = scheduler; + _this._events = []; + _this._infiniteTimeWindow = false; + _this._bufferSize = bufferSize < 1 ? 1 : bufferSize; + _this._windowTime = windowTime < 1 ? 1 : windowTime; + if (windowTime === Number.POSITIVE_INFINITY) { + _this._infiniteTimeWindow = true; + _this.next = _this.nextInfiniteTimeWindow; + } + else { + _this.next = _this.nextTimeWindow; + } + return _this; + } + ReplaySubject.prototype.nextInfiniteTimeWindow = function (value) { + if (!this.isStopped) { + var _events = this._events; + _events.push(value); + if (_events.length > this._bufferSize) { + _events.shift(); + } + } + _super.prototype.next.call(this, value); + }; + ReplaySubject.prototype.nextTimeWindow = function (value) { + if (!this.isStopped) { + this._events.push(new ReplayEvent(this._getNow(), value)); + this._trimBufferThenGetEvents(); + } + _super.prototype.next.call(this, value); + }; + ReplaySubject.prototype._subscribe = function (subscriber) { + var _infiniteTimeWindow = this._infiniteTimeWindow; + var _events = _infiniteTimeWindow ? this._events : this._trimBufferThenGetEvents(); + var scheduler = this.scheduler; + var len = _events.length; + var subscription; + if (this.closed) { + throw new ObjectUnsubscribedError(); + } + else if (this.isStopped || this.hasError) { + subscription = Subscription.EMPTY; + } + else { + this.observers.push(subscriber); + subscription = new SubjectSubscription(this, subscriber); + } + if (scheduler) { + subscriber.add(subscriber = new ObserveOnSubscriber(subscriber, scheduler)); + } + if (_infiniteTimeWindow) { + for (var i = 0; i < len && !subscriber.closed; i++) { + subscriber.next(_events[i]); + } + } + else { + for (var i = 0; i < len && !subscriber.closed; i++) { + subscriber.next(_events[i].value); + } + } + if (this.hasError) { + subscriber.error(this.thrownError); + } + else if (this.isStopped) { + subscriber.complete(); + } + return subscription; + }; + ReplaySubject.prototype._getNow = function () { + return (this.scheduler || queue).now(); + }; + ReplaySubject.prototype._trimBufferThenGetEvents = function () { + var now = this._getNow(); + var _bufferSize = this._bufferSize; + var _windowTime = this._windowTime; + var _events = this._events; + var eventsCount = _events.length; + var spliceCount = 0; + while (spliceCount < eventsCount) { + if ((now - _events[spliceCount].time) < _windowTime) { + break; + } + spliceCount++; + } + if (eventsCount > _bufferSize) { + spliceCount = Math.max(spliceCount, eventsCount - _bufferSize); + } + if (spliceCount > 0) { + _events.splice(0, spliceCount); + } + return _events; + }; + return ReplaySubject; + }(Subject)); + var ReplayEvent = (function () { + function ReplayEvent(time, value) { + this.time = time; + this.value = value; + } + return ReplayEvent; + }()); + + var AsyncSubject = (function (_super) { + __extends(AsyncSubject, _super); + function AsyncSubject() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.value = null; + _this.hasNext = false; + _this.hasCompleted = false; + return _this; + } + AsyncSubject.prototype._subscribe = function (subscriber) { + if (this.hasError) { + subscriber.error(this.thrownError); + return Subscription.EMPTY; + } + else if (this.hasCompleted && this.hasNext) { + subscriber.next(this.value); + subscriber.complete(); + return Subscription.EMPTY; + } + return _super.prototype._subscribe.call(this, subscriber); + }; + AsyncSubject.prototype.next = function (value) { + if (!this.hasCompleted) { + this.value = value; + this.hasNext = true; + } + }; + AsyncSubject.prototype.error = function (error) { + if (!this.hasCompleted) { + _super.prototype.error.call(this, error); + } + }; + AsyncSubject.prototype.complete = function () { + this.hasCompleted = true; + if (this.hasNext) { + _super.prototype.next.call(this, this.value); + } + _super.prototype.complete.call(this); + }; + return AsyncSubject; + }(Subject)); + + var nextHandle = 1; + var RESOLVED = (function () { return Promise.resolve(); })(); + var activeHandles = {}; + function findAndClearHandle(handle) { + if (handle in activeHandles) { + delete activeHandles[handle]; + return true; + } + return false; + } + var Immediate = { + setImmediate: function (cb) { + var handle = nextHandle++; + activeHandles[handle] = true; + RESOLVED.then(function () { return findAndClearHandle(handle) && cb(); }); + return handle; + }, + clearImmediate: function (handle) { + findAndClearHandle(handle); + }, + }; + + var AsapAction = (function (_super) { + __extends(AsapAction, _super); + function AsapAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + return _this; + } + AsapAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if (delay !== null && delay > 0) { + return _super.prototype.requestAsyncId.call(this, scheduler, id, delay); + } + scheduler.actions.push(this); + return scheduler.scheduled || (scheduler.scheduled = Immediate.setImmediate(scheduler.flush.bind(scheduler, null))); + }; + AsapAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) { + return _super.prototype.recycleAsyncId.call(this, scheduler, id, delay); + } + if (scheduler.actions.length === 0) { + Immediate.clearImmediate(id); + scheduler.scheduled = undefined; + } + return undefined; + }; + return AsapAction; + }(AsyncAction)); + + var AsapScheduler = (function (_super) { + __extends(AsapScheduler, _super); + function AsapScheduler() { + return _super !== null && _super.apply(this, arguments) || this; + } + AsapScheduler.prototype.flush = function (action) { + this.active = true; + this.scheduled = undefined; + var actions = this.actions; + var error; + var index = -1; + var count = actions.length; + action = action || actions.shift(); + do { + if (error = action.execute(action.state, action.delay)) { + break; + } + } while (++index < count && (action = actions.shift())); + this.active = false; + if (error) { + while (++index < count && (action = actions.shift())) { + action.unsubscribe(); + } + throw error; + } + }; + return AsapScheduler; + }(AsyncScheduler)); + + var asapScheduler = new AsapScheduler(AsapAction); + var asap = asapScheduler; + + var asyncScheduler = new AsyncScheduler(AsyncAction); + var async = asyncScheduler; + + var AnimationFrameAction = (function (_super) { + __extends(AnimationFrameAction, _super); + function AnimationFrameAction(scheduler, work) { + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + return _this; + } + AnimationFrameAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if (delay !== null && delay > 0) { + return _super.prototype.requestAsyncId.call(this, scheduler, id, delay); + } + scheduler.actions.push(this); + return scheduler.scheduled || (scheduler.scheduled = requestAnimationFrame(function () { return scheduler.flush(null); })); + }; + AnimationFrameAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) { + return _super.prototype.recycleAsyncId.call(this, scheduler, id, delay); + } + if (scheduler.actions.length === 0) { + cancelAnimationFrame(id); + scheduler.scheduled = undefined; + } + return undefined; + }; + return AnimationFrameAction; + }(AsyncAction)); + + var AnimationFrameScheduler = (function (_super) { + __extends(AnimationFrameScheduler, _super); + function AnimationFrameScheduler() { + return _super !== null && _super.apply(this, arguments) || this; + } + AnimationFrameScheduler.prototype.flush = function (action) { + this.active = true; + this.scheduled = undefined; + var actions = this.actions; + var error; + var index = -1; + var count = actions.length; + action = action || actions.shift(); + do { + if (error = action.execute(action.state, action.delay)) { + break; + } + } while (++index < count && (action = actions.shift())); + this.active = false; + if (error) { + while (++index < count && (action = actions.shift())) { + action.unsubscribe(); + } + throw error; + } + }; + return AnimationFrameScheduler; + }(AsyncScheduler)); + + var animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction); + var animationFrame = animationFrameScheduler; + + var VirtualTimeScheduler = (function (_super) { + __extends(VirtualTimeScheduler, _super); + function VirtualTimeScheduler(SchedulerAction, maxFrames) { + if (SchedulerAction === void 0) { SchedulerAction = VirtualAction; } + if (maxFrames === void 0) { maxFrames = Number.POSITIVE_INFINITY; } + var _this = _super.call(this, SchedulerAction, function () { return _this.frame; }) || this; + _this.maxFrames = maxFrames; + _this.frame = 0; + _this.index = -1; + return _this; + } + VirtualTimeScheduler.prototype.flush = function () { + var _a = this, actions = _a.actions, maxFrames = _a.maxFrames; + var error, action; + while ((action = actions[0]) && action.delay <= maxFrames) { + actions.shift(); + this.frame = action.delay; + if (error = action.execute(action.state, action.delay)) { + break; + } + } + if (error) { + while (action = actions.shift()) { + action.unsubscribe(); + } + throw error; + } + }; + VirtualTimeScheduler.frameTimeFactor = 10; + return VirtualTimeScheduler; + }(AsyncScheduler)); + var VirtualAction = (function (_super) { + __extends(VirtualAction, _super); + function VirtualAction(scheduler, work, index) { + if (index === void 0) { index = scheduler.index += 1; } + var _this = _super.call(this, scheduler, work) || this; + _this.scheduler = scheduler; + _this.work = work; + _this.index = index; + _this.active = true; + _this.index = scheduler.index = index; + return _this; + } + VirtualAction.prototype.schedule = function (state, delay) { + if (delay === void 0) { delay = 0; } + if (!this.id) { + return _super.prototype.schedule.call(this, state, delay); + } + this.active = false; + var action = new VirtualAction(this.scheduler, this.work); + this.add(action); + return action.schedule(state, delay); + }; + VirtualAction.prototype.requestAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + this.delay = scheduler.frame + delay; + var actions = scheduler.actions; + actions.push(this); + actions.sort(VirtualAction.sortActions); + return true; + }; + VirtualAction.prototype.recycleAsyncId = function (scheduler, id, delay) { + if (delay === void 0) { delay = 0; } + return undefined; + }; + VirtualAction.prototype._execute = function (state, delay) { + if (this.active === true) { + return _super.prototype._execute.call(this, state, delay); + } + }; + VirtualAction.sortActions = function (a, b) { + if (a.delay === b.delay) { + if (a.index === b.index) { + return 0; + } + else if (a.index > b.index) { + return 1; + } + else { + return -1; + } + } + else if (a.delay > b.delay) { + return 1; + } + else { + return -1; + } + }; + return VirtualAction; + }(AsyncAction)); + + function noop() { } + + function isObservable(obj) { + return !!obj && (obj instanceof Observable || (typeof obj.lift === 'function' && typeof obj.subscribe === 'function')); + } + + var ArgumentOutOfRangeErrorImpl = (function () { + function ArgumentOutOfRangeErrorImpl() { + Error.call(this); + this.message = 'argument out of range'; + this.name = 'ArgumentOutOfRangeError'; + return this; + } + ArgumentOutOfRangeErrorImpl.prototype = Object.create(Error.prototype); + return ArgumentOutOfRangeErrorImpl; + })(); + var ArgumentOutOfRangeError = ArgumentOutOfRangeErrorImpl; + + var EmptyErrorImpl = (function () { + function EmptyErrorImpl() { + Error.call(this); + this.message = 'no elements in sequence'; + this.name = 'EmptyError'; + return this; + } + EmptyErrorImpl.prototype = Object.create(Error.prototype); + return EmptyErrorImpl; + })(); + var EmptyError = EmptyErrorImpl; + + var TimeoutErrorImpl = (function () { + function TimeoutErrorImpl() { + Error.call(this); + this.message = 'Timeout has occurred'; + this.name = 'TimeoutError'; + return this; + } + TimeoutErrorImpl.prototype = Object.create(Error.prototype); + return TimeoutErrorImpl; + })(); + var TimeoutError = TimeoutErrorImpl; + + function map(project, thisArg) { + return function mapOperation(source) { + if (typeof project !== 'function') { + throw new TypeError('argument is not a function. Are you looking for `mapTo()`?'); + } + return source.lift(new MapOperator(project, thisArg)); + }; + } + var MapOperator = (function () { + function MapOperator(project, thisArg) { + this.project = project; + this.thisArg = thisArg; + } + MapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg)); + }; + return MapOperator; + }()); + var MapSubscriber = (function (_super) { + __extends(MapSubscriber, _super); + function MapSubscriber(destination, project, thisArg) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.count = 0; + _this.thisArg = thisArg || _this; + return _this; + } + MapSubscriber.prototype._next = function (value) { + var result; + try { + result = this.project.call(this.thisArg, value, this.count++); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return MapSubscriber; + }(Subscriber)); + + function bindCallback(callbackFunc, resultSelector, scheduler) { + if (resultSelector) { + if (isScheduler(resultSelector)) { + scheduler = resultSelector; + } + else { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return bindCallback(callbackFunc, scheduler).apply(void 0, args).pipe(map(function (args) { return isArray(args) ? resultSelector.apply(void 0, args) : resultSelector(args); })); + }; + } + } + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var context = this; + var subject; + var params = { + context: context, + subject: subject, + callbackFunc: callbackFunc, + scheduler: scheduler, + }; + return new Observable(function (subscriber) { + if (!scheduler) { + if (!subject) { + subject = new AsyncSubject(); + var handler = function () { + var innerArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + innerArgs[_i] = arguments[_i]; + } + subject.next(innerArgs.length <= 1 ? innerArgs[0] : innerArgs); + subject.complete(); + }; + try { + callbackFunc.apply(context, args.concat([handler])); + } + catch (err) { + if (canReportError(subject)) { + subject.error(err); + } + else { + console.warn(err); + } + } + } + return subject.subscribe(subscriber); + } + else { + var state = { + args: args, subscriber: subscriber, params: params, + }; + return scheduler.schedule(dispatch$1, 0, state); + } + }); + }; + } + function dispatch$1(state) { + var _this = this; + var args = state.args, subscriber = state.subscriber, params = state.params; + var callbackFunc = params.callbackFunc, context = params.context, scheduler = params.scheduler; + var subject = params.subject; + if (!subject) { + subject = params.subject = new AsyncSubject(); + var handler = function () { + var innerArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + innerArgs[_i] = arguments[_i]; + } + var value = innerArgs.length <= 1 ? innerArgs[0] : innerArgs; + _this.add(scheduler.schedule(dispatchNext, 0, { value: value, subject: subject })); + }; + try { + callbackFunc.apply(context, args.concat([handler])); + } + catch (err) { + subject.error(err); + } + } + this.add(subject.subscribe(subscriber)); + } + function dispatchNext(state) { + var value = state.value, subject = state.subject; + subject.next(value); + subject.complete(); + } + + function bindNodeCallback(callbackFunc, resultSelector, scheduler) { + if (resultSelector) { + if (isScheduler(resultSelector)) { + scheduler = resultSelector; + } + else { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return bindNodeCallback(callbackFunc, scheduler).apply(void 0, args).pipe(map(function (args) { return isArray(args) ? resultSelector.apply(void 0, args) : resultSelector(args); })); + }; + } + } + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var params = { + subject: undefined, + args: args, + callbackFunc: callbackFunc, + scheduler: scheduler, + context: this, + }; + return new Observable(function (subscriber) { + var context = params.context; + var subject = params.subject; + if (!scheduler) { + if (!subject) { + subject = params.subject = new AsyncSubject(); + var handler = function () { + var innerArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + innerArgs[_i] = arguments[_i]; + } + var err = innerArgs.shift(); + if (err) { + subject.error(err); + return; + } + subject.next(innerArgs.length <= 1 ? innerArgs[0] : innerArgs); + subject.complete(); + }; + try { + callbackFunc.apply(context, args.concat([handler])); + } + catch (err) { + if (canReportError(subject)) { + subject.error(err); + } + else { + console.warn(err); + } + } + } + return subject.subscribe(subscriber); + } + else { + return scheduler.schedule(dispatch$2, 0, { params: params, subscriber: subscriber, context: context }); + } + }); + }; + } + function dispatch$2(state) { + var _this = this; + var params = state.params, subscriber = state.subscriber, context = state.context; + var callbackFunc = params.callbackFunc, args = params.args, scheduler = params.scheduler; + var subject = params.subject; + if (!subject) { + subject = params.subject = new AsyncSubject(); + var handler = function () { + var innerArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + innerArgs[_i] = arguments[_i]; + } + var err = innerArgs.shift(); + if (err) { + _this.add(scheduler.schedule(dispatchError$1, 0, { err: err, subject: subject })); + } + else { + var value = innerArgs.length <= 1 ? innerArgs[0] : innerArgs; + _this.add(scheduler.schedule(dispatchNext$1, 0, { value: value, subject: subject })); + } + }; + try { + callbackFunc.apply(context, args.concat([handler])); + } + catch (err) { + this.add(scheduler.schedule(dispatchError$1, 0, { err: err, subject: subject })); + } + } + this.add(subject.subscribe(subscriber)); + } + function dispatchNext$1(arg) { + var value = arg.value, subject = arg.subject; + subject.next(value); + subject.complete(); + } + function dispatchError$1(arg) { + var err = arg.err, subject = arg.subject; + subject.error(err); + } + + var OuterSubscriber = (function (_super) { + __extends(OuterSubscriber, _super); + function OuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + OuterSubscriber.prototype.notifyError = function (error, innerSub) { + this.destination.error(error); + }; + OuterSubscriber.prototype.notifyComplete = function (innerSub) { + this.destination.complete(); + }; + return OuterSubscriber; + }(Subscriber)); + + var InnerSubscriber = (function (_super) { + __extends(InnerSubscriber, _super); + function InnerSubscriber(parent, outerValue, outerIndex) { + var _this = _super.call(this) || this; + _this.parent = parent; + _this.outerValue = outerValue; + _this.outerIndex = outerIndex; + _this.index = 0; + return _this; + } + InnerSubscriber.prototype._next = function (value) { + this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this); + }; + InnerSubscriber.prototype._error = function (error) { + this.parent.notifyError(error, this); + this.unsubscribe(); + }; + InnerSubscriber.prototype._complete = function () { + this.parent.notifyComplete(this); + this.unsubscribe(); + }; + return InnerSubscriber; + }(Subscriber)); + + var subscribeToPromise = function (promise) { return function (subscriber) { + promise.then(function (value) { + if (!subscriber.closed) { + subscriber.next(value); + subscriber.complete(); + } + }, function (err) { return subscriber.error(err); }) + .then(null, hostReportError); + return subscriber; + }; }; + + function getSymbolIterator() { + if (typeof Symbol !== 'function' || !Symbol.iterator) { + return '@@iterator'; + } + return Symbol.iterator; + } + var iterator = getSymbolIterator(); + + var subscribeToIterable = function (iterable) { return function (subscriber) { + var iterator$$1 = iterable[iterator](); + do { + var item = void 0; + try { + item = iterator$$1.next(); + } + catch (err) { + subscriber.error(err); + return subscriber; + } + if (item.done) { + subscriber.complete(); + break; + } + subscriber.next(item.value); + if (subscriber.closed) { + break; + } + } while (true); + if (typeof iterator$$1.return === 'function') { + subscriber.add(function () { + if (iterator$$1.return) { + iterator$$1.return(); + } + }); + } + return subscriber; + }; }; + + var subscribeToObservable = function (obj) { return function (subscriber) { + var obs = obj[observable](); + if (typeof obs.subscribe !== 'function') { + throw new TypeError('Provided object does not correctly implement Symbol.observable'); + } + else { + return obs.subscribe(subscriber); + } + }; }; + + var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; }); + + function isPromise(value) { + return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function'; + } + + var subscribeTo = function (result) { + if (!!result && typeof result[observable] === 'function') { + return subscribeToObservable(result); + } + else if (isArrayLike(result)) { + return subscribeToArray(result); + } + else if (isPromise(result)) { + return subscribeToPromise(result); + } + else if (!!result && typeof result[iterator] === 'function') { + return subscribeToIterable(result); + } + else { + var value = isObject(result) ? 'an invalid object' : "'" + result + "'"; + var msg = "You provided " + value + " where a stream was expected." + + ' You can provide an Observable, Promise, Array, or Iterable.'; + throw new TypeError(msg); + } + }; + + function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, innerSubscriber) { + if (innerSubscriber === void 0) { innerSubscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex); } + if (innerSubscriber.closed) { + return undefined; + } + if (result instanceof Observable) { + return result.subscribe(innerSubscriber); + } + return subscribeTo(result)(innerSubscriber); + } + + var NONE = {}; + function combineLatest() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var resultSelector = undefined; + var scheduler = undefined; + if (isScheduler(observables[observables.length - 1])) { + scheduler = observables.pop(); + } + if (typeof observables[observables.length - 1] === 'function') { + resultSelector = observables.pop(); + } + if (observables.length === 1 && isArray(observables[0])) { + observables = observables[0]; + } + return fromArray(observables, scheduler).lift(new CombineLatestOperator(resultSelector)); + } + var CombineLatestOperator = (function () { + function CombineLatestOperator(resultSelector) { + this.resultSelector = resultSelector; + } + CombineLatestOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CombineLatestSubscriber(subscriber, this.resultSelector)); + }; + return CombineLatestOperator; + }()); + var CombineLatestSubscriber = (function (_super) { + __extends(CombineLatestSubscriber, _super); + function CombineLatestSubscriber(destination, resultSelector) { + var _this = _super.call(this, destination) || this; + _this.resultSelector = resultSelector; + _this.active = 0; + _this.values = []; + _this.observables = []; + return _this; + } + CombineLatestSubscriber.prototype._next = function (observable) { + this.values.push(NONE); + this.observables.push(observable); + }; + CombineLatestSubscriber.prototype._complete = function () { + var observables = this.observables; + var len = observables.length; + if (len === 0) { + this.destination.complete(); + } + else { + this.active = len; + this.toRespond = len; + for (var i = 0; i < len; i++) { + var observable = observables[i]; + this.add(subscribeToResult(this, observable, undefined, i)); + } + } + }; + CombineLatestSubscriber.prototype.notifyComplete = function (unused) { + if ((this.active -= 1) === 0) { + this.destination.complete(); + } + }; + CombineLatestSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + var values = this.values; + var oldVal = values[outerIndex]; + var toRespond = !this.toRespond + ? 0 + : oldVal === NONE ? --this.toRespond : this.toRespond; + values[outerIndex] = innerValue; + if (toRespond === 0) { + if (this.resultSelector) { + this._tryResultSelector(values); + } + else { + this.destination.next(values.slice()); + } + } + }; + CombineLatestSubscriber.prototype._tryResultSelector = function (values) { + var result; + try { + result = this.resultSelector.apply(this, values); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return CombineLatestSubscriber; + }(OuterSubscriber)); + + function scheduleObservable(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + sub.add(scheduler.schedule(function () { + var observable$$1 = input[observable](); + sub.add(observable$$1.subscribe({ + next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); }, + error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); }, + complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); }, + })); + })); + return sub; + }); + } + + function schedulePromise(input, scheduler) { + return new Observable(function (subscriber) { + var sub = new Subscription(); + sub.add(scheduler.schedule(function () { return input.then(function (value) { + sub.add(scheduler.schedule(function () { + subscriber.next(value); + sub.add(scheduler.schedule(function () { return subscriber.complete(); })); + })); + }, function (err) { + sub.add(scheduler.schedule(function () { return subscriber.error(err); })); + }); })); + return sub; + }); + } + + function scheduleIterable(input, scheduler) { + if (!input) { + throw new Error('Iterable cannot be null'); + } + return new Observable(function (subscriber) { + var sub = new Subscription(); + var iterator$$1; + sub.add(function () { + if (iterator$$1 && typeof iterator$$1.return === 'function') { + iterator$$1.return(); + } + }); + sub.add(scheduler.schedule(function () { + iterator$$1 = input[iterator](); + sub.add(scheduler.schedule(function () { + if (subscriber.closed) { + return; + } + var value; + var done; + try { + var result = iterator$$1.next(); + value = result.value; + done = result.done; + } + catch (err) { + subscriber.error(err); + return; + } + if (done) { + subscriber.complete(); + } + else { + subscriber.next(value); + this.schedule(); + } + })); + })); + return sub; + }); + } + + function isInteropObservable(input) { + return input && typeof input[observable] === 'function'; + } + + function isIterable(input) { + return input && typeof input[iterator] === 'function'; + } + + function scheduled(input, scheduler) { + if (input != null) { + if (isInteropObservable(input)) { + return scheduleObservable(input, scheduler); + } + else if (isPromise(input)) { + return schedulePromise(input, scheduler); + } + else if (isArrayLike(input)) { + return scheduleArray(input, scheduler); + } + else if (isIterable(input) || typeof input === 'string') { + return scheduleIterable(input, scheduler); + } + } + throw new TypeError((input !== null && typeof input || input) + ' is not observable'); + } + + function from(input, scheduler) { + if (!scheduler) { + if (input instanceof Observable) { + return input; + } + return new Observable(subscribeTo(input)); + } + else { + return scheduled(input, scheduler); + } + } + + var SimpleInnerSubscriber = (function (_super) { + __extends(SimpleInnerSubscriber, _super); + function SimpleInnerSubscriber(parent) { + var _this = _super.call(this) || this; + _this.parent = parent; + return _this; + } + SimpleInnerSubscriber.prototype._next = function (value) { + this.parent.notifyNext(value); + }; + SimpleInnerSubscriber.prototype._error = function (error) { + this.parent.notifyError(error); + this.unsubscribe(); + }; + SimpleInnerSubscriber.prototype._complete = function () { + this.parent.notifyComplete(); + this.unsubscribe(); + }; + return SimpleInnerSubscriber; + }(Subscriber)); + var ComplexInnerSubscriber = (function (_super) { + __extends(ComplexInnerSubscriber, _super); + function ComplexInnerSubscriber(parent, outerValue, outerIndex) { + var _this = _super.call(this) || this; + _this.parent = parent; + _this.outerValue = outerValue; + _this.outerIndex = outerIndex; + return _this; + } + ComplexInnerSubscriber.prototype._next = function (value) { + this.parent.notifyNext(this.outerValue, value, this.outerIndex, this); + }; + ComplexInnerSubscriber.prototype._error = function (error) { + this.parent.notifyError(error); + this.unsubscribe(); + }; + ComplexInnerSubscriber.prototype._complete = function () { + this.parent.notifyComplete(this); + this.unsubscribe(); + }; + return ComplexInnerSubscriber; + }(Subscriber)); + var SimpleOuterSubscriber = (function (_super) { + __extends(SimpleOuterSubscriber, _super); + function SimpleOuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + SimpleOuterSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + SimpleOuterSubscriber.prototype.notifyError = function (err) { + this.destination.error(err); + }; + SimpleOuterSubscriber.prototype.notifyComplete = function () { + this.destination.complete(); + }; + return SimpleOuterSubscriber; + }(Subscriber)); + var ComplexOuterSubscriber = (function (_super) { + __extends(ComplexOuterSubscriber, _super); + function ComplexOuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + ComplexOuterSubscriber.prototype.notifyNext = function (_outerValue, innerValue, _outerIndex, _innerSub) { + this.destination.next(innerValue); + }; + ComplexOuterSubscriber.prototype.notifyError = function (error) { + this.destination.error(error); + }; + ComplexOuterSubscriber.prototype.notifyComplete = function (_innerSub) { + this.destination.complete(); + }; + return ComplexOuterSubscriber; + }(Subscriber)); + function innerSubscribe(result, innerSubscriber) { + if (innerSubscriber.closed) { + return undefined; + } + if (result instanceof Observable) { + return result.subscribe(innerSubscriber); + } + return subscribeTo(result)(innerSubscriber); + } + + function mergeMap(project, resultSelector, concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + if (typeof resultSelector === 'function') { + return function (source) { return source.pipe(mergeMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); }, concurrent)); }; + } + else if (typeof resultSelector === 'number') { + concurrent = resultSelector; + } + return function (source) { return source.lift(new MergeMapOperator(project, concurrent)); }; + } + var MergeMapOperator = (function () { + function MergeMapOperator(project, concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + this.project = project; + this.concurrent = concurrent; + } + MergeMapOperator.prototype.call = function (observer, source) { + return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent)); + }; + return MergeMapOperator; + }()); + var MergeMapSubscriber = (function (_super) { + __extends(MergeMapSubscriber, _super); + function MergeMapSubscriber(destination, project, concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.concurrent = concurrent; + _this.hasCompleted = false; + _this.buffer = []; + _this.active = 0; + _this.index = 0; + return _this; + } + MergeMapSubscriber.prototype._next = function (value) { + if (this.active < this.concurrent) { + this._tryNext(value); + } + else { + this.buffer.push(value); + } + }; + MergeMapSubscriber.prototype._tryNext = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (err) { + this.destination.error(err); + return; + } + this.active++; + this._innerSub(result); + }; + MergeMapSubscriber.prototype._innerSub = function (ish) { + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = innerSubscribe(ish, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } + }; + MergeMapSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.active === 0 && this.buffer.length === 0) { + this.destination.complete(); + } + this.unsubscribe(); + }; + MergeMapSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + MergeMapSubscriber.prototype.notifyComplete = function () { + var buffer = this.buffer; + this.active--; + if (buffer.length > 0) { + this._next(buffer.shift()); + } + else if (this.active === 0 && this.hasCompleted) { + this.destination.complete(); + } + }; + return MergeMapSubscriber; + }(SimpleOuterSubscriber)); + var flatMap = mergeMap; + + function mergeAll(concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + return mergeMap(identity, concurrent); + } + + function concatAll() { + return mergeAll(1); + } + + function concat() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return concatAll()(of.apply(void 0, observables)); + } + + function defer(observableFactory) { + return new Observable(function (subscriber) { + var input; + try { + input = observableFactory(); + } + catch (err) { + subscriber.error(err); + return undefined; + } + var source = input ? from(input) : empty$1(); + return source.subscribe(subscriber); + }); + } + + function forkJoin() { + var sources = []; + for (var _i = 0; _i < arguments.length; _i++) { + sources[_i] = arguments[_i]; + } + if (sources.length === 1) { + var first_1 = sources[0]; + if (isArray(first_1)) { + return forkJoinInternal(first_1, null); + } + if (isObject(first_1) && Object.getPrototypeOf(first_1) === Object.prototype) { + var keys = Object.keys(first_1); + return forkJoinInternal(keys.map(function (key) { return first_1[key]; }), keys); + } + } + if (typeof sources[sources.length - 1] === 'function') { + var resultSelector_1 = sources.pop(); + sources = (sources.length === 1 && isArray(sources[0])) ? sources[0] : sources; + return forkJoinInternal(sources, null).pipe(map(function (args) { return resultSelector_1.apply(void 0, args); })); + } + return forkJoinInternal(sources, null); + } + function forkJoinInternal(sources, keys) { + return new Observable(function (subscriber) { + var len = sources.length; + if (len === 0) { + subscriber.complete(); + return; + } + var values = new Array(len); + var completed = 0; + var emitted = 0; + var _loop_1 = function (i) { + var source = from(sources[i]); + var hasValue = false; + subscriber.add(source.subscribe({ + next: function (value) { + if (!hasValue) { + hasValue = true; + emitted++; + } + values[i] = value; + }, + error: function (err) { return subscriber.error(err); }, + complete: function () { + completed++; + if (completed === len || !hasValue) { + if (emitted === len) { + subscriber.next(keys ? + keys.reduce(function (result, key, i) { return (result[key] = values[i], result); }, {}) : + values); + } + subscriber.complete(); + } + } + })); + }; + for (var i = 0; i < len; i++) { + _loop_1(i); + } + }); + } + + function fromEvent(target, eventName, options, resultSelector) { + if (isFunction(options)) { + resultSelector = options; + options = undefined; + } + if (resultSelector) { + return fromEvent(target, eventName, options).pipe(map(function (args) { return isArray(args) ? resultSelector.apply(void 0, args) : resultSelector(args); })); + } + return new Observable(function (subscriber) { + function handler(e) { + if (arguments.length > 1) { + subscriber.next(Array.prototype.slice.call(arguments)); + } + else { + subscriber.next(e); + } + } + setupSubscription(target, eventName, handler, subscriber, options); + }); + } + function setupSubscription(sourceObj, eventName, handler, subscriber, options) { + var unsubscribe; + if (isEventTarget(sourceObj)) { + var source_1 = sourceObj; + sourceObj.addEventListener(eventName, handler, options); + unsubscribe = function () { return source_1.removeEventListener(eventName, handler, options); }; + } + else if (isJQueryStyleEventEmitter(sourceObj)) { + var source_2 = sourceObj; + sourceObj.on(eventName, handler); + unsubscribe = function () { return source_2.off(eventName, handler); }; + } + else if (isNodeStyleEventEmitter(sourceObj)) { + var source_3 = sourceObj; + sourceObj.addListener(eventName, handler); + unsubscribe = function () { return source_3.removeListener(eventName, handler); }; + } + else if (sourceObj && sourceObj.length) { + for (var i = 0, len = sourceObj.length; i < len; i++) { + setupSubscription(sourceObj[i], eventName, handler, subscriber, options); + } + } + else { + throw new TypeError('Invalid event target'); + } + subscriber.add(unsubscribe); + } + function isNodeStyleEventEmitter(sourceObj) { + return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function'; + } + function isJQueryStyleEventEmitter(sourceObj) { + return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function'; + } + function isEventTarget(sourceObj) { + return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function'; + } + + function fromEventPattern(addHandler, removeHandler, resultSelector) { + if (resultSelector) { + return fromEventPattern(addHandler, removeHandler).pipe(map(function (args) { return isArray(args) ? resultSelector.apply(void 0, args) : resultSelector(args); })); + } + return new Observable(function (subscriber) { + var handler = function () { + var e = []; + for (var _i = 0; _i < arguments.length; _i++) { + e[_i] = arguments[_i]; + } + return subscriber.next(e.length === 1 ? e[0] : e); + }; + var retValue; + try { + retValue = addHandler(handler); + } + catch (err) { + subscriber.error(err); + return undefined; + } + if (!isFunction(removeHandler)) { + return undefined; + } + return function () { return removeHandler(handler, retValue); }; + }); + } + + function generate(initialStateOrOptions, condition, iterate, resultSelectorOrObservable, scheduler) { + var resultSelector; + var initialState; + if (arguments.length == 1) { + var options = initialStateOrOptions; + initialState = options.initialState; + condition = options.condition; + iterate = options.iterate; + resultSelector = options.resultSelector || identity; + scheduler = options.scheduler; + } + else if (resultSelectorOrObservable === undefined || isScheduler(resultSelectorOrObservable)) { + initialState = initialStateOrOptions; + resultSelector = identity; + scheduler = resultSelectorOrObservable; + } + else { + initialState = initialStateOrOptions; + resultSelector = resultSelectorOrObservable; + } + return new Observable(function (subscriber) { + var state = initialState; + if (scheduler) { + return scheduler.schedule(dispatch$3, 0, { + subscriber: subscriber, + iterate: iterate, + condition: condition, + resultSelector: resultSelector, + state: state + }); + } + do { + if (condition) { + var conditionResult = void 0; + try { + conditionResult = condition(state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + if (!conditionResult) { + subscriber.complete(); + break; + } + } + var value = void 0; + try { + value = resultSelector(state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + subscriber.next(value); + if (subscriber.closed) { + break; + } + try { + state = iterate(state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + } while (true); + return undefined; + }); + } + function dispatch$3(state) { + var subscriber = state.subscriber, condition = state.condition; + if (subscriber.closed) { + return undefined; + } + if (state.needIterate) { + try { + state.state = state.iterate(state.state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + } + else { + state.needIterate = true; + } + if (condition) { + var conditionResult = void 0; + try { + conditionResult = condition(state.state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + if (!conditionResult) { + subscriber.complete(); + return undefined; + } + if (subscriber.closed) { + return undefined; + } + } + var value; + try { + value = state.resultSelector(state.state); + } + catch (err) { + subscriber.error(err); + return undefined; + } + if (subscriber.closed) { + return undefined; + } + subscriber.next(value); + if (subscriber.closed) { + return undefined; + } + return this.schedule(state); + } + + function iif(condition, trueResult, falseResult) { + if (trueResult === void 0) { trueResult = EMPTY; } + if (falseResult === void 0) { falseResult = EMPTY; } + return defer(function () { return condition() ? trueResult : falseResult; }); + } + + function isNumeric(val) { + return !isArray(val) && (val - parseFloat(val) + 1) >= 0; + } + + function interval(period, scheduler) { + if (period === void 0) { period = 0; } + if (scheduler === void 0) { scheduler = async; } + if (!isNumeric(period) || period < 0) { + period = 0; + } + if (!scheduler || typeof scheduler.schedule !== 'function') { + scheduler = async; + } + return new Observable(function (subscriber) { + subscriber.add(scheduler.schedule(dispatch$4, period, { subscriber: subscriber, counter: 0, period: period })); + return subscriber; + }); + } + function dispatch$4(state) { + var subscriber = state.subscriber, counter = state.counter, period = state.period; + subscriber.next(counter); + this.schedule({ subscriber: subscriber, counter: counter + 1, period: period }, period); + } + + function merge() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var concurrent = Number.POSITIVE_INFINITY; + var scheduler = null; + var last = observables[observables.length - 1]; + if (isScheduler(last)) { + scheduler = observables.pop(); + if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') { + concurrent = observables.pop(); + } + } + else if (typeof last === 'number') { + concurrent = observables.pop(); + } + if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) { + return observables[0]; + } + return mergeAll(concurrent)(fromArray(observables, scheduler)); + } + + var NEVER = new Observable(noop); + function never() { + return NEVER; + } + + function onErrorResumeNext() { + var sources = []; + for (var _i = 0; _i < arguments.length; _i++) { + sources[_i] = arguments[_i]; + } + if (sources.length === 0) { + return EMPTY; + } + var first = sources[0], remainder = sources.slice(1); + if (sources.length === 1 && isArray(first)) { + return onErrorResumeNext.apply(void 0, first); + } + return new Observable(function (subscriber) { + var subNext = function () { return subscriber.add(onErrorResumeNext.apply(void 0, remainder).subscribe(subscriber)); }; + return from(first).subscribe({ + next: function (value) { subscriber.next(value); }, + error: subNext, + complete: subNext, + }); + }); + } + + function pairs(obj, scheduler) { + if (!scheduler) { + return new Observable(function (subscriber) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length && !subscriber.closed; i++) { + var key = keys[i]; + if (obj.hasOwnProperty(key)) { + subscriber.next([key, obj[key]]); + } + } + subscriber.complete(); + }); + } + else { + return new Observable(function (subscriber) { + var keys = Object.keys(obj); + var subscription = new Subscription(); + subscription.add(scheduler.schedule(dispatch$5, 0, { keys: keys, index: 0, subscriber: subscriber, subscription: subscription, obj: obj })); + return subscription; + }); + } + } + function dispatch$5(state) { + var keys = state.keys, index = state.index, subscriber = state.subscriber, subscription = state.subscription, obj = state.obj; + if (!subscriber.closed) { + if (index < keys.length) { + var key = keys[index]; + subscriber.next([key, obj[key]]); + subscription.add(this.schedule({ keys: keys, index: index + 1, subscriber: subscriber, subscription: subscription, obj: obj })); + } + else { + subscriber.complete(); + } + } + } + + function not(pred, thisArg) { + function notPred() { + return !(notPred.pred.apply(notPred.thisArg, arguments)); + } + notPred.pred = pred; + notPred.thisArg = thisArg; + return notPred; + } + + function filter(predicate, thisArg) { + return function filterOperatorFunction(source) { + return source.lift(new FilterOperator(predicate, thisArg)); + }; + } + var FilterOperator = (function () { + function FilterOperator(predicate, thisArg) { + this.predicate = predicate; + this.thisArg = thisArg; + } + FilterOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new FilterSubscriber(subscriber, this.predicate, this.thisArg)); + }; + return FilterOperator; + }()); + var FilterSubscriber = (function (_super) { + __extends(FilterSubscriber, _super); + function FilterSubscriber(destination, predicate, thisArg) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.thisArg = thisArg; + _this.count = 0; + return _this; + } + FilterSubscriber.prototype._next = function (value) { + var result; + try { + result = this.predicate.call(this.thisArg, value, this.count++); + } + catch (err) { + this.destination.error(err); + return; + } + if (result) { + this.destination.next(value); + } + }; + return FilterSubscriber; + }(Subscriber)); + + function partition(source, predicate, thisArg) { + return [ + filter(predicate, thisArg)(new Observable(subscribeTo(source))), + filter(not(predicate, thisArg))(new Observable(subscribeTo(source))) + ]; + } + + function race() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + if (observables.length === 1) { + if (isArray(observables[0])) { + observables = observables[0]; + } + else { + return observables[0]; + } + } + return fromArray(observables, undefined).lift(new RaceOperator()); + } + var RaceOperator = (function () { + function RaceOperator() { + } + RaceOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RaceSubscriber(subscriber)); + }; + return RaceOperator; + }()); + var RaceSubscriber = (function (_super) { + __extends(RaceSubscriber, _super); + function RaceSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasFirst = false; + _this.observables = []; + _this.subscriptions = []; + return _this; + } + RaceSubscriber.prototype._next = function (observable) { + this.observables.push(observable); + }; + RaceSubscriber.prototype._complete = function () { + var observables = this.observables; + var len = observables.length; + if (len === 0) { + this.destination.complete(); + } + else { + for (var i = 0; i < len && !this.hasFirst; i++) { + var observable = observables[i]; + var subscription = subscribeToResult(this, observable, undefined, i); + if (this.subscriptions) { + this.subscriptions.push(subscription); + } + this.add(subscription); + } + this.observables = null; + } + }; + RaceSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + if (!this.hasFirst) { + this.hasFirst = true; + for (var i = 0; i < this.subscriptions.length; i++) { + if (i !== outerIndex) { + var subscription = this.subscriptions[i]; + subscription.unsubscribe(); + this.remove(subscription); + } + } + this.subscriptions = null; + } + this.destination.next(innerValue); + }; + return RaceSubscriber; + }(OuterSubscriber)); + + function range(start, count, scheduler) { + if (start === void 0) { start = 0; } + return new Observable(function (subscriber) { + if (count === undefined) { + count = start; + start = 0; + } + var index = 0; + var current = start; + if (scheduler) { + return scheduler.schedule(dispatch$6, 0, { + index: index, count: count, start: start, subscriber: subscriber + }); + } + else { + do { + if (index++ >= count) { + subscriber.complete(); + break; + } + subscriber.next(current++); + if (subscriber.closed) { + break; + } + } while (true); + } + return undefined; + }); + } + function dispatch$6(state) { + var start = state.start, index = state.index, count = state.count, subscriber = state.subscriber; + if (index >= count) { + subscriber.complete(); + return; + } + subscriber.next(start); + if (subscriber.closed) { + return; + } + state.index = index + 1; + state.start = start + 1; + this.schedule(state); + } + + function timer(dueTime, periodOrScheduler, scheduler) { + if (dueTime === void 0) { dueTime = 0; } + var period = -1; + if (isNumeric(periodOrScheduler)) { + period = Number(periodOrScheduler) < 1 && 1 || Number(periodOrScheduler); + } + else if (isScheduler(periodOrScheduler)) { + scheduler = periodOrScheduler; + } + if (!isScheduler(scheduler)) { + scheduler = async; + } + return new Observable(function (subscriber) { + var due = isNumeric(dueTime) + ? dueTime + : (+dueTime - scheduler.now()); + return scheduler.schedule(dispatch$7, due, { + index: 0, period: period, subscriber: subscriber + }); + }); + } + function dispatch$7(state) { + var index = state.index, period = state.period, subscriber = state.subscriber; + subscriber.next(index); + if (subscriber.closed) { + return; + } + else if (period === -1) { + return subscriber.complete(); + } + state.index = index + 1; + this.schedule(state, period); + } + + function using(resourceFactory, observableFactory) { + return new Observable(function (subscriber) { + var resource; + try { + resource = resourceFactory(); + } + catch (err) { + subscriber.error(err); + return undefined; + } + var result; + try { + result = observableFactory(resource); + } + catch (err) { + subscriber.error(err); + return undefined; + } + var source = result ? from(result) : EMPTY; + var subscription = source.subscribe(subscriber); + return function () { + subscription.unsubscribe(); + if (resource) { + resource.unsubscribe(); + } + }; + }); + } + + function zip() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var resultSelector = observables[observables.length - 1]; + if (typeof resultSelector === 'function') { + observables.pop(); + } + return fromArray(observables, undefined).lift(new ZipOperator(resultSelector)); + } + var ZipOperator = (function () { + function ZipOperator(resultSelector) { + this.resultSelector = resultSelector; + } + ZipOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ZipSubscriber(subscriber, this.resultSelector)); + }; + return ZipOperator; + }()); + var ZipSubscriber = (function (_super) { + __extends(ZipSubscriber, _super); + function ZipSubscriber(destination, resultSelector, values) { + if (values === void 0) { values = Object.create(null); } + var _this = _super.call(this, destination) || this; + _this.resultSelector = resultSelector; + _this.iterators = []; + _this.active = 0; + _this.resultSelector = (typeof resultSelector === 'function') ? resultSelector : undefined; + return _this; + } + ZipSubscriber.prototype._next = function (value) { + var iterators = this.iterators; + if (isArray(value)) { + iterators.push(new StaticArrayIterator(value)); + } + else if (typeof value[iterator] === 'function') { + iterators.push(new StaticIterator(value[iterator]())); + } + else { + iterators.push(new ZipBufferIterator(this.destination, this, value)); + } + }; + ZipSubscriber.prototype._complete = function () { + var iterators = this.iterators; + var len = iterators.length; + this.unsubscribe(); + if (len === 0) { + this.destination.complete(); + return; + } + this.active = len; + for (var i = 0; i < len; i++) { + var iterator$$1 = iterators[i]; + if (iterator$$1.stillUnsubscribed) { + var destination = this.destination; + destination.add(iterator$$1.subscribe()); + } + else { + this.active--; + } + } + }; + ZipSubscriber.prototype.notifyInactive = function () { + this.active--; + if (this.active === 0) { + this.destination.complete(); + } + }; + ZipSubscriber.prototype.checkIterators = function () { + var iterators = this.iterators; + var len = iterators.length; + var destination = this.destination; + for (var i = 0; i < len; i++) { + var iterator$$1 = iterators[i]; + if (typeof iterator$$1.hasValue === 'function' && !iterator$$1.hasValue()) { + return; + } + } + var shouldComplete = false; + var args = []; + for (var i = 0; i < len; i++) { + var iterator$$1 = iterators[i]; + var result = iterator$$1.next(); + if (iterator$$1.hasCompleted()) { + shouldComplete = true; + } + if (result.done) { + destination.complete(); + return; + } + args.push(result.value); + } + if (this.resultSelector) { + this._tryresultSelector(args); + } + else { + destination.next(args); + } + if (shouldComplete) { + destination.complete(); + } + }; + ZipSubscriber.prototype._tryresultSelector = function (args) { + var result; + try { + result = this.resultSelector.apply(this, args); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return ZipSubscriber; + }(Subscriber)); + var StaticIterator = (function () { + function StaticIterator(iterator$$1) { + this.iterator = iterator$$1; + this.nextResult = iterator$$1.next(); + } + StaticIterator.prototype.hasValue = function () { + return true; + }; + StaticIterator.prototype.next = function () { + var result = this.nextResult; + this.nextResult = this.iterator.next(); + return result; + }; + StaticIterator.prototype.hasCompleted = function () { + var nextResult = this.nextResult; + return Boolean(nextResult && nextResult.done); + }; + return StaticIterator; + }()); + var StaticArrayIterator = (function () { + function StaticArrayIterator(array) { + this.array = array; + this.index = 0; + this.length = 0; + this.length = array.length; + } + StaticArrayIterator.prototype[iterator] = function () { + return this; + }; + StaticArrayIterator.prototype.next = function (value) { + var i = this.index++; + var array = this.array; + return i < this.length ? { value: array[i], done: false } : { value: null, done: true }; + }; + StaticArrayIterator.prototype.hasValue = function () { + return this.array.length > this.index; + }; + StaticArrayIterator.prototype.hasCompleted = function () { + return this.array.length === this.index; + }; + return StaticArrayIterator; + }()); + var ZipBufferIterator = (function (_super) { + __extends(ZipBufferIterator, _super); + function ZipBufferIterator(destination, parent, observable) { + var _this = _super.call(this, destination) || this; + _this.parent = parent; + _this.observable = observable; + _this.stillUnsubscribed = true; + _this.buffer = []; + _this.isComplete = false; + return _this; + } + ZipBufferIterator.prototype[iterator] = function () { + return this; + }; + ZipBufferIterator.prototype.next = function () { + var buffer = this.buffer; + if (buffer.length === 0 && this.isComplete) { + return { value: null, done: true }; + } + else { + return { value: buffer.shift(), done: false }; + } + }; + ZipBufferIterator.prototype.hasValue = function () { + return this.buffer.length > 0; + }; + ZipBufferIterator.prototype.hasCompleted = function () { + return this.buffer.length === 0 && this.isComplete; + }; + ZipBufferIterator.prototype.notifyComplete = function () { + if (this.buffer.length > 0) { + this.isComplete = true; + this.parent.notifyInactive(); + } + else { + this.destination.complete(); + } + }; + ZipBufferIterator.prototype.notifyNext = function (innerValue) { + this.buffer.push(innerValue); + this.parent.checkIterators(); + }; + ZipBufferIterator.prototype.subscribe = function () { + return innerSubscribe(this.observable, new SimpleInnerSubscriber(this)); + }; + return ZipBufferIterator; + }(SimpleOuterSubscriber)); + + function audit(durationSelector) { + return function auditOperatorFunction(source) { + return source.lift(new AuditOperator(durationSelector)); + }; + } + var AuditOperator = (function () { + function AuditOperator(durationSelector) { + this.durationSelector = durationSelector; + } + AuditOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new AuditSubscriber(subscriber, this.durationSelector)); + }; + return AuditOperator; + }()); + var AuditSubscriber = (function (_super) { + __extends(AuditSubscriber, _super); + function AuditSubscriber(destination, durationSelector) { + var _this = _super.call(this, destination) || this; + _this.durationSelector = durationSelector; + _this.hasValue = false; + return _this; + } + AuditSubscriber.prototype._next = function (value) { + this.value = value; + this.hasValue = true; + if (!this.throttled) { + var duration = void 0; + try { + var durationSelector = this.durationSelector; + duration = durationSelector(value); + } + catch (err) { + return this.destination.error(err); + } + var innerSubscription = innerSubscribe(duration, new SimpleInnerSubscriber(this)); + if (!innerSubscription || innerSubscription.closed) { + this.clearThrottle(); + } + else { + this.add(this.throttled = innerSubscription); + } + } + }; + AuditSubscriber.prototype.clearThrottle = function () { + var _a = this, value = _a.value, hasValue = _a.hasValue, throttled = _a.throttled; + if (throttled) { + this.remove(throttled); + this.throttled = undefined; + throttled.unsubscribe(); + } + if (hasValue) { + this.value = undefined; + this.hasValue = false; + this.destination.next(value); + } + }; + AuditSubscriber.prototype.notifyNext = function () { + this.clearThrottle(); + }; + AuditSubscriber.prototype.notifyComplete = function () { + this.clearThrottle(); + }; + return AuditSubscriber; + }(SimpleOuterSubscriber)); + + function auditTime(duration, scheduler) { + if (scheduler === void 0) { scheduler = async; } + return audit(function () { return timer(duration, scheduler); }); + } + + function buffer(closingNotifier) { + return function bufferOperatorFunction(source) { + return source.lift(new BufferOperator(closingNotifier)); + }; + } + var BufferOperator = (function () { + function BufferOperator(closingNotifier) { + this.closingNotifier = closingNotifier; + } + BufferOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferSubscriber(subscriber, this.closingNotifier)); + }; + return BufferOperator; + }()); + var BufferSubscriber = (function (_super) { + __extends(BufferSubscriber, _super); + function BufferSubscriber(destination, closingNotifier) { + var _this = _super.call(this, destination) || this; + _this.buffer = []; + _this.add(innerSubscribe(closingNotifier, new SimpleInnerSubscriber(_this))); + return _this; + } + BufferSubscriber.prototype._next = function (value) { + this.buffer.push(value); + }; + BufferSubscriber.prototype.notifyNext = function () { + var buffer = this.buffer; + this.buffer = []; + this.destination.next(buffer); + }; + return BufferSubscriber; + }(SimpleOuterSubscriber)); + + function bufferCount(bufferSize, startBufferEvery) { + if (startBufferEvery === void 0) { startBufferEvery = null; } + return function bufferCountOperatorFunction(source) { + return source.lift(new BufferCountOperator(bufferSize, startBufferEvery)); + }; + } + var BufferCountOperator = (function () { + function BufferCountOperator(bufferSize, startBufferEvery) { + this.bufferSize = bufferSize; + this.startBufferEvery = startBufferEvery; + if (!startBufferEvery || bufferSize === startBufferEvery) { + this.subscriberClass = BufferCountSubscriber; + } + else { + this.subscriberClass = BufferSkipCountSubscriber; + } + } + BufferCountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new this.subscriberClass(subscriber, this.bufferSize, this.startBufferEvery)); + }; + return BufferCountOperator; + }()); + var BufferCountSubscriber = (function (_super) { + __extends(BufferCountSubscriber, _super); + function BufferCountSubscriber(destination, bufferSize) { + var _this = _super.call(this, destination) || this; + _this.bufferSize = bufferSize; + _this.buffer = []; + return _this; + } + BufferCountSubscriber.prototype._next = function (value) { + var buffer = this.buffer; + buffer.push(value); + if (buffer.length == this.bufferSize) { + this.destination.next(buffer); + this.buffer = []; + } + }; + BufferCountSubscriber.prototype._complete = function () { + var buffer = this.buffer; + if (buffer.length > 0) { + this.destination.next(buffer); + } + _super.prototype._complete.call(this); + }; + return BufferCountSubscriber; + }(Subscriber)); + var BufferSkipCountSubscriber = (function (_super) { + __extends(BufferSkipCountSubscriber, _super); + function BufferSkipCountSubscriber(destination, bufferSize, startBufferEvery) { + var _this = _super.call(this, destination) || this; + _this.bufferSize = bufferSize; + _this.startBufferEvery = startBufferEvery; + _this.buffers = []; + _this.count = 0; + return _this; + } + BufferSkipCountSubscriber.prototype._next = function (value) { + var _a = this, bufferSize = _a.bufferSize, startBufferEvery = _a.startBufferEvery, buffers = _a.buffers, count = _a.count; + this.count++; + if (count % startBufferEvery === 0) { + buffers.push([]); + } + for (var i = buffers.length; i--;) { + var buffer = buffers[i]; + buffer.push(value); + if (buffer.length === bufferSize) { + buffers.splice(i, 1); + this.destination.next(buffer); + } + } + }; + BufferSkipCountSubscriber.prototype._complete = function () { + var _a = this, buffers = _a.buffers, destination = _a.destination; + while (buffers.length > 0) { + var buffer = buffers.shift(); + if (buffer.length > 0) { + destination.next(buffer); + } + } + _super.prototype._complete.call(this); + }; + return BufferSkipCountSubscriber; + }(Subscriber)); + + function bufferTime(bufferTimeSpan) { + var length = arguments.length; + var scheduler = async; + if (isScheduler(arguments[arguments.length - 1])) { + scheduler = arguments[arguments.length - 1]; + length--; + } + var bufferCreationInterval = null; + if (length >= 2) { + bufferCreationInterval = arguments[1]; + } + var maxBufferSize = Number.POSITIVE_INFINITY; + if (length >= 3) { + maxBufferSize = arguments[2]; + } + return function bufferTimeOperatorFunction(source) { + return source.lift(new BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler)); + }; + } + var BufferTimeOperator = (function () { + function BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { + this.bufferTimeSpan = bufferTimeSpan; + this.bufferCreationInterval = bufferCreationInterval; + this.maxBufferSize = maxBufferSize; + this.scheduler = scheduler; + } + BufferTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferTimeSubscriber(subscriber, this.bufferTimeSpan, this.bufferCreationInterval, this.maxBufferSize, this.scheduler)); + }; + return BufferTimeOperator; + }()); + var Context = (function () { + function Context() { + this.buffer = []; + } + return Context; + }()); + var BufferTimeSubscriber = (function (_super) { + __extends(BufferTimeSubscriber, _super); + function BufferTimeSubscriber(destination, bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { + var _this = _super.call(this, destination) || this; + _this.bufferTimeSpan = bufferTimeSpan; + _this.bufferCreationInterval = bufferCreationInterval; + _this.maxBufferSize = maxBufferSize; + _this.scheduler = scheduler; + _this.contexts = []; + var context = _this.openContext(); + _this.timespanOnly = bufferCreationInterval == null || bufferCreationInterval < 0; + if (_this.timespanOnly) { + var timeSpanOnlyState = { subscriber: _this, context: context, bufferTimeSpan: bufferTimeSpan }; + _this.add(context.closeAction = scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); + } + else { + var closeState = { subscriber: _this, context: context }; + var creationState = { bufferTimeSpan: bufferTimeSpan, bufferCreationInterval: bufferCreationInterval, subscriber: _this, scheduler: scheduler }; + _this.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, closeState)); + _this.add(scheduler.schedule(dispatchBufferCreation, bufferCreationInterval, creationState)); + } + return _this; + } + BufferTimeSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + var len = contexts.length; + var filledBufferContext; + for (var i = 0; i < len; i++) { + var context_1 = contexts[i]; + var buffer = context_1.buffer; + buffer.push(value); + if (buffer.length == this.maxBufferSize) { + filledBufferContext = context_1; + } + } + if (filledBufferContext) { + this.onBufferFull(filledBufferContext); + } + }; + BufferTimeSubscriber.prototype._error = function (err) { + this.contexts.length = 0; + _super.prototype._error.call(this, err); + }; + BufferTimeSubscriber.prototype._complete = function () { + var _a = this, contexts = _a.contexts, destination = _a.destination; + while (contexts.length > 0) { + var context_2 = contexts.shift(); + destination.next(context_2.buffer); + } + _super.prototype._complete.call(this); + }; + BufferTimeSubscriber.prototype._unsubscribe = function () { + this.contexts = null; + }; + BufferTimeSubscriber.prototype.onBufferFull = function (context) { + this.closeContext(context); + var closeAction = context.closeAction; + closeAction.unsubscribe(); + this.remove(closeAction); + if (!this.closed && this.timespanOnly) { + context = this.openContext(); + var bufferTimeSpan = this.bufferTimeSpan; + var timeSpanOnlyState = { subscriber: this, context: context, bufferTimeSpan: bufferTimeSpan }; + this.add(context.closeAction = this.scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); + } + }; + BufferTimeSubscriber.prototype.openContext = function () { + var context = new Context(); + this.contexts.push(context); + return context; + }; + BufferTimeSubscriber.prototype.closeContext = function (context) { + this.destination.next(context.buffer); + var contexts = this.contexts; + var spliceIndex = contexts ? contexts.indexOf(context) : -1; + if (spliceIndex >= 0) { + contexts.splice(contexts.indexOf(context), 1); + } + }; + return BufferTimeSubscriber; + }(Subscriber)); + function dispatchBufferTimeSpanOnly(state) { + var subscriber = state.subscriber; + var prevContext = state.context; + if (prevContext) { + subscriber.closeContext(prevContext); + } + if (!subscriber.closed) { + state.context = subscriber.openContext(); + state.context.closeAction = this.schedule(state, state.bufferTimeSpan); + } + } + function dispatchBufferCreation(state) { + var bufferCreationInterval = state.bufferCreationInterval, bufferTimeSpan = state.bufferTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler; + var context = subscriber.openContext(); + var action = this; + if (!subscriber.closed) { + subscriber.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, { subscriber: subscriber, context: context })); + action.schedule(state, bufferCreationInterval); + } + } + function dispatchBufferClose(arg) { + var subscriber = arg.subscriber, context = arg.context; + subscriber.closeContext(context); + } + + function bufferToggle(openings, closingSelector) { + return function bufferToggleOperatorFunction(source) { + return source.lift(new BufferToggleOperator(openings, closingSelector)); + }; + } + var BufferToggleOperator = (function () { + function BufferToggleOperator(openings, closingSelector) { + this.openings = openings; + this.closingSelector = closingSelector; + } + BufferToggleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferToggleSubscriber(subscriber, this.openings, this.closingSelector)); + }; + return BufferToggleOperator; + }()); + var BufferToggleSubscriber = (function (_super) { + __extends(BufferToggleSubscriber, _super); + function BufferToggleSubscriber(destination, openings, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.closingSelector = closingSelector; + _this.contexts = []; + _this.add(subscribeToResult(_this, openings)); + return _this; + } + BufferToggleSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + var len = contexts.length; + for (var i = 0; i < len; i++) { + contexts[i].buffer.push(value); + } + }; + BufferToggleSubscriber.prototype._error = function (err) { + var contexts = this.contexts; + while (contexts.length > 0) { + var context_1 = contexts.shift(); + context_1.subscription.unsubscribe(); + context_1.buffer = null; + context_1.subscription = null; + } + this.contexts = null; + _super.prototype._error.call(this, err); + }; + BufferToggleSubscriber.prototype._complete = function () { + var contexts = this.contexts; + while (contexts.length > 0) { + var context_2 = contexts.shift(); + this.destination.next(context_2.buffer); + context_2.subscription.unsubscribe(); + context_2.buffer = null; + context_2.subscription = null; + } + this.contexts = null; + _super.prototype._complete.call(this); + }; + BufferToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue) { + outerValue ? this.closeBuffer(outerValue) : this.openBuffer(innerValue); + }; + BufferToggleSubscriber.prototype.notifyComplete = function (innerSub) { + this.closeBuffer(innerSub.context); + }; + BufferToggleSubscriber.prototype.openBuffer = function (value) { + try { + var closingSelector = this.closingSelector; + var closingNotifier = closingSelector.call(this, value); + if (closingNotifier) { + this.trySubscribe(closingNotifier); + } + } + catch (err) { + this._error(err); + } + }; + BufferToggleSubscriber.prototype.closeBuffer = function (context) { + var contexts = this.contexts; + if (contexts && context) { + var buffer = context.buffer, subscription = context.subscription; + this.destination.next(buffer); + contexts.splice(contexts.indexOf(context), 1); + this.remove(subscription); + subscription.unsubscribe(); + } + }; + BufferToggleSubscriber.prototype.trySubscribe = function (closingNotifier) { + var contexts = this.contexts; + var buffer = []; + var subscription = new Subscription(); + var context = { buffer: buffer, subscription: subscription }; + contexts.push(context); + var innerSubscription = subscribeToResult(this, closingNotifier, context); + if (!innerSubscription || innerSubscription.closed) { + this.closeBuffer(context); + } + else { + innerSubscription.context = context; + this.add(innerSubscription); + subscription.add(innerSubscription); + } + }; + return BufferToggleSubscriber; + }(OuterSubscriber)); + + function bufferWhen(closingSelector) { + return function (source) { + return source.lift(new BufferWhenOperator(closingSelector)); + }; + } + var BufferWhenOperator = (function () { + function BufferWhenOperator(closingSelector) { + this.closingSelector = closingSelector; + } + BufferWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferWhenSubscriber(subscriber, this.closingSelector)); + }; + return BufferWhenOperator; + }()); + var BufferWhenSubscriber = (function (_super) { + __extends(BufferWhenSubscriber, _super); + function BufferWhenSubscriber(destination, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.closingSelector = closingSelector; + _this.subscribing = false; + _this.openBuffer(); + return _this; + } + BufferWhenSubscriber.prototype._next = function (value) { + this.buffer.push(value); + }; + BufferWhenSubscriber.prototype._complete = function () { + var buffer = this.buffer; + if (buffer) { + this.destination.next(buffer); + } + _super.prototype._complete.call(this); + }; + BufferWhenSubscriber.prototype._unsubscribe = function () { + this.buffer = undefined; + this.subscribing = false; + }; + BufferWhenSubscriber.prototype.notifyNext = function () { + this.openBuffer(); + }; + BufferWhenSubscriber.prototype.notifyComplete = function () { + if (this.subscribing) { + this.complete(); + } + else { + this.openBuffer(); + } + }; + BufferWhenSubscriber.prototype.openBuffer = function () { + var closingSubscription = this.closingSubscription; + if (closingSubscription) { + this.remove(closingSubscription); + closingSubscription.unsubscribe(); + } + var buffer = this.buffer; + if (this.buffer) { + this.destination.next(buffer); + } + this.buffer = []; + var closingNotifier; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(); + } + catch (err) { + return this.error(err); + } + closingSubscription = new Subscription(); + this.closingSubscription = closingSubscription; + this.add(closingSubscription); + this.subscribing = true; + closingSubscription.add(innerSubscribe(closingNotifier, new SimpleInnerSubscriber(this))); + this.subscribing = false; + }; + return BufferWhenSubscriber; + }(SimpleOuterSubscriber)); + + function catchError(selector) { + return function catchErrorOperatorFunction(source) { + var operator = new CatchOperator(selector); + var caught = source.lift(operator); + return (operator.caught = caught); + }; + } + var CatchOperator = (function () { + function CatchOperator(selector) { + this.selector = selector; + } + CatchOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CatchSubscriber(subscriber, this.selector, this.caught)); + }; + return CatchOperator; + }()); + var CatchSubscriber = (function (_super) { + __extends(CatchSubscriber, _super); + function CatchSubscriber(destination, selector, caught) { + var _this = _super.call(this, destination) || this; + _this.selector = selector; + _this.caught = caught; + return _this; + } + CatchSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var result = void 0; + try { + result = this.selector(err, this.caught); + } + catch (err2) { + _super.prototype.error.call(this, err2); + return; + } + this._unsubscribeAndRecycle(); + var innerSubscriber = new SimpleInnerSubscriber(this); + this.add(innerSubscriber); + var innerSubscription = innerSubscribe(result, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + this.add(innerSubscription); + } + } + }; + return CatchSubscriber; + }(SimpleOuterSubscriber)); + + function combineAll(project) { + return function (source) { return source.lift(new CombineLatestOperator(project)); }; + } + + function combineLatest$1() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + var project = null; + if (typeof observables[observables.length - 1] === 'function') { + project = observables.pop(); + } + if (observables.length === 1 && isArray(observables[0])) { + observables = observables[0].slice(); + } + return function (source) { return source.lift.call(from([source].concat(observables)), new CombineLatestOperator(project)); }; + } + + function concat$1() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return function (source) { return source.lift.call(concat.apply(void 0, [source].concat(observables))); }; + } + + function concatMap(project, resultSelector) { + return mergeMap(project, resultSelector, 1); + } + + function concatMapTo(innerObservable, resultSelector) { + return concatMap(function () { return innerObservable; }, resultSelector); + } + + function count(predicate) { + return function (source) { return source.lift(new CountOperator(predicate, source)); }; + } + var CountOperator = (function () { + function CountOperator(predicate, source) { + this.predicate = predicate; + this.source = source; + } + CountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CountSubscriber(subscriber, this.predicate, this.source)); + }; + return CountOperator; + }()); + var CountSubscriber = (function (_super) { + __extends(CountSubscriber, _super); + function CountSubscriber(destination, predicate, source) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.source = source; + _this.count = 0; + _this.index = 0; + return _this; + } + CountSubscriber.prototype._next = function (value) { + if (this.predicate) { + this._tryPredicate(value); + } + else { + this.count++; + } + }; + CountSubscriber.prototype._tryPredicate = function (value) { + var result; + try { + result = this.predicate(value, this.index++, this.source); + } + catch (err) { + this.destination.error(err); + return; + } + if (result) { + this.count++; + } + }; + CountSubscriber.prototype._complete = function () { + this.destination.next(this.count); + this.destination.complete(); + }; + return CountSubscriber; + }(Subscriber)); + + function debounce(durationSelector) { + return function (source) { return source.lift(new DebounceOperator(durationSelector)); }; + } + var DebounceOperator = (function () { + function DebounceOperator(durationSelector) { + this.durationSelector = durationSelector; + } + DebounceOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DebounceSubscriber(subscriber, this.durationSelector)); + }; + return DebounceOperator; + }()); + var DebounceSubscriber = (function (_super) { + __extends(DebounceSubscriber, _super); + function DebounceSubscriber(destination, durationSelector) { + var _this = _super.call(this, destination) || this; + _this.durationSelector = durationSelector; + _this.hasValue = false; + return _this; + } + DebounceSubscriber.prototype._next = function (value) { + try { + var result = this.durationSelector.call(this, value); + if (result) { + this._tryNext(value, result); + } + } + catch (err) { + this.destination.error(err); + } + }; + DebounceSubscriber.prototype._complete = function () { + this.emitValue(); + this.destination.complete(); + }; + DebounceSubscriber.prototype._tryNext = function (value, duration) { + var subscription = this.durationSubscription; + this.value = value; + this.hasValue = true; + if (subscription) { + subscription.unsubscribe(); + this.remove(subscription); + } + subscription = innerSubscribe(duration, new SimpleInnerSubscriber(this)); + if (subscription && !subscription.closed) { + this.add(this.durationSubscription = subscription); + } + }; + DebounceSubscriber.prototype.notifyNext = function () { + this.emitValue(); + }; + DebounceSubscriber.prototype.notifyComplete = function () { + this.emitValue(); + }; + DebounceSubscriber.prototype.emitValue = function () { + if (this.hasValue) { + var value = this.value; + var subscription = this.durationSubscription; + if (subscription) { + this.durationSubscription = undefined; + subscription.unsubscribe(); + this.remove(subscription); + } + this.value = undefined; + this.hasValue = false; + _super.prototype._next.call(this, value); + } + }; + return DebounceSubscriber; + }(SimpleOuterSubscriber)); + + function debounceTime(dueTime, scheduler) { + if (scheduler === void 0) { scheduler = async; } + return function (source) { return source.lift(new DebounceTimeOperator(dueTime, scheduler)); }; + } + var DebounceTimeOperator = (function () { + function DebounceTimeOperator(dueTime, scheduler) { + this.dueTime = dueTime; + this.scheduler = scheduler; + } + DebounceTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler)); + }; + return DebounceTimeOperator; + }()); + var DebounceTimeSubscriber = (function (_super) { + __extends(DebounceTimeSubscriber, _super); + function DebounceTimeSubscriber(destination, dueTime, scheduler) { + var _this = _super.call(this, destination) || this; + _this.dueTime = dueTime; + _this.scheduler = scheduler; + _this.debouncedSubscription = null; + _this.lastValue = null; + _this.hasValue = false; + return _this; + } + DebounceTimeSubscriber.prototype._next = function (value) { + this.clearDebounce(); + this.lastValue = value; + this.hasValue = true; + this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext$2, this.dueTime, this)); + }; + DebounceTimeSubscriber.prototype._complete = function () { + this.debouncedNext(); + this.destination.complete(); + }; + DebounceTimeSubscriber.prototype.debouncedNext = function () { + this.clearDebounce(); + if (this.hasValue) { + var lastValue = this.lastValue; + this.lastValue = null; + this.hasValue = false; + this.destination.next(lastValue); + } + }; + DebounceTimeSubscriber.prototype.clearDebounce = function () { + var debouncedSubscription = this.debouncedSubscription; + if (debouncedSubscription !== null) { + this.remove(debouncedSubscription); + debouncedSubscription.unsubscribe(); + this.debouncedSubscription = null; + } + }; + return DebounceTimeSubscriber; + }(Subscriber)); + function dispatchNext$2(subscriber) { + subscriber.debouncedNext(); + } + + function defaultIfEmpty(defaultValue) { + if (defaultValue === void 0) { defaultValue = null; } + return function (source) { return source.lift(new DefaultIfEmptyOperator(defaultValue)); }; + } + var DefaultIfEmptyOperator = (function () { + function DefaultIfEmptyOperator(defaultValue) { + this.defaultValue = defaultValue; + } + DefaultIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue)); + }; + return DefaultIfEmptyOperator; + }()); + var DefaultIfEmptySubscriber = (function (_super) { + __extends(DefaultIfEmptySubscriber, _super); + function DefaultIfEmptySubscriber(destination, defaultValue) { + var _this = _super.call(this, destination) || this; + _this.defaultValue = defaultValue; + _this.isEmpty = true; + return _this; + } + DefaultIfEmptySubscriber.prototype._next = function (value) { + this.isEmpty = false; + this.destination.next(value); + }; + DefaultIfEmptySubscriber.prototype._complete = function () { + if (this.isEmpty) { + this.destination.next(this.defaultValue); + } + this.destination.complete(); + }; + return DefaultIfEmptySubscriber; + }(Subscriber)); + + function isDate(value) { + return value instanceof Date && !isNaN(+value); + } + + function delay(delay, scheduler) { + if (scheduler === void 0) { scheduler = async; } + var absoluteDelay = isDate(delay); + var delayFor = absoluteDelay ? (+delay - scheduler.now()) : Math.abs(delay); + return function (source) { return source.lift(new DelayOperator(delayFor, scheduler)); }; + } + var DelayOperator = (function () { + function DelayOperator(delay, scheduler) { + this.delay = delay; + this.scheduler = scheduler; + } + DelayOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DelaySubscriber(subscriber, this.delay, this.scheduler)); + }; + return DelayOperator; + }()); + var DelaySubscriber = (function (_super) { + __extends(DelaySubscriber, _super); + function DelaySubscriber(destination, delay, scheduler) { + var _this = _super.call(this, destination) || this; + _this.delay = delay; + _this.scheduler = scheduler; + _this.queue = []; + _this.active = false; + _this.errored = false; + return _this; + } + DelaySubscriber.dispatch = function (state) { + var source = state.source; + var queue = source.queue; + var scheduler = state.scheduler; + var destination = state.destination; + while (queue.length > 0 && (queue[0].time - scheduler.now()) <= 0) { + queue.shift().notification.observe(destination); + } + if (queue.length > 0) { + var delay_1 = Math.max(0, queue[0].time - scheduler.now()); + this.schedule(state, delay_1); + } + else { + this.unsubscribe(); + source.active = false; + } + }; + DelaySubscriber.prototype._schedule = function (scheduler) { + this.active = true; + var destination = this.destination; + destination.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, { + source: this, destination: this.destination, scheduler: scheduler + })); + }; + DelaySubscriber.prototype.scheduleNotification = function (notification) { + if (this.errored === true) { + return; + } + var scheduler = this.scheduler; + var message = new DelayMessage(scheduler.now() + this.delay, notification); + this.queue.push(message); + if (this.active === false) { + this._schedule(scheduler); + } + }; + DelaySubscriber.prototype._next = function (value) { + this.scheduleNotification(Notification.createNext(value)); + }; + DelaySubscriber.prototype._error = function (err) { + this.errored = true; + this.queue = []; + this.destination.error(err); + this.unsubscribe(); + }; + DelaySubscriber.prototype._complete = function () { + this.scheduleNotification(Notification.createComplete()); + this.unsubscribe(); + }; + return DelaySubscriber; + }(Subscriber)); + var DelayMessage = (function () { + function DelayMessage(time, notification) { + this.time = time; + this.notification = notification; + } + return DelayMessage; + }()); + + function delayWhen(delayDurationSelector, subscriptionDelay) { + if (subscriptionDelay) { + return function (source) { + return new SubscriptionDelayObservable(source, subscriptionDelay) + .lift(new DelayWhenOperator(delayDurationSelector)); + }; + } + return function (source) { return source.lift(new DelayWhenOperator(delayDurationSelector)); }; + } + var DelayWhenOperator = (function () { + function DelayWhenOperator(delayDurationSelector) { + this.delayDurationSelector = delayDurationSelector; + } + DelayWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DelayWhenSubscriber(subscriber, this.delayDurationSelector)); + }; + return DelayWhenOperator; + }()); + var DelayWhenSubscriber = (function (_super) { + __extends(DelayWhenSubscriber, _super); + function DelayWhenSubscriber(destination, delayDurationSelector) { + var _this = _super.call(this, destination) || this; + _this.delayDurationSelector = delayDurationSelector; + _this.completed = false; + _this.delayNotifierSubscriptions = []; + _this.index = 0; + return _this; + } + DelayWhenSubscriber.prototype.notifyNext = function (outerValue, _innerValue, _outerIndex, _innerIndex, innerSub) { + this.destination.next(outerValue); + this.removeSubscription(innerSub); + this.tryComplete(); + }; + DelayWhenSubscriber.prototype.notifyError = function (error, innerSub) { + this._error(error); + }; + DelayWhenSubscriber.prototype.notifyComplete = function (innerSub) { + var value = this.removeSubscription(innerSub); + if (value) { + this.destination.next(value); + } + this.tryComplete(); + }; + DelayWhenSubscriber.prototype._next = function (value) { + var index = this.index++; + try { + var delayNotifier = this.delayDurationSelector(value, index); + if (delayNotifier) { + this.tryDelay(delayNotifier, value); + } + } + catch (err) { + this.destination.error(err); + } + }; + DelayWhenSubscriber.prototype._complete = function () { + this.completed = true; + this.tryComplete(); + this.unsubscribe(); + }; + DelayWhenSubscriber.prototype.removeSubscription = function (subscription) { + subscription.unsubscribe(); + var subscriptionIdx = this.delayNotifierSubscriptions.indexOf(subscription); + if (subscriptionIdx !== -1) { + this.delayNotifierSubscriptions.splice(subscriptionIdx, 1); + } + return subscription.outerValue; + }; + DelayWhenSubscriber.prototype.tryDelay = function (delayNotifier, value) { + var notifierSubscription = subscribeToResult(this, delayNotifier, value); + if (notifierSubscription && !notifierSubscription.closed) { + var destination = this.destination; + destination.add(notifierSubscription); + this.delayNotifierSubscriptions.push(notifierSubscription); + } + }; + DelayWhenSubscriber.prototype.tryComplete = function () { + if (this.completed && this.delayNotifierSubscriptions.length === 0) { + this.destination.complete(); + } + }; + return DelayWhenSubscriber; + }(OuterSubscriber)); + var SubscriptionDelayObservable = (function (_super) { + __extends(SubscriptionDelayObservable, _super); + function SubscriptionDelayObservable(source, subscriptionDelay) { + var _this = _super.call(this) || this; + _this.source = source; + _this.subscriptionDelay = subscriptionDelay; + return _this; + } + SubscriptionDelayObservable.prototype._subscribe = function (subscriber) { + this.subscriptionDelay.subscribe(new SubscriptionDelaySubscriber(subscriber, this.source)); + }; + return SubscriptionDelayObservable; + }(Observable)); + var SubscriptionDelaySubscriber = (function (_super) { + __extends(SubscriptionDelaySubscriber, _super); + function SubscriptionDelaySubscriber(parent, source) { + var _this = _super.call(this) || this; + _this.parent = parent; + _this.source = source; + _this.sourceSubscribed = false; + return _this; + } + SubscriptionDelaySubscriber.prototype._next = function (unused) { + this.subscribeToSource(); + }; + SubscriptionDelaySubscriber.prototype._error = function (err) { + this.unsubscribe(); + this.parent.error(err); + }; + SubscriptionDelaySubscriber.prototype._complete = function () { + this.unsubscribe(); + this.subscribeToSource(); + }; + SubscriptionDelaySubscriber.prototype.subscribeToSource = function () { + if (!this.sourceSubscribed) { + this.sourceSubscribed = true; + this.unsubscribe(); + this.source.subscribe(this.parent); + } + }; + return SubscriptionDelaySubscriber; + }(Subscriber)); + + function dematerialize() { + return function dematerializeOperatorFunction(source) { + return source.lift(new DeMaterializeOperator()); + }; + } + var DeMaterializeOperator = (function () { + function DeMaterializeOperator() { + } + DeMaterializeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DeMaterializeSubscriber(subscriber)); + }; + return DeMaterializeOperator; + }()); + var DeMaterializeSubscriber = (function (_super) { + __extends(DeMaterializeSubscriber, _super); + function DeMaterializeSubscriber(destination) { + return _super.call(this, destination) || this; + } + DeMaterializeSubscriber.prototype._next = function (value) { + value.observe(this.destination); + }; + return DeMaterializeSubscriber; + }(Subscriber)); + + function distinct(keySelector, flushes) { + return function (source) { return source.lift(new DistinctOperator(keySelector, flushes)); }; + } + var DistinctOperator = (function () { + function DistinctOperator(keySelector, flushes) { + this.keySelector = keySelector; + this.flushes = flushes; + } + DistinctOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctSubscriber(subscriber, this.keySelector, this.flushes)); + }; + return DistinctOperator; + }()); + var DistinctSubscriber = (function (_super) { + __extends(DistinctSubscriber, _super); + function DistinctSubscriber(destination, keySelector, flushes) { + var _this = _super.call(this, destination) || this; + _this.keySelector = keySelector; + _this.values = new Set(); + if (flushes) { + _this.add(innerSubscribe(flushes, new SimpleInnerSubscriber(_this))); + } + return _this; + } + DistinctSubscriber.prototype.notifyNext = function () { + this.values.clear(); + }; + DistinctSubscriber.prototype.notifyError = function (error) { + this._error(error); + }; + DistinctSubscriber.prototype._next = function (value) { + if (this.keySelector) { + this._useKeySelector(value); + } + else { + this._finalizeNext(value, value); + } + }; + DistinctSubscriber.prototype._useKeySelector = function (value) { + var key; + var destination = this.destination; + try { + key = this.keySelector(value); + } + catch (err) { + destination.error(err); + return; + } + this._finalizeNext(key, value); + }; + DistinctSubscriber.prototype._finalizeNext = function (key, value) { + var values = this.values; + if (!values.has(key)) { + values.add(key); + this.destination.next(value); + } + }; + return DistinctSubscriber; + }(SimpleOuterSubscriber)); + + function distinctUntilChanged(compare, keySelector) { + return function (source) { return source.lift(new DistinctUntilChangedOperator(compare, keySelector)); }; + } + var DistinctUntilChangedOperator = (function () { + function DistinctUntilChangedOperator(compare, keySelector) { + this.compare = compare; + this.keySelector = keySelector; + } + DistinctUntilChangedOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector)); + }; + return DistinctUntilChangedOperator; + }()); + var DistinctUntilChangedSubscriber = (function (_super) { + __extends(DistinctUntilChangedSubscriber, _super); + function DistinctUntilChangedSubscriber(destination, compare, keySelector) { + var _this = _super.call(this, destination) || this; + _this.keySelector = keySelector; + _this.hasKey = false; + if (typeof compare === 'function') { + _this.compare = compare; + } + return _this; + } + DistinctUntilChangedSubscriber.prototype.compare = function (x, y) { + return x === y; + }; + DistinctUntilChangedSubscriber.prototype._next = function (value) { + var key; + try { + var keySelector = this.keySelector; + key = keySelector ? keySelector(value) : value; + } + catch (err) { + return this.destination.error(err); + } + var result = false; + if (this.hasKey) { + try { + var compare = this.compare; + result = compare(this.key, key); + } + catch (err) { + return this.destination.error(err); + } + } + else { + this.hasKey = true; + } + if (!result) { + this.key = key; + this.destination.next(value); + } + }; + return DistinctUntilChangedSubscriber; + }(Subscriber)); + + function distinctUntilKeyChanged(key, compare) { + return distinctUntilChanged(function (x, y) { return compare ? compare(x[key], y[key]) : x[key] === y[key]; }); + } + + function throwIfEmpty(errorFactory) { + if (errorFactory === void 0) { errorFactory = defaultErrorFactory; } + return function (source) { + return source.lift(new ThrowIfEmptyOperator(errorFactory)); + }; + } + var ThrowIfEmptyOperator = (function () { + function ThrowIfEmptyOperator(errorFactory) { + this.errorFactory = errorFactory; + } + ThrowIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrowIfEmptySubscriber(subscriber, this.errorFactory)); + }; + return ThrowIfEmptyOperator; + }()); + var ThrowIfEmptySubscriber = (function (_super) { + __extends(ThrowIfEmptySubscriber, _super); + function ThrowIfEmptySubscriber(destination, errorFactory) { + var _this = _super.call(this, destination) || this; + _this.errorFactory = errorFactory; + _this.hasValue = false; + return _this; + } + ThrowIfEmptySubscriber.prototype._next = function (value) { + this.hasValue = true; + this.destination.next(value); + }; + ThrowIfEmptySubscriber.prototype._complete = function () { + if (!this.hasValue) { + var err = void 0; + try { + err = this.errorFactory(); + } + catch (e) { + err = e; + } + this.destination.error(err); + } + else { + return this.destination.complete(); + } + }; + return ThrowIfEmptySubscriber; + }(Subscriber)); + function defaultErrorFactory() { + return new EmptyError(); + } + + function take(count) { + return function (source) { + if (count === 0) { + return empty$1(); + } + else { + return source.lift(new TakeOperator(count)); + } + }; + } + var TakeOperator = (function () { + function TakeOperator(total) { + this.total = total; + if (this.total < 0) { + throw new ArgumentOutOfRangeError; + } + } + TakeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeSubscriber(subscriber, this.total)); + }; + return TakeOperator; + }()); + var TakeSubscriber = (function (_super) { + __extends(TakeSubscriber, _super); + function TakeSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.count = 0; + return _this; + } + TakeSubscriber.prototype._next = function (value) { + var total = this.total; + var count = ++this.count; + if (count <= total) { + this.destination.next(value); + if (count === total) { + this.destination.complete(); + this.unsubscribe(); + } + } + }; + return TakeSubscriber; + }(Subscriber)); + + function elementAt(index, defaultValue) { + if (index < 0) { + throw new ArgumentOutOfRangeError(); + } + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(filter(function (v, i) { return i === index; }), take(1), hasDefaultValue + ? defaultIfEmpty(defaultValue) + : throwIfEmpty(function () { return new ArgumentOutOfRangeError(); })); }; + } + + function endWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + return function (source) { return concat(source, of.apply(void 0, array)); }; + } + + function every(predicate, thisArg) { + return function (source) { return source.lift(new EveryOperator(predicate, thisArg, source)); }; + } + var EveryOperator = (function () { + function EveryOperator(predicate, thisArg, source) { + this.predicate = predicate; + this.thisArg = thisArg; + this.source = source; + } + EveryOperator.prototype.call = function (observer, source) { + return source.subscribe(new EverySubscriber(observer, this.predicate, this.thisArg, this.source)); + }; + return EveryOperator; + }()); + var EverySubscriber = (function (_super) { + __extends(EverySubscriber, _super); + function EverySubscriber(destination, predicate, thisArg, source) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.thisArg = thisArg; + _this.source = source; + _this.index = 0; + _this.thisArg = thisArg || _this; + return _this; + } + EverySubscriber.prototype.notifyComplete = function (everyValueMatch) { + this.destination.next(everyValueMatch); + this.destination.complete(); + }; + EverySubscriber.prototype._next = function (value) { + var result = false; + try { + result = this.predicate.call(this.thisArg, value, this.index++, this.source); + } + catch (err) { + this.destination.error(err); + return; + } + if (!result) { + this.notifyComplete(false); + } + }; + EverySubscriber.prototype._complete = function () { + this.notifyComplete(true); + }; + return EverySubscriber; + }(Subscriber)); + + function exhaust() { + return function (source) { return source.lift(new SwitchFirstOperator()); }; + } + var SwitchFirstOperator = (function () { + function SwitchFirstOperator() { + } + SwitchFirstOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchFirstSubscriber(subscriber)); + }; + return SwitchFirstOperator; + }()); + var SwitchFirstSubscriber = (function (_super) { + __extends(SwitchFirstSubscriber, _super); + function SwitchFirstSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasCompleted = false; + _this.hasSubscription = false; + return _this; + } + SwitchFirstSubscriber.prototype._next = function (value) { + if (!this.hasSubscription) { + this.hasSubscription = true; + this.add(innerSubscribe(value, new SimpleInnerSubscriber(this))); + } + }; + SwitchFirstSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (!this.hasSubscription) { + this.destination.complete(); + } + }; + SwitchFirstSubscriber.prototype.notifyComplete = function () { + this.hasSubscription = false; + if (this.hasCompleted) { + this.destination.complete(); + } + }; + return SwitchFirstSubscriber; + }(SimpleOuterSubscriber)); + + function exhaustMap(project, resultSelector) { + if (resultSelector) { + return function (source) { return source.pipe(exhaustMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; + } + return function (source) { + return source.lift(new ExhaustMapOperator(project)); + }; + } + var ExhaustMapOperator = (function () { + function ExhaustMapOperator(project) { + this.project = project; + } + ExhaustMapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ExhaustMapSubscriber(subscriber, this.project)); + }; + return ExhaustMapOperator; + }()); + var ExhaustMapSubscriber = (function (_super) { + __extends(ExhaustMapSubscriber, _super); + function ExhaustMapSubscriber(destination, project) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.hasSubscription = false; + _this.hasCompleted = false; + _this.index = 0; + return _this; + } + ExhaustMapSubscriber.prototype._next = function (value) { + if (!this.hasSubscription) { + this.tryNext(value); + } + }; + ExhaustMapSubscriber.prototype.tryNext = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (err) { + this.destination.error(err); + return; + } + this.hasSubscription = true; + this._innerSub(result); + }; + ExhaustMapSubscriber.prototype._innerSub = function (result) { + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = innerSubscribe(result, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } + }; + ExhaustMapSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (!this.hasSubscription) { + this.destination.complete(); + } + this.unsubscribe(); + }; + ExhaustMapSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + ExhaustMapSubscriber.prototype.notifyError = function (err) { + this.destination.error(err); + }; + ExhaustMapSubscriber.prototype.notifyComplete = function () { + this.hasSubscription = false; + if (this.hasCompleted) { + this.destination.complete(); + } + }; + return ExhaustMapSubscriber; + }(SimpleOuterSubscriber)); + + function expand(project, concurrent, scheduler) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + concurrent = (concurrent || 0) < 1 ? Number.POSITIVE_INFINITY : concurrent; + return function (source) { return source.lift(new ExpandOperator(project, concurrent, scheduler)); }; + } + var ExpandOperator = (function () { + function ExpandOperator(project, concurrent, scheduler) { + this.project = project; + this.concurrent = concurrent; + this.scheduler = scheduler; + } + ExpandOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ExpandSubscriber(subscriber, this.project, this.concurrent, this.scheduler)); + }; + return ExpandOperator; + }()); + var ExpandSubscriber = (function (_super) { + __extends(ExpandSubscriber, _super); + function ExpandSubscriber(destination, project, concurrent, scheduler) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.concurrent = concurrent; + _this.scheduler = scheduler; + _this.index = 0; + _this.active = 0; + _this.hasCompleted = false; + if (concurrent < Number.POSITIVE_INFINITY) { + _this.buffer = []; + } + return _this; + } + ExpandSubscriber.dispatch = function (arg) { + var subscriber = arg.subscriber, result = arg.result, value = arg.value, index = arg.index; + subscriber.subscribeToProjection(result, value, index); + }; + ExpandSubscriber.prototype._next = function (value) { + var destination = this.destination; + if (destination.closed) { + this._complete(); + return; + } + var index = this.index++; + if (this.active < this.concurrent) { + destination.next(value); + try { + var project = this.project; + var result = project(value, index); + if (!this.scheduler) { + this.subscribeToProjection(result, value, index); + } + else { + var state = { subscriber: this, result: result, value: value, index: index }; + var destination_1 = this.destination; + destination_1.add(this.scheduler.schedule(ExpandSubscriber.dispatch, 0, state)); + } + } + catch (e) { + destination.error(e); + } + } + else { + this.buffer.push(value); + } + }; + ExpandSubscriber.prototype.subscribeToProjection = function (result, value, index) { + this.active++; + var destination = this.destination; + destination.add(innerSubscribe(result, new SimpleInnerSubscriber(this))); + }; + ExpandSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.hasCompleted && this.active === 0) { + this.destination.complete(); + } + this.unsubscribe(); + }; + ExpandSubscriber.prototype.notifyNext = function (innerValue) { + this._next(innerValue); + }; + ExpandSubscriber.prototype.notifyComplete = function () { + var buffer = this.buffer; + this.active--; + if (buffer && buffer.length > 0) { + this._next(buffer.shift()); + } + if (this.hasCompleted && this.active === 0) { + this.destination.complete(); + } + }; + return ExpandSubscriber; + }(SimpleOuterSubscriber)); + + function finalize(callback) { + return function (source) { return source.lift(new FinallyOperator(callback)); }; + } + var FinallyOperator = (function () { + function FinallyOperator(callback) { + this.callback = callback; + } + FinallyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new FinallySubscriber(subscriber, this.callback)); + }; + return FinallyOperator; + }()); + var FinallySubscriber = (function (_super) { + __extends(FinallySubscriber, _super); + function FinallySubscriber(destination, callback) { + var _this = _super.call(this, destination) || this; + _this.add(new Subscription(callback)); + return _this; + } + return FinallySubscriber; + }(Subscriber)); + + function find(predicate, thisArg) { + if (typeof predicate !== 'function') { + throw new TypeError('predicate is not a function'); + } + return function (source) { return source.lift(new FindValueOperator(predicate, source, false, thisArg)); }; + } + var FindValueOperator = (function () { + function FindValueOperator(predicate, source, yieldIndex, thisArg) { + this.predicate = predicate; + this.source = source; + this.yieldIndex = yieldIndex; + this.thisArg = thisArg; + } + FindValueOperator.prototype.call = function (observer, source) { + return source.subscribe(new FindValueSubscriber(observer, this.predicate, this.source, this.yieldIndex, this.thisArg)); + }; + return FindValueOperator; + }()); + var FindValueSubscriber = (function (_super) { + __extends(FindValueSubscriber, _super); + function FindValueSubscriber(destination, predicate, source, yieldIndex, thisArg) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.source = source; + _this.yieldIndex = yieldIndex; + _this.thisArg = thisArg; + _this.index = 0; + return _this; + } + FindValueSubscriber.prototype.notifyComplete = function (value) { + var destination = this.destination; + destination.next(value); + destination.complete(); + this.unsubscribe(); + }; + FindValueSubscriber.prototype._next = function (value) { + var _a = this, predicate = _a.predicate, thisArg = _a.thisArg; + var index = this.index++; + try { + var result = predicate.call(thisArg || this, value, index, this.source); + if (result) { + this.notifyComplete(this.yieldIndex ? index : value); + } + } + catch (err) { + this.destination.error(err); + } + }; + FindValueSubscriber.prototype._complete = function () { + this.notifyComplete(this.yieldIndex ? -1 : undefined); + }; + return FindValueSubscriber; + }(Subscriber)); + + function findIndex(predicate, thisArg) { + return function (source) { return source.lift(new FindValueOperator(predicate, source, true, thisArg)); }; + } + + function first(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, take(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); }; + } + + function ignoreElements() { + return function ignoreElementsOperatorFunction(source) { + return source.lift(new IgnoreElementsOperator()); + }; + } + var IgnoreElementsOperator = (function () { + function IgnoreElementsOperator() { + } + IgnoreElementsOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new IgnoreElementsSubscriber(subscriber)); + }; + return IgnoreElementsOperator; + }()); + var IgnoreElementsSubscriber = (function (_super) { + __extends(IgnoreElementsSubscriber, _super); + function IgnoreElementsSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + IgnoreElementsSubscriber.prototype._next = function (unused) { + }; + return IgnoreElementsSubscriber; + }(Subscriber)); + + function isEmpty() { + return function (source) { return source.lift(new IsEmptyOperator()); }; + } + var IsEmptyOperator = (function () { + function IsEmptyOperator() { + } + IsEmptyOperator.prototype.call = function (observer, source) { + return source.subscribe(new IsEmptySubscriber(observer)); + }; + return IsEmptyOperator; + }()); + var IsEmptySubscriber = (function (_super) { + __extends(IsEmptySubscriber, _super); + function IsEmptySubscriber(destination) { + return _super.call(this, destination) || this; + } + IsEmptySubscriber.prototype.notifyComplete = function (isEmpty) { + var destination = this.destination; + destination.next(isEmpty); + destination.complete(); + }; + IsEmptySubscriber.prototype._next = function (value) { + this.notifyComplete(false); + }; + IsEmptySubscriber.prototype._complete = function () { + this.notifyComplete(true); + }; + return IsEmptySubscriber; + }(Subscriber)); + + function takeLast(count) { + return function takeLastOperatorFunction(source) { + if (count === 0) { + return empty$1(); + } + else { + return source.lift(new TakeLastOperator(count)); + } + }; + } + var TakeLastOperator = (function () { + function TakeLastOperator(total) { + this.total = total; + if (this.total < 0) { + throw new ArgumentOutOfRangeError; + } + } + TakeLastOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeLastSubscriber(subscriber, this.total)); + }; + return TakeLastOperator; + }()); + var TakeLastSubscriber = (function (_super) { + __extends(TakeLastSubscriber, _super); + function TakeLastSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.ring = new Array(); + _this.count = 0; + return _this; + } + TakeLastSubscriber.prototype._next = function (value) { + var ring = this.ring; + var total = this.total; + var count = this.count++; + if (ring.length < total) { + ring.push(value); + } + else { + var index = count % total; + ring[index] = value; + } + }; + TakeLastSubscriber.prototype._complete = function () { + var destination = this.destination; + var count = this.count; + if (count > 0) { + var total = this.count >= this.total ? this.total : this.count; + var ring = this.ring; + for (var i = 0; i < total; i++) { + var idx = (count++) % total; + destination.next(ring[idx]); + } + } + destination.complete(); + }; + return TakeLastSubscriber; + }(Subscriber)); + + function last(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, takeLast(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); }; + } + + function mapTo(value) { + return function (source) { return source.lift(new MapToOperator(value)); }; + } + var MapToOperator = (function () { + function MapToOperator(value) { + this.value = value; + } + MapToOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MapToSubscriber(subscriber, this.value)); + }; + return MapToOperator; + }()); + var MapToSubscriber = (function (_super) { + __extends(MapToSubscriber, _super); + function MapToSubscriber(destination, value) { + var _this = _super.call(this, destination) || this; + _this.value = value; + return _this; + } + MapToSubscriber.prototype._next = function (x) { + this.destination.next(this.value); + }; + return MapToSubscriber; + }(Subscriber)); + + function materialize() { + return function materializeOperatorFunction(source) { + return source.lift(new MaterializeOperator()); + }; + } + var MaterializeOperator = (function () { + function MaterializeOperator() { + } + MaterializeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MaterializeSubscriber(subscriber)); + }; + return MaterializeOperator; + }()); + var MaterializeSubscriber = (function (_super) { + __extends(MaterializeSubscriber, _super); + function MaterializeSubscriber(destination) { + return _super.call(this, destination) || this; + } + MaterializeSubscriber.prototype._next = function (value) { + this.destination.next(Notification.createNext(value)); + }; + MaterializeSubscriber.prototype._error = function (err) { + var destination = this.destination; + destination.next(Notification.createError(err)); + destination.complete(); + }; + MaterializeSubscriber.prototype._complete = function () { + var destination = this.destination; + destination.next(Notification.createComplete()); + destination.complete(); + }; + return MaterializeSubscriber; + }(Subscriber)); + + function scan(accumulator, seed) { + var hasSeed = false; + if (arguments.length >= 2) { + hasSeed = true; + } + return function scanOperatorFunction(source) { + return source.lift(new ScanOperator(accumulator, seed, hasSeed)); + }; + } + var ScanOperator = (function () { + function ScanOperator(accumulator, seed, hasSeed) { + if (hasSeed === void 0) { hasSeed = false; } + this.accumulator = accumulator; + this.seed = seed; + this.hasSeed = hasSeed; + } + ScanOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ScanSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed)); + }; + return ScanOperator; + }()); + var ScanSubscriber = (function (_super) { + __extends(ScanSubscriber, _super); + function ScanSubscriber(destination, accumulator, _seed, hasSeed) { + var _this = _super.call(this, destination) || this; + _this.accumulator = accumulator; + _this._seed = _seed; + _this.hasSeed = hasSeed; + _this.index = 0; + return _this; + } + Object.defineProperty(ScanSubscriber.prototype, "seed", { + get: function () { + return this._seed; + }, + set: function (value) { + this.hasSeed = true; + this._seed = value; + }, + enumerable: true, + configurable: true + }); + ScanSubscriber.prototype._next = function (value) { + if (!this.hasSeed) { + this.seed = value; + this.destination.next(value); + } + else { + return this._tryNext(value); + } + }; + ScanSubscriber.prototype._tryNext = function (value) { + var index = this.index++; + var result; + try { + result = this.accumulator(this.seed, value, index); + } + catch (err) { + this.destination.error(err); + } + this.seed = result; + this.destination.next(result); + }; + return ScanSubscriber; + }(Subscriber)); + + function reduce(accumulator, seed) { + if (arguments.length >= 2) { + return function reduceOperatorFunctionWithSeed(source) { + return pipe(scan(accumulator, seed), takeLast(1), defaultIfEmpty(seed))(source); + }; + } + return function reduceOperatorFunction(source) { + return pipe(scan(function (acc, value, index) { return accumulator(acc, value, index + 1); }), takeLast(1))(source); + }; + } + + function max(comparer) { + var max = (typeof comparer === 'function') + ? function (x, y) { return comparer(x, y) > 0 ? x : y; } + : function (x, y) { return x > y ? x : y; }; + return reduce(max); + } + + function merge$1() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return function (source) { return source.lift.call(merge.apply(void 0, [source].concat(observables))); }; + } + + function mergeMapTo(innerObservable, resultSelector, concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + if (typeof resultSelector === 'function') { + return mergeMap(function () { return innerObservable; }, resultSelector, concurrent); + } + if (typeof resultSelector === 'number') { + concurrent = resultSelector; + } + return mergeMap(function () { return innerObservable; }, concurrent); + } + + function mergeScan(accumulator, seed, concurrent) { + if (concurrent === void 0) { concurrent = Number.POSITIVE_INFINITY; } + return function (source) { return source.lift(new MergeScanOperator(accumulator, seed, concurrent)); }; + } + var MergeScanOperator = (function () { + function MergeScanOperator(accumulator, seed, concurrent) { + this.accumulator = accumulator; + this.seed = seed; + this.concurrent = concurrent; + } + MergeScanOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MergeScanSubscriber(subscriber, this.accumulator, this.seed, this.concurrent)); + }; + return MergeScanOperator; + }()); + var MergeScanSubscriber = (function (_super) { + __extends(MergeScanSubscriber, _super); + function MergeScanSubscriber(destination, accumulator, acc, concurrent) { + var _this = _super.call(this, destination) || this; + _this.accumulator = accumulator; + _this.acc = acc; + _this.concurrent = concurrent; + _this.hasValue = false; + _this.hasCompleted = false; + _this.buffer = []; + _this.active = 0; + _this.index = 0; + return _this; + } + MergeScanSubscriber.prototype._next = function (value) { + if (this.active < this.concurrent) { + var index = this.index++; + var destination = this.destination; + var ish = void 0; + try { + var accumulator = this.accumulator; + ish = accumulator(this.acc, value, index); + } + catch (e) { + return destination.error(e); + } + this.active++; + this._innerSub(ish); + } + else { + this.buffer.push(value); + } + }; + MergeScanSubscriber.prototype._innerSub = function (ish) { + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = innerSubscribe(ish, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } + }; + MergeScanSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.active === 0 && this.buffer.length === 0) { + if (this.hasValue === false) { + this.destination.next(this.acc); + } + this.destination.complete(); + } + this.unsubscribe(); + }; + MergeScanSubscriber.prototype.notifyNext = function (innerValue) { + var destination = this.destination; + this.acc = innerValue; + this.hasValue = true; + destination.next(innerValue); + }; + MergeScanSubscriber.prototype.notifyComplete = function () { + var buffer = this.buffer; + this.active--; + if (buffer.length > 0) { + this._next(buffer.shift()); + } + else if (this.active === 0 && this.hasCompleted) { + if (this.hasValue === false) { + this.destination.next(this.acc); + } + this.destination.complete(); + } + }; + return MergeScanSubscriber; + }(SimpleOuterSubscriber)); + + function min(comparer) { + var min = (typeof comparer === 'function') + ? function (x, y) { return comparer(x, y) < 0 ? x : y; } + : function (x, y) { return x < y ? x : y; }; + return reduce(min); + } + + function multicast(subjectOrSubjectFactory, selector) { + return function multicastOperatorFunction(source) { + var subjectFactory; + if (typeof subjectOrSubjectFactory === 'function') { + subjectFactory = subjectOrSubjectFactory; + } + else { + subjectFactory = function subjectFactory() { + return subjectOrSubjectFactory; + }; + } + if (typeof selector === 'function') { + return source.lift(new MulticastOperator(subjectFactory, selector)); + } + var connectable = Object.create(source, connectableObservableDescriptor); + connectable.source = source; + connectable.subjectFactory = subjectFactory; + return connectable; + }; + } + var MulticastOperator = (function () { + function MulticastOperator(subjectFactory, selector) { + this.subjectFactory = subjectFactory; + this.selector = selector; + } + MulticastOperator.prototype.call = function (subscriber, source) { + var selector = this.selector; + var subject = this.subjectFactory(); + var subscription = selector(subject).subscribe(subscriber); + subscription.add(source.subscribe(subject)); + return subscription; + }; + return MulticastOperator; + }()); + + function onErrorResumeNext$1() { + var nextSources = []; + for (var _i = 0; _i < arguments.length; _i++) { + nextSources[_i] = arguments[_i]; + } + if (nextSources.length === 1 && isArray(nextSources[0])) { + nextSources = nextSources[0]; + } + return function (source) { return source.lift(new OnErrorResumeNextOperator(nextSources)); }; + } + var OnErrorResumeNextOperator = (function () { + function OnErrorResumeNextOperator(nextSources) { + this.nextSources = nextSources; + } + OnErrorResumeNextOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new OnErrorResumeNextSubscriber(subscriber, this.nextSources)); + }; + return OnErrorResumeNextOperator; + }()); + var OnErrorResumeNextSubscriber = (function (_super) { + __extends(OnErrorResumeNextSubscriber, _super); + function OnErrorResumeNextSubscriber(destination, nextSources) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.nextSources = nextSources; + return _this; + } + OnErrorResumeNextSubscriber.prototype.notifyError = function () { + this.subscribeToNextSource(); + }; + OnErrorResumeNextSubscriber.prototype.notifyComplete = function () { + this.subscribeToNextSource(); + }; + OnErrorResumeNextSubscriber.prototype._error = function (err) { + this.subscribeToNextSource(); + this.unsubscribe(); + }; + OnErrorResumeNextSubscriber.prototype._complete = function () { + this.subscribeToNextSource(); + this.unsubscribe(); + }; + OnErrorResumeNextSubscriber.prototype.subscribeToNextSource = function () { + var next = this.nextSources.shift(); + if (!!next) { + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = innerSubscribe(next, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } + } + else { + this.destination.complete(); + } + }; + return OnErrorResumeNextSubscriber; + }(SimpleOuterSubscriber)); + + function pairwise() { + return function (source) { return source.lift(new PairwiseOperator()); }; + } + var PairwiseOperator = (function () { + function PairwiseOperator() { + } + PairwiseOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new PairwiseSubscriber(subscriber)); + }; + return PairwiseOperator; + }()); + var PairwiseSubscriber = (function (_super) { + __extends(PairwiseSubscriber, _super); + function PairwiseSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasPrev = false; + return _this; + } + PairwiseSubscriber.prototype._next = function (value) { + var pair; + if (this.hasPrev) { + pair = [this.prev, value]; + } + else { + this.hasPrev = true; + } + this.prev = value; + if (pair) { + this.destination.next(pair); + } + }; + return PairwiseSubscriber; + }(Subscriber)); + + function partition$1(predicate, thisArg) { + return function (source) { return [ + filter(predicate, thisArg)(source), + filter(not(predicate, thisArg))(source) + ]; }; + } + + function pluck() { + var properties = []; + for (var _i = 0; _i < arguments.length; _i++) { + properties[_i] = arguments[_i]; + } + var length = properties.length; + if (length === 0) { + throw new Error('list of properties cannot be empty.'); + } + return function (source) { return map(plucker(properties, length))(source); }; + } + function plucker(props, length) { + var mapper = function (x) { + var currentProp = x; + for (var i = 0; i < length; i++) { + var p = currentProp != null ? currentProp[props[i]] : undefined; + if (p !== void 0) { + currentProp = p; + } + else { + return undefined; + } + } + return currentProp; + }; + return mapper; + } + + function publish(selector) { + return selector ? + multicast(function () { return new Subject(); }, selector) : + multicast(new Subject()); + } + + function publishBehavior(value) { + return function (source) { return multicast(new BehaviorSubject(value))(source); }; + } + + function publishLast() { + return function (source) { return multicast(new AsyncSubject())(source); }; + } + + function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { + if (selectorOrScheduler && typeof selectorOrScheduler !== 'function') { + scheduler = selectorOrScheduler; + } + var selector = typeof selectorOrScheduler === 'function' ? selectorOrScheduler : undefined; + var subject = new ReplaySubject(bufferSize, windowTime, scheduler); + return function (source) { return multicast(function () { return subject; }, selector)(source); }; + } + + function race$1() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return function raceOperatorFunction(source) { + if (observables.length === 1 && isArray(observables[0])) { + observables = observables[0]; + } + return source.lift.call(race.apply(void 0, [source].concat(observables))); + }; + } + + function repeat(count) { + if (count === void 0) { count = -1; } + return function (source) { + if (count === 0) { + return empty$1(); + } + else if (count < 0) { + return source.lift(new RepeatOperator(-1, source)); + } + else { + return source.lift(new RepeatOperator(count - 1, source)); + } + }; + } + var RepeatOperator = (function () { + function RepeatOperator(count, source) { + this.count = count; + this.source = source; + } + RepeatOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RepeatSubscriber(subscriber, this.count, this.source)); + }; + return RepeatOperator; + }()); + var RepeatSubscriber = (function (_super) { + __extends(RepeatSubscriber, _super); + function RepeatSubscriber(destination, count, source) { + var _this = _super.call(this, destination) || this; + _this.count = count; + _this.source = source; + return _this; + } + RepeatSubscriber.prototype.complete = function () { + if (!this.isStopped) { + var _a = this, source = _a.source, count = _a.count; + if (count === 0) { + return _super.prototype.complete.call(this); + } + else if (count > -1) { + this.count = count - 1; + } + source.subscribe(this._unsubscribeAndRecycle()); + } + }; + return RepeatSubscriber; + }(Subscriber)); + + function repeatWhen(notifier) { + return function (source) { return source.lift(new RepeatWhenOperator(notifier)); }; + } + var RepeatWhenOperator = (function () { + function RepeatWhenOperator(notifier) { + this.notifier = notifier; + } + RepeatWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RepeatWhenSubscriber(subscriber, this.notifier, source)); + }; + return RepeatWhenOperator; + }()); + var RepeatWhenSubscriber = (function (_super) { + __extends(RepeatWhenSubscriber, _super); + function RepeatWhenSubscriber(destination, notifier, source) { + var _this = _super.call(this, destination) || this; + _this.notifier = notifier; + _this.source = source; + _this.sourceIsBeingSubscribedTo = true; + return _this; + } + RepeatWhenSubscriber.prototype.notifyNext = function () { + this.sourceIsBeingSubscribedTo = true; + this.source.subscribe(this); + }; + RepeatWhenSubscriber.prototype.notifyComplete = function () { + if (this.sourceIsBeingSubscribedTo === false) { + return _super.prototype.complete.call(this); + } + }; + RepeatWhenSubscriber.prototype.complete = function () { + this.sourceIsBeingSubscribedTo = false; + if (!this.isStopped) { + if (!this.retries) { + this.subscribeToRetries(); + } + if (!this.retriesSubscription || this.retriesSubscription.closed) { + return _super.prototype.complete.call(this); + } + this._unsubscribeAndRecycle(); + this.notifications.next(undefined); + } + }; + RepeatWhenSubscriber.prototype._unsubscribe = function () { + var _a = this, notifications = _a.notifications, retriesSubscription = _a.retriesSubscription; + if (notifications) { + notifications.unsubscribe(); + this.notifications = undefined; + } + if (retriesSubscription) { + retriesSubscription.unsubscribe(); + this.retriesSubscription = undefined; + } + this.retries = undefined; + }; + RepeatWhenSubscriber.prototype._unsubscribeAndRecycle = function () { + var _unsubscribe = this._unsubscribe; + this._unsubscribe = null; + _super.prototype._unsubscribeAndRecycle.call(this); + this._unsubscribe = _unsubscribe; + return this; + }; + RepeatWhenSubscriber.prototype.subscribeToRetries = function () { + this.notifications = new Subject(); + var retries; + try { + var notifier = this.notifier; + retries = notifier(this.notifications); + } + catch (e) { + return _super.prototype.complete.call(this); + } + this.retries = retries; + this.retriesSubscription = innerSubscribe(retries, new SimpleInnerSubscriber(this)); + }; + return RepeatWhenSubscriber; + }(SimpleOuterSubscriber)); + + function retry(count) { + if (count === void 0) { count = -1; } + return function (source) { return source.lift(new RetryOperator(count, source)); }; + } + var RetryOperator = (function () { + function RetryOperator(count, source) { + this.count = count; + this.source = source; + } + RetryOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RetrySubscriber(subscriber, this.count, this.source)); + }; + return RetryOperator; + }()); + var RetrySubscriber = (function (_super) { + __extends(RetrySubscriber, _super); + function RetrySubscriber(destination, count, source) { + var _this = _super.call(this, destination) || this; + _this.count = count; + _this.source = source; + return _this; + } + RetrySubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _a = this, source = _a.source, count = _a.count; + if (count === 0) { + return _super.prototype.error.call(this, err); + } + else if (count > -1) { + this.count = count - 1; + } + source.subscribe(this._unsubscribeAndRecycle()); + } + }; + return RetrySubscriber; + }(Subscriber)); + + function retryWhen(notifier) { + return function (source) { return source.lift(new RetryWhenOperator(notifier, source)); }; + } + var RetryWhenOperator = (function () { + function RetryWhenOperator(notifier, source) { + this.notifier = notifier; + this.source = source; + } + RetryWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RetryWhenSubscriber(subscriber, this.notifier, this.source)); + }; + return RetryWhenOperator; + }()); + var RetryWhenSubscriber = (function (_super) { + __extends(RetryWhenSubscriber, _super); + function RetryWhenSubscriber(destination, notifier, source) { + var _this = _super.call(this, destination) || this; + _this.notifier = notifier; + _this.source = source; + return _this; + } + RetryWhenSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var errors = this.errors; + var retries = this.retries; + var retriesSubscription = this.retriesSubscription; + if (!retries) { + errors = new Subject(); + try { + var notifier = this.notifier; + retries = notifier(errors); + } + catch (e) { + return _super.prototype.error.call(this, e); + } + retriesSubscription = innerSubscribe(retries, new SimpleInnerSubscriber(this)); + } + else { + this.errors = undefined; + this.retriesSubscription = undefined; + } + this._unsubscribeAndRecycle(); + this.errors = errors; + this.retries = retries; + this.retriesSubscription = retriesSubscription; + errors.next(err); + } + }; + RetryWhenSubscriber.prototype._unsubscribe = function () { + var _a = this, errors = _a.errors, retriesSubscription = _a.retriesSubscription; + if (errors) { + errors.unsubscribe(); + this.errors = undefined; + } + if (retriesSubscription) { + retriesSubscription.unsubscribe(); + this.retriesSubscription = undefined; + } + this.retries = undefined; + }; + RetryWhenSubscriber.prototype.notifyNext = function () { + var _unsubscribe = this._unsubscribe; + this._unsubscribe = null; + this._unsubscribeAndRecycle(); + this._unsubscribe = _unsubscribe; + this.source.subscribe(this); + }; + return RetryWhenSubscriber; + }(SimpleOuterSubscriber)); + + function sample(notifier) { + return function (source) { return source.lift(new SampleOperator(notifier)); }; + } + var SampleOperator = (function () { + function SampleOperator(notifier) { + this.notifier = notifier; + } + SampleOperator.prototype.call = function (subscriber, source) { + var sampleSubscriber = new SampleSubscriber(subscriber); + var subscription = source.subscribe(sampleSubscriber); + subscription.add(innerSubscribe(this.notifier, new SimpleInnerSubscriber(sampleSubscriber))); + return subscription; + }; + return SampleOperator; + }()); + var SampleSubscriber = (function (_super) { + __extends(SampleSubscriber, _super); + function SampleSubscriber() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.hasValue = false; + return _this; + } + SampleSubscriber.prototype._next = function (value) { + this.value = value; + this.hasValue = true; + }; + SampleSubscriber.prototype.notifyNext = function () { + this.emitValue(); + }; + SampleSubscriber.prototype.notifyComplete = function () { + this.emitValue(); + }; + SampleSubscriber.prototype.emitValue = function () { + if (this.hasValue) { + this.hasValue = false; + this.destination.next(this.value); + } + }; + return SampleSubscriber; + }(SimpleOuterSubscriber)); + + function sampleTime(period, scheduler) { + if (scheduler === void 0) { scheduler = async; } + return function (source) { return source.lift(new SampleTimeOperator(period, scheduler)); }; + } + var SampleTimeOperator = (function () { + function SampleTimeOperator(period, scheduler) { + this.period = period; + this.scheduler = scheduler; + } + SampleTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SampleTimeSubscriber(subscriber, this.period, this.scheduler)); + }; + return SampleTimeOperator; + }()); + var SampleTimeSubscriber = (function (_super) { + __extends(SampleTimeSubscriber, _super); + function SampleTimeSubscriber(destination, period, scheduler) { + var _this = _super.call(this, destination) || this; + _this.period = period; + _this.scheduler = scheduler; + _this.hasValue = false; + _this.add(scheduler.schedule(dispatchNotification, period, { subscriber: _this, period: period })); + return _this; + } + SampleTimeSubscriber.prototype._next = function (value) { + this.lastValue = value; + this.hasValue = true; + }; + SampleTimeSubscriber.prototype.notifyNext = function () { + if (this.hasValue) { + this.hasValue = false; + this.destination.next(this.lastValue); + } + }; + return SampleTimeSubscriber; + }(Subscriber)); + function dispatchNotification(state) { + var subscriber = state.subscriber, period = state.period; + subscriber.notifyNext(); + this.schedule(state, period); + } + + function sequenceEqual(compareTo, comparator) { + return function (source) { return source.lift(new SequenceEqualOperator(compareTo, comparator)); }; + } + var SequenceEqualOperator = (function () { + function SequenceEqualOperator(compareTo, comparator) { + this.compareTo = compareTo; + this.comparator = comparator; + } + SequenceEqualOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SequenceEqualSubscriber(subscriber, this.compareTo, this.comparator)); + }; + return SequenceEqualOperator; + }()); + var SequenceEqualSubscriber = (function (_super) { + __extends(SequenceEqualSubscriber, _super); + function SequenceEqualSubscriber(destination, compareTo, comparator) { + var _this = _super.call(this, destination) || this; + _this.compareTo = compareTo; + _this.comparator = comparator; + _this._a = []; + _this._b = []; + _this._oneComplete = false; + _this.destination.add(compareTo.subscribe(new SequenceEqualCompareToSubscriber(destination, _this))); + return _this; + } + SequenceEqualSubscriber.prototype._next = function (value) { + if (this._oneComplete && this._b.length === 0) { + this.emit(false); + } + else { + this._a.push(value); + this.checkValues(); + } + }; + SequenceEqualSubscriber.prototype._complete = function () { + if (this._oneComplete) { + this.emit(this._a.length === 0 && this._b.length === 0); + } + else { + this._oneComplete = true; + } + this.unsubscribe(); + }; + SequenceEqualSubscriber.prototype.checkValues = function () { + var _c = this, _a = _c._a, _b = _c._b, comparator = _c.comparator; + while (_a.length > 0 && _b.length > 0) { + var a = _a.shift(); + var b = _b.shift(); + var areEqual = false; + try { + areEqual = comparator ? comparator(a, b) : a === b; + } + catch (e) { + this.destination.error(e); + } + if (!areEqual) { + this.emit(false); + } + } + }; + SequenceEqualSubscriber.prototype.emit = function (value) { + var destination = this.destination; + destination.next(value); + destination.complete(); + }; + SequenceEqualSubscriber.prototype.nextB = function (value) { + if (this._oneComplete && this._a.length === 0) { + this.emit(false); + } + else { + this._b.push(value); + this.checkValues(); + } + }; + SequenceEqualSubscriber.prototype.completeB = function () { + if (this._oneComplete) { + this.emit(this._a.length === 0 && this._b.length === 0); + } + else { + this._oneComplete = true; + } + }; + return SequenceEqualSubscriber; + }(Subscriber)); + var SequenceEqualCompareToSubscriber = (function (_super) { + __extends(SequenceEqualCompareToSubscriber, _super); + function SequenceEqualCompareToSubscriber(destination, parent) { + var _this = _super.call(this, destination) || this; + _this.parent = parent; + return _this; + } + SequenceEqualCompareToSubscriber.prototype._next = function (value) { + this.parent.nextB(value); + }; + SequenceEqualCompareToSubscriber.prototype._error = function (err) { + this.parent.error(err); + this.unsubscribe(); + }; + SequenceEqualCompareToSubscriber.prototype._complete = function () { + this.parent.completeB(); + this.unsubscribe(); + }; + return SequenceEqualCompareToSubscriber; + }(Subscriber)); + + function shareSubjectFactory() { + return new Subject(); + } + function share() { + return function (source) { return refCount()(multicast(shareSubjectFactory)(source)); }; + } + + function shareReplay(configOrBufferSize, windowTime, scheduler) { + var config; + if (configOrBufferSize && typeof configOrBufferSize === 'object') { + config = configOrBufferSize; + } + else { + config = { + bufferSize: configOrBufferSize, + windowTime: windowTime, + refCount: false, + scheduler: scheduler + }; + } + return function (source) { return source.lift(shareReplayOperator(config)); }; + } + function shareReplayOperator(_a) { + var _b = _a.bufferSize, bufferSize = _b === void 0 ? Number.POSITIVE_INFINITY : _b, _c = _a.windowTime, windowTime = _c === void 0 ? Number.POSITIVE_INFINITY : _c, useRefCount = _a.refCount, scheduler = _a.scheduler; + var subject; + var refCount = 0; + var subscription; + var hasError = false; + var isComplete = false; + return function shareReplayOperation(source) { + refCount++; + var innerSub; + if (!subject || hasError) { + hasError = false; + subject = new ReplaySubject(bufferSize, windowTime, scheduler); + innerSub = subject.subscribe(this); + subscription = source.subscribe({ + next: function (value) { subject.next(value); }, + error: function (err) { + hasError = true; + subject.error(err); + }, + complete: function () { + isComplete = true; + subscription = undefined; + subject.complete(); + }, + }); + } + else { + innerSub = subject.subscribe(this); + } + this.add(function () { + refCount--; + innerSub.unsubscribe(); + if (subscription && !isComplete && useRefCount && refCount === 0) { + subscription.unsubscribe(); + subscription = undefined; + subject = undefined; + } + }); + }; + } + + function single(predicate) { + return function (source) { return source.lift(new SingleOperator(predicate, source)); }; + } + var SingleOperator = (function () { + function SingleOperator(predicate, source) { + this.predicate = predicate; + this.source = source; + } + SingleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SingleSubscriber(subscriber, this.predicate, this.source)); + }; + return SingleOperator; + }()); + var SingleSubscriber = (function (_super) { + __extends(SingleSubscriber, _super); + function SingleSubscriber(destination, predicate, source) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.source = source; + _this.seenValue = false; + _this.index = 0; + return _this; + } + SingleSubscriber.prototype.applySingleValue = function (value) { + if (this.seenValue) { + this.destination.error('Sequence contains more than one element'); + } + else { + this.seenValue = true; + this.singleValue = value; + } + }; + SingleSubscriber.prototype._next = function (value) { + var index = this.index++; + if (this.predicate) { + this.tryNext(value, index); + } + else { + this.applySingleValue(value); + } + }; + SingleSubscriber.prototype.tryNext = function (value, index) { + try { + if (this.predicate(value, index, this.source)) { + this.applySingleValue(value); + } + } + catch (err) { + this.destination.error(err); + } + }; + SingleSubscriber.prototype._complete = function () { + var destination = this.destination; + if (this.index > 0) { + destination.next(this.seenValue ? this.singleValue : undefined); + destination.complete(); + } + else { + destination.error(new EmptyError); + } + }; + return SingleSubscriber; + }(Subscriber)); + + function skip(count) { + return function (source) { return source.lift(new SkipOperator(count)); }; + } + var SkipOperator = (function () { + function SkipOperator(total) { + this.total = total; + } + SkipOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SkipSubscriber(subscriber, this.total)); + }; + return SkipOperator; + }()); + var SkipSubscriber = (function (_super) { + __extends(SkipSubscriber, _super); + function SkipSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.count = 0; + return _this; + } + SkipSubscriber.prototype._next = function (x) { + if (++this.count > this.total) { + this.destination.next(x); + } + }; + return SkipSubscriber; + }(Subscriber)); + + function skipLast(count) { + return function (source) { return source.lift(new SkipLastOperator(count)); }; + } + var SkipLastOperator = (function () { + function SkipLastOperator(_skipCount) { + this._skipCount = _skipCount; + if (this._skipCount < 0) { + throw new ArgumentOutOfRangeError; + } + } + SkipLastOperator.prototype.call = function (subscriber, source) { + if (this._skipCount === 0) { + return source.subscribe(new Subscriber(subscriber)); + } + else { + return source.subscribe(new SkipLastSubscriber(subscriber, this._skipCount)); + } + }; + return SkipLastOperator; + }()); + var SkipLastSubscriber = (function (_super) { + __extends(SkipLastSubscriber, _super); + function SkipLastSubscriber(destination, _skipCount) { + var _this = _super.call(this, destination) || this; + _this._skipCount = _skipCount; + _this._count = 0; + _this._ring = new Array(_skipCount); + return _this; + } + SkipLastSubscriber.prototype._next = function (value) { + var skipCount = this._skipCount; + var count = this._count++; + if (count < skipCount) { + this._ring[count] = value; + } + else { + var currentIndex = count % skipCount; + var ring = this._ring; + var oldValue = ring[currentIndex]; + ring[currentIndex] = value; + this.destination.next(oldValue); + } + }; + return SkipLastSubscriber; + }(Subscriber)); + + function skipUntil(notifier) { + return function (source) { return source.lift(new SkipUntilOperator(notifier)); }; + } + var SkipUntilOperator = (function () { + function SkipUntilOperator(notifier) { + this.notifier = notifier; + } + SkipUntilOperator.prototype.call = function (destination, source) { + return source.subscribe(new SkipUntilSubscriber(destination, this.notifier)); + }; + return SkipUntilOperator; + }()); + var SkipUntilSubscriber = (function (_super) { + __extends(SkipUntilSubscriber, _super); + function SkipUntilSubscriber(destination, notifier) { + var _this = _super.call(this, destination) || this; + _this.hasValue = false; + var innerSubscriber = new SimpleInnerSubscriber(_this); + _this.add(innerSubscriber); + _this.innerSubscription = innerSubscriber; + var innerSubscription = innerSubscribe(notifier, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + _this.add(innerSubscription); + _this.innerSubscription = innerSubscription; + } + return _this; + } + SkipUntilSubscriber.prototype._next = function (value) { + if (this.hasValue) { + _super.prototype._next.call(this, value); + } + }; + SkipUntilSubscriber.prototype.notifyNext = function () { + this.hasValue = true; + if (this.innerSubscription) { + this.innerSubscription.unsubscribe(); + } + }; + SkipUntilSubscriber.prototype.notifyComplete = function () { + }; + return SkipUntilSubscriber; + }(SimpleOuterSubscriber)); + + function skipWhile(predicate) { + return function (source) { return source.lift(new SkipWhileOperator(predicate)); }; + } + var SkipWhileOperator = (function () { + function SkipWhileOperator(predicate) { + this.predicate = predicate; + } + SkipWhileOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SkipWhileSubscriber(subscriber, this.predicate)); + }; + return SkipWhileOperator; + }()); + var SkipWhileSubscriber = (function (_super) { + __extends(SkipWhileSubscriber, _super); + function SkipWhileSubscriber(destination, predicate) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.skipping = true; + _this.index = 0; + return _this; + } + SkipWhileSubscriber.prototype._next = function (value) { + var destination = this.destination; + if (this.skipping) { + this.tryCallPredicate(value); + } + if (!this.skipping) { + destination.next(value); + } + }; + SkipWhileSubscriber.prototype.tryCallPredicate = function (value) { + try { + var result = this.predicate(value, this.index++); + this.skipping = Boolean(result); + } + catch (err) { + this.destination.error(err); + } + }; + return SkipWhileSubscriber; + }(Subscriber)); + + function startWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + var scheduler = array[array.length - 1]; + if (isScheduler(scheduler)) { + array.pop(); + return function (source) { return concat(array, source, scheduler); }; + } + else { + return function (source) { return concat(array, source); }; + } + } + + var SubscribeOnObservable = (function (_super) { + __extends(SubscribeOnObservable, _super); + function SubscribeOnObservable(source, delayTime, scheduler) { + if (delayTime === void 0) { delayTime = 0; } + if (scheduler === void 0) { scheduler = asap; } + var _this = _super.call(this) || this; + _this.source = source; + _this.delayTime = delayTime; + _this.scheduler = scheduler; + if (!isNumeric(delayTime) || delayTime < 0) { + _this.delayTime = 0; + } + if (!scheduler || typeof scheduler.schedule !== 'function') { + _this.scheduler = asap; + } + return _this; + } + SubscribeOnObservable.create = function (source, delay, scheduler) { + if (delay === void 0) { delay = 0; } + if (scheduler === void 0) { scheduler = asap; } + return new SubscribeOnObservable(source, delay, scheduler); + }; + SubscribeOnObservable.dispatch = function (arg) { + var source = arg.source, subscriber = arg.subscriber; + return this.add(source.subscribe(subscriber)); + }; + SubscribeOnObservable.prototype._subscribe = function (subscriber) { + var delay = this.delayTime; + var source = this.source; + var scheduler = this.scheduler; + return scheduler.schedule(SubscribeOnObservable.dispatch, delay, { + source: source, subscriber: subscriber + }); + }; + return SubscribeOnObservable; + }(Observable)); + + function subscribeOn(scheduler, delay) { + if (delay === void 0) { delay = 0; } + return function subscribeOnOperatorFunction(source) { + return source.lift(new SubscribeOnOperator(scheduler, delay)); + }; + } + var SubscribeOnOperator = (function () { + function SubscribeOnOperator(scheduler, delay) { + this.scheduler = scheduler; + this.delay = delay; + } + SubscribeOnOperator.prototype.call = function (subscriber, source) { + return new SubscribeOnObservable(source, this.delay, this.scheduler).subscribe(subscriber); + }; + return SubscribeOnOperator; + }()); + + function switchMap(project, resultSelector) { + if (typeof resultSelector === 'function') { + return function (source) { return source.pipe(switchMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; + } + return function (source) { return source.lift(new SwitchMapOperator(project)); }; + } + var SwitchMapOperator = (function () { + function SwitchMapOperator(project) { + this.project = project; + } + SwitchMapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchMapSubscriber(subscriber, this.project)); + }; + return SwitchMapOperator; + }()); + var SwitchMapSubscriber = (function (_super) { + __extends(SwitchMapSubscriber, _super); + function SwitchMapSubscriber(destination, project) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.index = 0; + return _this; + } + SwitchMapSubscriber.prototype._next = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (error) { + this.destination.error(error); + return; + } + this._innerSub(result); + }; + SwitchMapSubscriber.prototype._innerSub = function (result) { + var innerSubscription = this.innerSubscription; + if (innerSubscription) { + innerSubscription.unsubscribe(); + } + var innerSubscriber = new SimpleInnerSubscriber(this); + var destination = this.destination; + destination.add(innerSubscriber); + this.innerSubscription = innerSubscribe(result, innerSubscriber); + if (this.innerSubscription !== innerSubscriber) { + destination.add(this.innerSubscription); + } + }; + SwitchMapSubscriber.prototype._complete = function () { + var innerSubscription = this.innerSubscription; + if (!innerSubscription || innerSubscription.closed) { + _super.prototype._complete.call(this); + } + this.unsubscribe(); + }; + SwitchMapSubscriber.prototype._unsubscribe = function () { + this.innerSubscription = undefined; + }; + SwitchMapSubscriber.prototype.notifyComplete = function () { + this.innerSubscription = undefined; + if (this.isStopped) { + _super.prototype._complete.call(this); + } + }; + SwitchMapSubscriber.prototype.notifyNext = function (innerValue) { + this.destination.next(innerValue); + }; + return SwitchMapSubscriber; + }(SimpleOuterSubscriber)); + + function switchAll() { + return switchMap(identity); + } + + function switchMapTo(innerObservable, resultSelector) { + return resultSelector ? switchMap(function () { return innerObservable; }, resultSelector) : switchMap(function () { return innerObservable; }); + } + + function takeUntil(notifier) { + return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; + } + var TakeUntilOperator = (function () { + function TakeUntilOperator(notifier) { + this.notifier = notifier; + } + TakeUntilOperator.prototype.call = function (subscriber, source) { + var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); + var notifierSubscription = innerSubscribe(this.notifier, new SimpleInnerSubscriber(takeUntilSubscriber)); + if (notifierSubscription && !takeUntilSubscriber.seenValue) { + takeUntilSubscriber.add(notifierSubscription); + return source.subscribe(takeUntilSubscriber); + } + return takeUntilSubscriber; + }; + return TakeUntilOperator; + }()); + var TakeUntilSubscriber = (function (_super) { + __extends(TakeUntilSubscriber, _super); + function TakeUntilSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.seenValue = false; + return _this; + } + TakeUntilSubscriber.prototype.notifyNext = function () { + this.seenValue = true; + this.complete(); + }; + TakeUntilSubscriber.prototype.notifyComplete = function () { + }; + return TakeUntilSubscriber; + }(SimpleOuterSubscriber)); + + function takeWhile(predicate, inclusive) { + if (inclusive === void 0) { inclusive = false; } + return function (source) { + return source.lift(new TakeWhileOperator(predicate, inclusive)); + }; + } + var TakeWhileOperator = (function () { + function TakeWhileOperator(predicate, inclusive) { + this.predicate = predicate; + this.inclusive = inclusive; + } + TakeWhileOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeWhileSubscriber(subscriber, this.predicate, this.inclusive)); + }; + return TakeWhileOperator; + }()); + var TakeWhileSubscriber = (function (_super) { + __extends(TakeWhileSubscriber, _super); + function TakeWhileSubscriber(destination, predicate, inclusive) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.inclusive = inclusive; + _this.index = 0; + return _this; + } + TakeWhileSubscriber.prototype._next = function (value) { + var destination = this.destination; + var result; + try { + result = this.predicate(value, this.index++); + } + catch (err) { + destination.error(err); + return; + } + this.nextOrComplete(value, result); + }; + TakeWhileSubscriber.prototype.nextOrComplete = function (value, predicateResult) { + var destination = this.destination; + if (Boolean(predicateResult)) { + destination.next(value); + } + else { + if (this.inclusive) { + destination.next(value); + } + destination.complete(); + } + }; + return TakeWhileSubscriber; + }(Subscriber)); + + function tap(nextOrObserver, error, complete) { + return function tapOperatorFunction(source) { + return source.lift(new DoOperator(nextOrObserver, error, complete)); + }; + } + var DoOperator = (function () { + function DoOperator(nextOrObserver, error, complete) { + this.nextOrObserver = nextOrObserver; + this.error = error; + this.complete = complete; + } + DoOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete)); + }; + return DoOperator; + }()); + var TapSubscriber = (function (_super) { + __extends(TapSubscriber, _super); + function TapSubscriber(destination, observerOrNext, error, complete) { + var _this = _super.call(this, destination) || this; + _this._tapNext = noop; + _this._tapError = noop; + _this._tapComplete = noop; + _this._tapError = error || noop; + _this._tapComplete = complete || noop; + if (isFunction(observerOrNext)) { + _this._context = _this; + _this._tapNext = observerOrNext; + } + else if (observerOrNext) { + _this._context = observerOrNext; + _this._tapNext = observerOrNext.next || noop; + _this._tapError = observerOrNext.error || noop; + _this._tapComplete = observerOrNext.complete || noop; + } + return _this; + } + TapSubscriber.prototype._next = function (value) { + try { + this._tapNext.call(this._context, value); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(value); + }; + TapSubscriber.prototype._error = function (err) { + try { + this._tapError.call(this._context, err); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.error(err); + }; + TapSubscriber.prototype._complete = function () { + try { + this._tapComplete.call(this._context); + } + catch (err) { + this.destination.error(err); + return; + } + return this.destination.complete(); + }; + return TapSubscriber; + }(Subscriber)); + + var defaultThrottleConfig = { + leading: true, + trailing: false + }; + function throttle(durationSelector, config) { + if (config === void 0) { config = defaultThrottleConfig; } + return function (source) { return source.lift(new ThrottleOperator(durationSelector, !!config.leading, !!config.trailing)); }; + } + var ThrottleOperator = (function () { + function ThrottleOperator(durationSelector, leading, trailing) { + this.durationSelector = durationSelector; + this.leading = leading; + this.trailing = trailing; + } + ThrottleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrottleSubscriber(subscriber, this.durationSelector, this.leading, this.trailing)); + }; + return ThrottleOperator; + }()); + var ThrottleSubscriber = (function (_super) { + __extends(ThrottleSubscriber, _super); + function ThrottleSubscriber(destination, durationSelector, _leading, _trailing) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.durationSelector = durationSelector; + _this._leading = _leading; + _this._trailing = _trailing; + _this._hasValue = false; + return _this; + } + ThrottleSubscriber.prototype._next = function (value) { + this._hasValue = true; + this._sendValue = value; + if (!this._throttled) { + if (this._leading) { + this.send(); + } + else { + this.throttle(value); + } + } + }; + ThrottleSubscriber.prototype.send = function () { + var _a = this, _hasValue = _a._hasValue, _sendValue = _a._sendValue; + if (_hasValue) { + this.destination.next(_sendValue); + this.throttle(_sendValue); + } + this._hasValue = false; + this._sendValue = undefined; + }; + ThrottleSubscriber.prototype.throttle = function (value) { + var duration = this.tryDurationSelector(value); + if (!!duration) { + this.add(this._throttled = innerSubscribe(duration, new SimpleInnerSubscriber(this))); + } + }; + ThrottleSubscriber.prototype.tryDurationSelector = function (value) { + try { + return this.durationSelector(value); + } + catch (err) { + this.destination.error(err); + return null; + } + }; + ThrottleSubscriber.prototype.throttlingDone = function () { + var _a = this, _throttled = _a._throttled, _trailing = _a._trailing; + if (_throttled) { + _throttled.unsubscribe(); + } + this._throttled = undefined; + if (_trailing) { + this.send(); + } + }; + ThrottleSubscriber.prototype.notifyNext = function () { + this.throttlingDone(); + }; + ThrottleSubscriber.prototype.notifyComplete = function () { + this.throttlingDone(); + }; + return ThrottleSubscriber; + }(SimpleOuterSubscriber)); + + function throttleTime(duration, scheduler, config) { + if (scheduler === void 0) { scheduler = async; } + if (config === void 0) { config = defaultThrottleConfig; } + return function (source) { return source.lift(new ThrottleTimeOperator(duration, scheduler, config.leading, config.trailing)); }; + } + var ThrottleTimeOperator = (function () { + function ThrottleTimeOperator(duration, scheduler, leading, trailing) { + this.duration = duration; + this.scheduler = scheduler; + this.leading = leading; + this.trailing = trailing; + } + ThrottleTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrottleTimeSubscriber(subscriber, this.duration, this.scheduler, this.leading, this.trailing)); + }; + return ThrottleTimeOperator; + }()); + var ThrottleTimeSubscriber = (function (_super) { + __extends(ThrottleTimeSubscriber, _super); + function ThrottleTimeSubscriber(destination, duration, scheduler, leading, trailing) { + var _this = _super.call(this, destination) || this; + _this.duration = duration; + _this.scheduler = scheduler; + _this.leading = leading; + _this.trailing = trailing; + _this._hasTrailingValue = false; + _this._trailingValue = null; + return _this; + } + ThrottleTimeSubscriber.prototype._next = function (value) { + if (this.throttled) { + if (this.trailing) { + this._trailingValue = value; + this._hasTrailingValue = true; + } + } + else { + this.add(this.throttled = this.scheduler.schedule(dispatchNext$3, this.duration, { subscriber: this })); + if (this.leading) { + this.destination.next(value); + } + else if (this.trailing) { + this._trailingValue = value; + this._hasTrailingValue = true; + } + } + }; + ThrottleTimeSubscriber.prototype._complete = function () { + if (this._hasTrailingValue) { + this.destination.next(this._trailingValue); + this.destination.complete(); + } + else { + this.destination.complete(); + } + }; + ThrottleTimeSubscriber.prototype.clearThrottle = function () { + var throttled = this.throttled; + if (throttled) { + if (this.trailing && this._hasTrailingValue) { + this.destination.next(this._trailingValue); + this._trailingValue = null; + this._hasTrailingValue = false; + } + throttled.unsubscribe(); + this.remove(throttled); + this.throttled = null; + } + }; + return ThrottleTimeSubscriber; + }(Subscriber)); + function dispatchNext$3(arg) { + var subscriber = arg.subscriber; + subscriber.clearThrottle(); + } + + function timeInterval(scheduler) { + if (scheduler === void 0) { scheduler = async; } + return function (source) { return defer(function () { + return source.pipe(scan(function (_a, value) { + var current = _a.current; + return ({ value: value, current: scheduler.now(), last: current }); + }, { current: scheduler.now(), value: undefined, last: undefined }), map(function (_a) { + var current = _a.current, last = _a.last, value = _a.value; + return new TimeInterval(value, current - last); + })); + }); }; + } + var TimeInterval = (function () { + function TimeInterval(value, interval) { + this.value = value; + this.interval = interval; + } + return TimeInterval; + }()); + + function timeoutWith(due, withObservable, scheduler) { + if (scheduler === void 0) { scheduler = async; } + return function (source) { + var absoluteTimeout = isDate(due); + var waitFor = absoluteTimeout ? (+due - scheduler.now()) : Math.abs(due); + return source.lift(new TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler)); + }; + } + var TimeoutWithOperator = (function () { + function TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler) { + this.waitFor = waitFor; + this.absoluteTimeout = absoluteTimeout; + this.withObservable = withObservable; + this.scheduler = scheduler; + } + TimeoutWithOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TimeoutWithSubscriber(subscriber, this.absoluteTimeout, this.waitFor, this.withObservable, this.scheduler)); + }; + return TimeoutWithOperator; + }()); + var TimeoutWithSubscriber = (function (_super) { + __extends(TimeoutWithSubscriber, _super); + function TimeoutWithSubscriber(destination, absoluteTimeout, waitFor, withObservable, scheduler) { + var _this = _super.call(this, destination) || this; + _this.absoluteTimeout = absoluteTimeout; + _this.waitFor = waitFor; + _this.withObservable = withObservable; + _this.scheduler = scheduler; + _this.scheduleTimeout(); + return _this; + } + TimeoutWithSubscriber.dispatchTimeout = function (subscriber) { + var withObservable = subscriber.withObservable; + subscriber._unsubscribeAndRecycle(); + subscriber.add(innerSubscribe(withObservable, new SimpleInnerSubscriber(subscriber))); + }; + TimeoutWithSubscriber.prototype.scheduleTimeout = function () { + var action = this.action; + if (action) { + this.action = action.schedule(this, this.waitFor); + } + else { + this.add(this.action = this.scheduler.schedule(TimeoutWithSubscriber.dispatchTimeout, this.waitFor, this)); + } + }; + TimeoutWithSubscriber.prototype._next = function (value) { + if (!this.absoluteTimeout) { + this.scheduleTimeout(); + } + _super.prototype._next.call(this, value); + }; + TimeoutWithSubscriber.prototype._unsubscribe = function () { + this.action = undefined; + this.scheduler = null; + this.withObservable = null; + }; + return TimeoutWithSubscriber; + }(SimpleOuterSubscriber)); + + function timeout(due, scheduler) { + if (scheduler === void 0) { scheduler = async; } + return timeoutWith(due, throwError(new TimeoutError()), scheduler); + } + + function timestamp(scheduler) { + if (scheduler === void 0) { scheduler = async; } + return map(function (value) { return new Timestamp(value, scheduler.now()); }); + } + var Timestamp = (function () { + function Timestamp(value, timestamp) { + this.value = value; + this.timestamp = timestamp; + } + return Timestamp; + }()); + + function toArrayReducer(arr, item, index) { + if (index === 0) { + return [item]; + } + arr.push(item); + return arr; + } + function toArray() { + return reduce(toArrayReducer, []); + } + + function window$1(windowBoundaries) { + return function windowOperatorFunction(source) { + return source.lift(new WindowOperator(windowBoundaries)); + }; + } + var WindowOperator = (function () { + function WindowOperator(windowBoundaries) { + this.windowBoundaries = windowBoundaries; + } + WindowOperator.prototype.call = function (subscriber, source) { + var windowSubscriber = new WindowSubscriber(subscriber); + var sourceSubscription = source.subscribe(windowSubscriber); + if (!sourceSubscription.closed) { + windowSubscriber.add(innerSubscribe(this.windowBoundaries, new SimpleInnerSubscriber(windowSubscriber))); + } + return sourceSubscription; + }; + return WindowOperator; + }()); + var WindowSubscriber = (function (_super) { + __extends(WindowSubscriber, _super); + function WindowSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.window = new Subject(); + destination.next(_this.window); + return _this; + } + WindowSubscriber.prototype.notifyNext = function () { + this.openWindow(); + }; + WindowSubscriber.prototype.notifyError = function (error) { + this._error(error); + }; + WindowSubscriber.prototype.notifyComplete = function () { + this._complete(); + }; + WindowSubscriber.prototype._next = function (value) { + this.window.next(value); + }; + WindowSubscriber.prototype._error = function (err) { + this.window.error(err); + this.destination.error(err); + }; + WindowSubscriber.prototype._complete = function () { + this.window.complete(); + this.destination.complete(); + }; + WindowSubscriber.prototype._unsubscribe = function () { + this.window = null; + }; + WindowSubscriber.prototype.openWindow = function () { + var prevWindow = this.window; + if (prevWindow) { + prevWindow.complete(); + } + var destination = this.destination; + var newWindow = this.window = new Subject(); + destination.next(newWindow); + }; + return WindowSubscriber; + }(SimpleOuterSubscriber)); + + function windowCount(windowSize, startWindowEvery) { + if (startWindowEvery === void 0) { startWindowEvery = 0; } + return function windowCountOperatorFunction(source) { + return source.lift(new WindowCountOperator(windowSize, startWindowEvery)); + }; + } + var WindowCountOperator = (function () { + function WindowCountOperator(windowSize, startWindowEvery) { + this.windowSize = windowSize; + this.startWindowEvery = startWindowEvery; + } + WindowCountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowCountSubscriber(subscriber, this.windowSize, this.startWindowEvery)); + }; + return WindowCountOperator; + }()); + var WindowCountSubscriber = (function (_super) { + __extends(WindowCountSubscriber, _super); + function WindowCountSubscriber(destination, windowSize, startWindowEvery) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.windowSize = windowSize; + _this.startWindowEvery = startWindowEvery; + _this.windows = [new Subject()]; + _this.count = 0; + destination.next(_this.windows[0]); + return _this; + } + WindowCountSubscriber.prototype._next = function (value) { + var startWindowEvery = (this.startWindowEvery > 0) ? this.startWindowEvery : this.windowSize; + var destination = this.destination; + var windowSize = this.windowSize; + var windows = this.windows; + var len = windows.length; + for (var i = 0; i < len && !this.closed; i++) { + windows[i].next(value); + } + var c = this.count - windowSize + 1; + if (c >= 0 && c % startWindowEvery === 0 && !this.closed) { + windows.shift().complete(); + } + if (++this.count % startWindowEvery === 0 && !this.closed) { + var window_1 = new Subject(); + windows.push(window_1); + destination.next(window_1); + } + }; + WindowCountSubscriber.prototype._error = function (err) { + var windows = this.windows; + if (windows) { + while (windows.length > 0 && !this.closed) { + windows.shift().error(err); + } + } + this.destination.error(err); + }; + WindowCountSubscriber.prototype._complete = function () { + var windows = this.windows; + if (windows) { + while (windows.length > 0 && !this.closed) { + windows.shift().complete(); + } + } + this.destination.complete(); + }; + WindowCountSubscriber.prototype._unsubscribe = function () { + this.count = 0; + this.windows = null; + }; + return WindowCountSubscriber; + }(Subscriber)); + + function windowTime(windowTimeSpan) { + var scheduler = async; + var windowCreationInterval = null; + var maxWindowSize = Number.POSITIVE_INFINITY; + if (isScheduler(arguments[3])) { + scheduler = arguments[3]; + } + if (isScheduler(arguments[2])) { + scheduler = arguments[2]; + } + else if (isNumeric(arguments[2])) { + maxWindowSize = Number(arguments[2]); + } + if (isScheduler(arguments[1])) { + scheduler = arguments[1]; + } + else if (isNumeric(arguments[1])) { + windowCreationInterval = Number(arguments[1]); + } + return function windowTimeOperatorFunction(source) { + return source.lift(new WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler)); + }; + } + var WindowTimeOperator = (function () { + function WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { + this.windowTimeSpan = windowTimeSpan; + this.windowCreationInterval = windowCreationInterval; + this.maxWindowSize = maxWindowSize; + this.scheduler = scheduler; + } + WindowTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowTimeSubscriber(subscriber, this.windowTimeSpan, this.windowCreationInterval, this.maxWindowSize, this.scheduler)); + }; + return WindowTimeOperator; + }()); + var CountedSubject = (function (_super) { + __extends(CountedSubject, _super); + function CountedSubject() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this._numberOfNextedValues = 0; + return _this; + } + CountedSubject.prototype.next = function (value) { + this._numberOfNextedValues++; + _super.prototype.next.call(this, value); + }; + Object.defineProperty(CountedSubject.prototype, "numberOfNextedValues", { + get: function () { + return this._numberOfNextedValues; + }, + enumerable: true, + configurable: true + }); + return CountedSubject; + }(Subject)); + var WindowTimeSubscriber = (function (_super) { + __extends(WindowTimeSubscriber, _super); + function WindowTimeSubscriber(destination, windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.windowTimeSpan = windowTimeSpan; + _this.windowCreationInterval = windowCreationInterval; + _this.maxWindowSize = maxWindowSize; + _this.scheduler = scheduler; + _this.windows = []; + var window = _this.openWindow(); + if (windowCreationInterval !== null && windowCreationInterval >= 0) { + var closeState = { subscriber: _this, window: window, context: null }; + var creationState = { windowTimeSpan: windowTimeSpan, windowCreationInterval: windowCreationInterval, subscriber: _this, scheduler: scheduler }; + _this.add(scheduler.schedule(dispatchWindowClose, windowTimeSpan, closeState)); + _this.add(scheduler.schedule(dispatchWindowCreation, windowCreationInterval, creationState)); + } + else { + var timeSpanOnlyState = { subscriber: _this, window: window, windowTimeSpan: windowTimeSpan }; + _this.add(scheduler.schedule(dispatchWindowTimeSpanOnly, windowTimeSpan, timeSpanOnlyState)); + } + return _this; + } + WindowTimeSubscriber.prototype._next = function (value) { + var windows = this.windows; + var len = windows.length; + for (var i = 0; i < len; i++) { + var window_1 = windows[i]; + if (!window_1.closed) { + window_1.next(value); + if (window_1.numberOfNextedValues >= this.maxWindowSize) { + this.closeWindow(window_1); + } + } + } + }; + WindowTimeSubscriber.prototype._error = function (err) { + var windows = this.windows; + while (windows.length > 0) { + windows.shift().error(err); + } + this.destination.error(err); + }; + WindowTimeSubscriber.prototype._complete = function () { + var windows = this.windows; + while (windows.length > 0) { + var window_2 = windows.shift(); + if (!window_2.closed) { + window_2.complete(); + } + } + this.destination.complete(); + }; + WindowTimeSubscriber.prototype.openWindow = function () { + var window = new CountedSubject(); + this.windows.push(window); + var destination = this.destination; + destination.next(window); + return window; + }; + WindowTimeSubscriber.prototype.closeWindow = function (window) { + window.complete(); + var windows = this.windows; + windows.splice(windows.indexOf(window), 1); + }; + return WindowTimeSubscriber; + }(Subscriber)); + function dispatchWindowTimeSpanOnly(state) { + var subscriber = state.subscriber, windowTimeSpan = state.windowTimeSpan, window = state.window; + if (window) { + subscriber.closeWindow(window); + } + state.window = subscriber.openWindow(); + this.schedule(state, windowTimeSpan); + } + function dispatchWindowCreation(state) { + var windowTimeSpan = state.windowTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler, windowCreationInterval = state.windowCreationInterval; + var window = subscriber.openWindow(); + var action = this; + var context = { action: action, subscription: null }; + var timeSpanState = { subscriber: subscriber, window: window, context: context }; + context.subscription = scheduler.schedule(dispatchWindowClose, windowTimeSpan, timeSpanState); + action.add(context.subscription); + action.schedule(state, windowCreationInterval); + } + function dispatchWindowClose(state) { + var subscriber = state.subscriber, window = state.window, context = state.context; + if (context && context.action && context.subscription) { + context.action.remove(context.subscription); + } + subscriber.closeWindow(window); + } + + function windowToggle(openings, closingSelector) { + return function (source) { return source.lift(new WindowToggleOperator(openings, closingSelector)); }; + } + var WindowToggleOperator = (function () { + function WindowToggleOperator(openings, closingSelector) { + this.openings = openings; + this.closingSelector = closingSelector; + } + WindowToggleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowToggleSubscriber(subscriber, this.openings, this.closingSelector)); + }; + return WindowToggleOperator; + }()); + var WindowToggleSubscriber = (function (_super) { + __extends(WindowToggleSubscriber, _super); + function WindowToggleSubscriber(destination, openings, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.openings = openings; + _this.closingSelector = closingSelector; + _this.contexts = []; + _this.add(_this.openSubscription = subscribeToResult(_this, openings, openings)); + return _this; + } + WindowToggleSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + if (contexts) { + var len = contexts.length; + for (var i = 0; i < len; i++) { + contexts[i].window.next(value); + } + } + }; + WindowToggleSubscriber.prototype._error = function (err) { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_1 = contexts[index]; + context_1.window.error(err); + context_1.subscription.unsubscribe(); + } + } + _super.prototype._error.call(this, err); + }; + WindowToggleSubscriber.prototype._complete = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_2 = contexts[index]; + context_2.window.complete(); + context_2.subscription.unsubscribe(); + } + } + _super.prototype._complete.call(this); + }; + WindowToggleSubscriber.prototype._unsubscribe = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_3 = contexts[index]; + context_3.window.unsubscribe(); + context_3.subscription.unsubscribe(); + } + } + }; + WindowToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + if (outerValue === this.openings) { + var closingNotifier = void 0; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(innerValue); + } + catch (e) { + return this.error(e); + } + var window_1 = new Subject(); + var subscription = new Subscription(); + var context_4 = { window: window_1, subscription: subscription }; + this.contexts.push(context_4); + var innerSubscription = subscribeToResult(this, closingNotifier, context_4); + if (innerSubscription.closed) { + this.closeWindow(this.contexts.length - 1); + } + else { + innerSubscription.context = context_4; + subscription.add(innerSubscription); + } + this.destination.next(window_1); + } + else { + this.closeWindow(this.contexts.indexOf(outerValue)); + } + }; + WindowToggleSubscriber.prototype.notifyError = function (err) { + this.error(err); + }; + WindowToggleSubscriber.prototype.notifyComplete = function (inner) { + if (inner !== this.openSubscription) { + this.closeWindow(this.contexts.indexOf(inner.context)); + } + }; + WindowToggleSubscriber.prototype.closeWindow = function (index) { + if (index === -1) { + return; + } + var contexts = this.contexts; + var context = contexts[index]; + var window = context.window, subscription = context.subscription; + contexts.splice(index, 1); + window.complete(); + subscription.unsubscribe(); + }; + return WindowToggleSubscriber; + }(OuterSubscriber)); + + function windowWhen(closingSelector) { + return function windowWhenOperatorFunction(source) { + return source.lift(new WindowOperator$1(closingSelector)); + }; + } + var WindowOperator$1 = (function () { + function WindowOperator(closingSelector) { + this.closingSelector = closingSelector; + } + WindowOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowSubscriber$1(subscriber, this.closingSelector)); + }; + return WindowOperator; + }()); + var WindowSubscriber$1 = (function (_super) { + __extends(WindowSubscriber, _super); + function WindowSubscriber(destination, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.closingSelector = closingSelector; + _this.openWindow(); + return _this; + } + WindowSubscriber.prototype.notifyNext = function (_outerValue, _innerValue, _outerIndex, _innerIndex, innerSub) { + this.openWindow(innerSub); + }; + WindowSubscriber.prototype.notifyError = function (error) { + this._error(error); + }; + WindowSubscriber.prototype.notifyComplete = function (innerSub) { + this.openWindow(innerSub); + }; + WindowSubscriber.prototype._next = function (value) { + this.window.next(value); + }; + WindowSubscriber.prototype._error = function (err) { + this.window.error(err); + this.destination.error(err); + this.unsubscribeClosingNotification(); + }; + WindowSubscriber.prototype._complete = function () { + this.window.complete(); + this.destination.complete(); + this.unsubscribeClosingNotification(); + }; + WindowSubscriber.prototype.unsubscribeClosingNotification = function () { + if (this.closingNotification) { + this.closingNotification.unsubscribe(); + } + }; + WindowSubscriber.prototype.openWindow = function (innerSub) { + if (innerSub === void 0) { innerSub = null; } + if (innerSub) { + this.remove(innerSub); + innerSub.unsubscribe(); + } + var prevWindow = this.window; + if (prevWindow) { + prevWindow.complete(); + } + var window = this.window = new Subject(); + this.destination.next(window); + var closingNotifier; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(); + } + catch (e) { + this.destination.error(e); + this.window.error(e); + return; + } + this.add(this.closingNotification = subscribeToResult(this, closingNotifier)); + }; + return WindowSubscriber; + }(OuterSubscriber)); + + function withLatestFrom() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return function (source) { + var project; + if (typeof args[args.length - 1] === 'function') { + project = args.pop(); + } + var observables = args; + return source.lift(new WithLatestFromOperator(observables, project)); + }; + } + var WithLatestFromOperator = (function () { + function WithLatestFromOperator(observables, project) { + this.observables = observables; + this.project = project; + } + WithLatestFromOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project)); + }; + return WithLatestFromOperator; + }()); + var WithLatestFromSubscriber = (function (_super) { + __extends(WithLatestFromSubscriber, _super); + function WithLatestFromSubscriber(destination, observables, project) { + var _this = _super.call(this, destination) || this; + _this.observables = observables; + _this.project = project; + _this.toRespond = []; + var len = observables.length; + _this.values = new Array(len); + for (var i = 0; i < len; i++) { + _this.toRespond.push(i); + } + for (var i = 0; i < len; i++) { + var observable = observables[i]; + _this.add(subscribeToResult(_this, observable, undefined, i)); + } + return _this; + } + WithLatestFromSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) { + this.values[outerIndex] = innerValue; + var toRespond = this.toRespond; + if (toRespond.length > 0) { + var found = toRespond.indexOf(outerIndex); + if (found !== -1) { + toRespond.splice(found, 1); + } + } + }; + WithLatestFromSubscriber.prototype.notifyComplete = function () { + }; + WithLatestFromSubscriber.prototype._next = function (value) { + if (this.toRespond.length === 0) { + var args = [value].concat(this.values); + if (this.project) { + this._tryProject(args); + } + else { + this.destination.next(args); + } + } + }; + WithLatestFromSubscriber.prototype._tryProject = function (args) { + var result; + try { + result = this.project.apply(this, args); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return WithLatestFromSubscriber; + }(OuterSubscriber)); + + function zip$1() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return function zipOperatorFunction(source) { + return source.lift.call(zip.apply(void 0, [source].concat(observables))); + }; + } + + function zipAll(project) { + return function (source) { return source.lift(new ZipOperator(project)); }; + } + + + + var _operators = /*#__PURE__*/Object.freeze({ + audit: audit, + auditTime: auditTime, + buffer: buffer, + bufferCount: bufferCount, + bufferTime: bufferTime, + bufferToggle: bufferToggle, + bufferWhen: bufferWhen, + catchError: catchError, + combineAll: combineAll, + combineLatest: combineLatest$1, + concat: concat$1, + concatAll: concatAll, + concatMap: concatMap, + concatMapTo: concatMapTo, + count: count, + debounce: debounce, + debounceTime: debounceTime, + defaultIfEmpty: defaultIfEmpty, + delay: delay, + delayWhen: delayWhen, + dematerialize: dematerialize, + distinct: distinct, + distinctUntilChanged: distinctUntilChanged, + distinctUntilKeyChanged: distinctUntilKeyChanged, + elementAt: elementAt, + endWith: endWith, + every: every, + exhaust: exhaust, + exhaustMap: exhaustMap, + expand: expand, + filter: filter, + finalize: finalize, + find: find, + findIndex: findIndex, + first: first, + groupBy: groupBy, + ignoreElements: ignoreElements, + isEmpty: isEmpty, + last: last, + map: map, + mapTo: mapTo, + materialize: materialize, + max: max, + merge: merge$1, + mergeAll: mergeAll, + mergeMap: mergeMap, + flatMap: flatMap, + mergeMapTo: mergeMapTo, + mergeScan: mergeScan, + min: min, + multicast: multicast, + observeOn: observeOn, + onErrorResumeNext: onErrorResumeNext$1, + pairwise: pairwise, + partition: partition$1, + pluck: pluck, + publish: publish, + publishBehavior: publishBehavior, + publishLast: publishLast, + publishReplay: publishReplay, + race: race$1, + reduce: reduce, + repeat: repeat, + repeatWhen: repeatWhen, + retry: retry, + retryWhen: retryWhen, + refCount: refCount, + sample: sample, + sampleTime: sampleTime, + scan: scan, + sequenceEqual: sequenceEqual, + share: share, + shareReplay: shareReplay, + single: single, + skip: skip, + skipLast: skipLast, + skipUntil: skipUntil, + skipWhile: skipWhile, + startWith: startWith, + subscribeOn: subscribeOn, + switchAll: switchAll, + switchMap: switchMap, + switchMapTo: switchMapTo, + take: take, + takeLast: takeLast, + takeUntil: takeUntil, + takeWhile: takeWhile, + tap: tap, + throttle: throttle, + throttleTime: throttleTime, + throwIfEmpty: throwIfEmpty, + timeInterval: timeInterval, + timeout: timeout, + timeoutWith: timeoutWith, + timestamp: timestamp, + toArray: toArray, + window: window$1, + windowCount: windowCount, + windowTime: windowTime, + windowToggle: windowToggle, + windowWhen: windowWhen, + withLatestFrom: withLatestFrom, + zip: zip$1, + zipAll: zipAll + }); + + var SubscriptionLog = (function () { + function SubscriptionLog(subscribedFrame, unsubscribedFrame) { + if (unsubscribedFrame === void 0) { unsubscribedFrame = Number.POSITIVE_INFINITY; } + this.subscribedFrame = subscribedFrame; + this.unsubscribedFrame = unsubscribedFrame; + } + return SubscriptionLog; + }()); + + var SubscriptionLoggable = (function () { + function SubscriptionLoggable() { + this.subscriptions = []; + } + SubscriptionLoggable.prototype.logSubscribedFrame = function () { + this.subscriptions.push(new SubscriptionLog(this.scheduler.now())); + return this.subscriptions.length - 1; + }; + SubscriptionLoggable.prototype.logUnsubscribedFrame = function (index) { + var subscriptionLogs = this.subscriptions; + var oldSubscriptionLog = subscriptionLogs[index]; + subscriptionLogs[index] = new SubscriptionLog(oldSubscriptionLog.subscribedFrame, this.scheduler.now()); + }; + return SubscriptionLoggable; + }()); + + function applyMixins(derivedCtor, baseCtors) { + for (var i = 0, len = baseCtors.length; i < len; i++) { + var baseCtor = baseCtors[i]; + var propertyKeys = Object.getOwnPropertyNames(baseCtor.prototype); + for (var j = 0, len2 = propertyKeys.length; j < len2; j++) { + var name_1 = propertyKeys[j]; + derivedCtor.prototype[name_1] = baseCtor.prototype[name_1]; + } + } + } + + var ColdObservable = (function (_super) { + __extends(ColdObservable, _super); + function ColdObservable(messages, scheduler) { + var _this = _super.call(this, function (subscriber) { + var observable = this; + var index = observable.logSubscribedFrame(); + var subscription = new Subscription(); + subscription.add(new Subscription(function () { + observable.logUnsubscribedFrame(index); + })); + observable.scheduleMessages(subscriber); + return subscription; + }) || this; + _this.messages = messages; + _this.subscriptions = []; + _this.scheduler = scheduler; + return _this; + } + ColdObservable.prototype.scheduleMessages = function (subscriber) { + var messagesLength = this.messages.length; + for (var i = 0; i < messagesLength; i++) { + var message = this.messages[i]; + subscriber.add(this.scheduler.schedule(function (_a) { + var message = _a.message, subscriber = _a.subscriber; + message.notification.observe(subscriber); + }, message.frame, { message: message, subscriber: subscriber })); + } + }; + return ColdObservable; + }(Observable)); + applyMixins(ColdObservable, [SubscriptionLoggable]); + + var HotObservable = (function (_super) { + __extends(HotObservable, _super); + function HotObservable(messages, scheduler) { + var _this = _super.call(this) || this; + _this.messages = messages; + _this.subscriptions = []; + _this.scheduler = scheduler; + return _this; + } + HotObservable.prototype._subscribe = function (subscriber) { + var subject = this; + var index = subject.logSubscribedFrame(); + var subscription = new Subscription(); + subscription.add(new Subscription(function () { + subject.logUnsubscribedFrame(index); + })); + subscription.add(_super.prototype._subscribe.call(this, subscriber)); + return subscription; + }; + HotObservable.prototype.setup = function () { + var subject = this; + var messagesLength = subject.messages.length; + for (var i = 0; i < messagesLength; i++) { + (function () { + var message = subject.messages[i]; + subject.scheduler.schedule(function () { message.notification.observe(subject); }, message.frame); + })(); + } + }; + return HotObservable; + }(Subject)); + applyMixins(HotObservable, [SubscriptionLoggable]); + + var defaultMaxFrame = 750; + var TestScheduler = (function (_super) { + __extends(TestScheduler, _super); + function TestScheduler(assertDeepEqual) { + var _this = _super.call(this, VirtualAction, defaultMaxFrame) || this; + _this.assertDeepEqual = assertDeepEqual; + _this.hotObservables = []; + _this.coldObservables = []; + _this.flushTests = []; + _this.runMode = false; + return _this; + } + TestScheduler.prototype.createTime = function (marbles) { + var indexOf = marbles.indexOf('|'); + if (indexOf === -1) { + throw new Error('marble diagram for time should have a completion marker "|"'); + } + return indexOf * TestScheduler.frameTimeFactor; + }; + TestScheduler.prototype.createColdObservable = function (marbles, values, error) { + if (marbles.indexOf('^') !== -1) { + throw new Error('cold observable cannot have subscription offset "^"'); + } + if (marbles.indexOf('!') !== -1) { + throw new Error('cold observable cannot have unsubscription marker "!"'); + } + var messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode); + var cold = new ColdObservable(messages, this); + this.coldObservables.push(cold); + return cold; + }; + TestScheduler.prototype.createHotObservable = function (marbles, values, error) { + if (marbles.indexOf('!') !== -1) { + throw new Error('hot observable cannot have unsubscription marker "!"'); + } + var messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode); + var subject = new HotObservable(messages, this); + this.hotObservables.push(subject); + return subject; + }; + TestScheduler.prototype.materializeInnerObservable = function (observable, outerFrame) { + var _this = this; + var messages = []; + observable.subscribe(function (value) { + messages.push({ frame: _this.frame - outerFrame, notification: Notification.createNext(value) }); + }, function (err) { + messages.push({ frame: _this.frame - outerFrame, notification: Notification.createError(err) }); + }, function () { + messages.push({ frame: _this.frame - outerFrame, notification: Notification.createComplete() }); + }); + return messages; + }; + TestScheduler.prototype.expectObservable = function (observable, subscriptionMarbles) { + var _this = this; + if (subscriptionMarbles === void 0) { subscriptionMarbles = null; } + var actual = []; + var flushTest = { actual: actual, ready: false }; + var subscriptionParsed = TestScheduler.parseMarblesAsSubscriptions(subscriptionMarbles, this.runMode); + var subscriptionFrame = subscriptionParsed.subscribedFrame === Number.POSITIVE_INFINITY ? + 0 : subscriptionParsed.subscribedFrame; + var unsubscriptionFrame = subscriptionParsed.unsubscribedFrame; + var subscription; + this.schedule(function () { + subscription = observable.subscribe(function (x) { + var value = x; + if (x instanceof Observable) { + value = _this.materializeInnerObservable(value, _this.frame); + } + actual.push({ frame: _this.frame, notification: Notification.createNext(value) }); + }, function (err) { + actual.push({ frame: _this.frame, notification: Notification.createError(err) }); + }, function () { + actual.push({ frame: _this.frame, notification: Notification.createComplete() }); + }); + }, subscriptionFrame); + if (unsubscriptionFrame !== Number.POSITIVE_INFINITY) { + this.schedule(function () { return subscription.unsubscribe(); }, unsubscriptionFrame); + } + this.flushTests.push(flushTest); + var runMode = this.runMode; + return { + toBe: function (marbles, values, errorValue) { + flushTest.ready = true; + flushTest.expected = TestScheduler.parseMarbles(marbles, values, errorValue, true, runMode); + } + }; + }; + TestScheduler.prototype.expectSubscriptions = function (actualSubscriptionLogs) { + var flushTest = { actual: actualSubscriptionLogs, ready: false }; + this.flushTests.push(flushTest); + var runMode = this.runMode; + return { + toBe: function (marbles) { + var marblesArray = (typeof marbles === 'string') ? [marbles] : marbles; + flushTest.ready = true; + flushTest.expected = marblesArray.map(function (marbles) { + return TestScheduler.parseMarblesAsSubscriptions(marbles, runMode); + }); + } + }; + }; + TestScheduler.prototype.flush = function () { + var _this = this; + var hotObservables = this.hotObservables; + while (hotObservables.length > 0) { + hotObservables.shift().setup(); + } + _super.prototype.flush.call(this); + this.flushTests = this.flushTests.filter(function (test) { + if (test.ready) { + _this.assertDeepEqual(test.actual, test.expected); + return false; + } + return true; + }); + }; + TestScheduler.parseMarblesAsSubscriptions = function (marbles, runMode) { + var _this = this; + if (runMode === void 0) { runMode = false; } + if (typeof marbles !== 'string') { + return new SubscriptionLog(Number.POSITIVE_INFINITY); + } + var len = marbles.length; + var groupStart = -1; + var subscriptionFrame = Number.POSITIVE_INFINITY; + var unsubscriptionFrame = Number.POSITIVE_INFINITY; + var frame = 0; + var _loop_1 = function (i) { + var nextFrame = frame; + var advanceFrameBy = function (count) { + nextFrame += count * _this.frameTimeFactor; + }; + var c = marbles[i]; + switch (c) { + case ' ': + if (!runMode) { + advanceFrameBy(1); + } + break; + case '-': + advanceFrameBy(1); + break; + case '(': + groupStart = frame; + advanceFrameBy(1); + break; + case ')': + groupStart = -1; + advanceFrameBy(1); + break; + case '^': + if (subscriptionFrame !== Number.POSITIVE_INFINITY) { + throw new Error('found a second subscription point \'^\' in a ' + + 'subscription marble diagram. There can only be one.'); + } + subscriptionFrame = groupStart > -1 ? groupStart : frame; + advanceFrameBy(1); + break; + case '!': + if (unsubscriptionFrame !== Number.POSITIVE_INFINITY) { + throw new Error('found a second subscription point \'^\' in a ' + + 'subscription marble diagram. There can only be one.'); + } + unsubscriptionFrame = groupStart > -1 ? groupStart : frame; + break; + default: + if (runMode && c.match(/^[0-9]$/)) { + if (i === 0 || marbles[i - 1] === ' ') { + var buffer = marbles.slice(i); + var match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /); + if (match) { + i += match[0].length - 1; + var duration = parseFloat(match[1]); + var unit = match[2]; + var durationInMs = void 0; + switch (unit) { + case 'ms': + durationInMs = duration; + break; + case 's': + durationInMs = duration * 1000; + break; + case 'm': + durationInMs = duration * 1000 * 60; + break; + default: + break; + } + advanceFrameBy(durationInMs / this_1.frameTimeFactor); + break; + } + } + } + throw new Error('there can only be \'^\' and \'!\' markers in a ' + + 'subscription marble diagram. Found instead \'' + c + '\'.'); + } + frame = nextFrame; + out_i_1 = i; + }; + var this_1 = this, out_i_1; + for (var i = 0; i < len; i++) { + _loop_1(i); + i = out_i_1; + } + if (unsubscriptionFrame < 0) { + return new SubscriptionLog(subscriptionFrame); + } + else { + return new SubscriptionLog(subscriptionFrame, unsubscriptionFrame); + } + }; + TestScheduler.parseMarbles = function (marbles, values, errorValue, materializeInnerObservables, runMode) { + var _this = this; + if (materializeInnerObservables === void 0) { materializeInnerObservables = false; } + if (runMode === void 0) { runMode = false; } + if (marbles.indexOf('!') !== -1) { + throw new Error('conventional marble diagrams cannot have the ' + + 'unsubscription marker "!"'); + } + var len = marbles.length; + var testMessages = []; + var subIndex = runMode ? marbles.replace(/^[ ]+/, '').indexOf('^') : marbles.indexOf('^'); + var frame = subIndex === -1 ? 0 : (subIndex * -this.frameTimeFactor); + var getValue = typeof values !== 'object' ? + function (x) { return x; } : + function (x) { + if (materializeInnerObservables && values[x] instanceof ColdObservable) { + return values[x].messages; + } + return values[x]; + }; + var groupStart = -1; + var _loop_2 = function (i) { + var nextFrame = frame; + var advanceFrameBy = function (count) { + nextFrame += count * _this.frameTimeFactor; + }; + var notification = void 0; + var c = marbles[i]; + switch (c) { + case ' ': + if (!runMode) { + advanceFrameBy(1); + } + break; + case '-': + advanceFrameBy(1); + break; + case '(': + groupStart = frame; + advanceFrameBy(1); + break; + case ')': + groupStart = -1; + advanceFrameBy(1); + break; + case '|': + notification = Notification.createComplete(); + advanceFrameBy(1); + break; + case '^': + advanceFrameBy(1); + break; + case '#': + notification = Notification.createError(errorValue || 'error'); + advanceFrameBy(1); + break; + default: + if (runMode && c.match(/^[0-9]$/)) { + if (i === 0 || marbles[i - 1] === ' ') { + var buffer = marbles.slice(i); + var match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /); + if (match) { + i += match[0].length - 1; + var duration = parseFloat(match[1]); + var unit = match[2]; + var durationInMs = void 0; + switch (unit) { + case 'ms': + durationInMs = duration; + break; + case 's': + durationInMs = duration * 1000; + break; + case 'm': + durationInMs = duration * 1000 * 60; + break; + default: + break; + } + advanceFrameBy(durationInMs / this_2.frameTimeFactor); + break; + } + } + } + notification = Notification.createNext(getValue(c)); + advanceFrameBy(1); + break; + } + if (notification) { + testMessages.push({ frame: groupStart > -1 ? groupStart : frame, notification: notification }); + } + frame = nextFrame; + out_i_2 = i; + }; + var this_2 = this, out_i_2; + for (var i = 0; i < len; i++) { + _loop_2(i); + i = out_i_2; + } + return testMessages; + }; + TestScheduler.prototype.run = function (callback) { + var prevFrameTimeFactor = TestScheduler.frameTimeFactor; + var prevMaxFrames = this.maxFrames; + TestScheduler.frameTimeFactor = 1; + this.maxFrames = Number.POSITIVE_INFINITY; + this.runMode = true; + AsyncScheduler.delegate = this; + var helpers = { + cold: this.createColdObservable.bind(this), + hot: this.createHotObservable.bind(this), + flush: this.flush.bind(this), + expectObservable: this.expectObservable.bind(this), + expectSubscriptions: this.expectSubscriptions.bind(this), + }; + try { + var ret = callback(helpers); + this.flush(); + return ret; + } + finally { + TestScheduler.frameTimeFactor = prevFrameTimeFactor; + this.maxFrames = prevMaxFrames; + this.runMode = false; + AsyncScheduler.delegate = undefined; + } + }; + return TestScheduler; + }(VirtualTimeScheduler)); + + + + var _testing = /*#__PURE__*/Object.freeze({ + TestScheduler: TestScheduler + }); + + var __window = typeof window !== 'undefined' && window; + var __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && + self instanceof WorkerGlobalScope && self; + var __global = typeof global !== 'undefined' && global; + var _root = __window || __global || __self; + (function () { + if (!_root) { + throw new Error('RxJS could not find any global context (window, self, global)'); + } + })(); + + function getCORSRequest() { + if (_root.XMLHttpRequest) { + return new _root.XMLHttpRequest(); + } + else if (!!_root.XDomainRequest) { + return new _root.XDomainRequest(); + } + else { + throw new Error('CORS is not supported by your browser'); + } + } + function getXMLHttpRequest() { + if (_root.XMLHttpRequest) { + return new _root.XMLHttpRequest(); + } + else { + var progId = void 0; + try { + var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0']; + for (var i = 0; i < 3; i++) { + try { + progId = progIds[i]; + if (new _root.ActiveXObject(progId)) { + break; + } + } + catch (e) { + } + } + return new _root.ActiveXObject(progId); + } + catch (e) { + throw new Error('XMLHttpRequest is not supported by your browser'); + } + } + } + function ajaxGet(url, headers) { + if (headers === void 0) { headers = null; } + return new AjaxObservable({ method: 'GET', url: url, headers: headers }); + } + function ajaxPost(url, body, headers) { + return new AjaxObservable({ method: 'POST', url: url, body: body, headers: headers }); + } + function ajaxDelete(url, headers) { + return new AjaxObservable({ method: 'DELETE', url: url, headers: headers }); + } + function ajaxPut(url, body, headers) { + return new AjaxObservable({ method: 'PUT', url: url, body: body, headers: headers }); + } + function ajaxPatch(url, body, headers) { + return new AjaxObservable({ method: 'PATCH', url: url, body: body, headers: headers }); + } + var mapResponse = map(function (x, index) { return x.response; }); + function ajaxGetJSON(url, headers) { + return mapResponse(new AjaxObservable({ + method: 'GET', + url: url, + responseType: 'json', + headers: headers + })); + } + var AjaxObservable = (function (_super) { + __extends(AjaxObservable, _super); + function AjaxObservable(urlOrRequest) { + var _this = _super.call(this) || this; + var request = { + async: true, + createXHR: function () { + return this.crossDomain ? getCORSRequest() : getXMLHttpRequest(); + }, + crossDomain: true, + withCredentials: false, + headers: {}, + method: 'GET', + responseType: 'json', + timeout: 0 + }; + if (typeof urlOrRequest === 'string') { + request.url = urlOrRequest; + } + else { + for (var prop in urlOrRequest) { + if (urlOrRequest.hasOwnProperty(prop)) { + request[prop] = urlOrRequest[prop]; + } + } + } + _this.request = request; + return _this; + } + AjaxObservable.prototype._subscribe = function (subscriber) { + return new AjaxSubscriber(subscriber, this.request); + }; + AjaxObservable.create = (function () { + var create = function (urlOrRequest) { + return new AjaxObservable(urlOrRequest); + }; + create.get = ajaxGet; + create.post = ajaxPost; + create.delete = ajaxDelete; + create.put = ajaxPut; + create.patch = ajaxPatch; + create.getJSON = ajaxGetJSON; + return create; + })(); + return AjaxObservable; + }(Observable)); + var AjaxSubscriber = (function (_super) { + __extends(AjaxSubscriber, _super); + function AjaxSubscriber(destination, request) { + var _this = _super.call(this, destination) || this; + _this.request = request; + _this.done = false; + var headers = request.headers = request.headers || {}; + if (!request.crossDomain && !_this.getHeader(headers, 'X-Requested-With')) { + headers['X-Requested-With'] = 'XMLHttpRequest'; + } + var contentTypeHeader = _this.getHeader(headers, 'Content-Type'); + if (!contentTypeHeader && !(_root.FormData && request.body instanceof _root.FormData) && typeof request.body !== 'undefined') { + headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + } + request.body = _this.serializeBody(request.body, _this.getHeader(request.headers, 'Content-Type')); + _this.send(); + return _this; + } + AjaxSubscriber.prototype.next = function (e) { + this.done = true; + var _a = this, xhr = _a.xhr, request = _a.request, destination = _a.destination; + var result; + try { + result = new AjaxResponse(e, xhr, request); + } + catch (err) { + return destination.error(err); + } + destination.next(result); + }; + AjaxSubscriber.prototype.send = function () { + var _a = this, request = _a.request, _b = _a.request, user = _b.user, method = _b.method, url = _b.url, async = _b.async, password = _b.password, headers = _b.headers, body = _b.body; + try { + var xhr = this.xhr = request.createXHR(); + this.setupEvents(xhr, request); + if (user) { + xhr.open(method, url, async, user, password); + } + else { + xhr.open(method, url, async); + } + if (async) { + xhr.timeout = request.timeout; + xhr.responseType = request.responseType; + } + if ('withCredentials' in xhr) { + xhr.withCredentials = !!request.withCredentials; + } + this.setHeaders(xhr, headers); + if (body) { + xhr.send(body); + } + else { + xhr.send(); + } + } + catch (err) { + this.error(err); + } + }; + AjaxSubscriber.prototype.serializeBody = function (body, contentType) { + if (!body || typeof body === 'string') { + return body; + } + else if (_root.FormData && body instanceof _root.FormData) { + return body; + } + if (contentType) { + var splitIndex = contentType.indexOf(';'); + if (splitIndex !== -1) { + contentType = contentType.substring(0, splitIndex); + } + } + switch (contentType) { + case 'application/x-www-form-urlencoded': + return Object.keys(body).map(function (key) { return encodeURIComponent(key) + "=" + encodeURIComponent(body[key]); }).join('&'); + case 'application/json': + return JSON.stringify(body); + default: + return body; + } + }; + AjaxSubscriber.prototype.setHeaders = function (xhr, headers) { + for (var key in headers) { + if (headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, headers[key]); + } + } + }; + AjaxSubscriber.prototype.getHeader = function (headers, headerName) { + for (var key in headers) { + if (key.toLowerCase() === headerName.toLowerCase()) { + return headers[key]; + } + } + return undefined; + }; + AjaxSubscriber.prototype.setupEvents = function (xhr, request) { + var progressSubscriber = request.progressSubscriber; + function xhrTimeout(e) { + var _a = xhrTimeout, subscriber = _a.subscriber, progressSubscriber = _a.progressSubscriber, request = _a.request; + if (progressSubscriber) { + progressSubscriber.error(e); + } + var error; + try { + error = new AjaxTimeoutError(this, request); + } + catch (err) { + error = err; + } + subscriber.error(error); + } + xhr.ontimeout = xhrTimeout; + xhrTimeout.request = request; + xhrTimeout.subscriber = this; + xhrTimeout.progressSubscriber = progressSubscriber; + if (xhr.upload && 'withCredentials' in xhr) { + if (progressSubscriber) { + var xhrProgress_1; + xhrProgress_1 = function (e) { + var progressSubscriber = xhrProgress_1.progressSubscriber; + progressSubscriber.next(e); + }; + if (_root.XDomainRequest) { + xhr.onprogress = xhrProgress_1; + } + else { + xhr.upload.onprogress = xhrProgress_1; + } + xhrProgress_1.progressSubscriber = progressSubscriber; + } + var xhrError_1; + xhrError_1 = function (e) { + var _a = xhrError_1, progressSubscriber = _a.progressSubscriber, subscriber = _a.subscriber, request = _a.request; + if (progressSubscriber) { + progressSubscriber.error(e); + } + var error; + try { + error = new AjaxError('ajax error', this, request); + } + catch (err) { + error = err; + } + subscriber.error(error); + }; + xhr.onerror = xhrError_1; + xhrError_1.request = request; + xhrError_1.subscriber = this; + xhrError_1.progressSubscriber = progressSubscriber; + } + function xhrReadyStateChange(e) { + return; + } + xhr.onreadystatechange = xhrReadyStateChange; + xhrReadyStateChange.subscriber = this; + xhrReadyStateChange.progressSubscriber = progressSubscriber; + xhrReadyStateChange.request = request; + function xhrLoad(e) { + var _a = xhrLoad, subscriber = _a.subscriber, progressSubscriber = _a.progressSubscriber, request = _a.request; + if (this.readyState === 4) { + var status_1 = this.status === 1223 ? 204 : this.status; + var response = (this.responseType === 'text' ? (this.response || this.responseText) : this.response); + if (status_1 === 0) { + status_1 = response ? 200 : 0; + } + if (status_1 < 400) { + if (progressSubscriber) { + progressSubscriber.complete(); + } + subscriber.next(e); + subscriber.complete(); + } + else { + if (progressSubscriber) { + progressSubscriber.error(e); + } + var error = void 0; + try { + error = new AjaxError('ajax error ' + status_1, this, request); + } + catch (err) { + error = err; + } + subscriber.error(error); + } + } + } + xhr.onload = xhrLoad; + xhrLoad.subscriber = this; + xhrLoad.progressSubscriber = progressSubscriber; + xhrLoad.request = request; + }; + AjaxSubscriber.prototype.unsubscribe = function () { + var _a = this, done = _a.done, xhr = _a.xhr; + if (!done && xhr && xhr.readyState !== 4 && typeof xhr.abort === 'function') { + xhr.abort(); + } + _super.prototype.unsubscribe.call(this); + }; + return AjaxSubscriber; + }(Subscriber)); + var AjaxResponse = (function () { + function AjaxResponse(originalEvent, xhr, request) { + this.originalEvent = originalEvent; + this.xhr = xhr; + this.request = request; + this.status = xhr.status; + this.responseType = xhr.responseType || request.responseType; + this.response = parseXhrResponse(this.responseType, xhr); + } + return AjaxResponse; + }()); + var AjaxErrorImpl = (function () { + function AjaxErrorImpl(message, xhr, request) { + Error.call(this); + this.message = message; + this.name = 'AjaxError'; + this.xhr = xhr; + this.request = request; + this.status = xhr.status; + this.responseType = xhr.responseType || request.responseType; + this.response = parseXhrResponse(this.responseType, xhr); + return this; + } + AjaxErrorImpl.prototype = Object.create(Error.prototype); + return AjaxErrorImpl; + })(); + var AjaxError = AjaxErrorImpl; + function parseJson(xhr) { + if ('response' in xhr) { + return xhr.responseType ? xhr.response : JSON.parse(xhr.response || xhr.responseText || 'null'); + } + else { + return JSON.parse(xhr.responseText || 'null'); + } + } + function parseXhrResponse(responseType, xhr) { + switch (responseType) { + case 'json': + return parseJson(xhr); + case 'xml': + return xhr.responseXML; + case 'text': + default: + return ('response' in xhr) ? xhr.response : xhr.responseText; + } + } + function AjaxTimeoutErrorImpl(xhr, request) { + AjaxError.call(this, 'ajax timeout', xhr, request); + this.name = 'AjaxTimeoutError'; + return this; + } + var AjaxTimeoutError = AjaxTimeoutErrorImpl; + + var ajax = (function () { return AjaxObservable.create; })(); + + + + var _ajax = /*#__PURE__*/Object.freeze({ + ajax: ajax, + AjaxResponse: AjaxResponse, + AjaxError: AjaxError, + AjaxTimeoutError: AjaxTimeoutError + }); + + var DEFAULT_WEBSOCKET_CONFIG = { + url: '', + deserializer: function (e) { return JSON.parse(e.data); }, + serializer: function (value) { return JSON.stringify(value); }, + }; + var WEBSOCKETSUBJECT_INVALID_ERROR_OBJECT = 'WebSocketSubject.error must be called with an object with an error code, and an optional reason: { code: number, reason: string }'; + var WebSocketSubject = (function (_super) { + __extends(WebSocketSubject, _super); + function WebSocketSubject(urlConfigOrSource, destination) { + var _this = _super.call(this) || this; + if (urlConfigOrSource instanceof Observable) { + _this.destination = destination; + _this.source = urlConfigOrSource; + } + else { + var config = _this._config = __assign({}, DEFAULT_WEBSOCKET_CONFIG); + _this._output = new Subject(); + if (typeof urlConfigOrSource === 'string') { + config.url = urlConfigOrSource; + } + else { + for (var key in urlConfigOrSource) { + if (urlConfigOrSource.hasOwnProperty(key)) { + config[key] = urlConfigOrSource[key]; + } + } + } + if (!config.WebSocketCtor && WebSocket) { + config.WebSocketCtor = WebSocket; + } + else if (!config.WebSocketCtor) { + throw new Error('no WebSocket constructor can be found'); + } + _this.destination = new ReplaySubject(); + } + return _this; + } + WebSocketSubject.prototype.lift = function (operator) { + var sock = new WebSocketSubject(this._config, this.destination); + sock.operator = operator; + sock.source = this; + return sock; + }; + WebSocketSubject.prototype._resetState = function () { + this._socket = null; + if (!this.source) { + this.destination = new ReplaySubject(); + } + this._output = new Subject(); + }; + WebSocketSubject.prototype.multiplex = function (subMsg, unsubMsg, messageFilter) { + var self = this; + return new Observable(function (observer) { + try { + self.next(subMsg()); + } + catch (err) { + observer.error(err); + } + var subscription = self.subscribe(function (x) { + try { + if (messageFilter(x)) { + observer.next(x); + } + } + catch (err) { + observer.error(err); + } + }, function (err) { return observer.error(err); }, function () { return observer.complete(); }); + return function () { + try { + self.next(unsubMsg()); + } + catch (err) { + observer.error(err); + } + subscription.unsubscribe(); + }; + }); + }; + WebSocketSubject.prototype._connectSocket = function () { + var _this = this; + var _a = this._config, WebSocketCtor = _a.WebSocketCtor, protocol = _a.protocol, url = _a.url, binaryType = _a.binaryType; + var observer = this._output; + var socket = null; + try { + socket = protocol ? + new WebSocketCtor(url, protocol) : + new WebSocketCtor(url); + this._socket = socket; + if (binaryType) { + this._socket.binaryType = binaryType; + } + } + catch (e) { + observer.error(e); + return; + } + var subscription = new Subscription(function () { + _this._socket = null; + if (socket && socket.readyState === 1) { + socket.close(); + } + }); + socket.onopen = function (e) { + var _socket = _this._socket; + if (!_socket) { + socket.close(); + _this._resetState(); + return; + } + var openObserver = _this._config.openObserver; + if (openObserver) { + openObserver.next(e); + } + var queue = _this.destination; + _this.destination = Subscriber.create(function (x) { + if (socket.readyState === 1) { + try { + var serializer = _this._config.serializer; + socket.send(serializer(x)); + } + catch (e) { + _this.destination.error(e); + } + } + }, function (e) { + var closingObserver = _this._config.closingObserver; + if (closingObserver) { + closingObserver.next(undefined); + } + if (e && e.code) { + socket.close(e.code, e.reason); + } + else { + observer.error(new TypeError(WEBSOCKETSUBJECT_INVALID_ERROR_OBJECT)); + } + _this._resetState(); + }, function () { + var closingObserver = _this._config.closingObserver; + if (closingObserver) { + closingObserver.next(undefined); + } + socket.close(); + _this._resetState(); + }); + if (queue && queue instanceof ReplaySubject) { + subscription.add(queue.subscribe(_this.destination)); + } + }; + socket.onerror = function (e) { + _this._resetState(); + observer.error(e); + }; + socket.onclose = function (e) { + _this._resetState(); + var closeObserver = _this._config.closeObserver; + if (closeObserver) { + closeObserver.next(e); + } + if (e.wasClean) { + observer.complete(); + } + else { + observer.error(e); + } + }; + socket.onmessage = function (e) { + try { + var deserializer = _this._config.deserializer; + observer.next(deserializer(e)); + } + catch (err) { + observer.error(err); + } + }; + }; + WebSocketSubject.prototype._subscribe = function (subscriber) { + var _this = this; + var source = this.source; + if (source) { + return source.subscribe(subscriber); + } + if (!this._socket) { + this._connectSocket(); + } + this._output.subscribe(subscriber); + subscriber.add(function () { + var _socket = _this._socket; + if (_this._output.observers.length === 0) { + if (_socket && _socket.readyState === 1) { + _socket.close(); + } + _this._resetState(); + } + }); + return subscriber; + }; + WebSocketSubject.prototype.unsubscribe = function () { + var _socket = this._socket; + if (_socket && _socket.readyState === 1) { + _socket.close(); + } + this._resetState(); + _super.prototype.unsubscribe.call(this); + }; + return WebSocketSubject; + }(AnonymousSubject)); + + function webSocket(urlConfigOrSource) { + return new WebSocketSubject(urlConfigOrSource); + } + + + + var _webSocket = /*#__PURE__*/Object.freeze({ + webSocket: webSocket, + WebSocketSubject: WebSocketSubject + }); + + function fromFetch(input, initWithSelector) { + if (initWithSelector === void 0) { initWithSelector = {}; } + var selector = initWithSelector.selector, init = __rest(initWithSelector, ["selector"]); + return new Observable(function (subscriber) { + var controller = new AbortController(); + var signal = controller.signal; + var abortable = true; + var unsubscribed = false; + var subscription = new Subscription(); + subscription.add(function () { + unsubscribed = true; + if (abortable) { + controller.abort(); + } + }); + var perSubscriberInit; + if (init) { + if (init.signal) { + if (init.signal.aborted) { + controller.abort(); + } + else { + var outerSignal_1 = init.signal; + var outerSignalHandler_1 = function () { + if (!signal.aborted) { + controller.abort(); + } + }; + outerSignal_1.addEventListener('abort', outerSignalHandler_1); + subscription.add(function () { return outerSignal_1.removeEventListener('abort', outerSignalHandler_1); }); + } + } + perSubscriberInit = __assign({}, init, { signal: signal }); + } + else { + perSubscriberInit = { signal: signal }; + } + fetch(input, perSubscriberInit).then(function (response) { + if (selector) { + subscription.add(from(selector(response)).subscribe(function (value) { return subscriber.next(value); }, function (err) { + abortable = false; + if (!unsubscribed) { + subscriber.error(err); + } + }, function () { + abortable = false; + subscriber.complete(); + })); + } + else { + abortable = false; + subscriber.next(response); + subscriber.complete(); + } + }).catch(function (err) { + abortable = false; + if (!unsubscribed) { + subscriber.error(err); + } + }); + return subscription; + }); + } + + + + var _fetch = /*#__PURE__*/Object.freeze({ + fromFetch: fromFetch + }); + + var operators = _operators; + var testing = _testing; + var ajax$1 = _ajax; + var webSocket$1 = _webSocket; + var fetch$1 = _fetch; + + exports.operators = operators; + exports.testing = testing; + exports.ajax = ajax$1; + exports.webSocket = webSocket$1; + exports.fetch = fetch$1; + exports.Observable = Observable; + exports.ConnectableObservable = ConnectableObservable; + exports.GroupedObservable = GroupedObservable; + exports.observable = observable; + exports.Subject = Subject; + exports.BehaviorSubject = BehaviorSubject; + exports.ReplaySubject = ReplaySubject; + exports.AsyncSubject = AsyncSubject; + exports.asap = asap; + exports.asapScheduler = asapScheduler; + exports.async = async; + exports.asyncScheduler = asyncScheduler; + exports.queue = queue; + exports.queueScheduler = queueScheduler; + exports.animationFrame = animationFrame; + exports.animationFrameScheduler = animationFrameScheduler; + exports.VirtualTimeScheduler = VirtualTimeScheduler; + exports.VirtualAction = VirtualAction; + exports.Scheduler = Scheduler; + exports.Subscription = Subscription; + exports.Subscriber = Subscriber; + exports.Notification = Notification; + exports.pipe = pipe; + exports.noop = noop; + exports.identity = identity; + exports.isObservable = isObservable; + exports.ArgumentOutOfRangeError = ArgumentOutOfRangeError; + exports.EmptyError = EmptyError; + exports.ObjectUnsubscribedError = ObjectUnsubscribedError; + exports.UnsubscriptionError = UnsubscriptionError; + exports.TimeoutError = TimeoutError; + exports.bindCallback = bindCallback; + exports.bindNodeCallback = bindNodeCallback; + exports.combineLatest = combineLatest; + exports.concat = concat; + exports.defer = defer; + exports.empty = empty$1; + exports.forkJoin = forkJoin; + exports.from = from; + exports.fromEvent = fromEvent; + exports.fromEventPattern = fromEventPattern; + exports.generate = generate; + exports.iif = iif; + exports.interval = interval; + exports.merge = merge; + exports.never = never; + exports.of = of; + exports.onErrorResumeNext = onErrorResumeNext; + exports.pairs = pairs; + exports.partition = partition; + exports.race = race; + exports.range = range; + exports.throwError = throwError; + exports.timer = timer; + exports.using = using; + exports.zip = zip; + exports.scheduled = scheduled; + exports.EMPTY = EMPTY; + exports.NEVER = NEVER; + exports.config = config; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); + +//# sourceMappingURL=rxjs.umd.js.map \ No newline at end of file diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraControlCommandV2Screen.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraControlCommandV2Screen.kt new file mode 100755 index 0000000..8851287 --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraControlCommandV2Screen.kt @@ -0,0 +1,67 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme.ThetaSimpleAndroidAppTheme + +/** + * Camera status screen. + */ +@Composable +fun CameraControlCommandV2Screen( + viewModel: ThetaViewModel, +) { + val infoText: String by viewModel.infoText.observeAsState("") + + ThetaSimpleAndroidAppTheme { + Scaffold( + topBar = { + TopAppBar(title = { + Text("Camera Control Command V2") + }) + }, + ) { + Column( + Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Button(onClick = { + viewModel.cameraControlCommandV2GetInfo() + }) { + Text("Get Info") + } + Button(onClick = { + viewModel.cameraControlCommandV2GetState() + }) { + Text("Get State") + } + Button(onClick = { + viewModel.cameraControlCommandV2GetState2() + }) { + Text("Get State2") + } + Button(onClick = { + viewModel.cameraControlCommandV2SetStateNotify() + }) { + Text("Set State Notify") + } + + Column(modifier = Modifier.fillMaxHeight()) { + Text(text = "\n$infoText") + } + } + } + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraStatusScreen.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraStatusScreen.kt new file mode 100755 index 0000000..fc07ecc --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/CameraStatusScreen.kt @@ -0,0 +1,136 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.ricoh360.thetableclient.service.data.ble.PluginControl +import com.ricoh360.thetableclient.service.data.values.CameraPower +import com.ricoh360.thetableclient.service.data.values.ChargingState +import com.ricoh360.thetableclient.service.data.values.PluginPowerStatus +import com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme.ThetaSimpleAndroidAppTheme + +/** + * Camera status screen. + */ +@Composable +fun CameraStatusScreen( + viewModel: ThetaViewModel, +) { + val padding = 10.dp + + val infoText: String by viewModel.infoText.observeAsState("") + val batteryLevel: Int by viewModel.batteryLevel.observeAsState(0) + val batteryStatus: ChargingState? by viewModel.batteryStatus.observeAsState() + val cameraPower: CameraPower? by viewModel.cameraPower.observeAsState() + val pluginControl: PluginControl? by viewModel.pluginControl.observeAsState() + + ThetaSimpleAndroidAppTheme { + Scaffold( + topBar = { + TopAppBar(title = { + Text("Camera status") + }) + }, + ) { + Column( + Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "Battery level: $batteryLevel") + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.updateBatteryLevel() + }) { + Text("Update") + } + } + + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "Battery status: ${batteryStatus?.name}") + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.updateBatteryStatus() + }) { + Text("Update") + } + } + + Column { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "Camera power: ${cameraPower?.name}") + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.updateCameraPower() + }) { + Text("Update") + } + } + Row { + Button(onClick = { + viewModel.setCameraPower(CameraPower.OFF) + }) { + Text("Off") + } + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.setCameraPower(CameraPower.ON) + }) { + Text("On") + } + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.setCameraPower(CameraPower.SLEEP) + }) { + Text("Sleep") + } + } + } + + Column { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "Plugin control: ${pluginControl?.pluginControl?.name}") + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.updatePluginControl() + }) { + Text("Update") + } + } + Row { + Button(onClick = { + viewModel.setPluginControl(PluginPowerStatus.STOP) + }) { + Text("Stop") + } + Spacer(modifier = Modifier.size(padding)) + Button(onClick = { + viewModel.setPluginControl(PluginPowerStatus.RUNNING) + }) { + Text("Running") + } + } + } + + Text(text = "\n$infoText") + } + } + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainActivity.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainActivity.kt new file mode 100755 index 0000000..2e9e8a9 --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainActivity.kt @@ -0,0 +1,106 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController + +const val REQUEST_MULTI_PERMISSIONS = 101 +const val APP_UUID = "6BEDD7A3-4E01-4FE4-9DFB-03BFF23ECFD3" +const val PREFERENCES_NAME = "demoBleApp" +const val KEY_LAST_DEVICE_NAME = "lastDeviceName" +const val KEY_LAST_USE_UUID = "lastUseUuid" + +class MainActivity : ComponentActivity() { + private lateinit var sharedViewModel: ThetaViewModel + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + sharedViewModel = ViewModelProvider(this)[ThetaViewModel::class.java] + + setContent { + val navController = rememberNavController() + NavHost(navController = navController, startDestination = "mainScreen") { + composable("mainScreen") { + MainScreen( + toCameraStatus = { navController.navigate("cameraStatusScreen") }, + toCameraControlCommandV2 = { navController.navigate("cameraControlCommandV2") }, + sharedViewModel, + ) + } + composable("cameraStatusScreen") { + CameraStatusScreen(sharedViewModel) + } + composable("cameraControlCommandV2") { + CameraControlCommandV2Screen(sharedViewModel) + } + navController.addOnDestinationChangedListener { _, destination, _ -> + when (destination.route) { + "mainScreen" -> { + sharedViewModel.cameraControlCommandV2ClearStateNotify() + } + } + } + } + } + + sharedViewModel.isConnected.observe(this) { + if (it) { + saveDevice() + } + } + + checkPermissions() + + loadDevice() + } + + private fun saveDevice() { + val preferences = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + val editor = preferences.edit() + editor.putString(KEY_LAST_DEVICE_NAME, sharedViewModel.deviceName.value) + editor.putBoolean(KEY_LAST_USE_UUID, sharedViewModel.useUuid.value ?: true) + editor.apply() + } + + private fun loadDevice() { + val preferences = getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + when (val deviceName = preferences.getString(KEY_LAST_DEVICE_NAME, null)) { + null -> { + sharedViewModel.setInfoText("Please connect wifi.") + } + + else -> { + val useUuid = preferences.getBoolean(KEY_LAST_USE_UUID, true) + sharedViewModel.setDevice(deviceName, useUuid) + } + } + } + + private fun checkPermissions(): Boolean { + val requestPermissions = mutableListOf() + // Bluetooth + if (Build.VERSION.SDK_INT > 30) { + if (checkSelfPermission(android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + requestPermissions.add(android.Manifest.permission.BLUETOOTH_CONNECT) + } + if (checkSelfPermission(android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { + requestPermissions.add(android.Manifest.permission.BLUETOOTH_SCAN) + } + } else { + if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + requestPermissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION) + } + } + if (requestPermissions.isNotEmpty()) { + requestPermissions(requestPermissions.toTypedArray(), REQUEST_MULTI_PERMISSIONS) + return false + } + return true + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainScreen.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainScreen.kt new file mode 100755 index 0000000..2768ae7 --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/MainScreen.kt @@ -0,0 +1,94 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme.ThetaSimpleAndroidAppTheme + +/** + * Main menu screen. + */ +@Composable +fun MainScreen( + toCameraStatus: (viewModel: ThetaViewModel) -> Unit, + toCameraControlCommandV2: (viewModel: ThetaViewModel) -> Unit, + viewModel: ThetaViewModel, +) { + val infoText: String by viewModel.infoText.observeAsState("") + val deviceName: String? by viewModel.deviceName.observeAsState() + val useUuid: Boolean? by viewModel.useUuid.observeAsState() + ThetaSimpleAndroidAppTheme { + Scaffold( + topBar = { + TopAppBar(title = { + Text(stringResource(id = R.string.app_name)) + }) + }, + ) { + Column( + Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Button(onClick = { + viewModel.connectWifi() + }) { + Text("Connect Wifi") + } + Text(text = "device: $deviceName${if (deviceName != null && useUuid != false) " use uuid" else ""}") + Button( + onClick = { + viewModel.scan() + }, + enabled = deviceName != null + ) { + Text("Scan BLE") + } + Button(onClick = { + viewModel.connect() + }) { + Text("Connect") + } + Button(onClick = { + viewModel.getInfo() + }) { + Text("Info") + } + Button(onClick = { + toCameraStatus(viewModel) + viewModel.checkCameraStatusCommand() + }) { + Text("Camera Status") + } + Button(onClick = { + viewModel.takePicture() + }) { + Text("Take Picture") + } + Button(onClick = { + toCameraControlCommandV2(viewModel) + viewModel.checkCameraControlCommandV2() + }) { + Text("Camera Control Command V2") + } + Button(onClick = { + viewModel.disconnect() + }) { + Text("Disconnect") + } + + Text(text = "\n$infoText") + } + } + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaSdkSampleApp.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaSdkSampleApp.kt new file mode 100755 index 0000000..92bc9ef --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaSdkSampleApp.kt @@ -0,0 +1,13 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import android.app.Application +import timber.log.Timber + +class ThetaSdkSampleApp : Application() { + override fun onCreate() { + super.onCreate() + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaViewModel.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaViewModel.kt new file mode 100644 index 0000000..a47cf3c --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ThetaViewModel.kt @@ -0,0 +1,657 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ricoh360.thetaclient.ThetaRepository +import com.ricoh360.thetableclient.ThetaBle +import com.ricoh360.thetableclient.service.CameraStatusCommand +import com.ricoh360.thetableclient.service.data.GpsInfo +import com.ricoh360.thetableclient.service.data.ThetaState +import com.ricoh360.thetableclient.service.data.ble.PluginControl +import com.ricoh360.thetableclient.service.data.values.CameraPower +import com.ricoh360.thetableclient.service.data.values.CaptureMode +import com.ricoh360.thetableclient.service.data.values.ChargingState +import com.ricoh360.thetableclient.service.data.values.PluginPowerStatus +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class ThetaViewModel : ViewModel() { + private val _infoText = MutableLiveData("Initialized") + val infoText: LiveData = _infoText + private val _batteryLevel = MutableLiveData(0) + val batteryLevel: LiveData = _batteryLevel + private val _batteryStatus = MutableLiveData() + val batteryStatus: LiveData = _batteryStatus + private val _cameraPower = MutableLiveData() + val cameraPower: LiveData = _cameraPower + private val _pluginControl = MutableLiveData() + val pluginControl: LiveData = _pluginControl + + private var _deviceName = MutableLiveData() + val deviceName: LiveData = _deviceName + private val _useUuid = MutableLiveData(true) + val useUuid: LiveData = _useUuid + private val _isConnected = MutableLiveData(false) + val isConnected: LiveData = _isConnected + + private val scope = CoroutineScope(Dispatchers.Default) + private val uuid = APP_UUID + private var thetaDevice: ThetaBle.ThetaDevice? = null + + fun connectWifi() { + scope.launch { + var thetaRepository: ThetaRepository? = null + try { + thetaRepository = ThetaRepository.newInstance("http://192.168.1.1") + thetaRepository.let { + val info = it.getThetaInfo() + val devName = info.serialNumber.takeLast(8) + setDevice(devName, false) + setInfoText("wifi connected. $devName") + } + } catch (e: Throwable) { + e.printStackTrace() + } + try { + thetaRepository?.let { + val name = it.setBluetoothDevice(uuid) + setDevice(name, true) + } + } catch (e: Throwable) { + e.printStackTrace() + } + try { + thetaRepository?.let { + val options = + ThetaRepository.Options(bluetoothPower = ThetaRepository.BluetoothPowerEnum.ON) + it.setOptions(options) + } + } catch (e: Throwable) { + e.printStackTrace() + } + } + } + + fun setDevice(devName: String, useUuid: Boolean) { + viewModelScope.launch { + _useUuid.value = useUuid + _deviceName.value = devName + } + } + + fun scan() { + scope.launch { + setInfoText("Scanning ${deviceName.value}...") + val timeout = ThetaBle.Timeout( + timeoutScan = 30_000, + timeoutPeripheral = 1_000, + timeoutConnect = 30_000, + timeoutTakePicture = 10_000, + ) + _deviceName.value?.let { + val device = ThetaBle.scan(it, timeout) + if (device == null) { + setInfoText("Error. $it not found.") + return@launch + } + thetaDevice = device + setInfoText("Scan. Found device: $it") + } + } + } + + fun connect() { + scope.launch { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + setLiveData(_isConnected, false) + return@launch + } + try { + setInfoText("Connecting... ${deviceName.value}") + val uuid = when (useUuid.value) { + false -> null + else -> APP_UUID + } + thetaDevice.connect(uuid) + setLiveData(_isConnected, true) + setInfoText("Connected. ${deviceName.value}") + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + setLiveData(_isConnected, false) + } + + try { + withContext(Dispatchers.IO) { + delay(1000) + thetaDevice.cameraStatusCommand?.let { + setNotifications(it) + } + } + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + private fun setNotifications(service: CameraStatusCommand) { + try { + service.setBatteryStatusNotify { value, error -> + error?.run { + setInfoText("Error battery status notification") + } ?: run { + setInfoText("battery status. ${value?.name}") + setLiveData(_batteryStatus, value) + } + } + } catch (e: ThetaBle.ThetaBleApiException) { + setInfoText("Not support battery status notification") + } + try { + service.setBatteryLevelNotify { value, error -> + error?.run { + setInfoText("Error battery level notification") + } ?: run { + setInfoText("Battery level. $value") + setLiveData(_batteryLevel, value) + } + } + } catch (e: ThetaBle.ThetaBleApiException) { + setInfoText("Not support battery level notification") + } + try { + service.setCameraPowerNotify { value, error -> + error?.run { + setInfoText("Error camera power notification") + } ?: run { + setInfoText("Camera power. ${value?.name}") + setLiveData(_cameraPower, value) + } + } + } catch (e: ThetaBle.ThetaBleApiException) { + setInfoText("Not support camera power notification") + } + try { + service.setCommandErrorDescriptionNotify { value, error -> + error?.run { + setInfoText("Error command error notification") + } ?: run { + setInfoText("Command error. ${value?.name}") + } + } + } catch (e: ThetaBle.ThetaBleApiException) { + setInfoText("Not support command error notification") + } + try { + service.setPluginControlNotify { value, error -> + error?.run { + setInfoText("Error plugin control notification") + } ?: run { + setInfoText("Plugin. ${value?.pluginControl?.name}") + setLiveData(_pluginControl, value) + } + } + } catch (e: ThetaBle.ThetaBleApiException) { + setInfoText("Not support plugin control notification") + } + } + + fun disconnect() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + if (device.isConnected()) { + device.disconnect() + } + setInfoText("Disconnected. ${deviceName.value}") + setLiveData(_isConnected, false) + } + } + + fun getInfo() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraInformation + service ?: run { + setInfoText("Unsupported Camera Information") + return@launch + } + try { + val firmware = service.getFirmwareRevision() + val manuName = service.getManufacturerName() + val model = service.getModelNumber() + val serial = service.getSerialNumber() + val wlanMac = service.getWlanMacAddress() + val bleMac = service.getBluetoothMacAddress() + + + setInfoText("Information\n firmware: $firmware\n maker: $manuName\n model: $model\nserial: $serial\n wlan: $wlanMac\n ble: $bleMac") + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun updateBatteryLevel() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + val value = service.getBatteryLevel() + setLiveData(_batteryLevel, value) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun updateBatteryStatus() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + val value = service.getBatteryStatus() + setLiveData(_batteryStatus, value) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun updateCameraPower() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + val value = service.getCameraPower() + setLiveData(_cameraPower, value) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun setCameraPower(value: CameraPower) { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + service.setCameraPower(value) + setLiveData(_cameraPower, value) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun updatePluginControl() { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + val value = service.getPluginControl() + setLiveData(_pluginControl, value) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + private suspend fun getFirstPlugin(): Int? { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return null + } + val service = device.cameraControlCommands + service ?: run { + setInfoText("Unsupported Camera Status Command") + return null + } + return try { + val orders = service.getPluginOrders() + orders.first + } catch (_: Throwable) { + null + } + } + fun setPluginControl(value: PluginPowerStatus) { + scope.launch { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return@launch + } + val service = device.cameraStatusCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return@launch + } + try { + if (_pluginControl.value == null) { + setInfoText("Error. Not yet acquired") + return@launch + } + if (value == PluginPowerStatus.STOP) { + service.setPluginControl(PluginControl(PluginPowerStatus.STOP, null)) + } else { + val firstPlugin = getFirstPlugin() + if (_pluginControl.value?.plugin != null && firstPlugin != null) { + service.setPluginControl( + PluginControl( + PluginPowerStatus.RUNNING, + firstPlugin, + ), + ) + } else { + service.setPluginControl( + PluginControl( + PluginPowerStatus.RUNNING, + null, + ), + ) + } + } + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun takePicture() { + val device = thetaDevice + device ?: run { + setInfoText("Error. No device.") + return + } + val service = device.shootingControlCommand + service ?: run { + setInfoText("Unsupported Camera Status Command") + return + } + scope.launch { + try { + if (service.getCaptureMode() != CaptureMode.IMAGE) { + setInfoText("Change capture mode...") + service.setCaptureMode(CaptureMode.IMAGE) + delay(1000) // Wait a little or you'll fail + } + setInfoText("Start take a picture.") + service.takePicture { + if (it == null) { + setInfoText("End take a picture.") + } else { + setInfoText("End take a picture. error:\n${it}\n message: ${it.message}") + } + } + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun setInfoText(text: String) { + setLiveData(_infoText, text) + } + + fun checkCameraControlCommandV2() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + if (thetaDevice.cameraControlCommandV2 == null) { + setInfoText("Unsupported CameraControlCommandV2.") + } else { + setInfoText("OK.") + } + } + + fun checkCameraStatusCommand() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + if (thetaDevice.cameraStatusCommand == null) { + setInfoText("Unsupported CameraStatusCommand.") + } else { + setInfoText("OK.") + } + } + + fun cameraControlCommandV2GetInfo() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + val service = thetaDevice.cameraControlCommandV2 + if (service == null) { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + scope.launch { + try { + val thetaInfo = service.getInfo() + val text = """ + info + manufacturer: ${thetaInfo.manufacturer} + model: ${thetaInfo.model.name} + serialNumber: ${thetaInfo.serialNumber} + wlanMacAddress: ${thetaInfo.wlanMacAddress} + bluetoothMacAddress: ${thetaInfo.bluetoothMacAddress} + firmwareVersion: ${thetaInfo.firmwareVersion} + uptime: ${thetaInfo.uptime} + """.trimIndent() + setInfoText(text) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + private fun getStateString(thetaState: ThetaState): String { + var text = "" + thetaState.batteryLevel?.let { + text += "batteryLevel: ${it}\n" + } + thetaState.captureStatus?.let { + text += "captureStatus: ${it}\n" + } + thetaState.recordedTime?.let { + text += "recordedTime: ${it}\n" + } + thetaState.recordableTime?.let { + text += "recordableTime: ${it}\n" + } + thetaState.capturedPictures?.let { + text += "capturedPictures: ${it}\n" + } + thetaState.latestFileUrl?.let { + text += "latestFileUrl: ${it}\n" + } + thetaState.batteryState?.let { + text += "batteryState: ${it}\n" + } + thetaState.function?.let { + text += "function: ${it}\n" + } + thetaState.cameraError?.let { + val errorText = it.joinToString("\n") + text += "cameraError: ${errorText}\n" + } + thetaState.batteryInsert?.let { + text += "batteryInsert: ${it}\n" + } + thetaState.boardTemp?.let { + text += "boardTemp: ${it}\n" + } + thetaState.batteryTemp?.let { + text += "batteryTemp: ${it}\n" + } + return text + } + + private fun getGpsInfoString(gpsInfo: GpsInfo, leftMargin: Int): String { + var text = "" + val margin = " ".repeat(leftMargin) + gpsInfo.lat?.let { + text += margin + "lat: ${it}\n" + } + gpsInfo.lng?.let { + text += margin + "lng: ${it}\n" + } + gpsInfo.altitude?.let { + text += margin + "altitude: ${it}\n" + } + gpsInfo.dateTimeZone?.let { + text += margin + "dateTimeZone: ${it}\n" + } + gpsInfo.datum?.let { + text += margin + "datum: ${it}\n" + } + return text + } + + fun cameraControlCommandV2GetState() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + val service = thetaDevice.cameraControlCommandV2 + if (service == null) { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + scope.launch { + try { + val thetaState = service.getState() + setInfoText("state:\n${getStateString(thetaState)}") + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + fun cameraControlCommandV2SetStateNotify() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + val service = thetaDevice.cameraControlCommandV2 + if (service == null) { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + service.setStateNotify { state, error -> + if (error != null) { + setInfoText("Error. ${error.message}") + } else if (state != null) { + setInfoText("state notify:\n${getStateString(state)}") + } + } + setInfoText("OK. set state notify") + } + + fun cameraControlCommandV2ClearStateNotify() { + val thetaDevice = thetaDevice ?: return + val service = thetaDevice.cameraControlCommandV2 ?: return + service.setStateNotify(null) + } + + fun cameraControlCommandV2GetState2() { + val thetaDevice = thetaDevice + if (thetaDevice == null) { + setInfoText("Error. No device.") + return + } + val service = thetaDevice.cameraControlCommandV2 + if (service == null) { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + scope.launch { + try { + val thetaState2 = service.getState2() + var text = "state2:\n" + thetaState2.externalGpsInfo?.let { stateGpsInfo -> + text += " externalGpsInfo:\n" + stateGpsInfo.gpsInfo?.let { + text += getGpsInfoString(it, 4) + } + } + thetaState2.internalGpsInfo?.let { stateGpsInfo -> + text += " internalGpsInfo:\n" + stateGpsInfo.gpsInfo?.let { + text += getGpsInfoString(it, 4) + } + } + setInfoText(text) + } catch (e: Throwable) { + setInfoText("Error. ${e.message}") + } + } + } + + private fun setLiveData(data: MutableLiveData, value: T) { + viewModelScope.launch { + data.value = value + } + } +} diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Color.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Color.kt new file mode 100755 index 0000000..a60dbe1 --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Shape.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Shape.kt new file mode 100755 index 0000000..8891cd2 --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Theme.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Theme.kt new file mode 100755 index 0000000..f05b24c --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Theme.kt @@ -0,0 +1,47 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun ThetaSimpleAndroidAppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Type.kt b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Type.kt new file mode 100755 index 0000000..331265f --- /dev/null +++ b/demos/demo-android/app/src/main/java/com/ricoh360/thetableclient/thetaBleClientDemo/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.ricoh360.thetableclient.thetaBleClientDemo.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/drawable/ic_launcher_background.xml b/demos/demo-android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100755 index 0000000..07d5da9 --- /dev/null +++ b/demos/demo-android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/demo-android/app/src/main/res/drawable/ic_launcher_foreground.xml b/demos/demo-android/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100755 index 0000000..2b068d1 --- /dev/null +++ b/demos/demo-android/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100755 index 0000000..eca70cf --- /dev/null +++ b/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100755 index 0000000..eca70cf --- /dev/null +++ b/demos/demo-android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100755 index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3 GIT binary patch literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG literal 0 HcmV?d00001 diff --git a/demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/demos/demo-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100755 index 0000000000000000000000000000000000000000..b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9 GIT binary patch literal 2898 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 literal 0 HcmV?d00001 diff --git a/demos/demo-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/demos/demo-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100755 index 0000000000000000000000000000000000000000..4f0f1d64e58ba64d180ce43ee13bf9a17835fbca GIT binary patch literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!TQj4N+cqN`nQhxvX7dAV-`K|Ub$-q+H-5I?Tx0g9jWxd@A|?POE8`3b8fO$T))xP* z(X?&brZw({`)WU&rdAs1iTa0x6F@PIxJ&&L|dpySV!ID|iUhjCcKz(@mE z!x@~W#3H<)4Ae(4eQJRk`Iz3<1)6^m)0b_4_TRZ+cz#eD3f8V;2r-1fE!F}W zEi0MEkTTx}8i1{`l_6vo0(Vuh0HD$I4SjZ=?^?k82R51bC)2D_{y8mi_?X^=U?2|F{Vr7s!k(AZC$O#ZMyavHhlQ7 zUR~QXuH~#o#>(b$u4?s~HLF*3IcF7023AlwAYudn0FV~|odGH^05AYPEfR)8p`i{n zwg3zPVp{+wOsxKc>)(pMupKF!Y2HoUqQ3|Yu|8lwR=?5zZuhG6J?H`bSNk_wPoM{u zSL{c@pY7+c2kck>`^q1^^gR0QB7Y?KUD{vz-uVX~;V-rW)PDcI)$_UjgVV?S?=oLR zf4}zz{#*R_{LkiJ#0RdQLNC^2Vp%JPEUvG9ra2BVZ92(p9h7Ka@!yf9(lj#}>+|u* z;^_?KWdzkM`6gqPo9;;r6&JEa)}R3X{(CWv?NvgLeOTq$cZXqf7|sPImi-7cS8DCN zGf;DVt3Am`>hH3{4-WzH43Ftx)SofNe^-#|0HdCo<+8Qs!}TZP{HH8~z5n`ExcHuT zDL1m&|DVpIy=xsLO>8k92HcmfSKhflQ0H~9=^-{#!I1g(;+44xw~=* zxvNz35vfsQE)@)Zsp*6_GjYD};Squ83<_?^SbALb{a`j<0Gn%6JY!zhp=Fg}Ga2|8 z52e1WU%^L1}15Ex0fF$e@eCT(()_P zvV?CA%#Sy08_U6VPt4EtmVQraWJX` zh=N|WQ>LgrvF~R&qOfB$!%D3cGv?;Xh_z$z7k&s4N)$WYf*k=|*jCEkO19{h_(%W4 zPuOqbCw`SeAX*R}UUsbVsgtuG?xs(#Ikx9`JZoQFz0n*7ZG@Fv@kZk`gzO$HoA9kN z8U5{-yY zvV{`&WKU2$mZeoBmiJrEdzUZAv1sRxpePdg1)F*X^Y)zp^Y*R;;z~vOv-z&)&G)JQ{m!C9cmziu1^nHA z`#`0c>@PnQ9CJKgC5NjJD8HM3|KC(g5nnCq$n0Gsu_DXk36@ql%npEye|?%RmG)

FJ$wK}0tWNB{uH;AM~i literal 0 HcmV?d00001 diff --git a/demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100755 index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0 GIT binary patch literal 1900 zcmV-y2b1_xNk&Fw2LJ$9MM6+kP&il$0000G0001A003VA06|PpNH75a00DqwTbm-~ zullQTcXxO9ki!OCRx^i?oR|n!<8G0=kI^!JSjFi-LL*`V;ET0H2IXfU0*i>o6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? literal 0 HcmV?d00001 diff --git a/demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/demos/demo-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100755 index 0000000000000000000000000000000000000000..1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f GIT binary patch literal 3918 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�(p-{x$&=IACIfoAR!za)F-^da-t3#0Dycnp zwO~NVXwXCl;jE<}>%@xz|=8fIJAB?>+E{7)|4l${4ngA3G|=r z2Dyv;VVWSgZx9Wj>qUjleGl3Ei9K4>h!(lPS%8VOG>Xu0%6VDz^O=bjJmuP7>DeUv zrbI}MlHB^^d?{zv6d=@_ZD2lg1&G7UjnVN{1}9WkaM3H~btX0GtSzB+tZ^qRgWo4m z!GmimlG$=wgXCnr6j@m<1gAL46#T~5Bnm=2{^@>|t&`9mkEPddj zAvG~@Tv~TAm2i%VW}R-g(Z0)z-Y|szHr@rk>4MAyG*Ma*7Yh#H7(!-5>DZ@8r;_dx z{prSe<>~099F8vsYd2xff7uAS%7{S)f(|@me3t2$iy&NEc7OUEchp@9A|X;;IA>8!oX+y(BKJ$EzV* znR$z;!L$s7uy@{OT~nG#B!NRraT8(X##Ho!0r_o@gg0CA-9H^;-uE&?$2$nHv_00o z%cbuUc-tCx$Uh&EZ4Nf4Zgqv)Y6>usG3>GeQnxx_Z6+PcbX-+ysbt1hQ`K1LDpOE? zrAhIZhSN9yVIAOa22gn577tbc&i3|3V8NWy&!tw##`}9*x}gtI^h1DzZRA>UuaJG) zaZ7j)dq!O}{?#8Y7~7i6fHh4{`pL?>-18|p!S75Y#^DM>-S3)vuZG+Q7l@ek zQP~#cBpWgg#mApc_sPYjpw8odQuRokmTkzcNl`^CcKB7e&;zViV;{Y{o^Y$%7i0m# z62%#1Lq!RC?}lK>%mp}T!3Xv;L*0v*>USLm``N%>w>@fwC+#T&Tx2bN4w(20JB}oU zuSa6v^kXi0xPs?pbaOHnyiqq6By1EZY9OZ^^QA>{q-Hsd&m`pbQ%8121aWG-F5xf zlZ%;B{;C>X19|`^_?dVyCq>n+41w7|!tUS!{9rHlbhX=SZO5CQ^;!Du_E7*`GiR^Q w)2!4MKjfSAeNo!9>IaV6aUZ*?W>} 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

UmY2RIYtNPVDpE$%vda+HD#3m z&VuXJ{BK&Qe+rBa7eq}Q(bq|tn(RrJAk|ztj2(i{d>nmQnM?;HF2k&9sA6up5tmjl z7lySlzMbifH17-m-Lwa_F&e7nOH?ESi3#ckR3tsM+jsck3`oG!uMS}|eAwVXv>}qxwq?QY%QJ0}r@^;fhuUA9W z*BVl>TGo&N004@xSiwDUXUvp51sVmqO3m)=B55aPwf@0=e}cN+$-BdKxY`YrT_4)0 z_d10#i44Q*rFr8MC>*)v$EJvz``(pb{e&*6k+b zsMz%($|1+8hn8c2?P(l@;Rb&CsZeYoCI3?2!LqjbwPXW3z4G$Qfj=cT5Yb%vY0(AX oeb?AaKtwrnc|$|zzw9vfvn^aJJ!zd)XFXqqy0000001=f@-~a#s literal 0 HcmV?d00001 diff --git a/demos/demo-android/app/src/main/res/values/colors.xml b/demos/demo-android/app/src/main/res/values/colors.xml new file mode 100755 index 0000000..f8c6127 --- /dev/null +++ b/demos/demo-android/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/values/strings.xml b/demos/demo-android/app/src/main/res/values/strings.xml new file mode 100755 index 0000000..363cd9f --- /dev/null +++ b/demos/demo-android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + demo-android for theta-ble-client + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/values/themes.xml b/demos/demo-android/app/src/main/res/values/themes.xml new file mode 100755 index 0000000..32827d4 --- /dev/null +++ b/demos/demo-android/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/xml/backup_rules.xml b/demos/demo-android/app/src/main/res/xml/backup_rules.xml new file mode 100755 index 0000000..fa0f996 --- /dev/null +++ b/demos/demo-android/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/demos/demo-android/app/src/main/res/xml/data_extraction_rules.xml b/demos/demo-android/app/src/main/res/xml/data_extraction_rules.xml new file mode 100755 index 0000000..9ee9997 --- /dev/null +++ b/demos/demo-android/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/demos/demo-android/build.gradle b/demos/demo-android/build.gradle new file mode 100755 index 0000000..4bcac07 --- /dev/null +++ b/demos/demo-android/build.gradle @@ -0,0 +1,22 @@ +buildscript { + ext { + compose_version = '1.5.3' // depends on Kotlin 1.9.10 + kotlin_version = '1.9.10' + coroutines_version = '1.7.3' + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + } + +} + +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '8.1.2' apply false + id 'com.android.library' version '8.1.2' apply false + id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/demos/demo-android/gradle.properties b/demos/demo-android/gradle.properties new file mode 100755 index 0000000..cd0519b --- /dev/null +++ b/demos/demo-android/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/demos/demo-android/gradle/wrapper/gradle-wrapper.jar b/demos/demo-android/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/demos/demo-android/gradle/wrapper/gradle-wrapper.properties b/demos/demo-android/gradle/wrapper/gradle-wrapper.properties new file mode 100755 index 0000000..4f749d8 --- /dev/null +++ b/demos/demo-android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jul 05 14:22:13 JST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/demos/demo-android/gradlew b/demos/demo-android/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/demos/demo-android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/demos/demo-android/gradlew.bat b/demos/demo-android/gradlew.bat new file mode 100755 index 0000000..ac1b06f --- /dev/null +++ b/demos/demo-android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/demos/demo-android/lint.xml b/demos/demo-android/lint.xml new file mode 100755 index 0000000..7e48ebf --- /dev/null +++ b/demos/demo-android/lint.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/demos/demo-android/settings.gradle b/demos/demo-android/settings.gradle new file mode 100755 index 0000000..46d9a95 --- /dev/null +++ b/demos/demo-android/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "demo-android" +include ':app' diff --git a/demos/demo-ios/.gitignore b/demos/demo-ios/.gitignore new file mode 100644 index 0000000..13b09f2 --- /dev/null +++ b/demos/demo-ios/.gitignore @@ -0,0 +1,13 @@ +Pods +.DS_Store +Podfile.lock +xcuserdata/ +*.xccheckout +*.xcscmblueprint + +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata + +**/xcshareddata/WorkspaceSettings.xcsettings diff --git a/demos/demo-ios/Podfile b/demos/demo-ios/Podfile new file mode 100644 index 0000000..84fb662 --- /dev/null +++ b/demos/demo-ios/Podfile @@ -0,0 +1,12 @@ +# Uncomment the next line to define a global platform for your project +platform :ios, '15.0' + +target 'demo-ios' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for demo-ios + pod 'THETAClient', '1.4.0' + pod 'THETABleClient', '1.0.0' + +end diff --git a/demos/demo-ios/README.ja.md b/demos/demo-ios/README.ja.md new file mode 100644 index 0000000..f13345b --- /dev/null +++ b/demos/demo-ios/README.ja.md @@ -0,0 +1,33 @@ +# iOS demo for theta-ble-client + +A simple sample iOS application using [theta-ble-client](https://github.com/ricohapi/theta-ble-client). + +## 目的 + +* THETA Client BLEを使う開発者に、簡単な実例を示す + +## Functions + +* Connect with THETA at bluetooth. +* Get THETA information. +* Take a photo with Theta. + +## 設計方針 + +* UIの簡潔な記述ができる[SwiftUI](https://developer.apple.com/jp/xcode/swiftui/)を使う + +## 留意点 + +* bundle id、signature情報はご自身のものに変更ください。 +* xcodeでのビルド前にpod installを実行しておくこと。 + Podfileは以下のように、`THETABleClient`を設定している + ``` + platform :ios, '15.0' + target 'demo-ios' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for demo-ios + pod 'THETABleClient' + end + ``` diff --git a/demos/demo-ios/README.md b/demos/demo-ios/README.md new file mode 100644 index 0000000..997f545 --- /dev/null +++ b/demos/demo-ios/README.md @@ -0,0 +1,33 @@ +# iOS demo for theta-ble-client + +A simple sample iOS application using [theta-ble-client](https://github.com/ricohapi/theta-ble-client). + +## Objective + +* Show developers how to use THETA Client BLE. + +## Functions + +* Connect with THETA at bluetooth. +* Get THETA information. +* Take a photo with Theta. + +## Policy + +* Use [SwiftUI](https://developer.apple.com/jp/xcode/swiftui/) that can describe UI simply. + +## Note + +* Change bundle id and signature to your own. +* Before xcode building, execute pod install. Example of Podfile is following: + + ``` + platform :ios, '15.0' + target 'demo-ios' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for demo-ios + pod 'THETABleClient' + end + ``` diff --git a/demos/demo-ios/demo-ios.xcodeproj/project.pbxproj b/demos/demo-ios/demo-ios.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a59f9e7 --- /dev/null +++ b/demos/demo-ios/demo-ios.xcodeproj/project.pbxproj @@ -0,0 +1,434 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 1A5CA7899BC0D829943A7117 /* Pods_demo_ios.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9813411A213924B4238F293E /* Pods_demo_ios.framework */; }; + C9434D072AD63E8100FC7903 /* CameraControlCommandV2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9434D062AD63E8100FC7903 /* CameraControlCommandV2View.swift */; }; + C98E162529C1DABF00054429 /* ThetaBleApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98E162429C1DABF00054429 /* ThetaBleApi.swift */; }; + C993A6F029C1D8ED00E2631D /* demo_iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C993A6EF29C1D8ED00E2631D /* demo_iosApp.swift */; }; + C993A6F229C1D8ED00E2631D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C993A6F129C1D8ED00E2631D /* ContentView.swift */; }; + C993A6F429C1D8F000E2631D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C993A6F329C1D8F000E2631D /* Assets.xcassets */; }; + C993A6F729C1D8F000E2631D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C993A6F629C1D8F000E2631D /* Preview Assets.xcassets */; }; + C9CEC3B829ED350100EA12D5 /* CameraStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CEC3B729ED350100EA12D5 /* CameraStatusView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 44D1D28D01F452A8D0329EF8 /* Pods-demo-ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demo-ios.debug.xcconfig"; path = "Target Support Files/Pods-demo-ios/Pods-demo-ios.debug.xcconfig"; sourceTree = ""; }; + 5B617CB2EB69FF6F4ACAF615 /* Pods-demo-ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demo-ios.release.xcconfig"; path = "Target Support Files/Pods-demo-ios/Pods-demo-ios.release.xcconfig"; sourceTree = ""; }; + 9813411A213924B4238F293E /* Pods_demo_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_demo_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C9434D062AD63E8100FC7903 /* CameraControlCommandV2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraControlCommandV2View.swift; sourceTree = ""; }; + C98E162429C1DABF00054429 /* ThetaBleApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThetaBleApi.swift; sourceTree = ""; }; + C993A6EC29C1D8ED00E2631D /* demo-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "demo-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + C993A6EF29C1D8ED00E2631D /* demo_iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = demo_iosApp.swift; sourceTree = ""; }; + C993A6F129C1D8ED00E2631D /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C993A6F329C1D8F000E2631D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C993A6F629C1D8F000E2631D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + C9CEC3B729ED350100EA12D5 /* CameraStatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraStatusView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C993A6E929C1D8ED00E2631D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A5CA7899BC0D829943A7117 /* Pods_demo_ios.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 51CA0FA6D9A47C2761297472 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9813411A213924B4238F293E /* Pods_demo_ios.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 8CF7916F809E0D0684E29B29 /* Pods */ = { + isa = PBXGroup; + children = ( + 44D1D28D01F452A8D0329EF8 /* Pods-demo-ios.debug.xcconfig */, + 5B617CB2EB69FF6F4ACAF615 /* Pods-demo-ios.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + C993A6E329C1D8ED00E2631D = { + isa = PBXGroup; + children = ( + C993A6EE29C1D8ED00E2631D /* demo-ios */, + C993A6ED29C1D8ED00E2631D /* Products */, + 8CF7916F809E0D0684E29B29 /* Pods */, + 51CA0FA6D9A47C2761297472 /* Frameworks */, + ); + sourceTree = ""; + }; + C993A6ED29C1D8ED00E2631D /* Products */ = { + isa = PBXGroup; + children = ( + C993A6EC29C1D8ED00E2631D /* demo-ios.app */, + ); + name = Products; + sourceTree = ""; + }; + C993A6EE29C1D8ED00E2631D /* demo-ios */ = { + isa = PBXGroup; + children = ( + C98E162429C1DABF00054429 /* ThetaBleApi.swift */, + C993A6EF29C1D8ED00E2631D /* demo_iosApp.swift */, + C993A6F129C1D8ED00E2631D /* ContentView.swift */, + C9434D062AD63E8100FC7903 /* CameraControlCommandV2View.swift */, + C9CEC3B729ED350100EA12D5 /* CameraStatusView.swift */, + C993A6F329C1D8F000E2631D /* Assets.xcassets */, + C993A6F529C1D8F000E2631D /* Preview Content */, + ); + path = "demo-ios"; + sourceTree = ""; + }; + C993A6F529C1D8F000E2631D /* Preview Content */ = { + isa = PBXGroup; + children = ( + C993A6F629C1D8F000E2631D /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C993A6EB29C1D8ED00E2631D /* demo-ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = C993A6FA29C1D8F000E2631D /* Build configuration list for PBXNativeTarget "demo-ios" */; + buildPhases = ( + 2A62176866E7C0BD0A0164AA /* [CP] Check Pods Manifest.lock */, + C993A6E829C1D8ED00E2631D /* Sources */, + C993A6E929C1D8ED00E2631D /* Frameworks */, + C993A6EA29C1D8ED00E2631D /* Resources */, + 4A9BB429D76C02647AE12C50 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "demo-ios"; + productName = "demo-ios"; + productReference = C993A6EC29C1D8ED00E2631D /* demo-ios.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C993A6E429C1D8ED00E2631D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + C993A6EB29C1D8ED00E2631D = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = C993A6E729C1D8ED00E2631D /* Build configuration list for PBXProject "demo-ios" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C993A6E329C1D8ED00E2631D; + productRefGroup = C993A6ED29C1D8ED00E2631D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C993A6EB29C1D8ED00E2631D /* demo-ios */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C993A6EA29C1D8ED00E2631D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C993A6F729C1D8F000E2631D /* Preview Assets.xcassets in Resources */, + C993A6F429C1D8F000E2631D /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2A62176866E7C0BD0A0164AA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-demo-ios-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 4A9BB429D76C02647AE12C50 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios/Pods-demo-ios-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios/Pods-demo-ios-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios/Pods-demo-ios-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C993A6E829C1D8ED00E2631D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C98E162529C1DABF00054429 /* ThetaBleApi.swift in Sources */, + C9CEC3B829ED350100EA12D5 /* CameraStatusView.swift in Sources */, + C993A6F229C1D8ED00E2631D /* ContentView.swift in Sources */, + C993A6F029C1D8ED00E2631D /* demo_iosApp.swift in Sources */, + C9434D072AD63E8100FC7903 /* CameraControlCommandV2View.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C993A6F829C1D8F000E2631D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C993A6F929C1D8F000E2631D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C993A6FB29C1D8F000E2631D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 44D1D28D01F452A8D0329EF8 /* Pods-demo-ios.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"demo-ios/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Use bluetooth"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.ricoh360.thetableclient.demoBle.demo-ios"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C993A6FC29C1D8F000E2631D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B617CB2EB69FF6F4ACAF615 /* Pods-demo-ios.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"demo-ios/Preview Content\""; + DEVELOPMENT_TEAM = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Use bluetooth"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.ricoh360.thetableclient.demoBle.demo-ios"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C993A6E729C1D8ED00E2631D /* Build configuration list for PBXProject "demo-ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C993A6F829C1D8F000E2631D /* Debug */, + C993A6F929C1D8F000E2631D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C993A6FA29C1D8F000E2631D /* Build configuration list for PBXNativeTarget "demo-ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C993A6FB29C1D8F000E2631D /* Debug */, + C993A6FC29C1D8F000E2631D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C993A6E429C1D8ED00E2631D /* Project object */; +} diff --git a/demos/demo-ios/demo-ios.xcworkspace/contents.xcworkspacedata b/demos/demo-ios/demo-ios.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..45f6008 --- /dev/null +++ b/demos/demo-ios/demo-ios.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/demos/demo-ios/demo-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/demo-ios/demo-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/demos/demo-ios/demo-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/demo-ios/demo-ios/Assets.xcassets/AccentColor.colorset/Contents.json b/demos/demo-ios/demo-ios/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/demos/demo-ios/demo-ios/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/demos/demo-ios/demo-ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/demos/demo-ios/demo-ios/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/demos/demo-ios/demo-ios/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/demos/demo-ios/demo-ios/Assets.xcassets/Contents.json b/demos/demo-ios/demo-ios/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/demos/demo-ios/demo-ios/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/demos/demo-ios/demo-ios/CameraControlCommandV2View.swift b/demos/demo-ios/demo-ios/CameraControlCommandV2View.swift new file mode 100644 index 0000000..acc1237 --- /dev/null +++ b/demos/demo-ios/demo-ios/CameraControlCommandV2View.swift @@ -0,0 +1,73 @@ +// +// CameraControlCommandV2View.swift +// demo-ios +// +// Created on 2023/10/11. +// + +import Foundation +import SwiftUI +import THETABleClient + +struct CameraControlCommandV2View: View { + + @ObservedObject var thetaBleApi: ThetaBleApi + + var body: some View { + VStack { + Text("Camera Control Command V2") + .fontWeight(.bold) + + Button("Get Info") { + Task { + try? await thetaBleApi.cameraControlCommandV2GetInfo() + } + } + .buttonStyle(.borderedProminent) + + Button("Get State") { + Task { + try? await thetaBleApi.cameraControlCommandV2GetState() + } + } + .buttonStyle(.borderedProminent) + + Button("Get State2") { + Task { + try? await thetaBleApi.cameraControlCommandV2GetState2() + } + } + .buttonStyle(.borderedProminent) + + Button("Set State Notify") { + Task { + thetaBleApi.cameraControlCommandV2SetStateNotify() + } + } + .buttonStyle(.borderedProminent) + + Text("Information\n\(thetaBleApi.infoText)") + .frame(maxHeight: .infinity, alignment: .top) + } + .padding() + .frame(maxHeight: .infinity) + .onAppear { + thetaBleApi.setInfoText("") + if thetaBleApi.checkCameraControlCommandV2() { + thetaBleApi.setInfoText("OK.") + } else { + thetaBleApi.setInfoText("Unsupported CameraControlCommandV2.") + } + } + .onDisappear { + thetaBleApi.cameraControlCommandV2ClearStateNotify() + thetaBleApi.setInfoText("") + } + } +} + +struct CameraControlCommandV2View_Previews: PreviewProvider { + static var previews: some View { + ContentView( thetaBleApi: ThetaBleApi()) + } +} diff --git a/demos/demo-ios/demo-ios/CameraStatusView.swift b/demos/demo-ios/demo-ios/CameraStatusView.swift new file mode 100644 index 0000000..e168c04 --- /dev/null +++ b/demos/demo-ios/demo-ios/CameraStatusView.swift @@ -0,0 +1,114 @@ +// +// CameraStatusView.swift +// demo-ios +// +// Created on 2023/04/18. +// + +import SwiftUI +import THETABleClient + +struct CameraStatusView: View { + + @ObservedObject var thetaBleApi: ThetaBleApi + + var body: some View { + VStack { + Text("Camera Status") + .fontWeight(.bold) + + HStack { + Text("Battery level: \(thetaBleApi.batteryLevel ?? 0)") + Button("Update") { + Task { + try? await thetaBleApi.updateBatteryLevel() + } + } + .buttonStyle(.borderedProminent) + } + HStack { + Text("Battery status: \(thetaBleApi.batteryStatus?.name ?? "nil")") + Button("Update") { + Task { + try? await thetaBleApi.updateBatteryStatus() + } + } + .buttonStyle(.borderedProminent) + } + VStack { + HStack { + Text("Camera power: \(thetaBleApi.cameraPower?.name ?? "nil")") + Button("Update") { + Task { + try? await thetaBleApi.updateCameraPower() + } + } + .buttonStyle(.borderedProminent) + } + HStack { + Button("Off") { + Task { + try? await thetaBleApi.setCameraPower(value: .off) + } + } + .buttonStyle(.borderedProminent) + Button("On") { + Task { + try? await thetaBleApi.setCameraPower(value: .on) + } + } + .buttonStyle(.borderedProminent) + Button("Sleep") { + Task { + try? await thetaBleApi.setCameraPower(value: .sleep) + } + } + .buttonStyle(.borderedProminent) + } + } + + VStack { + HStack { + Text("Plugin control: \(thetaBleApi.pluginControl?.pluginControl.name ?? "nil")") + Button("Update") { + Task { + try? await thetaBleApi.updatePluginControl() + } + } + .buttonStyle(.borderedProminent) + } + HStack { + Button("Stop") { + Task { + try? await thetaBleApi.setPluginControl(value: .stop) + } + } + .buttonStyle(.borderedProminent) + Button("Running") { + Task { + try? await thetaBleApi.setPluginControl(value: .running) + } + } + .buttonStyle(.borderedProminent) + } + } + + Text("Information\n\(thetaBleApi.infoText)") + } + .padding() + .onAppear { + thetaBleApi.setInfoText("") + if thetaBleApi.checkCameraStatusCommand() { + thetaBleApi.setInfoText("OK.") + } else { + thetaBleApi.setInfoText("Unsupported CameraStatusCommand.") + } + } + } +} + +struct CameraStatusView_Previews: PreviewProvider { + static var previews: some View { + ContentView( thetaBleApi: ThetaBleApi()) + } +} diff --git a/demos/demo-ios/demo-ios/ContentView.swift b/demos/demo-ios/demo-ios/ContentView.swift new file mode 100644 index 0000000..ec69c8a --- /dev/null +++ b/demos/demo-ios/demo-ios/ContentView.swift @@ -0,0 +1,134 @@ +// +// ContentView.swift +// demo-ios +// +// Created on 2023/03/15. +// + +import SwiftUI +import THETAClient +let KEY_LAST_DEVICE_NAME = "lastDeviceName" +let KEY_LAST_USE_UUID = "lastUseUuid" +let endPoint: String = "http://192.168.1.1" + +struct ContentView: View { + + @State var devName: String? + @State var useUuid = true + let uuid = "6BEDD7A3-4E01-4FE4-9DFB-03BFF23ECFD3" + + @ObservedObject var thetaBleApi: ThetaBleApi + + func loadDevice() { + devName = UserDefaults.standard.string(forKey: KEY_LAST_DEVICE_NAME) + useUuid = UserDefaults.standard.bool(forKey: KEY_LAST_USE_UUID) + } + + func saveDevice() { + if let devName { + UserDefaults.standard.set(devName, forKey: KEY_LAST_DEVICE_NAME) + UserDefaults.standard.set(useUuid, forKey: KEY_LAST_USE_UUID) + } + } + + var body: some View { + NavigationView { + VStack { + Text("THETA Client BLE") + .fontWeight(.bold) + Group { + Button("Connect Wifi") { + Task { + guard let theta = try? await ThetaRepository.Companion.shared.doNewInstance(endpoint: endPoint, config: nil, timeout: nil) + else { + thetaBleApi.setInfoText("Error. Connect THETA for wifi.") + return + } + guard let info = try? await theta.getThetaInfo() else { + thetaBleApi.setInfoText("Error. Get THETA info.") + return + } + devName = info.serialNumber.suffix(8).description + if let name = try? await theta.setBluetoothDevice(uuid: uuid) { + useUuid = true + devName = name + } else { + useUuid = false + } + let options = ThetaRepository.Options() + options.bluetoothPower = .on + try? await theta.setOptions(options: options) + + thetaBleApi.setInfoText("wifi connected. \(devName ?? "")") + } + } + .buttonStyle(.borderedProminent) + + Text("device: \(devName ?? "nil") \(devName != nil && useUuid ? " use uuid" : "")") + Button("Scan BLE") { + guard let devName else { return } + Task { + try await thetaBleApi.scan(name: devName) + } + } + .buttonStyle(.borderedProminent) + + Button("Connect") { + Task { + if await thetaBleApi.connect(uuid: useUuid ? uuid : nil) { + saveDevice() + } + } + } + .buttonStyle(.borderedProminent) + + Button("Info") { + Task { + try await thetaBleApi.getInfo() + } + } + .buttonStyle(.borderedProminent) + + NavigationLink(destination: CameraStatusView(thetaBleApi: thetaBleApi)) { + Text("Camera Status") + } + .buttonStyle(.borderedProminent) + + Button("Take Picture") { + Task { + try await thetaBleApi.takePicture() + } + } + .buttonStyle(.borderedProminent) + + NavigationLink(destination: CameraControlCommandV2View(thetaBleApi: thetaBleApi)) { + Text("Camera Control Command V2") + } + .buttonStyle(.borderedProminent) + + Button("Disconnect") { + Task { + try await thetaBleApi.disconnect() + } + } + .buttonStyle(.borderedProminent) + + Text("Information\n\(thetaBleApi.infoText)") + } + } + .padding() + } + .onAppear { + loadDevice() + if devName == nil { + thetaBleApi.setInfoText("Please connect wifi.") + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView( thetaBleApi: ThetaBleApi()) + } +} diff --git a/demos/demo-ios/demo-ios/Preview Content/Preview Assets.xcassets/Contents.json b/demos/demo-ios/demo-ios/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/demos/demo-ios/demo-ios/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/demos/demo-ios/demo-ios/ThetaBleApi.swift b/demos/demo-ios/demo-ios/ThetaBleApi.swift new file mode 100644 index 0000000..003490c --- /dev/null +++ b/demos/demo-ios/demo-ios/ThetaBleApi.swift @@ -0,0 +1,576 @@ +// +// ThetaBleApi.swift +// demo-ios +// +// Created on 2023/03/15. +// + +import Foundation +import THETABleClient + +let MESSAGE_ERROR_NO_DEVICE = "Error. No device." +let MESSAGE_ERROR_UNSUPPORTED = "Unsuppoted." + +@MainActor +class ThetaBleApi: ObservableObject { + @Published var infoText = "Init" + @Published var batteryLevel: Int? + @Published var batteryStatus: ChargingState? + @Published var cameraPower: CameraPower? + @Published var pluginControl: PluginControl? + + var thetaDevice: ThetaBle.ThetaDevice? + var devName: String = "" + + func setInfoText(_ value: String) { + DispatchQueue.main.async { + self.infoText = value + } + } + + func scan(name: String) async throws { + do { + setInfoText("Scanning...") + let timeout = ThetaBle.Timeout( + timeoutScan: 30000, + timeoutPeripheral: 1000, + timeoutConnect: 5000, + timeoutTakePicture: 10000 + ) + let device = try await ThetaBle.Companion.shared.scan(name: name, timeout: timeout) + if let device = device { + thetaDevice = device + + setInfoText("Scan. Found device: \(name)") + devName = name + } else { + setInfoText("Scan. Not found device: \(name)") + } + } catch { + setInfoText("Error. scan device.") + } + } + + func connect(uuid: String?) async -> Bool { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return false + } + do { + setInfoText("Connecting...") + try await device.connect(uuid: uuid) + setInfoText("Connected: \(devName)") + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.setNotifications(device: device) + } + } catch { + setInfoText("Error. connect") + return false + } + return true + } + + func setNotifications(device: ThetaBle.ThetaDevice) { + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + setBatteryLevelNotify(service: service) + setBatteryStatusNotify(service: service) + setCameraPowerNotify(service: service) + setCameraPowerNotify(service: service) + setPluginControlNotify(service: service) + } + + func setBatteryLevelNotify(service: CameraStatusCommand) { + do { + try service.setBatteryLevelNotify { level, error in + if error != nil { + self.setInfoText("Error battery level notification") + } else { + self.setInfoText("Battery level: \(level ?? 0)") + DispatchQueue.main.async { + self.batteryLevel = level?.intValue + } + } + } + } catch { + setInfoText("Not support battery level notification") + } + } + + func setBatteryStatusNotify(service: CameraStatusCommand) { + do { + try service.setBatteryStatusNotify {status, error in + if error != nil { + self.setInfoText("Error battery status notification") + } else { + self.setInfoText("Battery status: \(status?.name ?? "nil")") + DispatchQueue.main.async { + self.batteryStatus = status + } + } + } + } catch { + setInfoText("Not support battery status notification") + } + } + + func setCameraPowerNotify(service: CameraStatusCommand) { + do { + try service.setCameraPowerNotify { power, error in + if error != nil { + self.setInfoText("Error camera power notification") + } else { + self.setInfoText("Camera power: \(power?.name ?? "nil")") + DispatchQueue.main.async { + self.cameraPower = power + } + } + } + } catch { + setInfoText("Not support camera power notification") + } + } + + func setCommandErrorDescriptionNotify(service: CameraStatusCommand) { + do { + try service.setCommandErrorDescriptionNotify {value, error in + if error != nil { + self.setInfoText("Error command error notification") + } else { + self.setInfoText("Command error: \(value?.name ?? "nil")") + } + } + } catch { + setInfoText("Not support command error notification") + } + } + + func setPluginControlNotify(service: CameraStatusCommand) { + do { + try service.setPluginControlNotify { plugin, error in + if error != nil { + self.setInfoText("Error plugin control notification") + } else { + self.setInfoText("Plugin: \(plugin?.pluginControl.name ?? "nil")") + DispatchQueue.main.async { + self.pluginControl = plugin + } + } + } + } catch { + setInfoText("Not support plugin control notification") + } + } + + func updateBatteryLevel() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + let value = try await service.getBatteryLevel() + DispatchQueue.main.async { + self.batteryLevel = value.intValue + } + } catch { + setInfoText("Error.") + } + } + + func updateBatteryStatus() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + let value = try await service.getBatteryStatus() + DispatchQueue.main.async { + self.batteryStatus = value + } + } catch { + setInfoText("Error.") + } + } + + func updateCameraPower() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + let value = try await service.getCameraPower() + DispatchQueue.main.async { + self.cameraPower = value + } + } catch { + setInfoText("Error.") + } + } + + func setCameraPower(value: CameraPower) async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + try await service.setCameraPower(value: value) + } catch { + setInfoText("Error.") + } + } + + func updatePluginControl() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + let value = try await service.getPluginControl() + DispatchQueue.main.async { + self.pluginControl = value + } + } catch { + setInfoText("Error.") + } + } + + func getFirstPlugin() async -> Int32? { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return nil + } + guard let service = device.cameraControlCommands else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return nil + } + if let order = try? await service.getPluginOrders() { + return order.first + } else { + return nil + } + } + + func setPluginControl(value: PluginPowerStatus) async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraStatusCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + if let pluginControl = pluginControl { + do { + if value == PluginPowerStatus.stop { + try await service.setPluginControl(value: PluginControl(pluginControl: value, plugin: nil)) + } else { + if let firstPlugin = await getFirstPlugin(), pluginControl.plugin != nil { + try await service.setPluginControl(value: + PluginControl( + pluginControl: value, + plugin: KotlinInt(int: firstPlugin))) + } else { + try await service.setPluginControl(value: + PluginControl( + pluginControl: value, + plugin: nil)) + } + } + } catch { + setInfoText("Error.") + } + } else { + setInfoText("Error. Not yet acquired.") + } + + } + + func disconnect() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + do { + if device.isConnected() { + try await device.disconnect() + } + setInfoText("Disconnected.") + } catch { + setInfoText("Error. disconnect.") + } + } + + func getInfo() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraInformation else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + let firmware = try await service.getFirmwareRevision() + let manuName = try await service.getManufacturerName() + let model = try await service.getModelNumber() + let serial = try await service.getSerialNumber() + let wlanMac = try await service.getWlanMacAddress() + let bleMac = try await service.getBluetoothMacAddress() + + setInfoText( + " firmware: \(firmware)\n maker: \(manuName)\n model: \(model)\n serial: \(serial)\n wlan: \(wlanMac)\n ble: \(bleMac)." + ) + } catch { + setInfoText("Error. Get Information.") + } + } + + func takePicture() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.shootingControlCommand else { + setInfoText(MESSAGE_ERROR_UNSUPPORTED) + return + } + do { + if (try await service.getCaptureMode() != .image) { + setInfoText("Change capture mode...") + try await service.setCaptureMode(value: .image) + + // Wait a little or you'll fail + try await Task.sleep(nanoseconds: 1 * 1000 * 1000 * 1000) + } + + class Callback: KotlinSuspendFunction1 { + let thetaBleApi: ThetaBleApi + init(thetaBleApi: ThetaBleApi) { + self.thetaBleApi = thetaBleApi + } + func invoke(p1: Any?) async throws -> Any? { + if p1 == nil { + await self.thetaBleApi.setInfoText("End take a picture.") + } else { + await self.thetaBleApi.setInfoText("End take a picture. error:\(p1 ?? "unknown")") + } + return nil + } + } + + setInfoText("Start take a picture") + try service.takePicture(complete: Callback(thetaBleApi: self)) + } catch { + setInfoText("Error. Take a picture.") + } + } + + func checkCameraControlCommandV2() -> Bool { + guard let device = thetaDevice, device.cameraControlCommandV2 != nil else { + return false + } + return true + } + + func checkCameraStatusCommand() -> Bool { + guard let device = thetaDevice, device.cameraStatusCommand != nil else { + return false + } + return true + } + + func cameraControlCommandV2GetInfo() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraControlCommandV2 else { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + do { + let thetaInfo = try await service.getInfo() + let text = """ +info +manufacturer: \(thetaInfo.manufacturer) +model: \(thetaInfo.model.name) +serialNumber: \(thetaInfo.serialNumber) +wlanMacAddress: \(thetaInfo.wlanMacAddress ?? "") +bluetoothMacAddress: \(thetaInfo.bluetoothMacAddress ?? "") +firmwareVersion: \(thetaInfo.firmwareVersion) +uptime: \(thetaInfo.uptime) +""" + + setInfoText(text) + } catch { + setInfoText("Error. Get info.") + } + } + + func getStateString(thetaState: ThetaState) -> String{ + var text = "" + if let batteryLevel = thetaState.batteryLevel { + text += "batteryLevel: \(batteryLevel)\n" + } + if let captureStatus = thetaState.captureStatus { + text += "captureStatus: \(captureStatus.name)\n" + } + if let recordedTime = thetaState.recordedTime { + text += "recordedTime: \(recordedTime)\n" + } + if let recordableTime = thetaState.recordableTime { + text += "recordableTime: \(recordableTime)\n" + } + if let capturedPictures = thetaState.capturedPictures { + text += "capturedPictures: \(capturedPictures)\n" + } + if let latestFileUrl = thetaState.latestFileUrl { + text += "latestFileUrl: \(latestFileUrl)\n" + } + if let batteryState = thetaState.batteryState { + text += "batteryState: \(batteryState.name)\n" + } + if let function = thetaState.function { + text += "function: \(function.name)\n" + } + if let cameraError = thetaState.cameraError { + let errorText = cameraError.map { it in + it.name + }.joined(separator: "\n") + text += "cameraError: \(errorText)\n" + } + if let batteryInsert = thetaState.batteryInsert { + text += "batteryInsert: \(batteryInsert.boolValue ? "true" : "false")\n" + } + if let boardTemp = thetaState.boardTemp { + text += "boardTemp: \(boardTemp)\n" + } + if let batteryTemp = thetaState.batteryTemp { + text += "batteryTemp: \(batteryTemp)\n" + } + return text + } + + func cameraControlCommandV2GetState() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraControlCommandV2 else { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + do { + let thetaState = try await service.getState() + setInfoText("state\n\(getStateString(thetaState: thetaState))") + } catch { + setInfoText("Error. Get state.") + } + } + + func getGpsInfoString(gpsInfo: GpsInfo, leftMargin: Int) -> String{ + var text = "" + let margin = String(repeating: " ", count: leftMargin) + + if let lat = gpsInfo.lat { + text += margin + "lat: \(lat)\n" + } + if let lng = gpsInfo.lng { + text += margin + "lng: \(lng)\n" + } + if let altitude = gpsInfo.altitude { + text += margin + "altitude: \(altitude)\n" + } + if let dateTimeZone = gpsInfo.dateTimeZone { + text += margin + "dateTimeZone: \(dateTimeZone)\n" + } + if let datum = gpsInfo.datum { + text += margin + "datum: \(datum)\n" + } + + return text + } + + func cameraControlCommandV2GetState2() async throws { + guard let device = thetaDevice else { + setInfoText(MESSAGE_ERROR_NO_DEVICE) + return + } + guard let service = device.cameraControlCommandV2 else { + setInfoText("Unsupported CameraControlCommandV2.") + return + } + do { + let thetaState2 = try await service.getState2() + var text = "state2\n" + if let externalGpsInfo = thetaState2.externalGpsInfo { + text += " externalGpsInfo:\n" + if let gpsInfo = externalGpsInfo.gpsInfo { + text += getGpsInfoString(gpsInfo: gpsInfo, leftMargin: 4) + } + } + if let internalGpsInfo = thetaState2.internalGpsInfo { + text += " internalGpsInfo:\n" + if let gpsInfo = internalGpsInfo.gpsInfo { + text += getGpsInfoString(gpsInfo: gpsInfo, leftMargin: 4) + } + } + setInfoText(text) + } catch { + setInfoText("Error. Get state2.") + } + } + + func cameraControlCommandV2ClearStateNotify() { + guard let device = thetaDevice else { + return + } + guard let service = device.cameraControlCommandV2 else { + return + } + try? service.setStateNotify() + } + + func cameraControlCommandV2SetStateNotify() { + guard let device = thetaDevice else { + return + } + guard let service = device.cameraControlCommandV2 else { + return + } + do { + try service.setStateNotify { state, error in + if error != nil { + self.setInfoText("Error. Set state notify") + } else if let state { + self.setInfoText("state notify\n\(self.getStateString(thetaState: state))") + } + } + setInfoText("OK. set state notify.") + } catch { + setInfoText("Error. Set state notify.") + } + } +} diff --git a/demos/demo-ios/demo-ios/demo_iosApp.swift b/demos/demo-ios/demo-ios/demo_iosApp.swift new file mode 100644 index 0000000..59e31c3 --- /dev/null +++ b/demos/demo-ios/demo-ios/demo_iosApp.swift @@ -0,0 +1,25 @@ +// +// demo_iosApp.swift +// demo-ios +// +// Created on 2023/03/15. +// + +import SwiftUI + +@main +struct demo_iosApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + var body: some Scene { + WindowGroup { + ContentView( thetaBleApi: ThetaBleApi()) + } + } +} + +class AppDelegate : UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + return true + } +} + diff --git a/demos/demo-react-native/.bundle/config b/demos/demo-react-native/.bundle/config new file mode 100644 index 0000000..848943b --- /dev/null +++ b/demos/demo-react-native/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/demos/demo-react-native/.eslintrc.js b/demos/demo-react-native/.eslintrc.js new file mode 100644 index 0000000..c23b3c0 --- /dev/null +++ b/demos/demo-react-native/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + root: true, + extends: '@react-native-community', + env: { + es2019: true, + node: true, + }, + rules: { + semi: ['error', 'always'], + quotes: ['warn', 'single'], + indent: ['error', 2], + 'comma-dangle': ['error', 'always-multiline'], + eqeqeq: ['error', 'always', { null: 'ignore' }], + 'react-native/no-inline-styles': 0, + }, +}; diff --git a/demos/demo-react-native/.gitignore b/demos/demo-react-native/.gitignore new file mode 100644 index 0000000..16f8c30 --- /dev/null +++ b/demos/demo-react-native/.gitignore @@ -0,0 +1,63 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +ios/.xcode.env.local + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +/ios/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* diff --git a/demos/demo-react-native/.node-version b/demos/demo-react-native/.node-version new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/demos/demo-react-native/.node-version @@ -0,0 +1 @@ +18 diff --git a/demos/demo-react-native/.prettierrc.js b/demos/demo-react-native/.prettierrc.js new file mode 100644 index 0000000..2ae7b38 --- /dev/null +++ b/demos/demo-react-native/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + arrowParens: 'avoid', + bracketSameLine: true, + bracketSpacing: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/demos/demo-react-native/.ruby-version b/demos/demo-react-native/.ruby-version new file mode 100644 index 0000000..0aec50e --- /dev/null +++ b/demos/demo-react-native/.ruby-version @@ -0,0 +1 @@ +3.1.4 diff --git a/demos/demo-react-native/.watchmanconfig b/demos/demo-react-native/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/demos/demo-react-native/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/demos/demo-react-native/Gemfile b/demos/demo-react-native/Gemfile new file mode 100644 index 0000000..567e598 --- /dev/null +++ b/demos/demo-react-native/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby File.read(File.join(__dir__, '.ruby-version')).strip + +gem 'cocoapods', '~> 1.11', '>= 1.11.3' diff --git a/demos/demo-react-native/README.md b/demos/demo-react-native/README.md new file mode 100644 index 0000000..7dfc940 --- /dev/null +++ b/demos/demo-react-native/README.md @@ -0,0 +1,34 @@ +# React Native demo for theta-ble-client + +A simple sample React Native application using [theta-ble-client](https://github.com/ricohapi/theta-ble-client). + +## Objective + +* Show developers how to use Theta ble client. + +## Functions + +* Connect with THETA at bluetooth. +* Get THETA information. +* Take a photo with Theta. + +## Note + +* Change bundle id and signature to your own. + +## Building and execution + +* Execute following command to build and execute. + ``` + $ yarn install + $ yarn run android + + OR + + $ yarn run ios + ``` + + You can execute metro bundler in other terminal in advance. + ``` + $ yarn start + ``` diff --git a/demos/demo-react-native/__tests__/App-test.tsx b/demos/demo-react-native/__tests__/App-test.tsx new file mode 100644 index 0000000..4edaa0a --- /dev/null +++ b/demos/demo-react-native/__tests__/App-test.tsx @@ -0,0 +1,14 @@ +/** + * @format + */ + +import 'react-native'; +import React from 'react'; +import App from '../src/App'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + renderer.create(); +}); diff --git a/demos/demo-react-native/android/app/build.gradle b/demos/demo-react-native/android/app/build.gradle new file mode 100644 index 0000000..c2a5b22 --- /dev/null +++ b/demos/demo-react-native/android/app/build.gradle @@ -0,0 +1,170 @@ +apply plugin: "com.android.application" +apply plugin: "com.facebook.react" + +import com.android.build.OutputFile + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} + +/** + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Private function to get the list of Native Architectures you want to build. + * This reads the value from reactNativeArchitectures in your gradle.properties + * file and works together with the --active-arch-only flag of react-native run-android. + */ +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +android { + ndkVersion rootProject.ext.ndkVersion + + compileSdkVersion rootProject.ext.compileSdkVersion + + namespace "com.demoreactnative" + defaultConfig { + applicationId "com.demoreactnative" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include (*reactNativeArchitectures()) + } + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // https://developer.android.com/studio/build/configure-apk-splits.html + // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + defaultConfig.versionCode * 1000 + versionCodes.get(abi) + } + + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.squareup.okhttp3', module:'okhttp' + } + + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/demos/demo-react-native/android/app/debug.keystore b/demos/demo-react-native/android/app/debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de GIT binary patch literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc + + + + + + + + diff --git a/demos/demo-react-native/android/app/src/debug/java/com/demoreactnative/ReactNativeFlipper.java b/demos/demo-react-native/android/app/src/debug/java/com/demoreactnative/ReactNativeFlipper.java new file mode 100644 index 0000000..c70304f --- /dev/null +++ b/demos/demo-react-native/android/app/src/debug/java/com/demoreactnative/ReactNativeFlipper.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.demoreactnative; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceEventListener; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} diff --git a/demos/demo-react-native/android/app/src/main/AndroidManifest.xml b/demos/demo-react-native/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d74c243 --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainActivity.java b/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainActivity.java new file mode 100644 index 0000000..e922ddb --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainActivity.java @@ -0,0 +1,42 @@ +package com.demoreactnative; + +import android.os.Bundle; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity extends ReactActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(null); + } + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "DemoReactNative"; + } + + /** + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled + ); + } +} diff --git a/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainApplication.java b/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainApplication.java new file mode 100644 index 0000000..8923039 --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/java/com/demoreactnative/MainApplication.java @@ -0,0 +1,62 @@ +package com.demoreactnative; + +import android.app.Application; +import com.facebook.react.PackageList; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; +import com.facebook.soloader.SoLoader; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = + new DefaultReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + @SuppressWarnings("UnnecessaryLocalVariable") + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); + } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +} diff --git a/demos/demo-react-native/android/app/src/main/res/drawable/rn_edit_text_material.xml b/demos/demo-react-native/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 0000000..f35d996 --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/demos/demo-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/demos/demo-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/demos/demo-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/demos/demo-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/demos/demo-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/app/src/main/res/values/strings.xml b/demos/demo-react-native/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..24b704d --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + DemoReactNative + diff --git a/demos/demo-react-native/android/app/src/main/res/values/styles.xml b/demos/demo-react-native/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..7ba83a2 --- /dev/null +++ b/demos/demo-react-native/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/demos/demo-react-native/android/app/src/release/java/com/demoreactnative/ReactNativeFlipper.java b/demos/demo-react-native/android/app/src/release/java/com/demoreactnative/ReactNativeFlipper.java new file mode 100644 index 0000000..b0636f2 --- /dev/null +++ b/demos/demo-react-native/android/app/src/release/java/com/demoreactnative/ReactNativeFlipper.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.demoreactnative; + +import android.content.Context; +import com.facebook.react.ReactInstanceManager; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/demos/demo-react-native/android/build.gradle b/demos/demo-react-native/android/build.gradle new file mode 100644 index 0000000..bf7cb4d --- /dev/null +++ b/demos/demo-react-native/android/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "33.0.0" + minSdkVersion = 26 + compileSdkVersion = 33 + targetSdkVersion = 33 + + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" + + ext.kotlinVersion = "1.9.10" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + classpath("com.facebook.react:react-native-gradle-plugin") + } +} diff --git a/demos/demo-react-native/android/gradle.properties b/demos/demo-react-native/android/gradle.properties new file mode 100644 index 0000000..e4af465 --- /dev/null +++ b/demos/demo-react-native/android/gradle.properties @@ -0,0 +1,44 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Version of flipper SDK to use with React Native +FLIPPER_VERSION=0.125.0 + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.jar b/demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..41d9927a4d4fb3f96a785543079b8df6723c946b GIT binary patch literal 59821 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 literal 0 HcmV?d00001 diff --git a/demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.properties b/demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..8fad3f5 --- /dev/null +++ b/demos/demo-react-native/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/demos/demo-react-native/android/gradlew b/demos/demo-react-native/android/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/demos/demo-react-native/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/demos/demo-react-native/android/gradlew.bat b/demos/demo-react-native/android/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/demos/demo-react-native/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/demos/demo-react-native/android/settings.gradle b/demos/demo-react-native/android/settings.gradle new file mode 100644 index 0000000..6d92fae --- /dev/null +++ b/demos/demo-react-native/android/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'DemoReactNative' +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) +include ':app' +includeBuild('../node_modules/react-native-gradle-plugin') diff --git a/demos/demo-react-native/app.json b/demos/demo-react-native/app.json new file mode 100644 index 0000000..eba0407 --- /dev/null +++ b/demos/demo-react-native/app.json @@ -0,0 +1,4 @@ +{ + "name": "DemoReactNative", + "displayName": "DemoReactNative" +} \ No newline at end of file diff --git a/demos/demo-react-native/babel.config.js b/demos/demo-react-native/babel.config.js new file mode 100644 index 0000000..f842b77 --- /dev/null +++ b/demos/demo-react-native/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], +}; diff --git a/demos/demo-react-native/index.js b/demos/demo-react-native/index.js new file mode 100644 index 0000000..752e7ee --- /dev/null +++ b/demos/demo-react-native/index.js @@ -0,0 +1,9 @@ +/** + * @format + */ + +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/demos/demo-react-native/ios/.xcode.env b/demos/demo-react-native/ios/.xcode.env new file mode 100644 index 0000000..3d5782c --- /dev/null +++ b/demos/demo-react-native/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/demos/demo-react-native/ios/DemoReactNative.xcodeproj/project.pbxproj b/demos/demo-react-native/ios/DemoReactNative.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5f7152c --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative.xcodeproj/project.pbxproj @@ -0,0 +1,710 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 00E356F31AD99517003FC87E /* DemoReactNativeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* DemoReactNativeTests.m */; }; + 0C80B921A6F3F58F76C31292 /* libPods-DemoReactNative.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-DemoReactNative.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 7699B88040F8A987B510C191 /* libPods-DemoReactNative-DemoReactNativeTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-DemoReactNative-DemoReactNativeTests.a */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = DemoReactNative; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00E356EE1AD99517003FC87E /* DemoReactNativeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoReactNativeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* DemoReactNativeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoReactNativeTests.m; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* DemoReactNative.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoReactNative.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = DemoReactNative/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = DemoReactNative/AppDelegate.mm; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = DemoReactNative/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = DemoReactNative/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = DemoReactNative/main.m; sourceTree = ""; }; + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-DemoReactNative-DemoReactNativeTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-DemoReactNative-DemoReactNativeTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B4392A12AC88292D35C810B /* Pods-DemoReactNative.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoReactNative.debug.xcconfig"; path = "Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative.debug.xcconfig"; sourceTree = ""; }; + 5709B34CF0A7D63546082F79 /* Pods-DemoReactNative.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoReactNative.release.xcconfig"; path = "Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative.release.xcconfig"; sourceTree = ""; }; + 5B7EB9410499542E8C5724F5 /* Pods-DemoReactNative-DemoReactNativeTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoReactNative-DemoReactNativeTests.debug.xcconfig"; path = "Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests.debug.xcconfig"; sourceTree = ""; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-DemoReactNative.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-DemoReactNative.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = DemoReactNative/LaunchScreen.storyboard; sourceTree = ""; }; + 89C6BE57DB24E9ADA2F236DE /* Pods-DemoReactNative-DemoReactNativeTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoReactNative-DemoReactNativeTests.release.xcconfig"; path = "Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests.release.xcconfig"; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7699B88040F8A987B510C191 /* libPods-DemoReactNative-DemoReactNativeTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-DemoReactNative.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00E356EF1AD99517003FC87E /* DemoReactNativeTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* DemoReactNativeTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = DemoReactNativeTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* DemoReactNative */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.mm */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = DemoReactNative; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-DemoReactNative.a */, + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-DemoReactNative-DemoReactNativeTests.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* DemoReactNative */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* DemoReactNativeTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* DemoReactNative.app */, + 00E356EE1AD99517003FC87E /* DemoReactNativeTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-DemoReactNative.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-DemoReactNative.release.xcconfig */, + 5B7EB9410499542E8C5724F5 /* Pods-DemoReactNative-DemoReactNativeTests.debug.xcconfig */, + 89C6BE57DB24E9ADA2F236DE /* Pods-DemoReactNative-DemoReactNativeTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* DemoReactNativeTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "DemoReactNativeTests" */; + buildPhases = ( + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = DemoReactNativeTests; + productName = DemoReactNativeTests; + productReference = 00E356EE1AD99517003FC87E /* DemoReactNativeTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* DemoReactNative */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "DemoReactNative" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DemoReactNative; + productName = DemoReactNative; + productReference = 13B07F961A680F5B00A75B9A /* DemoReactNative.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "DemoReactNative" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* DemoReactNative */, + 00E356ED1AD99517003FC87E /* DemoReactNativeTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-DemoReactNative-DemoReactNativeTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-DemoReactNative-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DemoReactNative/Pods-DemoReactNative-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DemoReactNative-DemoReactNativeTests/Pods-DemoReactNative-DemoReactNativeTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* DemoReactNativeTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* DemoReactNative */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-DemoReactNative-DemoReactNativeTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = DemoReactNativeTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.ricoh360.thetableclient.DemoReactNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoReactNative.app/DemoReactNative"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-DemoReactNative-DemoReactNativeTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + INFOPLIST_FILE = DemoReactNativeTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.ricoh360.thetableclient.DemoReactNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoReactNative.app/DemoReactNative"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-DemoReactNative.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = DemoReactNative/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.ricoh360.thetableclient.--PRODUCT-NAME-rfc1034identifier-"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.ricoh360.thetableclient.DemoReactNative; + PRODUCT_NAME = DemoReactNative; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-DemoReactNative.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = DemoReactNative/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.ricoh360.thetableclient.--PRODUCT-NAME-rfc1034identifier-"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.ricoh360.thetableclient.DemoReactNative; + PRODUCT_NAME = DemoReactNative; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "DemoReactNativeTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "DemoReactNative" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "DemoReactNative" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/demos/demo-react-native/ios/DemoReactNative.xcodeproj/xcshareddata/xcschemes/DemoReactNative.xcscheme b/demos/demo-react-native/ios/DemoReactNative.xcodeproj/xcshareddata/xcschemes/DemoReactNative.xcscheme new file mode 100644 index 0000000..0f8a2a8 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative.xcodeproj/xcshareddata/xcschemes/DemoReactNative.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/demo-react-native/ios/DemoReactNative.xcworkspace/contents.xcworkspacedata b/demos/demo-react-native/ios/DemoReactNative.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7620f3e --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/demos/demo-react-native/ios/DemoReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/demo-react-native/ios/DemoReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/demo-react-native/ios/DemoReactNative/AppDelegate.h b/demos/demo-react-native/ios/DemoReactNative/AppDelegate.h new file mode 100644 index 0000000..5d28082 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : RCTAppDelegate + +@end diff --git a/demos/demo-react-native/ios/DemoReactNative/AppDelegate.mm b/demos/demo-react-native/ios/DemoReactNative/AppDelegate.mm new file mode 100644 index 0000000..e138c7a --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/AppDelegate.mm @@ -0,0 +1,36 @@ +#import "AppDelegate.h" + +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.moduleName = @"DemoReactNative"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end diff --git a/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/AppIcon.appiconset/Contents.json b/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..8121323 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/Contents.json b/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/Contents.json new file mode 100644 index 0000000..2d92bd5 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/demos/demo-react-native/ios/DemoReactNative/Info.plist b/demos/demo-react-native/ios/DemoReactNative/Info.plist new file mode 100644 index 0000000..2f3d2e5 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + DemoReactNative + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSBluetoothAlwaysUsageDescription + Use bluetooth + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/demos/demo-react-native/ios/DemoReactNative/LaunchScreen.storyboard b/demos/demo-react-native/ios/DemoReactNative/LaunchScreen.storyboard new file mode 100644 index 0000000..ab1380a --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/LaunchScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/demo-react-native/ios/DemoReactNative/main.m b/demos/demo-react-native/ios/DemoReactNative/main.m new file mode 100644 index 0000000..d645c72 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNative/main.m @@ -0,0 +1,10 @@ +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/demos/demo-react-native/ios/DemoReactNativeTests/DemoReactNativeTests.m b/demos/demo-react-native/ios/DemoReactNativeTests/DemoReactNativeTests.m new file mode 100644 index 0000000..e22612b --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNativeTests/DemoReactNativeTests.m @@ -0,0 +1,66 @@ +#import +#import + +#import +#import + +#define TIMEOUT_SECONDS 600 +#define TEXT_TO_LOOK_FOR @"Welcome to React" + +@interface DemoReactNativeTests : XCTestCase + +@end + +@implementation DemoReactNativeTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; +#ifdef DEBUG + RCTSetLogFunction( + ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); +#endif + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + +#ifdef DEBUG + RCTSetLogFunction(RCTDefaultLogFunction); +#endif + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + +@end diff --git a/demos/demo-react-native/ios/DemoReactNativeTests/Info.plist b/demos/demo-react-native/ios/DemoReactNativeTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/demos/demo-react-native/ios/DemoReactNativeTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/demos/demo-react-native/ios/Podfile b/demos/demo-react-native/ios/Podfile new file mode 100644 index 0000000..31ed02c --- /dev/null +++ b/demos/demo-react-native/ios/Podfile @@ -0,0 +1,60 @@ +require_relative '../node_modules/react-native/scripts/react_native_pods' +require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' + +platform :ios, 14 +prepare_react_native_project! + +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'DemoReactNative' do + config = use_native_modules! + + # Flags change depending on the env values. + flags = get_default_flags() + + use_react_native!( + :path => config[:reactNativePath], + # Hermes is now enabled by default. Disable by setting this flag to false. + # Upcoming versions of React Native may rely on get_default_flags(), but + # we make it explicit here to aid in the React Native upgrade process. + :hermes_enabled => flags[:hermes_enabled], + :fabric_enabled => flags[:fabric_enabled], + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable the next line. + :flipper_configuration => flipper_config, + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + target 'DemoReactNativeTests' do + inherit! :complete + # Pods for testing + end + + post_install do |installer| + react_native_post_install( + installer, + # Set `mac_catalyst_enabled` to `true` in order to apply patches + # necessary for Mac Catalyst builds + :mac_catalyst_enabled => false + ) + __apply_Xcode_12_5_M1_post_install_workaround(installer) + end +end diff --git a/demos/demo-react-native/ios/Podfile.lock b/demos/demo-react-native/ios/Podfile.lock new file mode 100644 index 0000000..aa391b8 --- /dev/null +++ b/demos/demo-react-native/ios/Podfile.lock @@ -0,0 +1,648 @@ +PODS: + - boost (1.76.0) + - CocoaAsyncSocket (7.6.5) + - DoubleConversion (1.1.6) + - FBLazyVector (0.71.14) + - FBReactNativeSpec (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.71.14) + - RCTTypeSafety (= 0.71.14) + - React-Core (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - Flipper (0.125.0): + - Flipper-Folly (~> 2.6) + - Flipper-RSocket (~> 1.4) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - Flipper-RSocket (1.4.3): + - Flipper-Folly (~> 2.6) + - FlipperKit (0.125.0): + - FlipperKit/Core (= 0.125.0) + - FlipperKit/Core (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.125.0) + - FlipperKit/FKPortForwarding (0.125.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.125.0) + - FlipperKit/FlipperKitLayoutHelpers (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin + - fmt (6.2.1) + - glog (0.3.5) + - hermes-engine (0.71.14): + - hermes-engine/Pre-built (= 0.71.14) + - hermes-engine/Pre-built (0.71.14) + - libevent (2.1.12) + - OpenSSL-Universal (1.1.1100) + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Futures (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - libevent + - RCTRequired (0.71.14) + - RCTTypeSafety (0.71.14): + - FBLazyVector (= 0.71.14) + - RCTRequired (= 0.71.14) + - React-Core (= 0.71.14) + - React (0.71.14): + - React-Core (= 0.71.14) + - React-Core/DevSupport (= 0.71.14) + - React-Core/RCTWebSocket (= 0.71.14) + - React-RCTActionSheet (= 0.71.14) + - React-RCTAnimation (= 0.71.14) + - React-RCTBlob (= 0.71.14) + - React-RCTImage (= 0.71.14) + - React-RCTLinking (= 0.71.14) + - React-RCTNetwork (= 0.71.14) + - React-RCTSettings (= 0.71.14) + - React-RCTText (= 0.71.14) + - React-RCTVibration (= 0.71.14) + - React-callinvoker (0.71.14) + - React-Codegen (0.71.14): + - FBReactNativeSpec + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.14) + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/CoreModulesHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/Default (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/DevSupport (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.14) + - React-Core/RCTWebSocket (= 0.71.14) + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-jsinspector (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTActionSheetHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTAnimationHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTBlobHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTImageHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTLinkingHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTNetworkHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTSettingsHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTTextHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTVibrationHeaders (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-Core/RCTWebSocket (0.71.14): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.14) + - React-cxxreact (= 0.71.14) + - React-hermes + - React-jsi (= 0.71.14) + - React-jsiexecutor (= 0.71.14) + - React-perflogger (= 0.71.14) + - Yoga + - React-CoreModules (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.14) + - React-Codegen (= 0.71.14) + - React-Core/CoreModulesHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - React-RCTBlob + - React-RCTImage (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-cxxreact (0.71.14): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.14) + - React-jsi (= 0.71.14) + - React-jsinspector (= 0.71.14) + - React-logger (= 0.71.14) + - React-perflogger (= 0.71.14) + - React-runtimeexecutor (= 0.71.14) + - React-hermes (0.71.14): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.71.14) + - React-jsi + - React-jsiexecutor (= 0.71.14) + - React-jsinspector (= 0.71.14) + - React-perflogger (= 0.71.14) + - React-jsi (0.71.14): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.71.14): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.14) + - React-jsi (= 0.71.14) + - React-perflogger (= 0.71.14) + - React-jsinspector (0.71.14) + - React-logger (0.71.14): + - glog + - react-native-safe-area-context (4.7.4): + - React-Core + - React-perflogger (0.71.14) + - React-RCTActionSheet (0.71.14): + - React-Core/RCTActionSheetHeaders (= 0.71.14) + - React-RCTAnimation (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.14) + - React-Codegen (= 0.71.14) + - React-Core/RCTAnimationHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTAppDelegate (0.71.14): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - React-RCTBlob (0.71.14): + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.14) + - React-Core/RCTBlobHeaders (= 0.71.14) + - React-Core/RCTWebSocket (= 0.71.14) + - React-jsi (= 0.71.14) + - React-RCTNetwork (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTImage (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.14) + - React-Codegen (= 0.71.14) + - React-Core/RCTImageHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - React-RCTNetwork (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTLinking (0.71.14): + - React-Codegen (= 0.71.14) + - React-Core/RCTLinkingHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTNetwork (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.14) + - React-Codegen (= 0.71.14) + - React-Core/RCTNetworkHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTSettings (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.14) + - React-Codegen (= 0.71.14) + - React-Core/RCTSettingsHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-RCTText (0.71.14): + - React-Core/RCTTextHeaders (= 0.71.14) + - React-RCTVibration (0.71.14): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.14) + - React-Core/RCTVibrationHeaders (= 0.71.14) + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/core (= 0.71.14) + - React-runtimeexecutor (0.71.14): + - React-jsi (= 0.71.14) + - ReactCommon/turbomodule/bridging (0.71.14): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.14) + - React-Core (= 0.71.14) + - React-cxxreact (= 0.71.14) + - React-jsi (= 0.71.14) + - React-logger (= 0.71.14) + - React-perflogger (= 0.71.14) + - ReactCommon/turbomodule/core (0.71.14): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.14) + - React-Core (= 0.71.14) + - React-cxxreact (= 0.71.14) + - React-jsi (= 0.71.14) + - React-logger (= 0.71.14) + - React-perflogger (= 0.71.14) + - RNDefaultPreference (1.4.4): + - React-Core + - RNScreens (3.27.0): + - RCT-Folly (= 2021.07.22.00) + - React-Core + - SocketRocket (0.6.1) + - theta-ble-client-react-native (1.0.0): + - React-Core + - Yoga (1.14.0) + - YogaKit (1.18.1): + - Yoga (~> 1.14) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.125.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - Flipper-RSocket (= 1.4.3) + - FlipperKit (= 0.125.0) + - FlipperKit/Core (= 0.125.0) + - FlipperKit/CppBridge (= 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) + - FlipperKit/FBDefines (= 0.125.0) + - FlipperKit/FKPortForwarding (= 0.125.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) + - FlipperKit/FlipperKitReactPlugin (= 0.125.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNDefaultPreference (from `../node_modules/react-native-default-preference`) + - RNScreens (from `../node_modules/react-native-screens`) + - theta-ble-client-react-native (from `../node_modules/theta-ble-client-react-native`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - CocoaAsyncSocket + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - Flipper-RSocket + - FlipperKit + - fmt + - libevent + - OpenSSL-Universal + - SocketRocket + - YogaKit + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + RNDefaultPreference: + :path: "../node_modules/react-native-default-preference" + RNScreens: + :path: "../node_modules/react-native-screens" + theta-ble-client-react-native: + :path: "../node_modules/theta-ble-client-react-native" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 57d2868c099736d80fcd648bf211b4431e51a558 + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + FBLazyVector: 12ea01e587c9594e7b144e1bfc86ac4d9ac28fde + FBReactNativeSpec: b6ae48e67aaba46442f84d6f9ba598ccfbe2ee66 + Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 + FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88 + libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: e9df143e880d0e879e7a498dc06923d728809c79 + RCTTypeSafety: c2d89c8308829c12c038ec1f431191eaa0d8c15c + React: 52b89a818f4b2579c98567f3aa8bde880d9e843b + React-callinvoker: 56e399c88c05e037fe99c31978f30e75fad5c286 + React-Codegen: 7ece62f4d4896ad1933f834a7dad697676636318 + React-Core: f06b7b00e0d49433a316760ae61a0f8f5dee6629 + React-CoreModules: bd520e5688b5aa4666965a1b3b8e6d4a2e19df20 + React-cxxreact: ba6a1663685837fa4c2ac97daa95dd2e47f1acdc + React-hermes: c862e573ca0228070936b5ec4f475c3e19e900e0 + React-jsi: 533030c161bcfcbc3a4ad0b357ced8f7b2be457e + React-jsiexecutor: 94cfc1788637ceaf8841ef1f69b10cc0d62baadc + React-jsinspector: 7bf923954b4e035f494b01ac16633963412660d7 + React-logger: 655ff5db8bd922acfbe76a4983ffab048916343e + react-native-safe-area-context: 2cd91d532de12acdb0a9cbc8d43ac72a8e4c897c + React-perflogger: 4987ad83731c23d11813c84263963b0d3028c966 + React-RCTActionSheet: 5ad952b2a9740d87a5bd77280c4bc23f6f89ea0c + React-RCTAnimation: d2de22af3f536cc80bb5b3918e1a455114d1b985 + React-RCTAppDelegate: 27f7d735cad3d522c13008ea80020d350017c422 + React-RCTBlob: b697e0e2e38ec85bd726176851a3b476a490ad33 + React-RCTImage: a07e8c7d4768f62ebc6277e4680f6b979c619967 + React-RCTLinking: d00ae55db37b2c12ebab91135f06f75391c0708d + React-RCTNetwork: b3a401276e5c08487d8a14fdec1720e78b5888db + React-RCTSettings: d606cbac31403604c5d5746e6dab53bb332f9301 + React-RCTText: b3bd40bc71bca0c3e2cc5ce2c40870a438f303b1 + React-RCTVibration: 64e412b9ac684c4edc938fa1187135ada9af7faf + React-runtimeexecutor: ffe826b7b1cfbc32a35ed5b64d5886c0ff75f501 + ReactCommon: 7f3dd5e98a9ec627c6b03d26c062bf37ea9fc888 + RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31 + RNScreens: 3c2d122f5e08c192e254c510b212306da97d2581 + SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 + theta-ble-client-react-native: ea3ae8821eb463d2612e1be01adbce33b436bb9c + Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 + YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + +PODFILE CHECKSUM: 281a8a53acd4b2fb973d9ba88fce0881e66806bc + +COCOAPODS: 1.12.1 diff --git a/demos/demo-react-native/metro.config.js b/demos/demo-react-native/metro.config.js new file mode 100644 index 0000000..e91aba9 --- /dev/null +++ b/demos/demo-react-native/metro.config.js @@ -0,0 +1,17 @@ +/** + * Metro configuration for React Native + * https://github.com/facebook/react-native + * + * @format + */ + +module.exports = { + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; diff --git a/demos/demo-react-native/package.json b/demos/demo-react-native/package.json new file mode 100644 index 0000000..5975a83 --- /dev/null +++ b/demos/demo-react-native/package.json @@ -0,0 +1,45 @@ +{ + "name": "DemoReactNative", + "version": "1.0.0", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "lint": "eslint .", + "lint:fix": "eslint --fix .", + "start": "react-native start", + "test": "jest" + }, + "dependencies": { + "@react-native-material/core": "^1.3.7", + "@react-navigation/native": "^6.1.6", + "@react-navigation/native-stack": "^6.9.12", + "react": "18.2.0", + "react-native": "0.71.14", + "react-native-default-preference": "^1.4.4", + "react-native-safe-area-context": "^4.5.1", + "react-native-safe-area-view": "^1.1.1", + "react-native-screens": "^3.20.0", + "theta-ble-client-react-native": "1.0.0" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native-community/eslint-config": "^3.2.0", + "@tsconfig/react-native": "^2.0.2", + "@types/jest": "^29.2.1", + "@types/react": "^18.0.24", + "@types/react-test-renderer": "^18.0.0", + "babel-jest": "^29.2.1", + "eslint": "^8.19.0", + "jest": "^29.2.1", + "metro-react-native-babel-preset": "0.73.8", + "prettier": "^2.4.1", + "react-test-renderer": "18.2.0", + "typescript": "4.8.4" + }, + "jest": { + "preset": "react-native" + } +} diff --git a/demos/demo-react-native/src/App.tsx b/demos/demo-react-native/src/App.tsx new file mode 100644 index 0000000..792f9fb --- /dev/null +++ b/demos/demo-react-native/src/App.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; + +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { NavigationContainer } from '@react-navigation/native'; +import { DeviceProvider } from './device-context'; +import MenuScreen from './screen/menu-screen'; +import CameraStatusScreen from './screen/camera-status-screen'; +import CameraControlCommandV2Screen from './screen/camera-control-command-v2'; + +const Stack = createNativeStackNavigator(); + +const RootStack = () => { + return ( + + + + + + ); +}; +export default function App() { + return ( + + + + + + ); +} diff --git a/demos/demo-react-native/src/components/ui/button/button.tsx b/demos/demo-react-native/src/components/ui/button/button.tsx new file mode 100644 index 0000000..beb6fb0 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/button/button.tsx @@ -0,0 +1,39 @@ +import * as React from 'react'; +import { + StyleProp, + TouchableOpacity, + View, + ViewStyle, + type ButtonProps, + Text, +} from 'react-native'; +import styles from './styles'; + +interface Props + extends Pick { + style?: StyleProp; +} + +export const Button: React.FC = ({ + disabled = false, + onPress, + style, + title, +}) => { + return ( + + + + {title} + + + + ); +}; + +Button.displayName = 'Button'; + +export default Button; diff --git a/demos/demo-react-native/src/components/ui/button/index.ts b/demos/demo-react-native/src/components/ui/button/index.ts new file mode 100644 index 0000000..0245aa0 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/button/index.ts @@ -0,0 +1 @@ +export { default } from './button'; diff --git a/demos/demo-react-native/src/components/ui/button/styles.tsx b/demos/demo-react-native/src/components/ui/button/styles.tsx new file mode 100644 index 0000000..17d5296 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/button/styles.tsx @@ -0,0 +1,24 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + button: { + color: 'white', + fontSize: 16, + }, + buttonBack: { + backgroundColor: '#6200ee', + borderRadius: 10, + padding: 10, + alignItems: 'center', + justifyContent: 'center', + }, + buttonBackDisabled: { + backgroundColor: 'gray', + borderRadius: 10, + padding: 10, + alignItems: 'center', + justifyContent: 'center', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/input-number/index.ts b/demos/demo-react-native/src/components/ui/input-number/index.ts new file mode 100644 index 0000000..16acbf3 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-number/index.ts @@ -0,0 +1 @@ +export * from './input-number'; diff --git a/demos/demo-react-native/src/components/ui/input-number/input-number.tsx b/demos/demo-react-native/src/components/ui/input-number/input-number.tsx new file mode 100644 index 0000000..65089ac --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-number/input-number.tsx @@ -0,0 +1,73 @@ +import * as React from 'react'; +import { + StyleProp, + View, + ViewStyle, + Text, + TextInput, + ViewProps, +} from 'react-native'; +import styles from './styles'; + +interface Props extends Pick { + title?: string; + style?: StyleProp; + value?: number; + editable?: boolean; + onChange?: (value?: number) => void; + placeHolder?: string; +} + +export const InputNumber: React.FC = ({ + style, + title, + value, + editable, + placeHolder, + onChange, +}) => { + const [editText, setEditText] = React.useState(value?.toString() ?? ''); + + React.useEffect(() => { + if (value != null) { + setEditText(String(value)); + } + }, [value]); + + const onChangeText = (text: string) => { + setEditText(text); + if (text.length === 0) { + onChange?.(undefined); + return; + } + const numValue = Number(text); + if (isNaN(numValue)) { + return; + } + onChange?.(numValue); + }; + + return ( + + + + {title} + + + + + + + ); +}; + +InputNumber.displayName = 'InputNumber'; + +export default InputNumber; diff --git a/demos/demo-react-native/src/components/ui/input-number/styles.tsx b/demos/demo-react-native/src/components/ui/input-number/styles.tsx new file mode 100644 index 0000000..50250cd --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-number/styles.tsx @@ -0,0 +1,32 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + titleText: { + color: 'black', + fontSize: 16, + paddingRight: 10, + }, + containerLayout: { + flexDirection: 'row', + padding: 5, + alignItems: 'center', + }, + titleBack: { + alignItems: 'center', + alignSelf: 'center', + }, + itemBack: { + alignItems: 'center', + padding: 5, + alignSelf: 'center', + borderColor: 'gray', + borderWidth: 1, + }, + inputText: { + minWidth: 70, + textAlign: 'right', + color: 'black', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/input-string/index.ts b/demos/demo-react-native/src/components/ui/input-string/index.ts new file mode 100644 index 0000000..bc6b758 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-string/index.ts @@ -0,0 +1 @@ +export * from './input-string'; diff --git a/demos/demo-react-native/src/components/ui/input-string/input-string.tsx b/demos/demo-react-native/src/components/ui/input-string/input-string.tsx new file mode 100644 index 0000000..47fe3ff --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-string/input-string.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { + StyleProp, + View, + ViewStyle, + Text, + TextInput, + ViewProps, +} from 'react-native'; +import styles from './styles'; + +interface Props extends Pick { + title?: string; + style?: StyleProp; + value?: string; + editable?: boolean; + onChange?: (value: string) => void; + placeHolder?: string; +} + +export const InputString: React.FC = ({ + style, + title, + value, + editable, + placeHolder, + onChange, +}) => { + const [editText, setEditText] = React.useState(value ?? ''); + + React.useEffect(() => { + if (value != null) { + setEditText(value); + } + }, [value]); + + const onChangeText = (text: string) => { + setEditText(text); + onChange?.(text); + }; + + return ( + + + + {title} + + + + + + + ); +}; + +InputString.displayName = 'InputString'; + +export default InputString; diff --git a/demos/demo-react-native/src/components/ui/input-string/styles.tsx b/demos/demo-react-native/src/components/ui/input-string/styles.tsx new file mode 100644 index 0000000..e912e14 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/input-string/styles.tsx @@ -0,0 +1,31 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + titleText: { + color: 'black', + fontSize: 16, + paddingRight: 10, + }, + containerLayout: { + flexDirection: 'row', + padding: 5, + alignItems: 'center', + }, + titleBack: { + alignItems: 'center', + alignSelf: 'center', + }, + itemBack: { + alignItems: 'center', + padding: 5, + alignSelf: 'center', + borderColor: 'gray', + borderWidth: 1, + }, + inputText: { + minWidth: 100, + color: 'black', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/item-list/index.ts b/demos/demo-react-native/src/components/ui/item-list/index.ts new file mode 100644 index 0000000..fae9f24 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/index.ts @@ -0,0 +1,7 @@ +export interface Item { + name: string; + + value: any; +} +export * from './item-selector-view'; +export * from './item-list-view'; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/index.ts b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/index.ts new file mode 100644 index 0000000..a15ae6c --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/index.ts @@ -0,0 +1 @@ +export * from './item-list-popup-view'; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/item-list-popup-view.tsx b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/item-list-popup-view.tsx new file mode 100644 index 0000000..0f62bf0 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/item-list-popup-view.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import { View, Text, Modal, SafeAreaView, ModalProps } from 'react-native'; +import styles from './styles'; +import ItemListView from '../item-list-view/item-list-view'; +import type { Item } from '..'; + +interface Props extends Pick { + title: string; + itemList: Item[]; + selectedItem?: Item; + onSelected?: (item: Item) => void; +} + +export const ItemListPopupView: React.FC = ({ + visible, + title, + itemList, + selectedItem, + onSelected, +}) => { + return ( + + + + + {title} + + { + onSelected?.(item); + }} + /> + + + + ); +}; + +ItemListPopupView.displayName = 'ItemSelectorView'; + +export default ItemListPopupView; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/styles.tsx b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/styles.tsx new file mode 100644 index 0000000..edbf8a9 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-popup-view/styles.tsx @@ -0,0 +1,34 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + safeAreaContainer: { + flex: 1, + backgroundColor: '#000000A0', + alignItems: 'center', + justifyContent: 'center', + }, + modalContainerLayout: { + backgroundColor: 'white', + width: '80%', + height: '80%', + }, + // titleText: { + // color: 'black', + // fontSize: 16, + // paddingRight: 10, + // }, + // itemText: { + // color: 'black', + // fontSize: 16, + // }, + listTitle: { + color: 'black', + fontSize: 18, + textAlign: 'center', + }, + listTitleBack: { + alignItems: 'center', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-view/index.ts b/demos/demo-react-native/src/components/ui/item-list/item-list-view/index.ts new file mode 100644 index 0000000..3c36735 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-view/index.ts @@ -0,0 +1 @@ +export * from './item-list-view'; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-view/item-list-view.tsx b/demos/demo-react-native/src/components/ui/item-list/item-list-view/item-list-view.tsx new file mode 100644 index 0000000..79c42aa --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-view/item-list-view.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { + type ViewProps, + type ViewStyle, + StyleProp, + TouchableOpacity, + Text, + View, + ScrollView, +} from 'react-native'; +import styles from './styles'; +import type { Item } from '..'; + +interface Props extends Pick { + style?: StyleProp; + itemList: Item[]; + selectedItem?: Item; + onSelected?: (item: Item) => void; +} + +export const ItemListView: React.FC = ({ + itemList, + onSelected, + selectedItem, +}) => { + const onPressItem = (item: Item) => { + onSelected?.(item); + }; + + const items = itemList.map(item => ( + onPressItem(item)}> + + {item.name} + + + )); + + return ( + + {items} + + ); +}; + +export default ItemListView; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-list-view/styles.tsx b/demos/demo-react-native/src/components/ui/item-list/item-list-view/styles.tsx new file mode 100644 index 0000000..e947b92 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-list-view/styles.tsx @@ -0,0 +1,25 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + itemText: { + color: 'black', + fontSize: 18, + paddingHorizontal: 10, + paddingVertical: 1, + }, + container: { + flex: 1, + }, + listContentContainer: { + flex: 1, + }, + listItemBase: { + width: '100%', + }, + selectedListItemBase: { + width: '100%', + backgroundColor: 'lightgray', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-selector-view/index.ts b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/index.ts new file mode 100644 index 0000000..be6f78b --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/index.ts @@ -0,0 +1 @@ +export * from './item-selector-view'; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-selector-view/item-selector-view.tsx b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/item-selector-view.tsx new file mode 100644 index 0000000..edc737d --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/item-selector-view.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import { + StyleProp, + TouchableOpacity, + View, + ViewStyle, + type ButtonProps, + Text, +} from 'react-native'; +import styles from './styles'; +import type { Item } from '..'; +import { ItemListPopupView } from '../item-list-popup-view'; + +interface Props extends Pick { + style?: StyleProp; + itemList: Item[]; + selectedItem?: Item; + onSelected?: (item: Item) => void; + placeHolder?: string; +} + +export const ItemSelectorView: React.FC = ({ + disabled = false, + style, + title, + itemList, + selectedItem, + placeHolder, + onSelected, +}) => { + const [isShowList, setShowList] = React.useState(false); + + const onPress = () => { + setShowList(true); + }; + return ( + + { + setShowList(false); + onSelected?.(item); + }} + /> + + + {title} + + + + {selectedItem?.name || placeHolder || 'select value'} + + + + + ); +}; + +ItemSelectorView.displayName = 'ItemSelectorView'; + +export default ItemSelectorView; diff --git a/demos/demo-react-native/src/components/ui/item-list/item-selector-view/styles.tsx b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/styles.tsx new file mode 100644 index 0000000..0aaf2bf --- /dev/null +++ b/demos/demo-react-native/src/components/ui/item-list/item-selector-view/styles.tsx @@ -0,0 +1,31 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + titleText: { + color: 'black', + fontSize: 16, + paddingRight: 10, + }, + itemText: { + color: 'black', + fontSize: 16, + }, + containerLayout: { + flexDirection: 'row', + padding: 5, + alignItems: 'center', + }, + titleBack: { + alignItems: 'center', + alignSelf: 'center', + }, + itemBack: { + alignItems: 'center', + padding: 5, + alignSelf: 'center', + borderColor: 'gray', + borderWidth: 1, + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/titled-switch/index.ts b/demos/demo-react-native/src/components/ui/titled-switch/index.ts new file mode 100644 index 0000000..b19e844 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/titled-switch/index.ts @@ -0,0 +1 @@ +export * from './titled-switch'; diff --git a/demos/demo-react-native/src/components/ui/titled-switch/styles.tsx b/demos/demo-react-native/src/components/ui/titled-switch/styles.tsx new file mode 100644 index 0000000..33bf56d --- /dev/null +++ b/demos/demo-react-native/src/components/ui/titled-switch/styles.tsx @@ -0,0 +1,25 @@ +import { StyleSheet } from 'react-native'; + +const styles = StyleSheet.create({ + titleText: { + color: 'black', + fontSize: 16, + paddingRight: 10, + }, + containerLayout: { + flexDirection: 'row', + padding: 5, + alignItems: 'center', + }, + titleBack: { + alignItems: 'center', + alignSelf: 'center', + }, + itemBack: { + alignItems: 'center', + padding: 5, + alignSelf: 'center', + }, +}); + +export default styles; diff --git a/demos/demo-react-native/src/components/ui/titled-switch/titled-switch.tsx b/demos/demo-react-native/src/components/ui/titled-switch/titled-switch.tsx new file mode 100644 index 0000000..123e9c4 --- /dev/null +++ b/demos/demo-react-native/src/components/ui/titled-switch/titled-switch.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import { + StyleProp, + View, + ViewStyle, + Text, + ViewProps, + Switch, +} from 'react-native'; +import styles from './styles'; + +interface Props extends Pick { + title?: string; + style?: StyleProp; + value?: boolean; + onChange?: (value: boolean) => void; +} + +export const TitledSwitch: React.FC = ({ + style, + title, + value, + onChange, +}) => { + const [editValue, setEditValue] = React.useState(value ?? false); + + React.useEffect(() => { + if (value != null) { + setEditValue(value); + } + }, [value]); + + const onChangeValue = (newValue: boolean) => { + setEditValue(newValue); + onChange?.(newValue); + }; + + return ( + + + + {title} + + + + + + + ); +}; + +TitledSwitch.displayName = 'TitledSwitch'; + +export default TitledSwitch; diff --git a/demos/demo-react-native/src/device-context.tsx b/demos/demo-react-native/src/device-context.tsx new file mode 100644 index 0000000..7eda5ca --- /dev/null +++ b/demos/demo-react-native/src/device-context.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import type { ThetaDevice } from 'theta-ble-client-react-native'; + +interface Props { + thetaDevice?: ThetaDevice; + setThetaDevice: (device?: ThetaDevice) => void; +} + +const DeviceContext = React.createContext({ + setThetaDevice: () => { + console.log('error'); + }, +}); + +export function useDeviceContext() { + return React.useContext(DeviceContext); +} +export function DeviceProvider({ children }) { + const [thetaDevice, setThetaDevice] = React.useState(); + + const value = { + thetaDevice, + setThetaDevice, + }; + + return ( + {children} + ); +} diff --git a/demos/demo-react-native/src/screen/camera-control-command-v2/camera-control-command-v2-screen.tsx b/demos/demo-react-native/src/screen/camera-control-command-v2/camera-control-command-v2-screen.tsx new file mode 100644 index 0000000..52d5a6c --- /dev/null +++ b/demos/demo-react-native/src/screen/camera-control-command-v2/camera-control-command-v2-screen.tsx @@ -0,0 +1,198 @@ +import * as React from 'react'; +import { useDeviceContext } from '../../device-context'; +import { + BleServiceEnum, + CameraControlCommandV2, +} from 'theta-ble-client-react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import styles from './styles'; +import { Alert, ScrollView, Text, View } from 'react-native'; +import { Item, ItemListView } from '../../components/ui/item-list'; +import Button from '../../components/ui/button'; + +const ERROR_MESSAGE_NO_DEVICE = 'No device.'; +const ERROR_MESSAGE_NOT_CONNECTED = 'Not connected.'; +const ERROR_MESSAGE_UNSUPPORTED = 'Unsupported.'; +const TITLE = 'Camera Control CommandV2'; + +interface CommandItem extends Item { + value: { + commandFunction: () => Promise; + }; +} + +function getJsonString(object: any) { + return JSON.stringify(JSON.parse(JSON.stringify(object)), null, 2); +} + +const CameraControlCommandV2Screen = ({ navigation }) => { + const { thetaDevice } = useDeviceContext(); + const [service, setService] = React.useState(); + const [selectedCommand, setSelectedCommand] = React.useState(); + const [message, setMessage] = React.useState(''); + + const commandList: CommandItem[] = [ + { + name: 'getInfo', + value: { + commandFunction: async () => { + if (service == null) { + return ERROR_MESSAGE_UNSUPPORTED; + } + try { + const result = await service.getInfo(); + return `OK getInfo()\n${getJsonString(result)}`; + } catch (error) { + return JSON.stringify(error); + } + }, + }, + }, + { + name: 'getState', + value: { + commandFunction: async () => { + if (service == null) { + return ERROR_MESSAGE_UNSUPPORTED; + } + try { + const result = await service.getState(); + return `OK getState()\n${getJsonString(result)}`; + } catch (error) { + return JSON.stringify(error); + } + }, + }, + }, + { + name: 'getState2', + value: { + commandFunction: async () => { + if (service == null) { + return ERROR_MESSAGE_UNSUPPORTED; + } + try { + const result = await service.getState2(); + return `OK getState2()\n${getJsonString(result)}`; + } catch (error) { + return JSON.stringify(error); + } + }, + }, + }, + { + name: 'setStateNotify', + value: { + commandFunction: async () => { + if (service == null) { + return ERROR_MESSAGE_UNSUPPORTED; + } + try { + await service.setStateNotify((state, error) => { + if (error) { + setMessage(JSON.stringify(error)); + } else { + setMessage(`Notify state:\n${getJsonString(state)}`); + } + }); + return 'OK setStateNotify()'; + } catch (error) { + return JSON.stringify(error); + } + }, + }, + }, + ]; + + const alertToGoBack = (alertMessage: string) => { + Alert.alert(TITLE, alertMessage, [ + { + text: 'OK', + onPress: () => { + navigation.goBack(); + }, + }, + ]); + }; + + const initService = async () => { + if (thetaDevice == null) { + alertToGoBack(ERROR_MESSAGE_NO_DEVICE); + return; + } + if (!(await thetaDevice.isConnected())) { + alertToGoBack(ERROR_MESSAGE_NOT_CONNECTED); + return; + } + const cameraControlCommandV2 = (await thetaDevice.getService( + BleServiceEnum.CAMERA_CONTROL_COMMAND_V2, + )) as CameraControlCommandV2 | undefined; + if (cameraControlCommandV2 == null) { + alertToGoBack(ERROR_MESSAGE_UNSUPPORTED); + return; + } + setService(cameraControlCommandV2); + }; + + const resetNotify = async () => { + if (service == null) { + return; + } + try { + await service.setStateNotify(); + } catch (_) {} + }; + + const onSelected = (item: Item) => { + console.log('selected: ' + item.name); + setSelectedCommand(item); + setMessage(''); + resetNotify(); + }; + + const onExecute = () => { + if (selectedCommand == null) { + return; + } + selectedCommand.value.commandFunction().then(result => { + setMessage(result); + }); + }; + + React.useEffect(() => { + initService(); + return () => { + resetNotify(); + }; + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, []); + + return ( + + + + + + +