Ejemplo n.º 1
0
func TestUniqueStringSlice(t *testing.T) {
	require.Equal(t, []string{}, UniqueStringSlice([]string{}))
	require.Equal(t, []string{"one"}, UniqueStringSlice([]string{"one"}))
	testutil.EqualSlicesWithoutOrder(t,
		[]string{"one", "two"},
		UniqueStringSlice([]string{"one", "two"}))
	testutil.EqualSlicesWithoutOrder(t,
		[]string{"one", "two", "three"},
		UniqueStringSlice([]string{"one", "two", "three", "two", "one"}))
}
Ejemplo n.º 2
0
func TestKeysOfStringInterfaceMap(t *testing.T) {
	t.Log("Empty map")
	{
		keys := KeysOfStringInterfaceMap(map[string]interface{}{})
		require.Equal(t, []string{}, keys)
		require.Equal(t, 0, len(keys))
	}

	t.Log("Nil map")
	{
		keys := KeysOfStringInterfaceMap(map[string]interface{}(nil))
		require.Equal(t, []string{}, keys)
		require.Equal(t, 0, len(keys))

		var nilMap map[string]interface{}
		keys = KeysOfStringInterfaceMap(nilMap)
		require.Equal(t, []string{}, keys)
		require.Equal(t, 0, len(keys))
	}

	t.Log("Single key")
	{
		keys := KeysOfStringInterfaceMap(map[string]interface{}{"a": "value"})
		require.Equal(t, 1, len(keys))
		require.Equal(t, []string{"a"}, keys)
	}

	t.Log("Multiple keys")
	{
		keys := KeysOfStringInterfaceMap(map[string]interface{}{"a": "value 1", "b": "value 2"})
		require.Equal(t, 2, len(keys))
		testutil.EqualSlicesWithoutOrder(t, []string{"a", "b"}, keys)
	}
}
func TestAllCmdEnvsForConfigType(t *testing.T) {
	t.Log("Empty")
	{
		machineConfig := MachineConfigModel{}
		allCmdEnvs := machineConfig.AllCmdEnvsForConfigType("")
		require.Equal(t, []string{}, allCmdEnvs)
	}

	t.Log("Priority of Envs - ConfigType Envs overwrite base Envs (other Envs also defined)")
	{
		machineConfig := MachineConfigModel{
			Envs: EnvItemsModel{
				"ENV_KEY_1":         "env value 1",
				"ENV_KEY_OVERWRITE": "value from Envs",
			},
			ConfigTypeEnvs: map[string]EnvItemsModel{
				"config-1": EnvItemsModel{
					"CONFIG_1_ENV_KEY_1": "config 1 - env value 1",
					"ENV_KEY_OVERWRITE":  "value from ConfigTypeEnvs",
				},
			},
		}
		allCmdEnvs := machineConfig.AllCmdEnvsForConfigType("config-1")
		testutil.EqualSlicesWithoutOrder(t, []string{
			"ENV_KEY_1=env value 1",
			"CONFIG_1_ENV_KEY_1=config 1 - env value 1",
			"ENV_KEY_OVERWRITE=value from ConfigTypeEnvs",
		}, allCmdEnvs)
	}
}
func Test_EnvItemsModel_ToCmdEnvs(t *testing.T) {
	empty := EnvItemsModel{}
	require.Equal(t, []string{}, empty.toCmdEnvs())

	one := EnvItemsModel{"key": "value"}
	require.Equal(t, []string{"key=value"}, one.toCmdEnvs())

	two := EnvItemsModel{"key1": "value 1", "key2": "value 2"}
	testutil.EqualSlicesWithoutOrder(t, []string{"key1=value 1", "key2=value 2"}, two.toCmdEnvs())

	envRef := EnvItemsModel{"key": "value with $HOME env ref"}
	require.Equal(t, []string{"key=value with $HOME env ref"}, envRef.toCmdEnvs())
}
Ejemplo n.º 5
0
func TestKeysOfStringStringMap(t *testing.T) {
	t.Log("Empty map")
	keys := KeysOfStringStringMap(map[string]string{})
	require.Equal(t, []string{}, keys)
	require.Equal(t, 0, len(keys))

	t.Log("Single key")
	keys = KeysOfStringStringMap(map[string]string{"a": "value"})
	require.Equal(t, 1, len(keys))
	require.Equal(t, []string{"a"}, keys)

	t.Log("Multiple keys")
	keys = KeysOfStringStringMap(map[string]string{"a": "value 1", "b": "value 2"})
	require.Equal(t, 2, len(keys))
	testutil.EqualSlicesWithoutOrder(t, []string{"a", "b"}, keys)
}
Ejemplo n.º 6
0
func Test_parseCodeSigningSettingsFromOutput(t *testing.T) {
	t.Log("Multiple Code Signing settings")
	{
		logOutput := `...

   	Target DeployOutputFiles:
   		Copying file from '/Users/USER/develop/tmp/xamarin-test/XamTest/iOS/obj/iPhone/Release/XamTest.iOS.exe.mdb' to
   '/Users/USER/develop/tmp/xamarin-test/XamTest/iOS/bin/iPhone/Release/XamTest.iOS.exe.mdb'
   		Copying file from '/Users/USER/develop/tmp/xamarin-test/XamTest/iOS/obj/iPhone/Release/XamTest.iOS.exe' to
   '/Users/USER/develop/tmp/xamarin-test/XamTest/iOS/bin/iPhone/Release/XamTest.iOS.exe'

   	Target _DetectSigningIdentity:
   		DetectSigningIdentity Task
   		  AppBundleName: XamTest.iOS
   		  AppManifest: Info.plist
   		  Keychain: <null>
   		  ProvisioningProfile: <null>
   		  RequireCodesigning: True
   		  SdkPlatform: iPhoneOS
   		  SdkIsSimulator: False
   		  SigningKey: iPhone Developer
   		Detected signing identity:
   		  Code Signing Key: "iPhone Developer: First Last (F72Z82XD37)" (CBAB0B7E123AE7AD790EE801EDFB45035360DB3F)
   		  Provisioning Profile: "iOS Team Provisioning Profile: *" (87af6d83-cb65-4dbe-aee7-f97a87d6fec1)
   		  Bundle Id: io.bitrise.xamtest
   		  App Id: 01SA2B3CDL.io.bitrise.xamtest

   	Target _ComputeBundleResourceOutputPaths:
   		ComputeBundleResourceOutputPaths Task
   		  AppBundleDir: bin/iPhone/Release/XamTest.iOS.app
   		  BundleIdentifier: io.bitrise.xamtest
   		  BundleResources:
   		    obj/iPhone/Release/ibtool-link/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
   		    obj/iPhone/Release/ibtool-link/LaunchScreen.storyboardc/Info.plist
   		    obj/iPhone/Release/ibtool-link/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
   		    obj/iPhone/Release/ibtool-link/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib
   		    obj/iPhone/Release/ibtool-link/Main.storyboardc/Info.plist
   		    obj/iPhone/Release/ibtool-link/Main.storyboardc/UIViewController-BYZ-38-t0r.nib
   		  IntermediateOutputPath: obj/iPhone/Release/
   		  OutputPath: bin/iPhone/Release/

...

   			Target _DetectSdkLocations:
   				DetectSdkLocations Task
   				  TargetFrameworkIdentifier: Xamarin.iOS
   				  TargetArchitectures: ARMv7, ARM64
   				  SdkVersion: 10.0
   				  XamarinSdkRoot: /Library/Frameworks/Xamarin.iOS.framework/Versions/Current
   				  SdkRoot: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk
   				  SdkDevPath: /Applications/Xcode.app/Contents/Developer
   				  SdkUsrPath: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr
   				  SdkPlatform: iPhoneOS
   				  SdkIsSimulator: False

   			Target _DetectSigningIdentity:
   				DetectSigningIdentity Task
   				  AppBundleName: TodayExt
   				  AppManifest: Info.plist
   				  Keychain: <null>
   				  ProvisioningProfile: <null>
   				  RequireCodesigning: True
   				  SdkPlatform: iPhoneOS
   				  SdkIsSimulator: False
   				  SigningKey: iPhone Developer
   				Detected signing identity:
   				  Code Signing Key: "iPhone Distribution: BFirst BLast (B72Z82XD37)" (CBAB0B7E123AE7AD790EE801EDFB45035360DB3F)
   				  Provisioning Profile: "Prov Profile 43" (97af6d83-cb65-4dbe-aee7-f97a87d6fec1)
   				  Bundle Id: io.bitrise.xamtest.ios.todayext
   				  App Id: 01SA2B3CDL.io.bitrise.xamtest.ios.todayext
   		Done building project "/Users/USER/develop/tmp/xamarin-test/XamTest/TodayExt/TodayExt.csproj".


   	Target _CompileToNative:
   		MTouch Task
   		  AppBundleDir: bin/iPhone/Release/XamTest.iOS.app
   		  AppExtensionReferences:
   		    /Users/USER/develop/tmp/xamarin-test/XamTest/TodayExt/bin/iPhone/Release/TodayExt.appex
   		  AppManifest: bin/iPhone/Release/XamTest.iOS.app/Info.plist
   		  Architectures: ARMv7, ARM64
   		  ArchiveSymbols: <null>
   		  BitcodeEnabled: False
   		  CompiledEntitlements: obj/iPhone/Release/Entitlements.xcent
...


`

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromOutput(logOutput)
		require.NoError(t, err)
		testutil.EqualSlicesWithoutOrder(t, []common.CodeSigningIdentityInfo{
			common.CodeSigningIdentityInfo{Title: "iPhone Developer: First Last (F72Z82XD37)"},
			common.CodeSigningIdentityInfo{Title: "iPhone Distribution: BFirst BLast (B72Z82XD37)"},
		}, parsedCodeSigningSettings.Identities)
		testutil.EqualSlicesWithoutOrder(t, []provprofile.ProvisioningProfileInfo{
			provprofile.ProvisioningProfileInfo{Title: "iOS Team Provisioning Profile: *", UUID: "87af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
			provprofile.ProvisioningProfileInfo{Title: "Prov Profile 43", UUID: "97af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
		}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{"01SA2B3CDL"},
			parsedCodeSigningSettings.TeamIDs)
		testutil.EqualSlicesWithoutOrder(t, []string{
			"01SA2B3CDL.io.bitrise.xamtest",
			"01SA2B3CDL.io.bitrise.xamtest.ios.todayext",
		},
			parsedCodeSigningSettings.AppIDs)
	}
}
Ejemplo n.º 7
0
func Test_parseCodeSigningSettingsFromXcodeOutput(t *testing.T) {
	t.Log("A single 'Entitlements:' section")
	{
		xcout := `ProcessProductPackaging "" /Users/USER/Library/Developer/Xcode/DerivedData/watch-test-bltvxiituqolzyajfqjtxedhckqq/Build/Intermediates/ArchiveIntermediates/watch-test/IntermediateBuildFilesPath/watch-test.build/Release-iphoneos/watch-test.build/watch-test.app.xcent
    cd /Users/USER/develop/bitrise/samples/sample-apps-ios-watchkit
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/USER/develop/go/bin:/usr/local/opt/go/libexec/bin"


Entitlements:

{
    "application-identifier" = "01SA2B3CDL.bitrise.watch-test";
    "com.apple.developer.team-identifier" = 01SA2B3CDL;
    "get-task-allow" = 1;
    "keychain-access-groups" =     (
        "01SA2B3CDL.bitrise.watch-test"
    );
}


    builtin-productPackagingUtility -entitlements -format xml -o /Users/USER/Library/Developer/Xcode/DerivedData/watch-test-bltvxiituqolzyajfqjtxedhckqq/Build/Intermediates/ArchiveIntermediates/watch-test/IntermediateBuildFilesPath/watch-test.build/Release-iphoneos/watch-test.build/watch-test.app.xcent`

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromXcodeOutput(xcout)
		require.NoError(t, err)
		require.Equal(t, []common.CodeSigningIdentityInfo{}, parsedCodeSigningSettings.Identities)
		require.Equal(t, []provprofile.ProvisioningProfileInfo{}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{"01SA2B3CDL"},
			parsedCodeSigningSettings.TeamIDs)
		require.Equal(t, []string{"01SA2B3CDL.bitrise.watch-test"},
			parsedCodeSigningSettings.AppIDs)
	}

	t.Log("A single Identity & Prov Profile")
	{
		xcout := `CodeSign /Users/bitrise/Library/...
    cd /Users/...
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform...

Signing Identity:     "iPhone Developer: First Last (F72Z82XD37)"
Provisioning Profile: "Prov Profile 42"
                      (87af6d83-cb65-4dbe-aee7-f97a87d6fec1)

    /usr/bin/codesign --force --sign E7D5FA3770F4ECC529CFCF683CBCDF874F7870FB --entitlements /Users/...`

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromXcodeOutput(xcout)
		require.NoError(t, err)
		require.Equal(t, []common.CodeSigningIdentityInfo{
			common.CodeSigningIdentityInfo{Title: "iPhone Developer: First Last (F72Z82XD37)"},
		}, parsedCodeSigningSettings.Identities)
		require.Equal(t, []provprofile.ProvisioningProfileInfo{
			provprofile.ProvisioningProfileInfo{Title: "Prov Profile 42", UUID: "87af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
		}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{}, parsedCodeSigningSettings.TeamIDs)
		require.Equal(t, []string{}, parsedCodeSigningSettings.AppIDs)
	}

	t.Log("A single Identity & Prov Profile - different style, and not after each other")
	{
		xcout := `CodeSign /Users/bitrise/Library/...
    cd /Users/...
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate

Signing Identity:     "iPhone Distribution: First Last Company (F72Z82XD37)"

    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform...

Provisioning Profile: "com.domain.app AdHoc"
                      (87af6d83-cb65-4dbe-aee7-f97a87d6fec1)

    /usr/bin/codesign --force --sign E7D5FA3770F4ECC529CFCF683CBCDF874F7870FB --entitlements /Users/...`

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromXcodeOutput(xcout)
		require.NoError(t, err)
		require.Equal(t, []common.CodeSigningIdentityInfo{
			common.CodeSigningIdentityInfo{Title: "iPhone Distribution: First Last Company (F72Z82XD37)"},
		}, parsedCodeSigningSettings.Identities)
		require.Equal(t, []provprofile.ProvisioningProfileInfo{
			provprofile.ProvisioningProfileInfo{Title: "com.domain.app AdHoc", UUID: "87af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
		}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{}, parsedCodeSigningSettings.TeamIDs)
		require.Equal(t, []string{}, parsedCodeSigningSettings.AppIDs)
	}

	t.Log("A single Identity & Prov Profile - wildcard Prov Profile")
	{
		xcout := `CodeSign /Users/bitrise/Library/...
    cd /Users/...
Signing Identity:     "iPhone Developer: First Last (F72Z82XD37)"
Provisioning Profile: "iOS Team Provisioning Profile: *"
                      (87af6d83-cb65-4dbe-aee7-f97a87d6fec1)

    /usr/bin/codesign --force --sign E7D5FA3770F4ECC529CFCF683CBCDF874F7870FB --entitlements /Users/...`

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromXcodeOutput(xcout)
		require.NoError(t, err)
		require.Equal(t, []common.CodeSigningIdentityInfo{
			common.CodeSigningIdentityInfo{Title: "iPhone Developer: First Last (F72Z82XD37)"},
		}, parsedCodeSigningSettings.Identities)
		require.Equal(t, []provprofile.ProvisioningProfileInfo{
			provprofile.ProvisioningProfileInfo{Title: "iOS Team Provisioning Profile: *", UUID: "87af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
		}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{}, parsedCodeSigningSettings.TeamIDs)
		require.Equal(t, []string{}, parsedCodeSigningSettings.AppIDs)
	}

	t.Log("Multiple Identity & Prov Profiles, as well as Entitlements sections")
	{
		xcout := `CodeSign /Users/bitrise/Library/...
    cd /Users/...
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate

Entitlements:

{
    "application-identifier" = "01SA2B3CDL.bitrise.watch-test";
    "com.apple.developer.team-identifier" = 01SA2B3CDL;
    "get-task-allow" = 1;
    "keychain-access-groups" =     (
        "01SA2B3CDL.bitrise.watch-test"
    );
}

    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform...

%s

    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform...

Signing Identity:     "iPhone Developer: First Last (F72Z82XD37)"
Provisioning Profile: "Prov Profile 42"
                      (87af6d83-cb65-4dbe-aee7-f97a87d6fec1)

    /usr/bin/codesign --force --sign E7D5FA3770F4ECC529CFCF683CBCDF874F7870FB --entitlements /Users/...
CodeSign /Users/bitrise/Library/...
    cd /Users/...
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate

Entitlements:

{
    "application-identifier" = "01SA2B3CDL.bitrise.watch-test.watchkitapp.watchkitextension";
    "com.apple.developer.team-identifier" = 01SA2B3CDL;
    "get-task-allow" = 1;
    "keychain-access-groups" =     (
        "01SA2B3CDL.bitrise.watch-test.watchkitapp.watchkitextension"
    );
}

    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform...

Signing Identity:     "iPhone Distribution: BFirst BLast (B72Z82XD37)"
Provisioning Profile: "Prov Profile 43"
                      (97af6d83-cb65-4dbe-aee7-f97a87d6fec1)

    /usr/bin/codesign --force --sign X8D5FA4870F4EBC529CFCF683CBCDF874F7870FB --entitlements /Users/...

CodeSign /Users/bitrise/Library/Developer/Xcode/DerivedData/MyProj-duvumlcdhycqqpgirstmnhtdyrpa/Build/Intermediates/ArchiveIntermediates/MyProj/InstallationBuildProductsLocation/Applications/MyProj.app
    cd /Users/bitrise/Documents/Asdf/ParentDir/new-world-ios/MyProj
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"

Signing Identity:     "iPhone Developer: Fname1 Lname1 (2343ABMJ4E)"
Provisioning Profile: "iOS Team Provisioning Profile: com.company.TheProject"
                      (b234b011-124e-3538-b4cd-0fa704c14048)

    /usr/bin/codesign --force --sign 1A2FB138B451B9BCAA0D12E639E450C29077D3E5 --entitlements /Users/bitrise/Library/Developer/Xcode/DerivedData/MyProj-duvumlcdhycqqpgirstmnhtdyrpa/Build/Intermediates/ArchiveIntermediates/MyProj/IntermediateBuildFilesPath/MyProj.build/Release-iphoneos/MyProj.build/MyProj.app.xcent --timestamp=none /Users/bitrise/Library/Developer/Xcode/DerivedData/MyProj-duvumlcdhycqqpgirstmnhtdyrpa/Build/Intermediates/ArchiveIntermediates/MyProj/InstallationBuildProductsLocation/Applications/MyProj.app

Validate /Users/bitrise/Library/Developer/Xcode/DerivedData/MyProj-duvumlcdhycqqpgirstmnhtdyrpa/Build/Intermediates/ArchiveIntermediates/MyProj/InstallationBuildProductsLocation/Applications/MyProj.app
    cd /Users/bitrise/Documents/Asdf/ParentDir/new-world-ios/MyProj
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    export PRODUCT_TYPE=com.apple.product-type.application
    builtin-validationUtility /Users/bitrise/Library/Developer/Xcode/DerivedData/MyProj-duvumlcdhycqqpgirstmnhtdyrpa/Build/Intermediates/ArchiveIntermediates/MyProj/InstallationBuildProductsLocation/Applications/MyProj.app -validate-for-store

...
`

		// inject a really long line
		xcout = fmt.Sprintf(xcout, strings.Repeat("a", 1000000))
		fmt.Println("xcout:", xcout)

		parsedCodeSigningSettings, err := parseCodeSigningSettingsFromXcodeOutput(xcout)
		require.NoError(t, err)
		testutil.EqualSlicesWithoutOrder(t, []common.CodeSigningIdentityInfo{
			common.CodeSigningIdentityInfo{Title: "iPhone Developer: First Last (F72Z82XD37)"},
			common.CodeSigningIdentityInfo{Title: "iPhone Distribution: BFirst BLast (B72Z82XD37)"},
			common.CodeSigningIdentityInfo{Title: "iPhone Developer: Fname1 Lname1 (2343ABMJ4E)"},
		}, parsedCodeSigningSettings.Identities)
		testutil.EqualSlicesWithoutOrder(t, []provprofile.ProvisioningProfileInfo{
			provprofile.ProvisioningProfileInfo{Title: "Prov Profile 42", UUID: "87af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
			provprofile.ProvisioningProfileInfo{Title: "Prov Profile 43", UUID: "97af6d83-cb65-4dbe-aee7-f97a87d6fec1"},
			provprofile.ProvisioningProfileInfo{Title: "iOS Team Provisioning Profile: com.company.TheProject", UUID: "b234b011-124e-3538-b4cd-0fa704c14048"},
		}, parsedCodeSigningSettings.ProvProfiles)
		require.Equal(t, []string{"01SA2B3CDL"},
			parsedCodeSigningSettings.TeamIDs)
		testutil.EqualSlicesWithoutOrder(t, []string{
			"01SA2B3CDL.bitrise.watch-test.watchkitapp.watchkitextension",
			"01SA2B3CDL.bitrise.watch-test",
		},
			parsedCodeSigningSettings.AppIDs)
	}
}