diff --git a/Boop/Boop.xcodeproj/project.pbxproj b/Boop/Boop.xcodeproj/project.pbxproj index 0ba59750..41258aca 100644 --- a/Boop/Boop.xcodeproj/project.pbxproj +++ b/Boop/Boop.xcodeproj/project.pbxproj @@ -61,6 +61,8 @@ 2C60A55724871273006496BA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C20667921FD62910082570E /* MainMenu.xib */; }; 2C60A55824871273006496BA /* Preferences.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C5ED41D2357F67200322893 /* Preferences.storyboard */; }; 2C60A56224871730006496BA /* UpdateTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C60A4E524870678006496BA /* UpdateTextField.swift */; }; + 2C873BE12697C2A800D9A3F0 /* PopoverContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C873BE02697C2A800D9A3F0 /* PopoverContainerView.swift */; }; + 2C873BE42697C34200D9A3F0 /* PopoverContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C873BE02697C2A800D9A3F0 /* PopoverContainerView.swift */; }; 2C8BE181249EBADC00099B73 /* SavannaKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2C8BE180249EBADC00099B73 /* SavannaKit */; }; 2C8BE182249EBADC00099B73 /* SavannaKit in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 2C8BE180249EBADC00099B73 /* SavannaKit */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 2C8BE184249EBAEC00099B73 /* SavannaKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2C8BE183249EBAEC00099B73 /* SavannaKit */; }; @@ -144,6 +146,7 @@ 2C60A4A3248300CE006496BA /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; 2C60A4E524870678006496BA /* UpdateTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTextField.swift; sourceTree = ""; }; 2C60A56024871273006496BA /* Boop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Boop.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2C873BE02697C2A800D9A3F0 /* PopoverContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopoverContainerView.swift; sourceTree = ""; }; 2C9118B523406B530018916F /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; 2C9761D42214E11600AFF8CD /* scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scripts; sourceTree = ""; }; 2C9761D82214E3B500AFF8CD /* ScriptsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptsTableViewController.swift; sourceTree = ""; }; @@ -284,6 +287,7 @@ 2C9761E02214E68D00AFF8CD /* ScriptTableViewCell.swift */, 2CA245DB224822EA00586DFD /* ScriptTableView.swift */, 2C60A4E524870678006496BA /* UpdateTextField.swift */, + 2C873BE02697C2A800D9A3F0 /* PopoverContainerView.swift */, ); path = Views; sourceTree = ""; @@ -496,6 +500,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C873BE12697C2A800D9A3F0 /* PopoverContainerView.swift in Sources */, 2CC211C5236FB5C1007CECEE /* ScriptsSettingsViewController.swift in Sources */, 2C53B6E0226D404E00DC6861 /* ScriptExecution.swift in Sources */, 2C0BC0DD24AAC518009B8631 /* Script+Require.swift in Sources */, @@ -539,6 +544,7 @@ 2C60A54224871273006496BA /* DefaultTheme.swift in Sources */, 2C60A54324871273006496BA /* ScriptManager.swift in Sources */, 2C60A54424871273006496BA /* AppDelegate.swift in Sources */, + 2C873BE42697C34200D9A3F0 /* PopoverContainerView.swift in Sources */, 2C60A54524871273006496BA /* OverlayView.swift in Sources */, 2C60A54624871273006496BA /* ScriptTableViewCell.swift in Sources */, 2C60A54724871273006496BA /* ScriptTableView.swift in Sources */, @@ -745,7 +751,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = RLZ8XBTX7G; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -758,7 +764,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.4.0; OTHER_CODE_SIGN_FLAGS = "--deep"; PRODUCT_BUNDLE_IDENTIFIER = com.OKatBest.Boop; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -775,7 +781,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -789,7 +795,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.4.0; OTHER_CODE_SIGN_FLAGS = "--deep"; PRODUCT_BUNDLE_IDENTIFIER = com.okatbest.boop; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -806,7 +812,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -819,7 +825,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.4.0; OTHER_CODE_SIGN_FLAGS = "--deep"; "OTHER_SWIFT_FLAGS[arch=*]" = "-D APPSTORE"; PRODUCT_BUNDLE_IDENTIFIER = com.OKatBest.Boop; @@ -834,11 +840,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Boop/Boop.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3; - DEVELOPMENT_TEAM = ""; + CURRENT_PROJECT_VERSION = 21; + DEVELOPMENT_TEAM = RLZ8XBTX7G; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Boop/Frameworks", @@ -850,7 +856,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.4.0; OTHER_CODE_SIGN_FLAGS = "--deep"; "OTHER_SWIFT_FLAGS[arch=*]" = "-D APPSTORE"; PRODUCT_BUNDLE_IDENTIFIER = com.okatbest.boop; @@ -906,8 +912,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/IvanMathy/savannakit"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.14.2; + branch = main; + kind = branch; }; }; 2C8BE186249EBB3D00099B73 /* XCRemoteSwiftPackageReference "fuse-swift" */ = { diff --git a/Boop/Boop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Boop/Boop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5e12eeac..263450c3 100644 --- a/Boop/Boop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Boop/Boop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,25 +1,23 @@ { - "object": { - "pins": [ - { - "package": "Fuse", - "repositoryURL": "https://github.com/IvanMathy/fuse-swift", - "state": { - "branch": null, - "revision": "acb9a2ec2789ce1dcca4d01872a20da801e7ac55", - "version": "2.0.0" - } - }, - { - "package": "SavannaKit", - "repositoryURL": "https://github.com/IvanMathy/savannakit", - "state": { - "branch": null, - "revision": "d0950476608b714f435c7026ab8c7f13b87e5e81", - "version": "0.14.2" - } + "pins" : [ + { + "identity" : "fuse-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/IvanMathy/fuse-swift", + "state" : { + "revision" : "acb9a2ec2789ce1dcca4d01872a20da801e7ac55", + "version" : "2.0.0" } - ] - }, - "version": 1 + }, + { + "identity" : "savannakit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/IvanMathy/savannakit", + "state" : { + "branch" : "main", + "revision" : "bb51ee074152a7361e7085d10723f699c79fe673" + } + } + ], + "version" : 2 } diff --git a/Boop/Boop/AppDelegate.swift b/Boop/Boop/AppDelegate.swift index 47435030..bff23474 100644 --- a/Boop/Boop/AppDelegate.swift +++ b/Boop/Boop/AppDelegate.swift @@ -23,8 +23,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { // Frame auto save name for app window frame restoration. private static let appWindowName = "boop.app.window" - func applicationDidFinishLaunching(_ aNotification: Notification) { - + func applicationWillFinishLaunching(_ notification: Notification) { ThemeSettingsViewController.applyTheme() NSWindow.allowsAutomaticWindowTabbing = false diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/16.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/16.png deleted file mode 100755 index 43889fcb..00000000 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/16.png and /dev/null differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/Contents.json b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/Contents.json old mode 100755 new mode 100644 index 966ce7f4..64dc11ee --- a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,13 +1,7 @@ { "images" : [ { - "filename" : "icon_512x512@2x-1.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "16.png", + "filename" : "icon_16x16.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128.png index e37cd17f..02cca9dc 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png index fc54e3b0..52cc76b3 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 00000000..2320d395 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png index ac3037d8..c492495a 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256.png index fc54e3b0..0e602f91 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png index 70ea40bb..5f2c75da 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32.png index ac3037d8..c492495a 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png index 36c702f7..eb658486 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512.png index 70ea40bb..5f2c75da 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512.png differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x-1.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x-1.png deleted file mode 100644 index 3a0990f6..00000000 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x-1.png and /dev/null differ diff --git a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png index 3a0990f6..1047c3f0 100644 Binary files a/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png and b/Boop/Boop/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ diff --git a/Boop/Boop/Assets.xcassets/Contents.json b/Boop/Boop/Assets.xcassets/Contents.json index da4a164c..73c00596 100644 --- a/Boop/Boop/Assets.xcassets/Contents.json +++ b/Boop/Boop/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Boop/Boop/Assets.xcassets/Icons/Contents.json b/Boop/Boop/Assets.xcassets/Icons/Contents.json index da4a164c..73c00596 100644 --- a/Boop/Boop/Assets.xcassets/Icons/Contents.json +++ b/Boop/Boop/Assets.xcassets/Icons/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/Contents.json new file mode 100644 index 00000000..666bb62b --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-abacus.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/icons8-abacus.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/icons8-abacus.pdf new file mode 100644 index 00000000..b0438c7c Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-abacus.imageset/icons8-abacus.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/Contents.json similarity index 85% rename from Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/Contents.json rename to Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/Contents.json index a82d6781..bc0f5692 100644 --- a/Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/Contents.json +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "TrimEnd.pdf", + "filename" : "icons8-camel.pdf", "idiom" : "universal" } ], diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/icons8-camel.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/icons8-camel.pdf new file mode 100644 index 00000000..8b2762eb Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-camel.imageset/icons8-camel.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/Contents.json index a59264bb..cb09bd4f 100644 --- a/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/Contents.json +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "icons8-collapse.pdf", + "filename" : "icons8-merge_horizontal.pdf", "idiom" : "universal" } ], diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-collapse.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-collapse.pdf deleted file mode 100644 index 973567a8..00000000 Binary files a/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-collapse.pdf and /dev/null differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-merge_horizontal.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-merge_horizontal.pdf new file mode 100644 index 00000000..05ed2586 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-collapse.imageset/icons8-merge_horizontal.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/Contents.json new file mode 100644 index 00000000..db8da321 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icons8-color_mode.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/icons8-color_mode.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/icons8-color_mode.pdf new file mode 100644 index 00000000..3075c845 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-color-wheel.imageset/icons8-color_mode.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/Contents.json new file mode 100644 index 00000000..0662e166 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-colosseum.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/icons8-colosseum.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/icons8-colosseum.pdf new file mode 100644 index 00000000..e4108e03 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-colosseum.imageset/icons8-colosseum.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/Contents.json new file mode 100644 index 00000000..425c07ad --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-run_command.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/icons8-run_command.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/icons8-run_command.pdf new file mode 100644 index 00000000..d62c2677 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-command.imageset/icons8-run_command.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/Contents.json new file mode 100644 index 00000000..67272a2b --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-elephant.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/icons8-elephant.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/icons8-elephant.pdf new file mode 100644 index 00000000..b59ed7d8 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-elephant.imageset/icons8-elephant.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/Contents.json new file mode 100644 index 00000000..f82d746f --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-test_tube.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/icons8-test_tube.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/icons8-test_tube.pdf new file mode 100644 index 00000000..22ff8da9 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-flask.imageset/icons8-test_tube.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/Contents.json new file mode 100644 index 00000000..88384418 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icons8-globe.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/icons8-globe.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/icons8-globe.pdf new file mode 100644 index 00000000..a9b038b7 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-globe.imageset/icons8-globe.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/Contents.json similarity index 85% rename from Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/Contents.json rename to Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/Contents.json index a2bdca6f..069fa642 100644 --- a/Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/Contents.json +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "TrimStart.pdf", + "filename" : "icons8-kebab.pdf", "idiom" : "universal" } ], diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/icons8-kebab.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/icons8-kebab.pdf new file mode 100644 index 00000000..c2f2ba63 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-kebab.imageset/icons8-kebab.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/Contents.json new file mode 100644 index 00000000..a68e082d --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icons8-percentage.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/icons8-percentage.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/icons8-percentage.pdf new file mode 100644 index 00000000..ef7b344b Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-percentage.imageset/icons8-percentage.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/Contents.json new file mode 100644 index 00000000..d70259bc --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "icons8-pineapple.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/icons8-pineapple.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/icons8-pineapple.pdf new file mode 100644 index 00000000..9624c337 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-pineapple.imageset/icons8-pineapple.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/Contents.json new file mode 100644 index 00000000..b4f30a8c --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-roman_helmet.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/icons8-roman_helmet.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/icons8-roman_helmet.pdf new file mode 100644 index 00000000..9c6add70 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-roman.imageset/icons8-roman_helmet.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/Contents.json new file mode 100644 index 00000000..87bd91c8 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-scissors.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/icons8-scissors.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/icons8-scissors.pdf new file mode 100644 index 00000000..3efd4715 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-scissors.imageset/icons8-scissors.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/Contents.json similarity index 85% rename from Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Contents.json rename to Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/Contents.json index e97debc2..2cbeeea0 100644 --- a/Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Contents.json +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Trim.pdf", + "filename" : "icons8-snake.pdf", "idiom" : "universal" } ], diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/icons8-snake.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/icons8-snake.pdf new file mode 100644 index 00000000..045aa701 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-snake.imageset/icons8-snake.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/Contents.json new file mode 100644 index 00000000..1f185c4c --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-alphabetical_sorting.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/icons8-alphabetical_sorting.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/icons8-alphabetical_sorting.pdf new file mode 100644 index 00000000..d6039691 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-characters.imageset/icons8-alphabetical_sorting.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/Contents.json new file mode 100644 index 00000000..1bf8c3c5 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-reversed_numerical_sorting.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/icons8-reversed_numerical_sorting.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/icons8-reversed_numerical_sorting.pdf new file mode 100644 index 00000000..c14138af Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-sort-numbers.imageset/icons8-reversed_numerical_sorting.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/Contents.json b/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/Contents.json new file mode 100644 index 00000000..571ea188 --- /dev/null +++ b/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icons8-translation.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/icons8-translation.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/icons8-translation.pdf new file mode 100644 index 00000000..18f98b04 Binary files /dev/null and b/Boop/Boop/Assets.xcassets/Icons/icons8-translation.imageset/icons8-translation.pdf differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Trim.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Trim.pdf deleted file mode 100644 index 81be955b..00000000 Binary files a/Boop/Boop/Assets.xcassets/Icons/icons8-trim.imageset/Trim.pdf and /dev/null differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/TrimEnd.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/TrimEnd.pdf deleted file mode 100644 index 03637cc1..00000000 Binary files a/Boop/Boop/Assets.xcassets/Icons/icons8-trimend.imageset/TrimEnd.pdf and /dev/null differ diff --git a/Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/TrimStart.pdf b/Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/TrimStart.pdf deleted file mode 100644 index 7a55ca2c..00000000 Binary files a/Boop/Boop/Assets.xcassets/Icons/icons8-trimstart.imageset/TrimStart.pdf and /dev/null differ diff --git a/Boop/Boop/Controllers/MainViewController.swift b/Boop/Boop/Controllers/MainViewController.swift index a6cede71..762b7f49 100644 --- a/Boop/Boop/Controllers/MainViewController.swift +++ b/Boop/Boop/Controllers/MainViewController.swift @@ -30,12 +30,12 @@ class MainViewController: NSViewController { } @IBAction func openHelp(_ sender: Any) { - open(url: "https://github.com/IvanMathy/Boop/blob/master/Boop/Documentation/Readme.md") + open(url: "https://boop.okat.best/docs/") } @IBAction func openScripts(_ sender: Any) { - open(url: "https://github.com/IvanMathy/Boop/tree/main/Scripts") + open(url: "https://boop.okat.best/scripts/") } diff --git a/Boop/Boop/Controllers/PopoverViewController.swift b/Boop/Boop/Controllers/PopoverViewController.swift index da7748a0..286fedab 100644 --- a/Boop/Boop/Controllers/PopoverViewController.swift +++ b/Boop/Boop/Controllers/PopoverViewController.swift @@ -12,7 +12,7 @@ import SavannaKit class PopoverViewController: NSViewController { @IBOutlet weak var overlayView: OverlayView! - @IBOutlet weak var popoverView: PopoverView! + @IBOutlet weak var popoverView: PopoverContainerView! @IBOutlet weak var searchField: SearchField! @IBOutlet weak var editorView: SyntaxTextView! @IBOutlet weak var statusView: StatusView! @@ -28,6 +28,14 @@ class PopoverViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() + + // Double-click script selection + tableView.doubleAction = #selector(runSelectedScript) + + // Dismiss popover on background view click + overlayView.onMouseDown = { [weak self] in + self?.hide() + } setupKeyHandlers() } @@ -41,6 +49,7 @@ class PopoverViewController: NSViewController { var didSomething = false // Key codes: + let kVKTab = 0x30 // 125 is down arrow // 126 is up // 53 is escape @@ -55,24 +64,29 @@ class PopoverViewController: NSViewController { } if theEvent.keyCode == 36 && self.enabled { // ENTER - - guard let script = self.tableViewController.selectedScript else { - return theEvent // Return event to beep + + guard self.tableViewController.selectedScript != nil else { + return theEvent } - - - // Let's dismiss the popover - self.hide() - - // Run the script afterwards in case we need to show a status - self.scriptManager.runScript(script, into: self.editorView) - + + self.runSelectedScript() didSomething = true } - + let window = self.view.window + if theEvent.keyCode == kVKTab && self.enabled { + if window?.firstResponder is NSTextView && + (window?.firstResponder as! NSTextView).delegate is SearchField { + let offset = theEvent.modifierFlags.contains(.shift) ? -1 : 1 + let newSel = IndexSet([self.tableView.selectedRow + offset]) + self.tableView.selectRowIndexes(newSel, byExtendingSelection: false) + self.tableView.scrollRowToVisible(self.tableView.selectedRow) + } + didSomething = true // prevent tabbing back into text document + } + if window?.firstResponder is NSTextView && (window?.firstResponder as! NSTextView).delegate is SearchField && theEvent.keyCode == 125 { // DOWN @@ -142,6 +156,18 @@ class PopoverViewController: NSViewController { func runScriptAgain() { self.scriptManager.runScriptAgain(editor: self.editorView) } + + @objc private func runSelectedScript() { + guard let script = tableViewController.selectedScript else { + return + } + + // Let's dismiss the popover + hide() + + // Run the script afterwards in case we need to show a status + scriptManager.runScript(script, into: editorView) + } } @@ -154,6 +180,6 @@ extension PopoverViewController: NSTextFieldDelegate { let results = scriptManager.search(searchField.stringValue) tableViewController.results = results - self.tableHeightConstraint.constant = CGFloat(47 * min(5, results.count)) + self.tableHeightConstraint.constant = CGFloat(45 * min(5, results.count) + ((results.count != 0) ? 20 : 0)) } } diff --git a/Boop/Boop/Controllers/Preferences/ScriptsSettingsViewController.swift b/Boop/Boop/Controllers/Preferences/ScriptsSettingsViewController.swift index 3a727774..1aca2e39 100644 --- a/Boop/Boop/Controllers/Preferences/ScriptsSettingsViewController.swift +++ b/Boop/Boop/Controllers/Preferences/ScriptsSettingsViewController.swift @@ -54,7 +54,7 @@ class ScriptsSettingsViewController: NSViewController { @IBAction func didClickHelpButton(_ sender: Any) { - guard let url = URL(string: "https://github.com/IvanMathy/Boop/blob/master/Boop/Documentation/CustomScripts.md#custom-scripts") else { + guard let url = URL(string: "https://boop.okat.best/docs/scripts") else { assertionFailure("Could not generate help URL.") return } diff --git a/Boop/Boop/Controllers/ScriptsTableViewController.swift b/Boop/Boop/Controllers/ScriptsTableViewController.swift index 5443eedd..e712ca70 100644 --- a/Boop/Boop/Controllers/ScriptsTableViewController.swift +++ b/Boop/Boop/Controllers/ScriptsTableViewController.swift @@ -22,6 +22,20 @@ class ScriptsTableViewController: NSViewController, NSTableViewDelegate, NSTable return results.count } + private func scriptIcon(identifier: String?) -> NSImage? { + guard let identifier = identifier else { + return NSImage(named: "icons8-unknown") + } + if let namedImage = NSImage(named: "icons8-\(identifier)") { + return namedImage + } + if #available(macOS 11.0, *), + let systemImage = NSImage(systemSymbolName: identifier, accessibilityDescription: nil) { + return systemImage + } + return nil + } + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let view = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "scriptCell"), owner: self) as! ScriptTableViewCell @@ -33,7 +47,7 @@ class ScriptsTableViewController: NSViewController, NSTableViewDelegate, NSTable view.titleLabel.stringValue = script.name ?? "No Name 🤔" view.subtitleLabel.stringValue = script.desc ?? "No Description 😢" - view.imageView?.image = NSImage(named: "icons8-\(script.icon ?? "unknown")") + view.imageView?.image = self.scriptIcon(identifier: script.icon) return view diff --git a/Boop/Boop/Editor/BoopLexer.swift b/Boop/Boop/Editor/BoopLexer.swift index 6d3b8a32..1e392b3f 100644 --- a/Boop/Boop/Editor/BoopLexer.swift +++ b/Boop/Boop/Editor/BoopLexer.swift @@ -21,13 +21,7 @@ class BoopLexer: RegexLexer { func generators(source: String) -> [TokenGenerator] { - let standalonePrefix = "(?<=[\\s]|^|[\\(,:])" - let standaloneSuffix = "(?=[\\s\\?\\!,:\\)\\();]|$)" - - let quoteLookahead = "(?=(?:(?:[^\"]*\"){2})*[^\"]*$)" - - let quotes = "(\"|@\")(?:[^\"\\\\\\n]|\\\\.)*[^\"\\n]*(@\"|\")" - let number = "\\b(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)\\b" + let number = #"\b(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)\b"# var generators = [TokenGenerator?]() @@ -36,48 +30,46 @@ class BoopLexer: RegexLexer { // Find common attributes - generators.append(regexToken(.attribute, "\(standalonePrefix)(\(commonAttributes.joined(separator: "|")))\(standaloneSuffix)", options: .caseInsensitive)) + generators.append(regexToken(.attribute, #"\b(\#(commonAttributes.joined(separator: "|")))\b"#, options: .caseInsensitive)) - generators.append(regexToken(.keyword, "\(standalonePrefix)(\(moreAttributes.joined(separator: "|")))\(standaloneSuffix)", options: .caseInsensitive)) + generators.append(regexToken(.keyword, #"\b(\#(moreAttributes.joined(separator: "|")))\b"#, options: .caseInsensitive)) // Extras let UTCDate = "(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\\s+)?(0[1-9]|[1-2]?[0-9]|3[01])\\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s+(19[0-9]{2}|[2-9][0-9]{3})\\s+(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?\\s+([-\\+][0-9]{2}[0-5][0-9]|(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z]))" - generators.append(regexToken(.number, "\(standalonePrefix)(\(UTCDate))\(standaloneSuffix)")) + generators.append(regexToken(.number, UTCDate)) // - Match MD5 strings - generators.append(regexToken(.keyword, "\(standalonePrefix)([a-f0-9]{32})\(standaloneSuffix)")) + generators.append(regexToken(.keyword, "[a-f0-9]{32}")) // - Bootleg XML-like tags match: - generators.append(regexToken(.attribute, "(?m)\(quoteLookahead)<(?:.*?)\\b[^>]*\\/?>")) + generators.append(regexToken(.attribute, "<(?:.*?)\\b[^>]*\\/?>")) - // Strings - generators.append(regexToken(.string, quotes, options: [.dotMatchesLineSeparators, .caseInsensitive])) + // - Match JSON labels and generic parameters + generators.append(regexToken(.extra, #""([^"]+?)"\s*(?=:)"#, greedy: true)) - generators.append(regexToken(.string, "`(?:[^`\\\\\\n]|\\\\.)*[^`\\n]*`", options: [.dotMatchesLineSeparators, .caseInsensitive])) + // Strings - generators.append(regexToken(.string, "'(?:[^\'\\\\\\n]|\\\\.)*[^\'\\n]*'", options: [.dotMatchesLineSeparators, .caseInsensitive])) + let quotes = #"(["'`])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1"# - generators.append(regexToken(.string, "(\"\"\")(.*?)(\"\"\")", options: [.dotMatchesLineSeparators, .caseInsensitive])) + generators.append(regexToken(.string, quotes, greedy: true)) - // More Extras + generators.append(regexToken(.string, "(\"\"\")(.*?)(\"\"\")", options: [.dotMatchesLineSeparators, .caseInsensitive], greedy: true)) - // - Match JSON labels and generic parameters - generators.append(regexToken(.extra, "(?m)\(quoteLookahead)(?=(?:[ {\\[]*))([^\\r\\n:\\s\\w]+?|\(quotes))\\s*(?=\\:(?!\\:))")) // Comments - generators.append(regexToken(.comment, "\(quoteLookahead)//(.*)")) + generators.append(regexToken(.comment, #"(?=(\/\/.*))"#)) - generators.append(regexToken(.comment, "\(quoteLookahead)/\\*.*?\\*/", options: [.dotMatchesLineSeparators, .caseInsensitive])) + generators.append(regexToken(.comment, #"(?=(\/\*[\s\S]*?(?:\*\/|$)))"#, options: [.dotMatchesLineSeparators], greedy: true)) - generators.append(regexToken(.comment, "\(quoteLookahead)<\\!--[\\s\\S]*?(?:-\\->|$)", options: [.dotMatchesLineSeparators, .caseInsensitive])) + generators.append(regexToken(.comment, #""#, options: [.dotMatchesLineSeparators, .caseInsensitive], greedy: true)) @@ -85,12 +77,12 @@ class BoopLexer: RegexLexer { return generators.compactMap( { $0 }) } - func regexToken(_ type: BoopToken.TokenType, _ pattern:String, options: NSRegularExpression.Options = .caseInsensitive) -> TokenGenerator? { + func regexToken(_ type: BoopToken.TokenType, _ pattern:String, options: NSRegularExpression.Options = .caseInsensitive, greedy: Bool = false) -> TokenGenerator? { guard let regex = try? NSRegularExpression(pattern: pattern, options: options) else { return nil } let generator = RegexTokenGenerator(regularExpression: regex, tokenTransformer: { (range) -> Token in - return BoopToken(type: type, range: range) + return BoopToken(type: type, range: range, greedy: greedy) }) return TokenGenerator.regex(generator) } diff --git a/Boop/Boop/Editor/BoopToken.swift b/Boop/Boop/Editor/BoopToken.swift index 7c7689f5..62386b02 100644 --- a/Boop/Boop/Editor/BoopToken.swift +++ b/Boop/Boop/Editor/BoopToken.swift @@ -9,9 +9,11 @@ import Cocoa import SavannaKit -class BoopToken: Token { +class BoopToken: Token, CustomStringConvertible { - public enum TokenType { + + + public enum TokenType: String { case comment case string case attribute @@ -26,15 +28,22 @@ class BoopToken: Token { // Plain tokens are not even parsed in the first place. var isPlain = false - var range: Range + var isActive = true + var isGreedy: Bool + + var range: NSRange var type: BoopToken.TokenType - init(type:TokenType, range: Range) { + init(type:TokenType, range: NSRange, greedy: Bool = false) { self.range = range self.type = type + self.isGreedy = greedy } + var description: String { + return type.rawValue + } } diff --git a/Boop/Boop/Editor/Themes/Colors.swift b/Boop/Boop/Editor/Themes/Colors.swift index 33465645..e2706d36 100644 --- a/Boop/Boop/Editor/Themes/Colors.swift +++ b/Boop/Boop/Editor/Themes/Colors.swift @@ -45,12 +45,16 @@ struct ColorPair { static let orangish = ColorPair(light: Colors.orangeABitDarker, dark: Colors.orangeish) static let body = ColorPair(light: .init(white: 0.1, alpha: 1), dark: .white) - static let normal = ColorPair(light: .white, dark: .init(white: 0.1, alpha: 1)) - static let gutter = ColorPair(light: .init(white: 240/255, alpha: 1), dark: .init(white: 22/255, alpha: 1)) - static let popover = ColorPair(light: .white, dark: .init(white: 0.05, alpha: 1)) + static let normal = ColorPair(light: .init(white: 0.85, alpha: 1), dark: .init(white: 0.3, alpha: 1)) + static let gutter = ColorPair(light: .init(white: 240/255, alpha: 1), dark: .init(white: 27/255, alpha: 1)) + static let popover = ColorPair(light: .init(white: 0.95, alpha: 1), dark: .init(white: 0.12, alpha: 1)) + static let comments = ColorPair(light: Colors.commentGreyDarkest, dark: Colors.commentGreyDarkest) - static let separator = ColorPair(light: .init(white: 220/255, alpha: 1), dark: .init(white: 15/255, alpha: 1)) - static let background = ColorPair(light: .init(white: 0.95, alpha: 1), dark: NSColor(red: 31/255.0, green: 31/255, blue: 31/255, alpha: 1.0)) + static let separator = ColorPair(light: .init(white: 220/255, alpha: 1), dark: .init(white: 45/255, alpha: 1)) + static let background = ColorPair(light: .init(white: 0.95, alpha: 1.0), dark: .init(white: 31/255, alpha: 1.0)) + static let overlayColor = ColorPair(light: .init(white: 0.85, alpha: 0.6), dark: .init(white: 0.08, alpha: 0.6)) + static let popoverBorder = ColorPair(light: .init(white: 220/255, alpha: 1), dark: .init(white: 75/255, alpha: 1)) + static let popoverOutline = ColorPair(light: .init(white: 150/255, alpha: 1), dark: .init(white: 20/255, alpha: 1)) let light: NSColor diff --git a/Boop/Boop/System/Models/Script.swift b/Boop/Boop/System/Models/Script.swift index 8aa1b575..eaa3b1ba 100644 --- a/Boop/Boop/System/Models/Script.swift +++ b/Boop/Boop/System/Models/Script.swift @@ -16,6 +16,7 @@ class Script: NSObject { var url: URL var scriptCode: String + lazy var context: JSContext = { [unowned self] in let context: JSContext = JSContext() context.name = self.name ?? "Unknown Script" diff --git a/Boop/Boop/System/ScriptManager.swift b/Boop/Boop/System/ScriptManager.swift index 7654c0b4..9461c4f3 100644 --- a/Boop/Boop/System/ScriptManager.swift +++ b/Boop/Boop/System/ScriptManager.swift @@ -221,6 +221,7 @@ class ScriptManager: NSObject { func runScript(_ script: Script, selection: String? = nil, fullText: String, insertIndex: Int? = nil) -> String { let scriptExecution = ScriptExecution(selection: selection, fullText: fullText, script: script, insertIndex: insertIndex) + self.statusView.setStatus(.normal) script.run(with: scriptExecution) return scriptExecution.text ?? "" diff --git a/Boop/Boop/Views/OverlayView.swift b/Boop/Boop/Views/OverlayView.swift index 5beb372b..b74fa7f2 100644 --- a/Boop/Boop/Views/OverlayView.swift +++ b/Boop/Boop/Views/OverlayView.swift @@ -10,18 +10,28 @@ import Cocoa class OverlayView: NSView { + var onMouseDown: (() -> Void)? + required init?(coder decoder: NSCoder) { super.init(coder: decoder) self.wantsLayer = true - self.layer?.backgroundColor = NSColor(calibratedWhite: 0.05, alpha: 1).cgColor self.animator().isHidden = true self.alphaValue = 0; + + setBackground() + } + + func setBackground() { + + self.layer?.backgroundColor = ColorPair.overlayColor.value(for: self.effectiveAppearance).cgColor + + } func show() { - self.animator().alphaValue = 0.6 + self.animator().alphaValue = 1 self.animator().isHidden = false } @@ -32,7 +42,12 @@ class OverlayView: NSView { } override func mouseDown(with event: NSEvent) { - return + onMouseDown?() + } + + override func viewDidChangeEffectiveAppearance() { + super.viewDidChangeEffectiveAppearance() + self.setBackground() } } diff --git a/Boop/Boop/Views/PopoverContainerView.swift b/Boop/Boop/Views/PopoverContainerView.swift new file mode 100644 index 00000000..50a9969e --- /dev/null +++ b/Boop/Boop/Views/PopoverContainerView.swift @@ -0,0 +1,60 @@ +// +// PopoverContainerView.swift +// Boop +// +// Created by Ivan on 7/8/21. +// Copyright © 2021 OKatBest. All rights reserved. +// + +import Foundation +import AppKit + + +class PopoverContainerView: NSView { + + // This is a wrapper view so that the child popver actually clips + // the contained table. The issue was the shadow is technically + // part of the mask so rounded corners would get ignored. + + required init?(coder decoder: NSCoder) { + super.init(coder: decoder) + + self.wantsLayer = true + self.layer?.cornerRadius = 12.0 + + let dropShadow = NSShadow() + dropShadow.shadowColor = NSColor(calibratedWhite: 0, alpha: 0.45) + dropShadow.shadowOffset = NSMakeSize(0, -20.0) + dropShadow.shadowBlurRadius = 10.0 + + + self.layer?.borderWidth = 0.5 + + self.shadow = dropShadow + + self.isHidden = true + + self.setOutline() + + } + + func setOutline() { + self.layer?.borderColor = ColorPair.popoverOutline.value(for: self.effectiveAppearance).cgColor + } + + override func viewDidChangeEffectiveAppearance() { + super.viewDidChangeEffectiveAppearance() + self.setOutline() + } + + func show() { + self.animator().alphaValue = 1 + self.animator().isHidden = false + } + + func hide() { + self.animator().alphaValue = 0 + self.animator().isHidden = true; + } + +} diff --git a/Boop/Boop/Views/PopoverView.swift b/Boop/Boop/Views/PopoverView.swift index 9a439d79..f360a144 100644 --- a/Boop/Boop/Views/PopoverView.swift +++ b/Boop/Boop/Views/PopoverView.swift @@ -15,35 +15,20 @@ class PopoverView: NSView { // UI set up self.wantsLayer = true - self.layer?.cornerRadius = 5.0 + self.layer?.cornerRadius = 12.0 self.layer?.masksToBounds = true - self.setBackground() - - let dropShadow = NSShadow() - dropShadow.shadowColor = NSColor(calibratedWhite: 0, alpha: 1) - dropShadow.shadowOffset = NSMakeSize(0, -10.0) - dropShadow.shadowBlurRadius = 10.0 - - self.shadow = dropShadow + self.layer?.borderWidth = 1.5 - self.isHidden = true + self.setBackground() + } - func show() { - self.animator().alphaValue = 1 - self.animator().isHidden = false - } - - func hide() { - self.animator().alphaValue = 0 - self.animator().isHidden = true; - } - func setBackground() { self.layer?.backgroundColor = ColorPair.popover.value(for: self.effectiveAppearance).cgColor + self.layer?.borderColor = ColorPair.popoverBorder.value(for: self.effectiveAppearance).cgColor } diff --git a/Boop/Boop/Views/StatusView.swift b/Boop/Boop/Views/StatusView.swift index 64e685e4..09d060af 100644 --- a/Boop/Boop/Views/StatusView.swift +++ b/Boop/Boop/Views/StatusView.swift @@ -36,7 +36,7 @@ class StatusView: NSView { self.wantsLayer = true - self.layer?.backgroundColor = NSColor.textBackgroundColor.cgColor + self.layer?.backgroundColor = ColorPair.normal.value(for: self.effectiveAppearance).cgColor self.layer?.cornerRadius = 5 } diff --git a/Boop/Boop/scripts/ASCIIToHex.js b/Boop/Boop/scripts/ASCIIToHex.js new file mode 100644 index 00000000..e0323b0c --- /dev/null +++ b/Boop/Boop/scripts/ASCIIToHex.js @@ -0,0 +1,20 @@ +/** + { + "api":1, + "name":"ASCII To Hex", + "description":"Converts ASCII characters to hexadecimal codes.", + "author":"aWZHY0yQH81uOYvH", + "icon":"metamorphose", + "tags":"ascii,hex,convert" + } +**/ + +function main(state) { + buf = ""; + for(i = 0; i < state.fullText.length; i ++) { + code = state.fullText.charCodeAt(i).toString(16); + if(code.length < 2) buf += "0"; + buf += code; + } + state.fullText = buf.toUpperCase(); +} diff --git a/Boop/Boop/scripts/AddSlashes.js b/Boop/Boop/scripts/AddSlashes.js index c3df233c..ffe54fc0 100644 --- a/Boop/Boop/scripts/AddSlashes.js +++ b/Boop/Boop/scripts/AddSlashes.js @@ -2,7 +2,7 @@ { "api":1, "name":"Add Slashes", - "description":"Escapes your text", + "description":"Escapes your text.", "author":"Ivan", "icon":"quote", "tags":"add,slashes,escape" diff --git a/Boop/Boop/scripts/AndroidIOSStrings.js b/Boop/Boop/scripts/AndroidIOSStrings.js new file mode 100644 index 00000000..40fffe13 --- /dev/null +++ b/Boop/Boop/scripts/AndroidIOSStrings.js @@ -0,0 +1,24 @@ +/** + { + "api":1, + "name":"Android Strings to iOS Localizables", + "description":"Converts Android Strings to iOS localizables.", + "author":"Manuel Kunz (https://github.com/KunzManuel)", + "icon":"translation", + "tags":"string,android,ios" + } +**/ + +function main(input) { + let lines = input.fullText.split('\n') + var result = [] + lines.forEach(element => { + var temp = element + temp = temp.replace("", "\";") + temp = temp.replace(">", " = \"") + result.push(temp) + }) + + input.fullText = result.join('\n') +} diff --git a/Boop/Boop/scripts/BinaryToDecimal.js b/Boop/Boop/scripts/BinaryToDecimal.js new file mode 100644 index 00000000..c962d276 --- /dev/null +++ b/Boop/Boop/scripts/BinaryToDecimal.js @@ -0,0 +1,31 @@ +/** + { + "api": 1, + "name": "Binary to Decimal", + "description": "Converts binary values to decimal.", + "author": "Maurice", + "icon": "metamorphose", + "tags": "decimal,binary,dec,bin" + } + **/ + +function main(state) { + var text = state.text; + var lines = text.split(/\n/); + var result = ""; + + for (const index in lines) { + var text = lines[index].trim(); + var decimal = parseInt(text, 2); + + if (isNaN(decimal)) { + result += text; + } else { + result += decimal; + } + + result += "\n"; + } + + state.text = result.trim(); +} diff --git a/Boop/Boop/scripts/CSVtoJSON.js b/Boop/Boop/scripts/CSVtoJSON.js index 4625385f..e368a024 100644 --- a/Boop/Boop/scripts/CSVtoJSON.js +++ b/Boop/Boop/scripts/CSVtoJSON.js @@ -1,33 +1,22 @@ /** { - "api":1, + "api":2, "name":"CSV to JSON", "description":"Converts comma-separated tables to JSON.", "author":"Ivan", "icon":"table", "tags":"table,convert", - "bias": -0.2 + "bias": -0.2 } **/ - -// Inspired by https://github.com/30-seconds/30-seconds-of-code +const Papa = require('@boop/papaparse.js'); function main(state) { - try { - const delimiter = ',' - const data = state.text - const titles = data.slice(0, data.indexOf('\n')).split(delimiter); - state.text = JSON.stringify(data - .slice(data.indexOf('\n') + 1) - .split('\n') - .map(v => { - const values = v.split(delimiter); - return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); - }), null, 2); - } - catch(error) { - state.postError("Invalid CSV") - } - - + try { + const { data } = Papa.parse(state.text, { header:true }); + state.text = JSON.stringify(data, null, 2); + } + catch(error) { + state.postError("Invalid CSV") + } } diff --git a/Boop/Boop/scripts/CamelCase.js b/Boop/Boop/scripts/CamelCase.js index 559ae1d2..eeaaa728 100644 --- a/Boop/Boop/scripts/CamelCase.js +++ b/Boop/Boop/scripts/CamelCase.js @@ -4,7 +4,7 @@ "name":"Camel Case", "description":"convertsYourTextToCamelCase", "author":"Ivan", - "icon":"metamorphose", + "icon":"camel", "tags":"camel,case,function,lodash" } **/ diff --git a/Boop/Boop/scripts/CountCharacters.js b/Boop/Boop/scripts/CountCharacters.js index 38b928f5..a5b497c7 100644 --- a/Boop/Boop/scripts/CountCharacters.js +++ b/Boop/Boop/scripts/CountCharacters.js @@ -2,15 +2,19 @@ { "api":1, "name":"Count Characters", - "description":"Get the length of your text.", + "description":"Get the length of your text", "author":"Ivan", "icon":"counter", "tags":"count,length,size,character" } **/ + +const { size } = require('@boop/lodash.boop') + function main(input) { - input.postInfo(`${input.text.length} characters`) + input.postInfo(`${size(input.text)} characters`) -} \ No newline at end of file +} + diff --git a/Boop/Boop/scripts/CountLines.js b/Boop/Boop/scripts/CountLines.js index a1a006c0..2bfe67e6 100644 --- a/Boop/Boop/scripts/CountLines.js +++ b/Boop/Boop/scripts/CountLines.js @@ -2,7 +2,7 @@ { "api":1, "name":"Count Lines", - "description":"Get the line count of your text.", + "description":"Get the line count of your text", "author":"andipaetzold", "icon":"counter", "tags":"count,length,size,line" diff --git a/Boop/Boop/scripts/CountWords.js b/Boop/Boop/scripts/CountWords.js index 81f8bdaa..8d222427 100644 --- a/Boop/Boop/scripts/CountWords.js +++ b/Boop/Boop/scripts/CountWords.js @@ -2,7 +2,7 @@ { "api":1, "name":"Count Words", - "description":"Get the word count of your text.", + "description":"Get the word count of your text", "author":"Daniel Stone", "icon":"counter", "tags":"count,length,size,words" diff --git a/Boop/Boop/scripts/DateToTimestamp.js b/Boop/Boop/scripts/DateToTimestamp.js index ec5addfb..c42067b5 100644 --- a/Boop/Boop/scripts/DateToTimestamp.js +++ b/Boop/Boop/scripts/DateToTimestamp.js @@ -2,7 +2,7 @@ { "api":1, "name":"Date to Timestamp", - "description":"Converts dates to Unix timestamp", + "description":"Converts dates to Unix timestamp.", "author":"Noah Halford", "icon":"watch", "tags":"date,time,calendar,unix,timestamp" diff --git a/Boop/Boop/scripts/Deburr.js b/Boop/Boop/scripts/Deburr.js index 64c8271d..2d1f6a93 100644 --- a/Boop/Boop/scripts/Deburr.js +++ b/Boop/Boop/scripts/Deburr.js @@ -2,9 +2,9 @@ { "api":1, "name":"Deburr", - "description":"Converts your text to basic latin characters", + "description":"Converts your text to basic latin characters.", "author":"Ivan", - "icon":"metamorphose", + "icon":"colosseum", "tags":"burr,special,characters,function,lodash" } **/ diff --git a/Boop/Boop/scripts/DecimalToBinary.js b/Boop/Boop/scripts/DecimalToBinary.js new file mode 100644 index 00000000..caacf2b7 --- /dev/null +++ b/Boop/Boop/scripts/DecimalToBinary.js @@ -0,0 +1,31 @@ +/** + { + "api": 1, + "name": "Decimal to Binary", + "description": "Converts decimal values to binary.", + "author": "Maurice", + "icon": "metamorphose", + "tags": "decimal,binary,dec,bin" + } + **/ + +function main(state) { + var text = state.text; + var lines = text.split(/\n/); + var result = ""; + + for (const index in lines) { + var text = lines[index].trim(); + var bin = parseInt(text).toString(2).toUpperCase(); + + if (isNaN(bin)) { + result += text; + } else { + result += bin; + } + + result += "\n"; + } + + state.text = result.trim(); +} diff --git a/Boop/Boop/scripts/DecimalToHex.js b/Boop/Boop/scripts/DecimalToHex.js new file mode 100644 index 00000000..0f221454 --- /dev/null +++ b/Boop/Boop/scripts/DecimalToHex.js @@ -0,0 +1,30 @@ +/** + { + "api": 1, + "name": "Decimal to Hex", + "description": "Converts decimal values to hexadecimal.", + "author": "Maurice", + "icon": "metamorphose", + "tags": "decimal,hexadecimal,dec,hex" + } + **/ + +function main(state) { + var text = state.text; + var lines = text.split(/\n/); + var result = ""; + + for (const index in lines) { + var text = lines[index].trim(); + + if (isNaN(text)) { + result += text; + } else { + result += parseInt(text).toString(16).toUpperCase(); + } + + result += "\n"; + } + + state.text = result.trim(); +} diff --git a/Boop/Boop/scripts/Downcase.js b/Boop/Boop/scripts/Downcase.js index 2729b9b7..a0f54796 100644 --- a/Boop/Boop/scripts/Downcase.js +++ b/Boop/Boop/scripts/Downcase.js @@ -2,7 +2,7 @@ { "api":1, "name":"Downcase", - "description":"Converts to lowercase", + "description":"Converts your text to lowercase.", "author":"Dan2552", "icon":"type", "tags":"downcase,lowercase" diff --git a/Boop/Boop/scripts/EvalJavascript.js b/Boop/Boop/scripts/EvalJavascript.js index 35fb7745..713d7534 100644 --- a/Boop/Boop/scripts/EvalJavascript.js +++ b/Boop/Boop/scripts/EvalJavascript.js @@ -1,10 +1,10 @@ /** { "api":1, - "name":"Eval", - "description":"Evaluate Javascript.", + "name":"Eval Javascript", + "description":"Runs your text as Javascript Code.", "author":"Sebastiaan Besselsen", - "icon":"unknown", + "icon":"command", "tags":"js,script,run" } **/ diff --git a/Boop/Boop/scripts/FishHexPathConverter.js b/Boop/Boop/scripts/FishHexPathConverter.js new file mode 100644 index 00000000..8b1ad2bd --- /dev/null +++ b/Boop/Boop/scripts/FishHexPathConverter.js @@ -0,0 +1,41 @@ +/** +{ + "api": 1, + "name": "Fish PATH Hex Converter", + "description": "Escapes terminal characters.", + "author": "Paul Seelman", + "icon": "broom", + "tags": "fish_user_paths, fish, hex, ascii, path, var" +} +**/ +function convert(string) { + var chars = string.split(""); + var dict = { + " ": ":", + "%": "25", + "&": "26", + "+": "2b", + "-": "2d", + ".": "2e", + "*": "2a", + ":": "3a", + "@": "40", + ";": "3b" + }; + + for (var i = chars.length - 1; i >= 0; i--) { + var char = chars[i]; + var hex = dict[char]; + + if (hex !== undefined) { + var slash_x = '\\x'; + chars[i] = slash_x.concat(hex); + } + } + + return chars.join(""); +} + +function main(input) { + input.text = convert(input.text); +} diff --git a/Boop/Boop/scripts/HTMLEncodeAll.js b/Boop/Boop/scripts/HTMLEncodeAll.js new file mode 100644 index 00000000..233827dc --- /dev/null +++ b/Boop/Boop/scripts/HTMLEncodeAll.js @@ -0,0 +1,20 @@ +/** + { + "api":1, + "name":"HTML Encode all characters", + "description":"HTML Encodes every character in your text", + "author":"Ivan", + "icon":"HTML", + "tags":"html,encode,web,email", + "bias":-0.1 + } +**/ + +function main(input) { + let str = input.text; + var out = ""; + for (var i = 0; i < str.length; i++) { + out += `&#${str.charCodeAt(i)};`; + } + input.text = out; +} diff --git a/Boop/Boop/scripts/HexToASCII.js b/Boop/Boop/scripts/HexToASCII.js new file mode 100644 index 00000000..4987b280 --- /dev/null +++ b/Boop/Boop/scripts/HexToASCII.js @@ -0,0 +1,30 @@ +/** + { + "api":1, + "name":"Hex To ASCII", + "description":"Converts hexadecimal values into ASCII characters", + "author":"aWZHY0yQH81uOYvH", + "icon":"metamorphose", + "tags":"hex,ascii,convert" + } +**/ + +function main(state) { + input = state.fullText.toUpperCase(); + buf = ""; + hexBuf = ""; + for(i = 0; i < input.length; i ++) { + c = input.charAt(i); + if("0123456789ABCDEF".includes(c)) { + hexBuf += c; + if(hexBuf.length >= 2) { + buf += String.fromCharCode(parseInt(hexBuf, 16)); + hexBuf = ""; + } + } else if(c != ' ' && c != '\t' && c != '\n' && c != '\r') { + state.postError("Text is not hex") + throw "Not hex"; + } + } + state.fullText = buf; +} diff --git a/Boop/Boop/scripts/HexToDecimal.js b/Boop/Boop/scripts/HexToDecimal.js new file mode 100644 index 00000000..d02fb35f --- /dev/null +++ b/Boop/Boop/scripts/HexToDecimal.js @@ -0,0 +1,31 @@ +/** + { + "api": 1, + "name": "Hex to Dec", + "description": "Converts hexadecimal to decimal.", + "author": "Maurice", + "icon": "metamorphose", + "tags": "decimal,hexadecimal,dec,hex" + } + **/ + +function main(state) { + var text = state.text; + var lines = text.split(/\n/); + var result = ""; + + for (const index in lines) { + var text = lines[index].trim(); + var decimal = parseInt(text, 16); + + if (isNaN(decimal)) { + result += text; + } else { + result += decimal; + } + + result += "\n"; + } + + state.text = result.trim(); +} diff --git a/Boop/Boop/scripts/IOSAndroidStrings.js b/Boop/Boop/scripts/IOSAndroidStrings.js new file mode 100644 index 00000000..28d0d5fe --- /dev/null +++ b/Boop/Boop/scripts/IOSAndroidStrings.js @@ -0,0 +1,28 @@ +/** + { + "api":1, + "name":"iOS Localizables to Android Strings", + "description":"Converts iOS Localizables to Android Strings", + "author":"Manuel Kunz (https://github.com/KunzManuel)", + "icon":"translation", + "tags":"string,android,ios" + } +**/ + +function main(input) { + let lines = input.fullText.split('\n') + var result = [] + lines.forEach(element => { + if(element !== "") { + var regex = /"(.*?)"/g + var matches = []; + var match = regex.exec(element); + while (match != null) { + matches.push(match[1]); + match = regex.exec(element); + } + result.push("" + matches[1] + "") + } + }) + input.fullText = result.join('\n') +} diff --git a/Boop/Boop/scripts/JSONtoYAML.js b/Boop/Boop/scripts/JSONtoYAML.js new file mode 100644 index 00000000..a717186d --- /dev/null +++ b/Boop/Boop/scripts/JSONtoYAML.js @@ -0,0 +1,21 @@ +/** + { + "api":1, + "name":"JSON to YAML", + "description":"Converts JSON to YAML.", + "author":"Ivan", + "icon":"metamorphose", + "tags":"markup,convert" + } +**/ + +const yaml = require('@boop/js-yaml') + +function main(input) { + try { + input.text = yaml.safeDump(JSON.parse(input.text)) + } + catch(error) { + input.postError("Invalid JSON") + } +} \ No newline at end of file diff --git a/Boop/Boop/scripts/JWTDecode.js b/Boop/Boop/scripts/JWTDecode.js index 0208a5a3..b558b7a3 100644 --- a/Boop/Boop/scripts/JWTDecode.js +++ b/Boop/Boop/scripts/JWTDecode.js @@ -10,18 +10,18 @@ **/ -const { base64decode } = require('@boop/base64') +const { decode } = require('@boop/base64'); function main(input) { - var t = input.text - var jwtParts = t.split(".") - if(jwtParts.length != 3) { - input.postError("Invalid Token") - return + var t = input.text; + var jwtParts = t.split("."); + if (jwtParts.length != 3) { + input.postError("Invalid Token"); + return; } - var header = base64decode(jwtParts[0]); - var payload = base64decode(jwtParts[1]); + var header = decode(jwtParts[0]); + var payload = decode(jwtParts[1]); var signature = jwtParts[2]; try { @@ -29,11 +29,11 @@ function main(input) { "header": JSON.parse(header), "payload": JSON.parse(payload), "signature": signature - } + }; // Prettyprint the JSOM input.text = JSON.stringify(fullJson, null, 2); } catch(err) { - input.postError("Error while parsing JSON") + input.postError("Error while parsing JSON"); } } diff --git a/Boop/Boop/scripts/JoinLines.js b/Boop/Boop/scripts/JoinLines.js deleted file mode 100644 index cc22c322..00000000 --- a/Boop/Boop/scripts/JoinLines.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - { - "api":1, - "name":"Join Lines", - "description":"Joins All Lines Without any Delimiter", - "author":"riesentoaster", - "icon":"table", - "tags":"join" - } -**/ - -function main(input) { - input.text = input.text.replace('\n', ''); -} diff --git a/Boop/Boop/scripts/JsonToQuery.js b/Boop/Boop/scripts/JsonToQuery.js index c86f5db7..eb28adb5 100644 --- a/Boop/Boop/scripts/JsonToQuery.js +++ b/Boop/Boop/scripts/JsonToQuery.js @@ -2,7 +2,7 @@ { "api":1, "name":"JSON to Query String", - "description":"Converts JSON to URL query string", + "description":"Converts JSON to URL query string.", "author":"Ota Mares ", "icon":"website", "tags":"url,query,params,json,convert,encode" diff --git a/Boop/Boop/scripts/KebabCase.js b/Boop/Boop/scripts/KebabCase.js index b468e45b..704a6c72 100644 --- a/Boop/Boop/scripts/KebabCase.js +++ b/Boop/Boop/scripts/KebabCase.js @@ -2,9 +2,9 @@ { "api":1, "name":"Kebab Case", - "description":"converts-your-text-to-kebab-case", + "description":"converts-your-text-to-kebab-case.", "author":"Ivan", - "icon":"metamorphose", + "icon":"kebab", "tags":"kebab,case,function,lodash" } **/ diff --git a/Boop/Boop/scripts/LoremIpsum.js b/Boop/Boop/scripts/LoremIpsum.js new file mode 100644 index 00000000..8fd4acfe --- /dev/null +++ b/Boop/Boop/scripts/LoremIpsum.js @@ -0,0 +1,26 @@ +/** + { + "api":1, + "name":"Lorem Ipsum", + "description":"Generates Lorem Ipsum placeholder text.", + "author":"luisfontes19", + "icon":"type", + "tags":"generate,lorem,ipsum,text", + "bias": -0.1 + } +**/ + + +function main(state) { + const words = ["ad", "adipisicing", "aliqua", "aliquip", "amet", "anim", "aute", "cillum", "commodo", "consectetur", "consequat", "culpa", "cupidatat", "deserunt", "do", "dolor", "dolore", "duis", "ea", "eiusmod", "elit", "enim", "esse", "est", "et", "eu", "ex", "excepteur", "exercitation", "fugiat", "id", "in", "incididunt", "ipsum", "irure", "labore", "laboris", "laborum", "Lorem", "magna", "minim", "mollit", "nisi", "non", "nostrud", "nulla", "occaecat", "officia", "pariatur", "proident", "qui", "quis", "reprehenderit", "sint", "sit", "sunt", "tempor", "ullamco", "ut", "velit", "veniam", "voluptate"]; + let sentence = ""; + + for (let i = 0; i < 100; i++) { + const pos = Math.floor(Math.random() * (words.length - 1)); + sentence += words[pos] + " "; + } + + sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1).trim() + "."; + + state.text = sentence; +} diff --git a/Boop/Boop/scripts/MD5.js b/Boop/Boop/scripts/MD5.js index eec5e4f0..f9ba7209 100644 --- a/Boop/Boop/scripts/MD5.js +++ b/Boop/Boop/scripts/MD5.js @@ -2,395 +2,16 @@ { "api":1, "name":"MD5 Checksum", - "description":"Computes the checksum of your text", + "description":"Computes the checksum of your text (Hex encoded).", "author":"Ivan", "icon":"fingerprint", "tags":"strip,slashes,remove" } **/ -function main(state) { - - state.text = hex_md5(state.text) -} - - -/* - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ - -/* - * Configurable variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - */ -var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ -var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ - -/* - * These are the functions you'll usually want to call - * They take string arguments and return either hex or base-64 encoded strings - */ -function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } -function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } -function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } -function hex_hmac_md5(k, d) - { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } -function b64_hmac_md5(k, d) - { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } -function any_hmac_md5(k, d, e) - { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } - -/* - * Perform a simple self-test to see if the VM is working - */ -function md5_vm_test() -{ - return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72"; -} - -/* - * Calculate the MD5 of a raw string - */ -function rstr_md5(s) -{ - return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); -} - -/* - * Calculate the HMAC-MD5, of a key and some data (raw strings) - */ -function rstr_hmac_md5(key, data) -{ - var bkey = rstr2binl(key); - if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); - - var ipad = Array(16), opad = Array(16); - for(var i = 0; i < 16; i++) - { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); - return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); -} +const Hashes = require('@boop/hashes') -/* - * Convert a raw string to a hex string - */ -function rstr2hex(input) -{ - try { hexcase } catch(e) { hexcase=0; } - var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - var output = ""; - var x; - for(var i = 0; i < input.length; i++) - { - x = input.charCodeAt(i); - output += hex_tab.charAt((x >>> 4) & 0x0F) - + hex_tab.charAt( x & 0x0F); - } - return output; -} - -/* - * Convert a raw string to a base-64 string - */ -function rstr2b64(input) -{ - try { b64pad } catch(e) { b64pad=''; } - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - var output = ""; - var len = input.length; - for(var i = 0; i < len; i += 3) - { - var triplet = (input.charCodeAt(i) << 16) - | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) - | (i + 2 < len ? input.charCodeAt(i+2) : 0); - for(var j = 0; j < 4; j++) - { - if(i * 8 + j * 6 > input.length * 8) output += b64pad; - else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); - } - } - return output; -} - -/* - * Convert a raw string to an arbitrary string encoding - */ -function rstr2any(input, encoding) -{ - var divisor = encoding.length; - var i, j, q, x, quotient; - - /* Convert to an array of 16-bit big-endian values, forming the dividend */ - var dividend = Array(Math.ceil(input.length / 2)); - for(i = 0; i < dividend.length; i++) - { - dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); - } - - /* - * Repeatedly perform a long division. The binary array forms the dividend, - * the length of the encoding is the divisor. Once computed, the quotient - * forms the dividend for the next step. All remainders are stored for later - * use. - */ - var full_length = Math.ceil(input.length * 8 / - (Math.log(encoding.length) / Math.log(2))); - var remainders = Array(full_length); - for(j = 0; j < full_length; j++) - { - quotient = Array(); - x = 0; - for(i = 0; i < dividend.length; i++) - { - x = (x << 16) + dividend[i]; - q = Math.floor(x / divisor); - x -= q * divisor; - if(quotient.length > 0 || q > 0) - quotient[quotient.length] = q; - } - remainders[j] = x; - dividend = quotient; - } - - /* Convert the remainders to the output string */ - var output = ""; - for(i = remainders.length - 1; i >= 0; i--) - output += encoding.charAt(remainders[i]); - - return output; -} - -/* - * Encode a string as utf-8. - * For efficiency, this assumes the input is valid utf-16. - */ -function str2rstr_utf8(input) -{ - var output = ""; - var i = -1; - var x, y; - - while(++i < input.length) - { - /* Decode utf-16 surrogate pairs */ - x = input.charCodeAt(i); - y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; - if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) - { - x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); - i++; - } - - /* Encode output as utf-8 */ - if(x <= 0x7F) - output += String.fromCharCode(x); - else if(x <= 0x7FF) - output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), - 0x80 | ( x & 0x3F)); - else if(x <= 0xFFFF) - output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), - 0x80 | ((x >>> 6 ) & 0x3F), - 0x80 | ( x & 0x3F)); - else if(x <= 0x1FFFFF) - output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), - 0x80 | ((x >>> 12) & 0x3F), - 0x80 | ((x >>> 6 ) & 0x3F), - 0x80 | ( x & 0x3F)); - } - return output; -} - -/* - * Encode a string as utf-16 - */ -function str2rstr_utf16le(input) -{ - var output = ""; - for(var i = 0; i < input.length; i++) - output += String.fromCharCode( input.charCodeAt(i) & 0xFF, - (input.charCodeAt(i) >>> 8) & 0xFF); - return output; -} - -function str2rstr_utf16be(input) -{ - var output = ""; - for(var i = 0; i < input.length; i++) - output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, - input.charCodeAt(i) & 0xFF); - return output; -} - -/* - * Convert a raw string to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ -function rstr2binl(input) -{ - var output = Array(input.length >> 2); - for(var i = 0; i < output.length; i++) - output[i] = 0; - for(var i = 0; i < input.length * 8; i += 8) - output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); - return output; -} - -/* - * Convert an array of little-endian words to a string - */ -function binl2rstr(input) -{ - var output = ""; - for(var i = 0; i < input.length * 32; i += 8) - output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); - return output; -} - -/* - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ -function binl_md5(x, len) -{ - /* append padding */ - x[len >> 5] |= 0x80 << ((len) % 32); - x[(((len + 64) >>> 9) << 4) + 14] = len; - - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; - - for(var i = 0; i < x.length; i += 16) - { - var olda = a; - var oldb = b; - var oldc = c; - var oldd = d; - - a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); - d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); - c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); - b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); - d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); - c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); - b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); - a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); - d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); - c = md5_ff(c, d, a, b, x[i+10], 17, -42063); - b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); - a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); - d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); - b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); - - a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); - d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); - c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); - b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); - a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); - d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); - c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); - b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); - d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); - c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); - b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); - a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); - d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); - c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); - b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); - - a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); - d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); - b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); - a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); - d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); - c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); - b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); - a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); - d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); - c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); - b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); - d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); - c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); - b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); - - a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); - d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); - c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); - b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); - a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); - d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); - b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); - a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); - d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); - c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); - b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); - a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); - d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); - c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); - b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - } - return Array(a, b, c, d); -} - -/* - * These functions implement the four basic operations the algorithm uses. - */ -function md5_cmn(q, a, b, x, s, t) -{ - return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); -} -function md5_ff(a, b, c, d, x, s, t) -{ - return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); -} -function md5_gg(a, b, c, d, x, s, t) -{ - return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); -} -function md5_hh(a, b, c, d, x, s, t) -{ - return md5_cmn(b ^ c ^ d, a, b, x, s, t); -} -function md5_ii(a, b, c, d, x, s, t) -{ - return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); -} - -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ -function safe_add(x, y) -{ - var lsw = (x & 0xFFFF) + (y & 0xFFFF); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); +function main(state) { + var MD5 = new Hashes.MD5; + state.text = MD5.hex(state.text) } - -/* - * Bitwise rotate a 32-bit number to the left. - */ -function bit_rol(num, cnt) -{ - return (num << cnt) | (num >>> (32 - cnt)); -} \ No newline at end of file diff --git a/Boop/Boop/scripts/MarkdownQuote.js b/Boop/Boop/scripts/MarkdownQuote.js index 9c801b29..cf4ce375 100644 --- a/Boop/Boop/scripts/MarkdownQuote.js +++ b/Boop/Boop/scripts/MarkdownQuote.js @@ -2,7 +2,7 @@ { "api":1, "name":"Markdown Quote", - "description":"Adds > to the start of every line of your text", + "description":"Adds > to the start of every line of your text.", "author":"Dan2552", "icon":"term", "tags":"quote,markdown" diff --git a/Boop/Boop/scripts/NatSort.js b/Boop/Boop/scripts/NatSort.js index 177d7c17..5bf860bc 100644 --- a/Boop/Boop/scripts/NatSort.js +++ b/Boop/Boop/scripts/NatSort.js @@ -4,7 +4,7 @@ "name":"Natural Sort Lines", "description":"Sort lines with smart handling of numbers.", "author":"Sebastiaan Besselsen", - "icon":"table", + "icon":"sort-numbers", "tags":"sort,natural,natsort" } **/ diff --git a/Boop/Boop/scripts/PhpUnserialize.js b/Boop/Boop/scripts/PhpUnserialize.js new file mode 100644 index 00000000..ab2d34b1 --- /dev/null +++ b/Boop/Boop/scripts/PhpUnserialize.js @@ -0,0 +1,169 @@ +/** + { + "api":1, + "name":"PHP Unserialize", + "description":"Convert PHP serialized data to JSON", + "author":"Rob Bogie", + "icon":"elephant", + "tags":"php,serialize,unserialize,json" + } +**/ + +function main(state) { + try { + const input = state.text + const unserialized = unserialize(input) + const data = unserialized[0] + + if(unserialized[1] != input.length) { + throw new Error("Invalid serialized string") + } + + if(data === null || data === undefined) { + state.text = null + } else if(typeof data === 'object') { + state.text = JSON.stringify(data, null, 2) + } else { + state.text = data.toString() + } + } catch (e) { + state.postError(e.message) + } +} + +function decodeInt(text, startPos) { + const lastChar = text.indexOf(';', startPos) + if(lastChar <= 0) { + throw new Error("decodeInt: unexpected end of string") + } + return [Number.parseInt(text.slice(startPos, lastChar)), lastChar + 1] +} + +function decodeBool(text, startPos) { + const lastChar = text.indexOf(';', startPos) + if(lastChar != startPos + 1) { + throw new Error("decodeBool: unexpected data length") + } + switch (text.charAt(startPos)) { + case '0': + return [false, startPos + 2] + case '1': + return [true, startPos + 2] + default: + throw new Error("decodeBool: found unexpected data") + } +} + +function decodeFloat(text, startPos) { + const lastChar = text.indexOf(';', startPos) + if(lastChar <= 0) { + throw new Error("decodeFloat: unexpected end of string") + } + return [Number.parseFloat(text.slice(startPos, lastChar)), lastChar + 1] +} + +function decodeString(text, startPos) { + const lengthEnd = text.indexOf(':', startPos) + if(lengthEnd <= 0) { + throw new Error("decodeString: no string length found") + } + const byteLength = Number.parseInt(text.slice(startPos, lengthEnd)) + + startPos = lengthEnd + 2 + let currentStrLength = 0 + let numBytes = 0; + while((currentStrLength + startPos) < text.length && numBytes < byteLength) { + const nextPos = text.indexOf('";', startPos+currentStrLength+1)-startPos + if(nextPos > currentStrLength) { + currentStrLength = nextPos + } else { + // No end will be found anymore, exit and do our safety checks as if we reached the end + break + } + + const subStr = text.slice(startPos, startPos + currentStrLength) + try { + const encodedStr = encodeURI(subStr) + numBytes = encodedStr.split(/%..|./).length - 1 + } catch(e) { + // encodeURI will fail when an invalid UTF16 character is found, which happens with 4 byte characters (e.g. emoji) + // We will simply try again on the next position + } + } + + if(numBytes != byteLength) { + throw new Error("Could not decode string: field length mismatch") + } + + return [text.slice(startPos, startPos + currentStrLength), startPos + currentStrLength + 2] +} + +function decodeArray(text, startPos) { + const lengthEnd = text.indexOf(':', startPos) + if(lengthEnd <= 0) { + throw new Error("decodeArray: no arraylength found") + } + const numItems = Number.parseInt(text.slice(startPos, lengthEnd)) + let data = {} + startPos = lengthEnd + 2 + let continuous = true + for(let i = 0; i < numItems; i++) { + const keyData = unserialize(text, startPos) + const valueData = unserialize(text, keyData[1]) + startPos = valueData[1] + + if(keyData[0] !== i) { + continuous = false + } + + data[keyData[0]] = valueData[0] + } + + if(continuous) { + // Convert non key-value maps to array + const array = new Array(numItems) + for(let i = 0; i < numItems; i++) { + array[i] = data[i] + } + data = array + } + return [data, startPos+1] +} + +function decodeObject(text, startPos) { + const classNameLengthEnd = text.indexOf(':', startPos) + if(classNameLengthEnd <= 0) { + throw new Error("decodeObject: no arraylength found") + } + const classNameLength = Number.parseInt(text.slice(startPos, classNameLengthEnd)) + startPos = classNameLengthEnd + 2 + if(classNameLength !== 8 || text.slice(startPos, startPos + 8) !== 'stdClass') { + throw new Error("decodeObject: object type not supported") + } + + startPos += 10 + + return decodeArray(text, startPos) +} + +function unserialize(text, startPos = 0) { + const type = text[startPos] + switch(type) { + case 'i': + return decodeInt(text, startPos + 2) + case 'b': + return decodeBool(text, startPos + 2) + case 'N': + return [null, startPos + 2] + case 'd': + return decodeFloat(text, startPos + 2) + case 's': + return decodeString(text, startPos + 2) + case 'a': + return decodeArray(text, startPos + 2) + case 'O': + return decodeObject(text, startPos + 2) + default: + throw new Error("unknown type found: " + type + " at "+startPos) + } +} diff --git a/Boop/Boop/scripts/QueryToJson.js b/Boop/Boop/scripts/QueryToJson.js index 5f746744..41a1d7ed 100644 --- a/Boop/Boop/scripts/QueryToJson.js +++ b/Boop/Boop/scripts/QueryToJson.js @@ -2,7 +2,7 @@ { "api":1, "name":"Query String to JSON", - "description":"Converts URL query string to JSON", + "description":"Converts URL query string to JSON.", "author":"Ota Mares ", "icon":"website", "tags":"url,query,params,json,convert,decode" diff --git a/Boop/Boop/scripts/RemoveDuplicates.js b/Boop/Boop/scripts/RemoveDuplicates.js index 162df269..5dc1540e 100644 --- a/Boop/Boop/scripts/RemoveDuplicates.js +++ b/Boop/Boop/scripts/RemoveDuplicates.js @@ -2,7 +2,7 @@ { "api":1, "name":"Remove Duplicate Lines", - "description":"Ensures each line of your text is unique", + "description":"Ensures each line of your text is unique.", "author":"andipaetzold", "icon":"filtration", "tags":"unique,duplicate" @@ -11,7 +11,7 @@ function main(input) { let lines = input.text.split('\n') - let out = unique(lines) + let out = unique(lines) input.text = out.join('\n') diff --git a/Boop/Boop/scripts/RemoveSlashes.js b/Boop/Boop/scripts/RemoveSlashes.js index aac8ac17..95243a59 100644 --- a/Boop/Boop/scripts/RemoveSlashes.js +++ b/Boop/Boop/scripts/RemoveSlashes.js @@ -2,7 +2,7 @@ { "api":1, "name":"Remove Slashes", - "description":"Unescapes your text", + "description":"Unescapes your text.", "author":"Ivan", "icon":"quote", "tags":"strip,slashes,remove,unescape" diff --git a/Boop/Boop/scripts/ReplaceSmartQuotes.js b/Boop/Boop/scripts/ReplaceSmartQuotes.js new file mode 100644 index 00000000..a06b9ab8 --- /dev/null +++ b/Boop/Boop/scripts/ReplaceSmartQuotes.js @@ -0,0 +1,17 @@ +/** + { + "api":1, + "name":"Replace Smart Quotes", + "description":"Replace Smart Quotes with their simpler values.", + "author":"Thomas Bauer (https://github.com/tbauer428)", + "icon":"broom", + "tags":"smart,quotes,quotations,quotation,smart-quotes,smart-quotations" + } +**/ + +function main(input) { + input.text = input.text + .replace(/[\u2018\u2019]/g, "'") + .replace(/[\u201C\u201D]/g, '"') + .replace(/“”/g, '"'); +} diff --git a/Boop/Boop/scripts/ReverseLines.js b/Boop/Boop/scripts/ReverseLines.js index 92372ba1..b5cc8273 100644 --- a/Boop/Boop/scripts/ReverseLines.js +++ b/Boop/Boop/scripts/ReverseLines.js @@ -2,7 +2,7 @@ { "api":1, "name":"Reverse Lines", - "description":"Flips every line of your text", + "description":"Flips every line of your text.", "author":"@Clarko", "icon":"flip", "tags":"reverse,order,invert,mirror,flip,upside,down" diff --git a/Boop/Boop/scripts/Rot13.js b/Boop/Boop/scripts/Rot13.js index b3e58750..bd70f380 100644 --- a/Boop/Boop/scripts/Rot13.js +++ b/Boop/Boop/scripts/Rot13.js @@ -2,9 +2,9 @@ { "api":1, "name":"Rot13", - "description":"Applies the Rot13 cypher to your text", + "description":"Applies the Rot13 cypher to your text.", "author":"Paul Starr", - "icon":"flip", + "icon":"roman", "tags":"spoilers,encryption,plaintext" } **/ diff --git a/Boop/Boop/scripts/SHA1.js b/Boop/Boop/scripts/SHA1.js new file mode 100644 index 00000000..887144b8 --- /dev/null +++ b/Boop/Boop/scripts/SHA1.js @@ -0,0 +1,16 @@ +/** + { + "api":1, + "name":"SHA1 Hash", + "description":"Computes the SHA1 hash of your text (Hex encoded)", + "icon":"fingerprint", + "tags":"strip,slashes,remove" + } +**/ + +const Hashes = require('@boop/hashes') + +function main(state) { + var SHA1 = new Hashes.SHA1; + state.text = SHA1.hex(state.text) +} diff --git a/Boop/Boop/scripts/SHA256.js b/Boop/Boop/scripts/SHA256.js new file mode 100644 index 00000000..11437ef5 --- /dev/null +++ b/Boop/Boop/scripts/SHA256.js @@ -0,0 +1,15 @@ +/** + { + "api":1, + "name":"SHA256 Hash", + "description":"Computes the SHA256 hash of your text (Hex encoded)", + "icon":"fingerprint", + "tags":"strip,slashes,remove" + } +**/ +const Hashes = require('@boop/hashes') + +function main(state) { + var SHA256 = new Hashes.SHA256; + state.text = SHA256.hex(state.text) +} diff --git a/Boop/Boop/scripts/SHA512.js b/Boop/Boop/scripts/SHA512.js new file mode 100644 index 00000000..b749a271 --- /dev/null +++ b/Boop/Boop/scripts/SHA512.js @@ -0,0 +1,16 @@ +/** + { + "api":1, + "name":"SHA512 Hash", + "description":"Computes the SHA512 hash of your text (Hex encoded)", + "icon":"fingerprint", + "tags":"strip,slashes,remove" + } +**/ + +const Hashes = require('@boop/hashes') + +function main(state) { + var SHA512 = new Hashes.SHA512; + state.text = SHA512.hex(state.text) +} diff --git a/Boop/Boop/scripts/ShuffleLines.js b/Boop/Boop/scripts/ShuffleLines.js index 0c2d3458..002abdd8 100644 --- a/Boop/Boop/scripts/ShuffleLines.js +++ b/Boop/Boop/scripts/ShuffleLines.js @@ -2,7 +2,7 @@ { "api":1, "name":"Shuffle Lines", - "description":"Randomize each line of your text", + "description":"Randomize each line of your text.", "author":"@Clarko", "icon":"dice", "tags":"shuffle,random" diff --git a/Boop/Boop/scripts/SnakeCase.js b/Boop/Boop/scripts/SnakeCase.js index 54961777..eec7bfac 100644 --- a/Boop/Boop/scripts/SnakeCase.js +++ b/Boop/Boop/scripts/SnakeCase.js @@ -2,9 +2,9 @@ { "api":1, "name":"Snake Case", - "description":"converts_your_text_to_snake_case", + "description":"converts_your_text_to_snake_case.", "author":"Ivan", - "icon":"metamorphose", + "icon":"snake", "tags":"snake,case,function,lodash" } **/ diff --git a/Boop/Boop/scripts/Sort.js b/Boop/Boop/scripts/Sort.js index 2cfab192..58ae5f8d 100644 --- a/Boop/Boop/scripts/Sort.js +++ b/Boop/Boop/scripts/Sort.js @@ -4,7 +4,7 @@ "name":"Sort lines", "description":"Sort lines alphabetically.", "author":"Sebastiaan Besselsen", - "icon":"table", + "icon":"sort-characters", "tags":"sort,alphabet" } **/ diff --git a/Boop/Boop/scripts/SortJSON.js b/Boop/Boop/scripts/SortJSON.js new file mode 100644 index 00000000..64983ef0 --- /dev/null +++ b/Boop/Boop/scripts/SortJSON.js @@ -0,0 +1,63 @@ +/** + { + "api":1, + "name":"Sort JSON", + "description":"Sort JSON", + "author":"MaDnh", + "icon":"sort-characters", + "tags":"json,sort" + } +**/ + +function main(state) { + let value = state.text; + + try { + value = JSON.parse(value); + } catch (e) { + state.postError("Invalid JSON"); + return; + } + + value = sort(value); + + state.text = JSON.stringify(value, null, 2); +} + + +function sort(obj) { + if (obj instanceof Array) { + let out = obj.map(item => sort(item)); + out.sort((a, b) => { + let fa = JSON.stringify(a), + fb = JSON.stringify(b); + + if (fa < fb) { + return -1; + } + if (fa > fb) { + return 1; + } + return 0; + }); + return out; + } + + if (!isPlainObject(obj)) { + return obj + } + + const result = {}; + const keys = Object.keys(obj); + + keys.sort(); + keys.forEach(key => { + result[key] = sort(obj[key]) + }); + + return result; +} + +function isPlainObject(value) { + return Object.prototype.toString.call(value) === '[object Object]' +} diff --git a/Boop/Boop/scripts/SpongeCase.js b/Boop/Boop/scripts/SpongeCase.js new file mode 100644 index 00000000..3e5403da --- /dev/null +++ b/Boop/Boop/scripts/SpongeCase.js @@ -0,0 +1,27 @@ +/** +{ + "api": 1, + "name": "Sponge Case", + "description": "CoNvERtS yoUR Text To A HIghER fOrM Of CoMMUnICAtIOn", + "author": "Paul Seelman", + "icon": "pineapple", + "tags": "bob,sarcasm,no,this,is,patrick" +} +**/ +function spongeText(string) { + const chars = string.split(""); + for (let i = chars.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * Math.floor(2)); + if (j == 0) { + chars[i] = chars[i].toLowerCase(); + } else { + chars[i] = chars[i].toUpperCase(); + } + } + + return chars.join(""); +} + +function main(input) { + input.text = spongeText(input.text); +} diff --git a/Boop/Boop/scripts/StartCase.js b/Boop/Boop/scripts/StartCase.js index 5601b405..52904ca6 100644 --- a/Boop/Boop/scripts/StartCase.js +++ b/Boop/Boop/scripts/StartCase.js @@ -2,9 +2,9 @@ { "api":1, "name":"Start Case", - "description":"Converts Your Text To Start Case", + "description":"Converts Your Text To Start Case.", "author":"Ivan", - "icon":"metamorphose", + "icon":"type", "tags":"start,case,function,lodash" } **/ diff --git a/Boop/Boop/scripts/SumAll.js b/Boop/Boop/scripts/SumAll.js index 8f28a241..d25c3bbc 100644 --- a/Boop/Boop/scripts/SumAll.js +++ b/Boop/Boop/scripts/SumAll.js @@ -2,9 +2,9 @@ { "api":1, "name":"Sum All", - "description":"Sum a list of numbers (separated by be either a new line, comma, or semicolon)", + "description":"Sums up a list of numbers.", "author":"Annie Tran", - "icon":"counter", + "icon":"abacus", "tags":"sum,calculator,addition,add" } **/ diff --git a/Boop/Boop/scripts/Test.js b/Boop/Boop/scripts/Test.js index 43132445..b4edeadc 100644 --- a/Boop/Boop/scripts/Test.js +++ b/Boop/Boop/scripts/Test.js @@ -4,7 +4,7 @@ "name":"Test Script", "description":"Testing script", "author":"Ivan", - "icon":"quote", + "icon":"flask", "tags":"test,test,one,two" } **/ diff --git a/Boop/Boop/scripts/Trim.js b/Boop/Boop/scripts/Trim.js index 93e9c65f..585fa31b 100644 --- a/Boop/Boop/scripts/Trim.js +++ b/Boop/Boop/scripts/Trim.js @@ -2,9 +2,9 @@ { "api":1, "name":"Trim", - "description":"Trims leading and trailing whitespace", + "description":"Trims leading and trailing whitespace.", "author":"Joshua Nozzi", - "icon":"trim", + "icon":"scissors", "tags":"trim,whitespace,empty,space", } **/ diff --git a/Boop/Boop/scripts/URLDecode.js b/Boop/Boop/scripts/URLDecode.js index 42e94166..e48092e3 100644 --- a/Boop/Boop/scripts/URLDecode.js +++ b/Boop/Boop/scripts/URLDecode.js @@ -2,7 +2,7 @@ { "api":1, "name":"URL Decode", - "description":"Decodes URL entities", + "description":"Decodes URL entities in your text.", "author":"Ivan", "icon":"link", "tags":"url,decode,convert" diff --git a/Boop/Boop/scripts/URLDefang.js b/Boop/Boop/scripts/URLDefang.js new file mode 100644 index 00000000..2bde9559 --- /dev/null +++ b/Boop/Boop/scripts/URLDefang.js @@ -0,0 +1,18 @@ +/** + { + "api":1, + "name":"Defang", + "description":"Defangs dangerous URLs and other IOCs", + "author":"Ross", + "icon":"link", + "tags":"defang,url,ioc" + } +**/ + +function main(input) { + url = input.text; + url = url.replace(/\./g, "[.]"); + url = url.replace(/http/gi, "hXXp"); + url = url.replace(/:\/\//g, "[://]"); + input.text = url; +} \ No newline at end of file diff --git a/Boop/Boop/scripts/URLEncode.js b/Boop/Boop/scripts/URLEncode.js index 428a7635..94ae3e99 100644 --- a/Boop/Boop/scripts/URLEncode.js +++ b/Boop/Boop/scripts/URLEncode.js @@ -2,7 +2,7 @@ { "api":1, "name":"URL Encode", - "description":"Encodes URL entities", + "description":"Encodes URL entities in your text.", "author":"Ivan", "icon":"link", "tags":"url,encode,convert" diff --git a/Boop/Boop/scripts/URLEntitiesDecode.js b/Boop/Boop/scripts/URLEntitiesDecode.js new file mode 100644 index 00000000..dd22e0e6 --- /dev/null +++ b/Boop/Boop/scripts/URLEntitiesDecode.js @@ -0,0 +1,27 @@ +/** + { + "api":1, + "name":"URL Entities Decode", + "description":"URL Decodes all characters in your text.", + "author":"luisfontes19", + "icon":"percentage", + "tags":"url,decode,full", + "bias": -0.1 + } +**/ + + +function fullUrlDecode(str) { + var codes = str.split("%"); + var decoded = ''; + + for (var i = 0; i < codes.length; i++) { + decoded += String.fromCharCode(parseInt(codes[i], 16)); + } + + return decoded; +} + +function main(state) { + state.text = fullUrlDecode(state.text); +} diff --git a/Boop/Boop/scripts/URLEntitiesEncode.js b/Boop/Boop/scripts/URLEntitiesEncode.js new file mode 100644 index 00000000..b83a9e35 --- /dev/null +++ b/Boop/Boop/scripts/URLEntitiesEncode.js @@ -0,0 +1,27 @@ +/** + { + "api":1, + "name":"URL Entity Encode", + "description":"URL Encodes all characters in your text.", + "author":"luisfontes19", + "icon":"percentage", + "tags":"url,encode,full", + "bias": -0.1 + } +**/ + + +function fullUrlEncode(str) { + var encoded = ''; + + for (var i = 0; i < str.length; i++) { + var h = parseInt(str.charCodeAt(i)).toString(16); + encoded += '%' + h; + } + + return encoded; +} + +function main(state) { + state.text = fullUrlEncode(state.text); +} diff --git a/Boop/Boop/scripts/URLRefang.js b/Boop/Boop/scripts/URLRefang.js new file mode 100644 index 00000000..9a2fa37a --- /dev/null +++ b/Boop/Boop/scripts/URLRefang.js @@ -0,0 +1,18 @@ +/** + { + "api":1, + "name":"Refang", + "description":"Removes defanging from dangerous URLs and other IOCs", + "author":"Ross", + "icon":"link", + "tags":"refang,url,ioc" + } +**/ + +function main(input) { + url = input.text; + url = url.replace(/\[\.\]/g, "."); + url = url.replace(/hXXp/gi, "http"); + url = url.replace(/\[:\/\/\]/g, "://"); + input.text = url; +} \ No newline at end of file diff --git a/Boop/Boop/scripts/Upcase.js b/Boop/Boop/scripts/Upcase.js index 12fc29a3..368fc665 100644 --- a/Boop/Boop/scripts/Upcase.js +++ b/Boop/Boop/scripts/Upcase.js @@ -2,7 +2,7 @@ { "api":1, "name":"Upcase", - "description":"Converts to uppercase", + "description":"Converts your text to uppercase.", "author":"Dan2552", "icon":"type", "tags":"upcase,uppercase,capital,capitalize,capitalization" diff --git a/Boop/Boop/scripts/YAMLtoJSON.js b/Boop/Boop/scripts/YAMLtoJSON.js new file mode 100644 index 00000000..e3d8c57b --- /dev/null +++ b/Boop/Boop/scripts/YAMLtoJSON.js @@ -0,0 +1,23 @@ +/** + { + "api":1, + "name":"YAML to JSON", + "description":"Converts YAML to JSON.", + "author":"Ivan", + "icon":"metamorphose", + "tags":"markup,convert" + } +**/ + +const yaml = require('@boop/js-yaml') + +function main(input) { + + try { + input.text = JSON.stringify(yaml.safeLoad(input.text), null, 2) + } + catch(error) { + input.postError("Invalid YAML") + } + +} \ No newline at end of file diff --git a/Scripts/hex2rgb.js b/Boop/Boop/scripts/hex2rgb.js similarity index 86% rename from Scripts/hex2rgb.js rename to Boop/Boop/scripts/hex2rgb.js index d0710950..6ce92b96 100644 --- a/Scripts/hex2rgb.js +++ b/Boop/Boop/scripts/hex2rgb.js @@ -1,11 +1,11 @@ /** { "api":1, - "name":"HEX2RGB", + "name":"Hex to RGB", "description":"Convert color in hexadecimal to RGB.", "author":"Venkat", - "icon":"table", - "tags":"flip" + "icon":"color-wheel", + "tags":"hex,color,rgb,convert" } **/ diff --git a/Boop/Boop/scripts/lib/hashes.js b/Boop/Boop/scripts/lib/hashes.js new file mode 100644 index 00000000..a416ad50 --- /dev/null +++ b/Boop/Boop/scripts/lib/hashes.js @@ -0,0 +1,1767 @@ +/** + * jshashes - https://github.com/h2non/jshashes + * Released under the "New BSD" license + * + * Algorithms specification: + * + * MD5 - http://www.ietf.org/rfc/rfc1321.txt + * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + * SHA1 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + * HMAC - http://www.ietf.org/rfc/rfc2104.txt + */ +(function() { + var Hashes; + + function utf8Encode(str) { + var x, y, output = '', + i = -1, + l; + + if (str && str.length) { + l = str.length; + while ((i += 1) < l) { + /* Decode utf-16 surrogate pairs */ + x = str.charCodeAt(i); + y = i + 1 < l ? str.charCodeAt(i + 1) : 0; + if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i += 1; + } + /* Encode output as utf-8 */ + if (x <= 0x7F) { + output += String.fromCharCode(x); + } else if (x <= 0x7FF) { + output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F), + 0x80 | (x & 0x3F)); + } else if (x <= 0xFFFF) { + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6) & 0x3F), + 0x80 | (x & 0x3F)); + } else if (x <= 0x1FFFFF) { + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6) & 0x3F), + 0x80 | (x & 0x3F)); + } + } + } + return output; + } + + function utf8Decode(str) { + var i, ac, c1, c2, c3, arr = [], + l; + i = ac = c1 = c2 = c3 = 0; + + if (str && str.length) { + l = str.length; + str += ''; + + while (i < l) { + c1 = str.charCodeAt(i); + ac += 1; + if (c1 < 128) { + arr[ac] = String.fromCharCode(c1); + i += 1; + } else if (c1 > 191 && c1 < 224) { + c2 = str.charCodeAt(i + 1); + arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = str.charCodeAt(i + 1); + c3 = str.charCodeAt(i + 2); + arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + } + return arr.join(''); + } + + /** + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + + function safe_add(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } + + /** + * Bitwise rotate a 32-bit number to the left. + */ + + function bit_rol(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + } + + /** + * Convert a raw string to a hex string + */ + + function rstr2hex(input, hexcase) { + var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef', + output = '', + x, i = 0, + l = input.length; + for (; i < l; i += 1) { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F); + } + return output; + } + + /** + * Encode a string as utf-16 + */ + + function str2rstr_utf16le(input) { + var i, l = input.length, + output = ''; + for (i = 0; i < l; i += 1) { + output += String.fromCharCode(input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF); + } + return output; + } + + function str2rstr_utf16be(input) { + var i, l = input.length, + output = ''; + for (i = 0; i < l; i += 1) { + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF); + } + return output; + } + + /** + * Convert an array of big-endian words to a string + */ + + function binb2rstr(input) { + var i, l = input.length * 32, + output = ''; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF); + } + return output; + } + + /** + * Convert an array of little-endian words to a string + */ + + function binl2rstr(input) { + var i, l = input.length * 32, + output = ''; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); + } + return output; + } + + /** + * Convert a raw string to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ + + function rstr2binl(input) { + var i, l = input.length * 8, + output = Array(input.length >> 2), + lo = output.length; + for (i = 0; i < lo; i += 1) { + output[i] = 0; + } + for (i = 0; i < l; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32); + } + return output; + } + + /** + * Convert a raw string to an array of big-endian words + * Characters >255 have their high-byte silently ignored. + */ + + function rstr2binb(input) { + var i, l = input.length * 8, + output = Array(input.length >> 2), + lo = output.length; + for (i = 0; i < lo; i += 1) { + output[i] = 0; + } + for (i = 0; i < l; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); + } + return output; + } + + /** + * Convert a raw string to an arbitrary string encoding + */ + + function rstr2any(input, encoding) { + var divisor = encoding.length, + remainders = Array(), + i, q, x, ld, quotient, dividend, output, full_length; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + dividend = Array(Math.ceil(input.length / 2)); + ld = dividend.length; + for (i = 0; i < ld; i += 1) { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /** + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zerHashes. + * All remainders are stored for later use. + */ + while (dividend.length > 0) { + quotient = Array(); + x = 0; + for (i = 0; i < dividend.length; i += 1) { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if (quotient.length > 0 || q > 0) { + quotient[quotient.length] = q; + } + } + remainders[remainders.length] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + output = ''; + for (i = remainders.length - 1; i >= 0; i--) { + output += encoding.charAt(remainders[i]); + } + + /* Append leading zero equivalents */ + full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2))); + for (i = output.length; i < full_length; i += 1) { + output = encoding[0] + output; + } + return output; + } + + /** + * Convert a raw string to a base-64 string + */ + + function rstr2b64(input, b64pad) { + var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + output = '', + len = input.length, + i, j, triplet; + b64pad = b64pad || '='; + for (i = 0; i < len; i += 3) { + triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 > input.length * 8) { + output += b64pad; + } else { + output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); + } + } + } + return output; + } + + Hashes = { + /** + * @property {String} version + * @readonly + */ + VERSION: '1.0.6', + /** + * @member Hashes + * @class Base64 + * @constructor + */ + Base64: function() { + // private properties + var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + pad = '=', // default pad according with the RFC standard + url = false, // URL encoding support @todo + utf8 = true; // by default enable UTF-8 support encoding + + // public method for encoding + this.encode = function(input) { + var i, j, triplet, + output = '', + len = input.length; + + pad = pad || '='; + input = (utf8) ? utf8Encode(input) : input; + + for (i = 0; i < len; i += 3) { + triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0); + for (j = 0; j < 4; j += 1) { + if (i * 8 + j * 6 > len * 8) { + output += pad; + } else { + output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); + } + } + } + return output; + }; + + // public method for decoding + this.decode = function(input) { + // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var i, o1, o2, o3, h1, h2, h3, h4, bits, ac, + dec = '', + arr = []; + if (!input) { + return input; + } + + i = ac = 0; + input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '=' + //input += ''; + + do { // unpack four hexets into three octets using index points in b64 + h1 = tab.indexOf(input.charAt(i += 1)); + h2 = tab.indexOf(input.charAt(i += 1)); + h3 = tab.indexOf(input.charAt(i += 1)); + h4 = tab.indexOf(input.charAt(i += 1)); + + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + ac += 1; + + if (h3 === 64) { + arr[ac] = String.fromCharCode(o1); + } else if (h4 === 64) { + arr[ac] = String.fromCharCode(o1, o2); + } else { + arr[ac] = String.fromCharCode(o1, o2, o3); + } + } while (i < input.length); + + dec = arr.join(''); + dec = (utf8) ? utf8Decode(dec) : dec; + + return dec; + }; + + // set custom pad string + this.setPad = function(str) { + pad = str || pad; + return this; + }; + // set custom tab string characters + this.setTab = function(str) { + tab = str || tab; + return this; + }; + this.setUTF8 = function(bool) { + if (typeof bool === 'boolean') { + utf8 = bool; + } + return this; + }; + }, + + /** + * CRC-32 calculation + * @member Hashes + * @method CRC32 + * @static + * @param {String} str Input String + * @return {String} + */ + CRC32: function(str) { + var crc = 0, + x = 0, + y = 0, + table, i, iTop; + str = utf8Encode(str); + + table = [ + '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', + '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', + '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', + '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', + 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', + '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', + 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', + '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', + 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', + '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', + 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', + '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', + 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', + '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', + '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', + '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', + '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', + 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', + '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', + 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', + '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', + 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', + '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', + 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', + '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', + 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D' + ].join(''); + + crc = crc ^ (-1); + for (i = 0, iTop = str.length; i < iTop; i += 1) { + y = (crc ^ str.charCodeAt(i)) & 0xFF; + x = '0x' + table.substr(y * 9, 8); + crc = (crc >>> 8) ^ x; + } + // always return a positive number (that's what >>> 0 does) + return (crc ^ (-1)) >>> 0; + }, + /** + * @member Hashes + * @class MD5 + * @constructor + * @param {Object} [config] + * + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See for more infHashes. + */ + MD5: function(options) { + /** + * Private config properties. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding + + // privileged (public) methods + this.hex = function(s) { + return rstr2hex(rstr(s, utf8), hexcase); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d), hexcase); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * Enable/disable uppercase hexadecimal returned string + * @param {Boolean} + * @return {Object} this + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * Defines a base64 pad string + * @param {String} Pad + * @return {Object} this + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * Defines a base64 pad string + * @param {Boolean} + * @return {Object} [this] + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + // private methods + + /** + * Calculate the MD5 of a raw string + */ + + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binl2rstr(binl(rstr2binl(s), s.length * 8)); + } + + /** + * Calculate the HMAC-MD5, of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + var bkey, ipad, opad, hash, i; + + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + bkey = rstr2binl(key); + if (bkey.length > 16) { + bkey = binl(bkey, key.length * 8); + } + + ipad = Array(16); + opad = Array(16); + + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl(opad.concat(hash), 512 + 128)); + } + + /** + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ + + function binl(x, len) { + var i, olda, oldb, oldc, oldd, + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878; + + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + for (i = 0; i < x.length; i += 16) { + olda = a; + oldb = b; + oldc = c; + oldd = d; + + a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); + } + + /** + * These functions implement the four basic operations the algorithm uses. + */ + + function md5_cmn(q, a, b, x, s, t) { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); + } + + function md5_ff(a, b, c, d, x, s, t) { + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); + } + + function md5_gg(a, b, c, d, x, s, t) { + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); + } + + function md5_hh(a, b, c, d, x, s, t) { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); + } + + function md5_ii(a, b, c, d, x, s, t) { + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); + } + }, + /** + * @member Hashes + * @class Hashes.SHA1 + * @param {Object} [config] + * @constructor + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1 + * Version 2.2 Copyright Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + */ + SHA1: function(options) { + /** + * Private config properties. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase} + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding + + // public methods + this.hex = function(s) { + return rstr2hex(rstr(s, utf8), hexcase); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + // private methods + + /** + * Calculate the SHA-512 of a raw string + */ + + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); + } + + /** + * Calculate the HMAC-SHA1 of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + var bkey, ipad, opad, i, hash; + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + bkey = rstr2binb(key); + + if (bkey.length > 16) { + bkey = binb(bkey, key.length * 8); + } + ipad = Array(16), opad = Array(16); + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 512 + 160)); + } + + /** + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ + + function binb(x, len) { + var i, j, t, olda, oldb, oldc, oldd, olde, + w = Array(80), + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878, + e = -1009589776; + + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + for (i = 0; i < x.length; i += 16) { + olda = a; + oldb = b; + oldc = c; + oldd = d; + olde = e; + + for (j = 0; j < 80; j += 1) { + if (j < 16) { + w[j] = x[i + j]; + } else { + w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); + } + t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = bit_rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + } + + /** + * Perform the appropriate triplet combination function for the current + * iteration + */ + + function sha1_ft(t, b, c, d) { + if (t < 20) { + return (b & c) | ((~b) & d); + } + if (t < 40) { + return b ^ c ^ d; + } + if (t < 60) { + return (b & c) | (b & d) | (c & d); + } + return b ^ c ^ d; + } + + /** + * Determine the appropriate additive constant for the current iteration + */ + + function sha1_kt(t) { + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; + } + }, + /** + * @class Hashes.SHA256 + * @param {config} + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2 + * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + * Also http://anmar.eu.org/projects/jssha2/ + */ + SHA256: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + sha256_K; + + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s, utf8)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + // private methods + + /** + * Calculate the SHA-512 of a raw string + */ + + function rstr(s, utf8) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); + } + + /** + * Calculate the HMAC-sha256 of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + var hash, i = 0, + bkey = rstr2binb(key), + ipad = Array(16), + opad = Array(16); + + if (bkey.length > 16) { + bkey = binb(bkey, key.length * 8); + } + + for (; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 512 + 256)); + } + + /* + * Main sha256 function, with its support functions + */ + + function sha256_S(X, n) { + return (X >>> n) | (X << (32 - n)); + } + + function sha256_R(X, n) { + return (X >>> n); + } + + function sha256_Ch(x, y, z) { + return ((x & y) ^ ((~x) & z)); + } + + function sha256_Maj(x, y, z) { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + function sha256_Sigma0256(x) { + return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22)); + } + + function sha256_Sigma1256(x) { + return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25)); + } + + function sha256_Gamma0256(x) { + return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3)); + } + + function sha256_Gamma1256(x) { + return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10)); + } + + function sha256_Sigma0512(x) { + return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39)); + } + + function sha256_Sigma1512(x) { + return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41)); + } + + function sha256_Gamma0512(x) { + return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7)); + } + + function sha256_Gamma1512(x) { + return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6)); + } + + sha256_K = [ + 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, + 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, + 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, + 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, + 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, + 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, + 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998 + ]; + + function binb(m, l) { + var HASH = [1779033703, -1150833019, 1013904242, -1521486534, + 1359893119, -1694144372, 528734635, 1541459225 + ]; + var W = new Array(64); + var a, b, c, d, e, f, g, h; + var i, j, T1, T2; + + /* append padding */ + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; + + for (i = 0; i < m.length; i += 16) { + a = HASH[0]; + b = HASH[1]; + c = HASH[2]; + d = HASH[3]; + e = HASH[4]; + f = HASH[5]; + g = HASH[6]; + h = HASH[7]; + + for (j = 0; j < 64; j += 1) { + if (j < 16) { + W[j] = m[j + i]; + } else { + W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), + sha256_Gamma0256(W[j - 15])), W[j - 16]); + } + + T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), + sha256_K[j]), W[j]); + T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c)); + h = g; + g = f; + f = e; + e = safe_add(d, T1); + d = c; + c = b; + b = a; + a = safe_add(T1, T2); + } + + HASH[0] = safe_add(a, HASH[0]); + HASH[1] = safe_add(b, HASH[1]); + HASH[2] = safe_add(c, HASH[2]); + HASH[3] = safe_add(d, HASH[3]); + HASH[4] = safe_add(e, HASH[4]); + HASH[5] = safe_add(f, HASH[5]); + HASH[6] = safe_add(g, HASH[6]); + HASH[7] = safe_add(h, HASH[7]); + } + return HASH; + } + + }, + + /** + * @class Hashes.SHA512 + * @param {config} + * + * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2 + * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + */ + SHA512: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, + /* hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + sha512_k; + + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + b64pad = a || b64pad; + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + /* private methods */ + + /** + * Calculate the SHA-512 of a raw string + */ + + function rstr(s) { + s = (utf8) ? utf8Encode(s) : s; + return binb2rstr(binb(rstr2binb(s), s.length * 8)); + } + /* + * Calculate the HMAC-SHA-512 of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + + var hash, i = 0, + bkey = rstr2binb(key), + ipad = Array(32), + opad = Array(32); + + if (bkey.length > 32) { + bkey = binb(bkey, key.length * 8); + } + + for (; i < 32; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8); + return binb2rstr(binb(opad.concat(hash), 1024 + 512)); + } + + /** + * Calculate the SHA-512 of an array of big-endian dwords, and a bit length + */ + + function binb(x, len) { + var j, i, l, + W = new Array(80), + hash = new Array(16), + //Initial hash values + H = [ + new int64(0x6a09e667, -205731576), + new int64(-1150833019, -2067093701), + new int64(0x3c6ef372, -23791573), + new int64(-1521486534, 0x5f1d36f1), + new int64(0x510e527f, -1377402159), + new int64(-1694144372, 0x2b3e6c1f), + new int64(0x1f83d9ab, -79577749), + new int64(0x5be0cd19, 0x137e2179) + ], + T1 = new int64(0, 0), + T2 = new int64(0, 0), + a = new int64(0, 0), + b = new int64(0, 0), + c = new int64(0, 0), + d = new int64(0, 0), + e = new int64(0, 0), + f = new int64(0, 0), + g = new int64(0, 0), + h = new int64(0, 0), + //Temporary variables not specified by the document + s0 = new int64(0, 0), + s1 = new int64(0, 0), + Ch = new int64(0, 0), + Maj = new int64(0, 0), + r1 = new int64(0, 0), + r2 = new int64(0, 0), + r3 = new int64(0, 0); + + if (sha512_k === undefined) { + //SHA512 constants + sha512_k = [ + new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), + new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), + new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), + new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), + new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), + new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), + new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), + new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), + new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), + new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), + new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), + new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), + new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), + new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), + new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), + new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), + new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), + new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), + new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), + new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), + new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), + new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), + new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), + new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), + new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), + new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), + new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), + new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), + new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), + new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), + new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), + new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), + new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), + new int64(-354779690, -840897762), new int64(-176337025, -294727304), + new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), + new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), + new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), + new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), + new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), + new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817) + ]; + } + + for (i = 0; i < 80; i += 1) { + W[i] = new int64(0, 0); + } + + // append padding to the source string. The format is described in the FIPS. + x[len >> 5] |= 0x80 << (24 - (len & 0x1f)); + x[((len + 128 >> 10) << 5) + 31] = len; + l = x.length; + for (i = 0; i < l; i += 32) { //32 dwords is the block size + int64copy(a, H[0]); + int64copy(b, H[1]); + int64copy(c, H[2]); + int64copy(d, H[3]); + int64copy(e, H[4]); + int64copy(f, H[5]); + int64copy(g, H[6]); + int64copy(h, H[7]); + + for (j = 0; j < 16; j += 1) { + W[j].h = x[i + 2 * j]; + W[j].l = x[i + 2 * j + 1]; + } + + for (j = 16; j < 80; j += 1) { + //sigma1 + int64rrot(r1, W[j - 2], 19); + int64revrrot(r2, W[j - 2], 29); + int64shr(r3, W[j - 2], 6); + s1.l = r1.l ^ r2.l ^ r3.l; + s1.h = r1.h ^ r2.h ^ r3.h; + //sigma0 + int64rrot(r1, W[j - 15], 1); + int64rrot(r2, W[j - 15], 8); + int64shr(r3, W[j - 15], 7); + s0.l = r1.l ^ r2.l ^ r3.l; + s0.h = r1.h ^ r2.h ^ r3.h; + + int64add4(W[j], s1, W[j - 7], s0, W[j - 16]); + } + + for (j = 0; j < 80; j += 1) { + //Ch + Ch.l = (e.l & f.l) ^ (~e.l & g.l); + Ch.h = (e.h & f.h) ^ (~e.h & g.h); + + //Sigma1 + int64rrot(r1, e, 14); + int64rrot(r2, e, 18); + int64revrrot(r3, e, 9); + s1.l = r1.l ^ r2.l ^ r3.l; + s1.h = r1.h ^ r2.h ^ r3.h; + + //Sigma0 + int64rrot(r1, a, 28); + int64revrrot(r2, a, 2); + int64revrrot(r3, a, 7); + s0.l = r1.l ^ r2.l ^ r3.l; + s0.h = r1.h ^ r2.h ^ r3.h; + + //Maj + Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l); + Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h); + + int64add5(T1, h, s1, Ch, sha512_k[j], W[j]); + int64add(T2, s0, Maj); + + int64copy(h, g); + int64copy(g, f); + int64copy(f, e); + int64add(e, d, T1); + int64copy(d, c); + int64copy(c, b); + int64copy(b, a); + int64add(a, T1, T2); + } + int64add(H[0], H[0], a); + int64add(H[1], H[1], b); + int64add(H[2], H[2], c); + int64add(H[3], H[3], d); + int64add(H[4], H[4], e); + int64add(H[5], H[5], f); + int64add(H[6], H[6], g); + int64add(H[7], H[7], h); + } + + //represent the hash as an array of 32-bit dwords + for (i = 0; i < 8; i += 1) { + hash[2 * i] = H[i].h; + hash[2 * i + 1] = H[i].l; + } + return hash; + } + + //A constructor for 64-bit numbers + + function int64(h, l) { + this.h = h; + this.l = l; + //this.toString = int64toString; + } + + //Copies src into dst, assuming both are 64-bit numbers + + function int64copy(dst, src) { + dst.h = src.h; + dst.l = src.l; + } + + //Right-rotates a 64-bit number by shift + //Won't handle cases of shift>=32 + //The function revrrot() is for that + + function int64rrot(dst, x, shift) { + dst.l = (x.l >>> shift) | (x.h << (32 - shift)); + dst.h = (x.h >>> shift) | (x.l << (32 - shift)); + } + + //Reverses the dwords of the source and then rotates right by shift. + //This is equivalent to rotation by 32+shift + + function int64revrrot(dst, x, shift) { + dst.l = (x.h >>> shift) | (x.l << (32 - shift)); + dst.h = (x.l >>> shift) | (x.h << (32 - shift)); + } + + //Bitwise-shifts right a 64-bit number by shift + //Won't handle shift>=32, but it's never needed in SHA512 + + function int64shr(dst, x, shift) { + dst.l = (x.l >>> shift) | (x.h << (32 - shift)); + dst.h = (x.h >>> shift); + } + + //Adds two 64-bit numbers + //Like the original implementation, does not rely on 32-bit operations + + function int64add(dst, x, y) { + var w0 = (x.l & 0xffff) + (y.l & 0xffff); + var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16); + var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16); + var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } + + //Same, except with 4 addends. Works faster than adding them one by one. + + function int64add4(dst, a, b, c, d) { + var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff); + var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16); + var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16); + var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } + + //Same, except with 5 addends + + function int64add5(dst, a, b, c, d, e) { + var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff), + w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16), + w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16), + w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16); + dst.l = (w0 & 0xffff) | (w1 << 16); + dst.h = (w2 & 0xffff) | (w3 << 16); + } + }, + /** + * @class Hashes.RMD160 + * @constructor + * @param {Object} [config] + * + * A JavaScript implementation of the RIPEMD-160 Algorithm + * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * See http://pajhome.org.uk/crypt/md5 for details. + * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/ + */ + RMD160: function(options) { + /** + * Private properties configuration variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + * @see this.setUpperCase() method + * @see this.setPad() method + */ + var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, + /* hexadecimal output case format. false - lowercase; true - uppercase */ + b64pad = (options && typeof options.pad === 'string') ? options.pa : '=', + /* base-64 pad character. Default '=' for strict RFC compliance */ + utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, + /* enable/disable utf8 encoding */ + rmd160_r1 = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 + ], + rmd160_r2 = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 + ], + rmd160_s1 = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 + ], + rmd160_s2 = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 + ]; + + /* privileged (public) methods */ + this.hex = function(s) { + return rstr2hex(rstr(s, utf8)); + }; + this.b64 = function(s) { + return rstr2b64(rstr(s, utf8), b64pad); + }; + this.any = function(s, e) { + return rstr2any(rstr(s, utf8), e); + }; + this.raw = function(s) { + return rstr(s, utf8); + }; + this.hex_hmac = function(k, d) { + return rstr2hex(rstr_hmac(k, d)); + }; + this.b64_hmac = function(k, d) { + return rstr2b64(rstr_hmac(k, d), b64pad); + }; + this.any_hmac = function(k, d, e) { + return rstr2any(rstr_hmac(k, d), e); + }; + /** + * Perform a simple self-test to see if the VM is working + * @return {String} Hexadecimal hash sample + * @public + */ + this.vm_test = function() { + return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72'; + }; + /** + * @description Enable/disable uppercase hexadecimal returned string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUpperCase = function(a) { + if (typeof a === 'boolean') { + hexcase = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {string} Pad + * @return {Object} this + * @public + */ + this.setPad = function(a) { + if (typeof a !== 'undefined') { + b64pad = a; + } + return this; + }; + /** + * @description Defines a base64 pad string + * @param {boolean} + * @return {Object} this + * @public + */ + this.setUTF8 = function(a) { + if (typeof a === 'boolean') { + utf8 = a; + } + return this; + }; + + /* private methods */ + + /** + * Calculate the rmd160 of a raw string + */ + + function rstr(s, utf8) { + s = (utf8) ? utf8Encode(s) : s; + return binl2rstr(binl(rstr2binl(s), s.length * 8)); + } + + /** + * Calculate the HMAC-rmd160 of a key and some data (raw strings) + */ + + function rstr_hmac(key, data) { + key = (utf8) ? utf8Encode(key) : key; + data = (utf8) ? utf8Encode(data) : data; + var i, hash, + bkey = rstr2binl(key), + ipad = Array(16), + opad = Array(16); + + if (bkey.length > 16) { + bkey = binl(bkey, key.length * 8); + } + + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl(opad.concat(hash), 512 + 160)); + } + + /** + * Convert an array of little-endian words to a string + */ + + function binl2rstr(input) { + var i, output = '', + l = input.length * 32; + for (i = 0; i < l; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); + } + return output; + } + + /** + * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length. + */ + + function binl(x, len) { + var T, j, i, l, + h0 = 0x67452301, + h1 = 0xefcdab89, + h2 = 0x98badcfe, + h3 = 0x10325476, + h4 = 0xc3d2e1f0, + A1, B1, C1, D1, E1, + A2, B2, C2, D2, E2; + + /* append padding */ + x[len >> 5] |= 0x80 << (len % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + l = x.length; + + for (i = 0; i < l; i += 16) { + A1 = A2 = h0; + B1 = B2 = h1; + C1 = C2 = h2; + D1 = D2 = h3; + E1 = E2 = h4; + for (j = 0; j <= 79; j += 1) { + T = safe_add(A1, rmd160_f(j, B1, C1, D1)); + T = safe_add(T, x[i + rmd160_r1[j]]); + T = safe_add(T, rmd160_K1(j)); + T = safe_add(bit_rol(T, rmd160_s1[j]), E1); + A1 = E1; + E1 = D1; + D1 = bit_rol(C1, 10); + C1 = B1; + B1 = T; + T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2)); + T = safe_add(T, x[i + rmd160_r2[j]]); + T = safe_add(T, rmd160_K2(j)); + T = safe_add(bit_rol(T, rmd160_s2[j]), E2); + A2 = E2; + E2 = D2; + D2 = bit_rol(C2, 10); + C2 = B2; + B2 = T; + } + + T = safe_add(h1, safe_add(C1, D2)); + h1 = safe_add(h2, safe_add(D1, E2)); + h2 = safe_add(h3, safe_add(E1, A2)); + h3 = safe_add(h4, safe_add(A1, B2)); + h4 = safe_add(h0, safe_add(B1, C2)); + h0 = T; + } + return [h0, h1, h2, h3, h4]; + } + + // specific algorithm methods + + function rmd160_f(j, x, y, z) { + return (0 <= j && j <= 15) ? (x ^ y ^ z) : + (16 <= j && j <= 31) ? (x & y) | (~x & z) : + (32 <= j && j <= 47) ? (x | ~y) ^ z : + (48 <= j && j <= 63) ? (x & z) | (y & ~z) : + (64 <= j && j <= 79) ? x ^ (y | ~z) : + 'rmd160_f: j out of range'; + } + + function rmd160_K1(j) { + return (0 <= j && j <= 15) ? 0x00000000 : + (16 <= j && j <= 31) ? 0x5a827999 : + (32 <= j && j <= 47) ? 0x6ed9eba1 : + (48 <= j && j <= 63) ? 0x8f1bbcdc : + (64 <= j && j <= 79) ? 0xa953fd4e : + 'rmd160_K1: j out of range'; + } + + function rmd160_K2(j) { + return (0 <= j && j <= 15) ? 0x50a28be6 : + (16 <= j && j <= 31) ? 0x5c4dd124 : + (32 <= j && j <= 47) ? 0x6d703ef3 : + (48 <= j && j <= 63) ? 0x7a6d76e9 : + (64 <= j && j <= 79) ? 0x00000000 : + 'rmd160_K2: j out of range'; + } + } + }; + + // exposes Hashes + (function(window) { + var freeExports = false; + if (typeof exports === 'object') { + freeExports = exports; + if (exports && typeof global === 'object' && global && global === global.global) { + window = global; + } + } + + if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + // define as an anonymous module, so, through path mapping, it can be aliased + define(function() { + return Hashes; + }); + } else if (freeExports) { + // in Node.js or RingoJS v0.8.0+ + if (typeof module === 'object' && module && module.exports === freeExports) { + module.exports = Hashes; + } + // in Narwhal or RingoJS v0.7.0- + else { + freeExports.Hashes = Hashes; + } + } else { + // in a browser or Rhino + window.Hashes = Hashes; + } + }(this)); +}()); // IIFE diff --git a/Boop/Boop/scripts/lib/js-yaml.js b/Boop/Boop/scripts/lib/js-yaml.js new file mode 100644 index 00000000..995e8e63 --- /dev/null +++ b/Boop/Boop/scripts/lib/js-yaml.js @@ -0,0 +1,3991 @@ + +/* js-yaml 3.14.0 https://github.com/nodeca/js-yaml */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsyaml = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + +function State(options) { + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// [34] ns-char ::= nb-char - s-white +// [27] nb-char ::= c-printable - b-char - c-byte-order-mark +// [26] b-char ::= b-line-feed | b-carriage-return +// [24] b-line-feed ::= #xA /* LF */ +// [25] b-carriage-return ::= #xD /* CR */ +// [3] c-byte-order-mark ::= #xFEFF +function isNsChar(c) { + return isPrintable(c) && !isWhitespace(c) + // byte-order-mark + && c !== 0xFEFF + // b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; +} + +// Simplified test for values allowed after the first character in plain style. +function isPlainSafe(c, prev) { + // Uses a subset of nb-char - c-flow-indicator - ":" - "#" + // where nb-char ::= c-printable - b-char - c-byte-order-mark. + return isPrintable(c) && c !== 0xFEFF + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // - ":" - "#" + // /* An ns-char preceding */ "#" + && c !== CHAR_COLON + && ((c !== CHAR_SHARP) || (prev && isNsChar(prev))); +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + return isPrintable(c) && c !== 0xFEFF + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +// Determines whether block indentation indicator is required. +function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { + var i; + var char, prev_char; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(string.charCodeAt(0)) + && !isWhitespace(string.charCodeAt(string.length - 1)); + + if (singleLineOnly) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + prev_char = i > 0 ? string.charCodeAt(i - 1) : null; + plain = plain && isPlainSafe(char, prev_char); + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + prev_char = i > 0 ? string.charCodeAt(i - 1) : null; + plain = plain && isPlainSafe(char, prev_char); + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + return plain && !testAmbiguousType(string) + ? STYLE_PLAIN : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey) { + state.dump = (function () { + if (string.length === 0) { + return "''"; + } + if (!state.noCompatMode && + DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { + return "'" + string + "'"; + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new YAMLException('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char, nextChar; + var escapeSeq; + + for (var i = 0; i < string.length; i++) { + char = string.charCodeAt(i); + // Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates"). + if (char >= 0xD800 && char <= 0xDBFF/* high surrogate */) { + nextChar = string.charCodeAt(i + 1); + if (nextChar >= 0xDC00 && nextChar <= 0xDFFF/* low surrogate */) { + // Combine the surrogate pair and store it escaped. + result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000); + // Advance index one extra since we already used that char here. + i++; continue; + } + } + escapeSeq = ESCAPE_SEQUENCES[char]; + result += !escapeSeq && isPrintable(char) + ? string[i] + : escapeSeq || encodeHex(char); + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level, object[index], false, false)) { + if (index !== 0) _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length; + + for (index = 0, length = object.length; index < length; index += 1) { + // Write only valid elements. + if (writeNode(state, level + 1, object[index], true, true)) { + if (!compact || index !== 0) { + _result += generateNextLine(state, level); + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } + + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + + pairBuffer = ''; + if (index !== 0) pairBuffer += ', '; + + if (state.condenseFlow) pairBuffer += '"'; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new YAMLException('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || index !== 0) { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + state.tag = explicit ? type.tag : '?'; + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + var arrayLevel = (state.noArrayIndent && (level > 0)) ? level - 1 : level; + if (block && (state.dump.length !== 0)) { + writeBlockSequence(state, arrayLevel, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, arrayLevel, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey); + } + } else { + if (state.skipInvalid) return false; + throw new YAMLException('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + state.dump = '!<' + state.tag + '> ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + if (writeNode(state, 0, input, true, true)) return state.dump + '\n'; + + return ''; +} + +function safeDump(input, options) { + return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + +module.exports.dump = dump; +module.exports.safeDump = safeDump; + +},{"./common":2,"./exception":4,"./schema/default_full":9,"./schema/default_safe":10}],4:[function(require,module,exports){ +// YAML error class. http://stackoverflow.com/questions/8458984 +// +'use strict'; + +function YAMLException(reason, mark) { + // Super constructor + Error.call(this); + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : ''); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } +} + + +// Inherit from Error +YAMLException.prototype = Object.create(Error.prototype); +YAMLException.prototype.constructor = YAMLException; + + +YAMLException.prototype.toString = function toString(compact) { + var result = this.name + ': '; + + result += this.reason || '(unknown reason)'; + + if (!compact && this.mark) { + result += ' ' + this.mark.toString(); + } + + return result; +}; + + +module.exports = YAMLException; + +},{}],5:[function(require,module,exports){ +'use strict'; + +/*eslint-disable max-len,no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Mark = require('./mark'); +var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); +var DEFAULT_FULL_SCHEMA = require('./schema/default_full'); + + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function _class(obj) { return Object.prototype.toString.call(obj); } + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; + this.onWarning = options['onWarning'] || null; + this.legacy = options['legacy'] || false; + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + return new YAMLException( + message, + new Mark(state.filename, state.input, state.position, state.line, (state.position - state.lineStart))); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + var match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } else { + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + } + + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startPos) { + var index, quantity; + + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } + + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty.call(overridableKeys, keyNode) && + _hasOwnProperty.call(_result, keyNode)) { + state.line = startLine || state.line; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + _result[keyNode] = valueNode; + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = {}, + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _pos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = {}, + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + _pos = state.position; + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else { + break; // Reading is done. Go to the epilogue. + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _pos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if (state.lineIndent > nodeIndent && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!state.anchorMap.hasOwnProperty(alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag !== null && state.tag !== '!') { + if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = {}; + state.anchorMap = {}; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State(input, options); + + var nullpos = input.indexOf('\0'); + + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + var documents = loadDocuments(input, options); + + if (typeof iterator !== 'function') { + return documents; + } + + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException('expected a single document in the stream, but found more'); +} + + +function safeLoadAll(input, iterator, options) { + if (typeof iterator === 'object' && iterator !== null && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + return loadAll(input, iterator, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +function safeLoad(input, options) { + return load(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); +} + + +module.exports.loadAll = loadAll; +module.exports.load = load; +module.exports.safeLoadAll = safeLoadAll; +module.exports.safeLoad = safeLoad; + +},{"./common":2,"./exception":4,"./mark":6,"./schema/default_full":9,"./schema/default_safe":10}],6:[function(require,module,exports){ +'use strict'; + + +var common = require('./common'); + + +function Mark(name, buffer, position, line, column) { + this.name = name; + this.buffer = buffer; + this.position = position; + this.line = line; + this.column = column; +} + + +Mark.prototype.getSnippet = function getSnippet(indent, maxLength) { + var head, start, tail, end, snippet; + + if (!this.buffer) return null; + + indent = indent || 4; + maxLength = maxLength || 75; + + head = ''; + start = this.position; + + while (start > 0 && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(start - 1)) === -1) { + start -= 1; + if (this.position - start > (maxLength / 2 - 1)) { + head = ' ... '; + start += 5; + break; + } + } + + tail = ''; + end = this.position; + + while (end < this.buffer.length && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(end)) === -1) { + end += 1; + if (end - this.position > (maxLength / 2 - 1)) { + tail = ' ... '; + end -= 5; + break; + } + } + + snippet = this.buffer.slice(start, end); + + return common.repeat(' ', indent) + head + snippet + tail + '\n' + + common.repeat(' ', indent + this.position - start + head.length) + '^'; +}; + + +Mark.prototype.toString = function toString(compact) { + var snippet, where = ''; + + if (this.name) { + where += 'in "' + this.name + '" '; + } + + where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1); + + if (!compact) { + snippet = this.getSnippet(); + + if (snippet) { + where += ':\n' + snippet; + } + } + + return where; +}; + + +module.exports = Mark; + +},{"./common":2}],7:[function(require,module,exports){ +'use strict'; + +/*eslint-disable max-len*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var Type = require('./type'); + + +function compileList(schema, name, result) { + var exclude = []; + + schema.include.forEach(function (includedSchema) { + result = compileList(includedSchema, name, result); + }); + + schema[name].forEach(function (currentType) { + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) { + exclude.push(previousIndex); + } + }); + + result.push(currentType); + }); + + return result.filter(function (type, index) { + return exclude.indexOf(index) === -1; + }); +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {} + }, index, length; + + function collectType(type) { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema(definition) { + this.include = definition.include || []; + this.implicit = definition.implicit || []; + this.explicit = definition.explicit || []; + + this.implicit.forEach(function (type) { + if (type.loadKind && type.loadKind !== 'scalar') { + throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + }); + + this.compiledImplicit = compileList(this, 'implicit', []); + this.compiledExplicit = compileList(this, 'explicit', []); + this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit); +} + + +Schema.DEFAULT = null; + + +Schema.create = function createSchema() { + var schemas, types; + + switch (arguments.length) { + case 1: + schemas = Schema.DEFAULT; + types = arguments[0]; + break; + + case 2: + schemas = arguments[0]; + types = arguments[1]; + break; + + default: + throw new YAMLException('Wrong number of arguments for Schema.create function'); + } + + schemas = common.toArray(schemas); + types = common.toArray(types); + + if (!schemas.every(function (schema) { return schema instanceof Schema; })) { + throw new YAMLException('Specified list of super schemas (or a single Schema object) contains a non-Schema object.'); + } + + if (!types.every(function (type) { return type instanceof Type; })) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + return new Schema({ + include: schemas, + explicit: types + }); +}; + + +module.exports = Schema; + +},{"./common":2,"./exception":4,"./type":13}],8:[function(require,module,exports){ +// Standard YAML's Core schema. +// http://www.yaml.org/spec/1.2/spec.html#id2804923 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, Core schema has no distinctions from JSON schema is JS-YAML. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./json') + ] +}); + +},{"../schema":7,"./json":12}],9:[function(require,module,exports){ +// JS-YAML's default schema for `load` function. +// It is not described in the YAML specification. +// +// This schema is based on JS-YAML's default safe schema and includes +// JavaScript-specific types: !!js/undefined, !!js/regexp and !!js/function. +// +// Also this schema is used as default base schema at `Schema.create` function. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = Schema.DEFAULT = new Schema({ + include: [ + require('./default_safe') + ], + explicit: [ + require('../type/js/undefined'), + require('../type/js/regexp'), + require('../type/js/function') + ] +}); + +},{"../schema":7,"../type/js/function":18,"../type/js/regexp":19,"../type/js/undefined":20,"./default_safe":10}],10:[function(require,module,exports){ +// JS-YAML's default schema for `safeLoad` function. +// It is not described in the YAML specification. +// +// This schema is based on standard YAML's Core schema and includes most of +// extra types described at YAML tag repository. (http://yaml.org/type/) + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./core') + ], + implicit: [ + require('../type/timestamp'), + require('../type/merge') + ], + explicit: [ + require('../type/binary'), + require('../type/omap'), + require('../type/pairs'), + require('../type/set') + ] +}); + +},{"../schema":7,"../type/binary":14,"../type/merge":22,"../type/omap":24,"../type/pairs":25,"../type/set":27,"../type/timestamp":29,"./core":8}],11:[function(require,module,exports){ +// Standard YAML's Failsafe schema. +// http://www.yaml.org/spec/1.2/spec.html#id2802346 + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + explicit: [ + require('../type/str'), + require('../type/seq'), + require('../type/map') + ] +}); + +},{"../schema":7,"../type/map":21,"../type/seq":26,"../type/str":28}],12:[function(require,module,exports){ +// Standard YAML's JSON schema. +// http://www.yaml.org/spec/1.2/spec.html#id2803231 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, this schema is not such strict as defined in the YAML specification. +// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc. + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + include: [ + require('./failsafe') + ], + implicit: [ + require('../type/null'), + require('../type/bool'), + require('../type/int'), + require('../type/float') + ] +}); + +},{"../schema":7,"../type/bool":15,"../type/float":16,"../type/int":17,"../type/null":23,"./failsafe":11}],13:[function(require,module,exports){ +'use strict'; + +var YAMLException = require('./exception'); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; + +},{"./exception":4}],14:[function(require,module,exports){ +'use strict'; + +/*eslint-disable no-bitwise*/ + +var NodeBuffer; + +try { + // A trick for browserified version, to not include `Buffer` shim + var _require = require; + NodeBuffer = _require('buffer').Buffer; +} catch (__) {} + +var Type = require('../type'); + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + // Wrap into Buffer for NodeJS and leave Array for browser + if (NodeBuffer) { + // Support node 6.+ Buffer API when available + return NodeBuffer.from ? NodeBuffer.from(result) : new NodeBuffer(result); + } + + return result; +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(object) { + return NodeBuffer && NodeBuffer.isBuffer(object); +} + +module.exports = new Type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); + +},{"../type":13}],15:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +module.exports = new Type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); + +},{"../type":13}],16:[function(require,module,exports){ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // 20:59 + '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; +} + +function constructYamlFloat(data) { + var value, sign, base, digits; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + digits = []; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + + } else if (value.indexOf(':') >= 0) { + value.split(':').forEach(function (v) { + digits.unshift(parseFloat(v, 10)); + }); + + value = 0.0; + base = 1; + + digits.forEach(function (d) { + value += d * base; + base *= 60; + }); + + return sign * value; + + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); + +},{"../common":2,"../type":13}],17:[function(require,module,exports){ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + // base 8 + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + // base 10 (except 0) or base 60 + + // value should not start with `_`; + if (ch === '_') return false; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch === ':') break; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; + + // if !base60 - done; + if (ch !== ':') return true; + + // base60 almost not used, no needs to optimize + return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch, base, digits = []; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value, 16); + return sign * parseInt(value, 8); + } + + if (value.indexOf(':') !== -1) { + value.split(':').forEach(function (v) { + digits.unshift(parseInt(v, 10)); + }); + + value = 0; + base = 1; + + digits.forEach(function (d) { + value += (d * base); + base *= 60; + }); + + return sign * value; + + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0' + obj.toString(8) : '-0' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); + +},{"../common":2,"../type":13}],18:[function(require,module,exports){ +'use strict'; + +var esprima; + +// Browserified version does not have esprima +// +// 1. For node.js just require module as deps +// 2. For browser try to require mudule via external AMD system. +// If not found - try to fallback to window.esprima. If not +// found too - then fail to parse. +// +try { + // workaround to exclude package from browserify list. + var _require = require; + esprima = _require('esprima'); +} catch (_) { + /* eslint-disable no-redeclare */ + /* global window */ + if (typeof window !== 'undefined') esprima = window.esprima; +} + +var Type = require('../../type'); + +function resolveJavascriptFunction(data) { + if (data === null) return false; + + try { + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }); + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + (ast.body[0].expression.type !== 'ArrowFunctionExpression' && + ast.body[0].expression.type !== 'FunctionExpression')) { + return false; + } + + return true; + } catch (err) { + return false; + } +} + +function constructJavascriptFunction(data) { + /*jslint evil:true*/ + + var source = '(' + data + ')', + ast = esprima.parse(source, { range: true }), + params = [], + body; + + if (ast.type !== 'Program' || + ast.body.length !== 1 || + ast.body[0].type !== 'ExpressionStatement' || + (ast.body[0].expression.type !== 'ArrowFunctionExpression' && + ast.body[0].expression.type !== 'FunctionExpression')) { + throw new Error('Failed to resolve function'); + } + + ast.body[0].expression.params.forEach(function (param) { + params.push(param.name); + }); + + body = ast.body[0].expression.body.range; + + // Esprima's ranges include the first '{' and the last '}' characters on + // function expressions. So cut them out. + if (ast.body[0].expression.body.type === 'BlockStatement') { + /*eslint-disable no-new-func*/ + return new Function(params, source.slice(body[0] + 1, body[1] - 1)); + } + // ES6 arrow functions can omit the BlockStatement. In that case, just return + // the body. + /*eslint-disable no-new-func*/ + return new Function(params, 'return ' + source.slice(body[0], body[1])); +} + +function representJavascriptFunction(object /*, style*/) { + return object.toString(); +} + +function isFunction(object) { + return Object.prototype.toString.call(object) === '[object Function]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/function', { + kind: 'scalar', + resolve: resolveJavascriptFunction, + construct: constructJavascriptFunction, + predicate: isFunction, + represent: representJavascriptFunction +}); + +},{"../../type":13}],19:[function(require,module,exports){ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptRegExp(data) { + if (data === null) return false; + if (data.length === 0) return false; + + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // if regexp starts with '/' it can have modifiers and must be properly closed + // `/foo/gim` - modifiers tail can be maximum 3 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + + if (modifiers.length > 3) return false; + // if expression starts with /, is should be properly terminated + if (regexp[regexp.length - modifiers.length - 1] !== '/') return false; + } + + return true; +} + +function constructJavascriptRegExp(data) { + var regexp = data, + tail = /\/([gim]*)$/.exec(data), + modifiers = ''; + + // `/foo/gim` - tail can be maximum 4 chars + if (regexp[0] === '/') { + if (tail) modifiers = tail[1]; + regexp = regexp.slice(1, regexp.length - modifiers.length - 1); + } + + return new RegExp(regexp, modifiers); +} + +function representJavascriptRegExp(object /*, style*/) { + var result = '/' + object.source + '/'; + + if (object.global) result += 'g'; + if (object.multiline) result += 'm'; + if (object.ignoreCase) result += 'i'; + + return result; +} + +function isRegExp(object) { + return Object.prototype.toString.call(object) === '[object RegExp]'; +} + +module.exports = new Type('tag:yaml.org,2002:js/regexp', { + kind: 'scalar', + resolve: resolveJavascriptRegExp, + construct: constructJavascriptRegExp, + predicate: isRegExp, + represent: representJavascriptRegExp +}); + +},{"../../type":13}],20:[function(require,module,exports){ +'use strict'; + +var Type = require('../../type'); + +function resolveJavascriptUndefined() { + return true; +} + +function constructJavascriptUndefined() { + /*eslint-disable no-undefined*/ + return undefined; +} + +function representJavascriptUndefined() { + return ''; +} + +function isUndefined(object) { + return typeof object === 'undefined'; +} + +module.exports = new Type('tag:yaml.org,2002:js/undefined', { + kind: 'scalar', + resolve: resolveJavascriptUndefined, + construct: constructJavascriptUndefined, + predicate: isUndefined, + represent: representJavascriptUndefined +}); + +},{"../../type":13}],21:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); + +},{"../type":13}],22:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +module.exports = new Type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); + +},{"../type":13}],23:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +module.exports = new Type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; } + }, + defaultStyle: 'lowercase' +}); + +},{"../type":13}],24:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; +var _toString = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +module.exports = new Type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); + +},{"../type":13}],25:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _toString = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +module.exports = new Type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); + +},{"../type":13}],26:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); + +},{"../type":13}],27:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +module.exports = new Type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); + +},{"../type":13}],28:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); + +},{"../type":13}],29:[function(require,module,exports){ +'use strict'; + +var Type = require('../type'); + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +module.exports = new Type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); + +},{"../type":13}],"/":[function(require,module,exports){ +'use strict'; + + +var yaml = require('./lib/js-yaml.js'); + + +module.exports = yaml; + +},{"./lib/js-yaml.js":1}]},{},[])("/") +}); diff --git a/Boop/Boop/scripts/lib/lodash.boop.js b/Boop/Boop/scripts/lib/lodash.boop.js index b26b8c88..77a673a9 100644 --- a/Boop/Boop/scripts/lib/lodash.boop.js +++ b/Boop/Boop/scripts/lib/lodash.boop.js @@ -1,14 +1,18 @@ /** * @license * Lodash (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE - * Build: `lodash include="camelCase,deburr,escapeRegExp,kebabCase,snakeCase,startCase,"` + * Build: `lodash include="camelCase,deburr,escapeRegExp,kebabCase,snakeCase,startCase,size"` */ -;(function(){function u(){}function f(u){if(typeof u=="string")return u;if(R(u)){for(var e=-1,x=null==u?0:u.length,d=Array(x);++et&&(t=-t>n?0:n+t),r=r>n?n:r,0>r&&(r+=n),n=t>r?0:r-t>>>0,t>>>=0,r=Array(n);++f=u}function a(u){var e=typeof u;return null!=u&&("object"==e||"function"==e); +}function d(u){return null!=u&&typeof u=="object"}function i(u){return typeof u=="string"||!tu(u)&&d(u)&&"[object String]"==e(u)}function l(u){return typeof u=="symbol"||d(u)&&"[object Symbol]"==e(u)}function b(u){return null==u?"":f(u)}function s(u){return nu(b(u).toLowerCase())}function p(u){return(u=b(u))&&u.replace(S,k).replace(w,"")}function j(u,e,f){return u=b(u),e=f?g:e,e===g?_.test(u)?u.match(R)||[]:u.match(O)||[]:u.match(e)||[]}var g,y=1/0,A=/[\\^$.*+?()[\]{}|]/g,h=RegExp(A.source),O=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,E=/^\[object .+?Constructor\]$/,S=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,m="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",v="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+m,z="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",Z=RegExp("['\u2019]","g"),w=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),L=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+z+m,"g"),R=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])|\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])|\\d+",v].join("|"),"g"),C=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),_=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,m=typeof self=="object"&&self&&self.Object===Object&&self,m=typeof global=="object"&&global&&global.Object===Object&&global||m||Function("return this")(),z=(v=typeof exports=="object"&&exports&&!exports.nodeType&&exports)&&typeof module=="object"&&module&&!module.nodeType&&module,I=function(u){ +return function(e){return null==e?g:e[u]}}("length"),k=function(u){return function(e){return null==u?g:u[e]}}({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O", +"\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d", +"\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L", +"\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T", +"\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),T=Object.prototype,U=m["__core-js_shared__"],D=Function.prototype.toString,M=T.hasOwnProperty,$=function(){ +var u=/[^.]+$/.exec(U&&U.keys&&U.keys.IE_PROTO||"");return u?"Symbol(src)_1."+u:""}(),N=T.toString,F=RegExp("^"+D.call(M).replace(A,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),P=m.Symbol,V=P?P.toStringTag:g,G=function(u,e){return function(f){return u(e(f))}}(Object.keys,Object),W=n(m,"DataView"),H=n(m,"Map"),Y=n(m,"Promise"),J=n(m,"Set"),B=n(m,"WeakMap"),K=r(W),q=r(H),Q=r(Y),X=r(J),uu=r(B),eu=(P=P?P.prototype:g)?P.toString:g,fu=e;(W&&"[object DataView]"!=fu(new W(new ArrayBuffer(1)))||H&&"[object Map]"!=fu(new H)||Y&&"[object Promise]"!=fu(Y.resolve())||J&&"[object Set]"!=fu(new J)||B&&"[object WeakMap]"!=fu(new B))&&(fu=function(u){ +var f=e(u);if(u=(u="[object Object]"==f?u.constructor:g)?r(u):"")switch(u){case K:return"[object DataView]";case q:return"[object Map]";case Q:return"[object Promise]";case X:return"[object Set]";case uu:return"[object WeakMap]"}return f});var tu=Array.isArray,W=t(function(u,e,f){return e=e.toLowerCase(),u+(f?s(e):e)}),H=t(function(u,e,f){return u+(f?"-":"")+e.toLowerCase()}),Y=t(function(u,e,f){return u+(f?"_":"")+e.toLowerCase()}),J=t(function(u,e,f){return u+(f?" ":"")+nu(e)}),nu=function(u){return function(e){ +e=b(e);var f;C.test(e)?(f=e,f=C.test(f)?f.match(L)||[]:f.split("")):f=g;var t=f;if(f=t?t[0]:e.charAt(0),t){var n;e=t.length;var r=n=n===g?e:n;n=1,e=-1;var o=t.length;for(0>n&&(n=-n>o?0:o+n),r=r>o?o:r,0>r&&(r+=o),o=n>r?0:r-n>>>0,n>>>=0,r=Array(o);++e=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(U(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!U(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){U(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1})}}function l(e){var r;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(r=new XMLHttpRequest,this._config.withCredentials&&(r.withCredentials=this._config.withCredentials),n||(r.onload=y(this._chunkLoaded,this),r.onerror=y(this._chunkError,this)),r.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)r.setRequestHeader(t,e[t])}if(this._config.chunkSize){var i=this._start+this._config.chunkSize-1;r.setRequestHeader("Range","bytes="+this._start+"-"+i)}try{r.send(this._config.downloadRequestBody)}catch(e){this._chunkError(e.message)}n&&0===r.status&&this._chunkError()}},this._chunkLoaded=function(){4===r.readyState&&(r.status<200||400<=r.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:r.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(r),this.parseChunk(r.responseText)))},this._chunkError=function(e){var t=r.statusText||e;this._sendError(new Error(t))}}function c(e){var r,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((r=new FileReader).onload=y(this._chunkLoaded,this),r.onerror=y(this._chunkError,this)):r=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(r.error)}}function p(e){var i;u.call(this,e=e||{}),this.stream=function(e){return i=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=i.substring(0,t),i=i.substring(t)):(e=i,i=""),this._finished=!i,this.parseChunk(e)}}}function g(e){u.call(this,e=e||{});var t=[],i=!0,r=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){r&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):i=!0},this._streamData=y(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),i&&(i=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=y(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=y(function(){this._streamCleanUp(),r=!0,this._streamData("")},this),this._streamCleanUp=y(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function i(_){var a,o,h,r=Math.pow(2,53),n=-r,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)(e[-+]?\d+)?\s*$/,u=/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,t=this,i=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(U(_.step)){var p=_.step;_.step=function(e){if(c=e,m())g();else{if(g(),0===c.data.length)return;i+=e.data.length,_.preview&&i>_.preview?o.abort():(c.data=c.data[0],p(c,t))}}}function v(e){return"greedy"===_.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){if(c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),_.skipEmptyLines)for(var e=0;e=l.length?"__parsed_extra":l[i]),_.transform&&(s=_.transform(s,n)),s=y(n,s),"__parsed_extra"===n?(r[n]=r[n]||[],r[n].push(s)):r[n]=s}return _.header&&(i>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+i,f+t):i=r.length/2?"\r\n":"\r"}(e,r)),h=!1,_.delimiter)U(_.delimiter)&&(_.delimiter=_.delimiter(e),c.meta.delimiter=_.delimiter);else{var n=function(e,t,i,r,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=L)return R(!0)}else for(_=M,M++;;){if(-1===(_=a.indexOf(O,_+1)))return i||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:M}),E();if(_===r-1)return E(a.substring(M,_).replace(m,O));if(O!==z||a[_+1]!==z){if(O===z||0===_||a[_-1]!==z){-1!==p&&p<_+1&&(p=a.indexOf(D,_+1)),-1!==g&&g<_+1&&(g=a.indexOf(I,_+1));var y=w(-1===g?p:Math.min(p,g));if(a[_+1+y]===D){f.push(a.substring(M,_).replace(m,O)),a[M=_+1+y+e]!==O&&(_=a.indexOf(O,M)),p=a.indexOf(D,M),g=a.indexOf(I,M);break}var k=w(g);if(a.substring(_+1+k,_+1+k+n)===I){if(f.push(a.substring(M,_).replace(m,O)),C(_+1+k+n),p=a.indexOf(D,M),_=a.indexOf(O,M),o&&(S(),j))return R();if(L&&h.length>=L)return R(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:M}),_++}}else _++}return E();function b(e){h.push(e),d=M}function w(e){var t=0;if(-1!==e){var i=a.substring(_+1,e);i&&""===i.trim()&&(t=i.length)}return t}function E(e){return i||(void 0===e&&(e=a.substring(M)),f.push(e),M=r,b(f),o&&S()),R()}function C(e){M=e,b(f),f=[],g=a.indexOf(I,M)}function R(e){return{data:h,errors:u,meta:{delimiter:D,linebreak:I,aborted:j,truncated:!!e,cursor:d+(t||0)}}}function S(){A(R()),h=[],u=[]}function x(e,t,i){var r={nextDelim:void 0,quoteSearch:void 0},n=a.indexOf(O,t+1);if(t - + - + @@ -36,20 +36,19 @@ - + - + - - + + - - + @@ -496,13 +495,17 @@ Gw + + + + - + @@ -518,133 +521,146 @@ Gw - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + - - - + - - - - - - - + + + + @@ -655,7 +671,7 @@ Gw - + @@ -666,9 +682,9 @@ Gw - - - + + + @@ -677,7 +693,7 @@ Gw - + diff --git a/Boop/UI/Preferences.storyboard b/Boop/UI/Preferences.storyboard index 3b982643..271f65d3 100644 --- a/Boop/UI/Preferences.storyboard +++ b/Boop/UI/Preferences.storyboard @@ -1,8 +1,8 @@ - + - + @@ -32,8 +32,8 @@ - - + + @@ -76,10 +76,10 @@ - + - + @@ -134,14 +134,14 @@ - + - + - + @@ -170,7 +170,7 @@