@brightcove/components-embed-code-modal 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +7 -0
- package/.eslintrc +23 -0
- package/.github/workflows/ci.yml +23 -0
- package/.husky/pre-commit +4 -0
- package/.nvmrc +1 -0
- package/.prettierignore +7 -0
- package/.prettierrc +5 -0
- package/.release-it.json +40 -0
- package/.whitesource +3 -0
- package/CHANGELOG.md +387 -0
- package/CODEOWNERS +37 -0
- package/PULL_REQUEST_TEMPLATE.md +17 -0
- package/__tests__/EmbedCode.test.tsx +51 -0
- package/__tests__/InteractivityProject.test.tsx +50 -0
- package/__tests__/PlayerPreview.test.tsx +23 -0
- package/__tests__/TabsHeader.test.tsx +19 -0
- package/__tests__/TabsSection.test.tsx +46 -0
- package/__tests__/TitleWithTooltip.test.tsx +45 -0
- package/__tests__/VideoPlayer.test.tsx +38 -0
- package/__tests__/embedCodeGenerator.test.ts +111 -0
- package/__tests__/util.test.ts +89 -0
- package/babel.config.json +17 -0
- package/build/README.md +109 -0
- package/build/package.json +100 -0
- package/etc/wildcard.brightcove.com.key +27 -0
- package/etc/wildcard.brightcove.com.pem +96 -0
- package/jest/jest.setup.js +62 -0
- package/jest/jest.stub.js +4 -0
- package/jest.config.js +24 -0
- package/package.json +15 -5
- package/scripts/create-dist-pkg-prod.js +18 -0
- package/src/index.ts +17 -0
- package/src/js/EmbedCodeModal.tsx +105 -0
- package/src/js/components/CustomSettingsDropdown.tsx +184 -0
- package/src/js/components/EmbedCopySection.tsx +130 -0
- package/src/js/components/ModalContainer.tsx +367 -0
- package/src/js/components/NoPlayerModal.tsx +42 -0
- package/src/js/components/PlayerPreview.tsx +116 -0
- package/src/js/components/TabsHeader.tsx +31 -0
- package/src/js/components/TabsSection.tsx +74 -0
- package/src/js/components/TitleWithTooltip.tsx +39 -0
- package/src/js/components/VideoLinks.tsx +83 -0
- package/src/js/components/VideoPlayer.tsx +324 -0
- package/src/js/components/index.ts +9 -0
- package/src/js/components/prism/PrismLiveModal.tsx +162 -0
- package/src/js/components/prism/PrismPlayerControls.tsx +343 -0
- package/src/js/components/prism/PrismPlayerPreview.tsx +98 -0
- package/src/js/components/prism/index.ts +3 -0
- package/src/js/constants/baseUrls.ts +4 -0
- package/src/js/constants/embed.ts +12 -0
- package/src/js/constants/player.ts +32 -0
- package/src/js/constants/pluginsRegistry.ts +30 -0
- package/src/js/hooks/useGetPlayers.ts +12 -0
- package/src/js/i18n.ts +43 -0
- package/src/js/services/players-api.ts +26 -0
- package/src/js/services/url-shortener.ts +10 -0
- package/src/js/types/EmbedCodeModalProps.ts +72 -0
- package/src/js/types/EmbedCodeProps.ts +13 -0
- package/src/js/types/brightcoveEmbedCode.d.ts +18 -0
- package/src/js/types/players.ts +64 -0
- package/src/js/types/react-i18next.d.ts +8 -0
- package/src/js/types/studioModule.ts +7 -0
- package/src/js/utils/addPluginsDataToPlayers.ts +59 -0
- package/src/js/utils/call.ts +31 -0
- package/src/js/utils/dimensions.ts +53 -0
- package/src/js/utils/embedCodeGenerator.ts +120 -0
- package/src/js/utils/featureSwitches.ts +16 -0
- package/src/js/utils/util.ts +153 -0
- package/src/module.tsx +280 -0
- package/src/styles/CustomSettingsDropdown.sass +42 -0
- package/src/styles/EmbedCode.sass +30 -0
- package/src/styles/EmbedCodeModal.sass +76 -0
- package/src/styles/base.sass +1 -0
- package/src/styles/prism/PrismLiveModal.sass +155 -0
- package/src/styles/theme.sass +11 -0
- package/src/styles/typings.td.ts +9 -0
- package/src/translations/en.json +61 -0
- package/src/translations/es.json +61 -0
- package/src/translations/fr.json +61 -0
- package/src/translations/ja.json +61 -0
- package/src/translations/ko.json +61 -0
- package/src/translations/zh.json +61 -0
- package/src/types/studio.ts +197 -0
- package/tsconfig.json +34 -0
- package/webpack.config.js +117 -0
- /package/{__tests__ → build/__tests__}/EmbedCode.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/EmbedCode.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/InteractivityProject.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/InteractivityProject.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/PlayerPreview.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/PlayerPreview.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/TabsHeader.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/TabsHeader.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/TabsSection.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/TabsSection.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/TitleWithTooltip.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/TitleWithTooltip.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/VideoPlayer.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/VideoPlayer.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/embedCodeGenerator.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/embedCodeGenerator.test.d.ts.map +0 -0
- /package/{__tests__ → build/__tests__}/util.test.d.ts +0 -0
- /package/{__tests__ → build/__tests__}/util.test.d.ts.map +0 -0
- /package/{index.js → build/index.js} +0 -0
- /package/{index.js.map → build/index.js.map} +0 -0
- /package/{src → build/src}/index.d.ts +0 -0
- /package/{src → build/src}/index.d.ts.map +0 -0
- /package/{src → build/src}/js/EmbedCodeModal.d.ts +0 -0
- /package/{src → build/src}/js/EmbedCodeModal.d.ts.map +0 -0
- /package/{src → build/src}/js/components/CustomSettingsDropdown.d.ts +0 -0
- /package/{src → build/src}/js/components/CustomSettingsDropdown.d.ts.map +0 -0
- /package/{src → build/src}/js/components/EmbedCopySection.d.ts +0 -0
- /package/{src → build/src}/js/components/EmbedCopySection.d.ts.map +0 -0
- /package/{src → build/src}/js/components/ModalContainer.d.ts +0 -0
- /package/{src → build/src}/js/components/ModalContainer.d.ts.map +0 -0
- /package/{src → build/src}/js/components/NoPlayerModal.d.ts +0 -0
- /package/{src → build/src}/js/components/NoPlayerModal.d.ts.map +0 -0
- /package/{src → build/src}/js/components/PlayerPreview.d.ts +0 -0
- /package/{src → build/src}/js/components/PlayerPreview.d.ts.map +0 -0
- /package/{src → build/src}/js/components/TabsHeader.d.ts +0 -0
- /package/{src → build/src}/js/components/TabsHeader.d.ts.map +0 -0
- /package/{src → build/src}/js/components/TabsSection.d.ts +0 -0
- /package/{src → build/src}/js/components/TabsSection.d.ts.map +0 -0
- /package/{src → build/src}/js/components/TitleWithTooltip.d.ts +0 -0
- /package/{src → build/src}/js/components/TitleWithTooltip.d.ts.map +0 -0
- /package/{src → build/src}/js/components/VideoLinks.d.ts +0 -0
- /package/{src → build/src}/js/components/VideoLinks.d.ts.map +0 -0
- /package/{src → build/src}/js/components/VideoPlayer.d.ts +0 -0
- /package/{src → build/src}/js/components/VideoPlayer.d.ts.map +0 -0
- /package/{src → build/src}/js/components/index.d.ts +0 -0
- /package/{src → build/src}/js/components/index.d.ts.map +0 -0
- /package/{src → build/src}/js/components/prism/PrismLiveModal.d.ts +0 -0
- /package/{src → build/src}/js/components/prism/PrismLiveModal.d.ts.map +0 -0
- /package/{src → build/src}/js/components/prism/PrismPlayerControls.d.ts +0 -0
- /package/{src → build/src}/js/components/prism/PrismPlayerControls.d.ts.map +0 -0
- /package/{src → build/src}/js/components/prism/PrismPlayerPreview.d.ts +0 -0
- /package/{src → build/src}/js/components/prism/PrismPlayerPreview.d.ts.map +0 -0
- /package/{src → build/src}/js/components/prism/index.d.ts +0 -0
- /package/{src → build/src}/js/components/prism/index.d.ts.map +0 -0
- /package/{src → build/src}/js/constants/baseUrls.d.ts +0 -0
- /package/{src → build/src}/js/constants/baseUrls.d.ts.map +0 -0
- /package/{src → build/src}/js/constants/embed.d.ts +0 -0
- /package/{src → build/src}/js/constants/embed.d.ts.map +0 -0
- /package/{src → build/src}/js/constants/player.d.ts +0 -0
- /package/{src → build/src}/js/constants/player.d.ts.map +0 -0
- /package/{src → build/src}/js/constants/pluginsRegistry.d.ts +0 -0
- /package/{src → build/src}/js/constants/pluginsRegistry.d.ts.map +0 -0
- /package/{src → build/src}/js/hooks/useGetPlayers.d.ts +0 -0
- /package/{src → build/src}/js/hooks/useGetPlayers.d.ts.map +0 -0
- /package/{src → build/src}/js/i18n.d.ts +0 -0
- /package/{src → build/src}/js/i18n.d.ts.map +0 -0
- /package/{src → build/src}/js/services/players-api.d.ts +0 -0
- /package/{src → build/src}/js/services/players-api.d.ts.map +0 -0
- /package/{src → build/src}/js/services/url-shortener.d.ts +0 -0
- /package/{src → build/src}/js/services/url-shortener.d.ts.map +0 -0
- /package/{src → build/src}/js/types/EmbedCodeModalProps.d.ts +0 -0
- /package/{src → build/src}/js/types/EmbedCodeModalProps.d.ts.map +0 -0
- /package/{src → build/src}/js/types/EmbedCodeProps.d.ts +0 -0
- /package/{src → build/src}/js/types/EmbedCodeProps.d.ts.map +0 -0
- /package/{src → build/src}/js/types/players.d.ts +0 -0
- /package/{src → build/src}/js/types/players.d.ts.map +0 -0
- /package/{src → build/src}/js/types/studioModule.d.ts +0 -0
- /package/{src → build/src}/js/types/studioModule.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/addPluginsDataToPlayers.d.ts +0 -0
- /package/{src → build/src}/js/utils/addPluginsDataToPlayers.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/call.d.ts +0 -0
- /package/{src → build/src}/js/utils/call.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/dimensions.d.ts +0 -0
- /package/{src → build/src}/js/utils/dimensions.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/embedCodeGenerator.d.ts +0 -0
- /package/{src → build/src}/js/utils/embedCodeGenerator.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/featureSwitches.d.ts +0 -0
- /package/{src → build/src}/js/utils/featureSwitches.d.ts.map +0 -0
- /package/{src → build/src}/js/utils/util.d.ts +0 -0
- /package/{src → build/src}/js/utils/util.d.ts.map +0 -0
- /package/{src → build/src}/module.d.ts +0 -0
- /package/{src → build/src}/module.d.ts.map +0 -0
- /package/{src → build/src}/styles/typings.td.d.ts +0 -0
- /package/{src → build/src}/styles/typings.td.d.ts.map +0 -0
- /package/{src → build/src}/types/studio.d.ts +0 -0
- /package/{src → build/src}/types/studio.d.ts.map +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { PlayerPreview } from '../src/js/components';
|
|
4
|
+
import { QueryClientProvider, QueryClient } from 'react-query';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_MODAL_COMP = {
|
|
7
|
+
id: 'default',
|
|
8
|
+
accountId: '456',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const wrappedComponent = (children: React.ReactElement) => (
|
|
12
|
+
<QueryClientProvider client={new QueryClient()}>
|
|
13
|
+
{children}
|
|
14
|
+
</QueryClientProvider>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
test('renders PlayerPreview component with right information', () => {
|
|
18
|
+
render(wrappedComponent(<PlayerPreview {...DEFAULT_MODAL_COMP} />));
|
|
19
|
+
expect(screen.getByText('getURL')).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText('previewButton')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByRole('tab', { name: /javascript/i })).toBeInTheDocument();
|
|
22
|
+
expect(screen.getByRole('tab', { name: /IFrame/i })).toBeInTheDocument();
|
|
23
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { act, fireEvent, render } from '@testing-library/react';
|
|
3
|
+
import { TabsHeader } from '../src/js/components';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_MODAL_COMP = {
|
|
6
|
+
currentTab: 'iframe',
|
|
7
|
+
handleTabChange: jest.fn(),
|
|
8
|
+
iframeLabel: 'iframe',
|
|
9
|
+
jsLabel: 'js',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
test('renders TabsHeader clickeable tabs', async () => {
|
|
13
|
+
const { getByRole } = render(<TabsHeader {...DEFAULT_MODAL_COMP} />);
|
|
14
|
+
const jsBtn = getByRole('tab', { name: DEFAULT_MODAL_COMP.jsLabel });
|
|
15
|
+
act(() => {
|
|
16
|
+
fireEvent.click(jsBtn);
|
|
17
|
+
});
|
|
18
|
+
expect(DEFAULT_MODAL_COMP.handleTabChange).toBeCalled();
|
|
19
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { act, fireEvent, render } from '@testing-library/react';
|
|
3
|
+
import { TabsSection } from 'js/components';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_MODAL_COMP = {
|
|
6
|
+
playerId: 'default',
|
|
7
|
+
videoId: '1234',
|
|
8
|
+
accountId: 'default',
|
|
9
|
+
isBcMapTracking: false,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
test('renders TabsSection clickeable tabs', async () => {
|
|
13
|
+
const { getByRole, getByText } = render(
|
|
14
|
+
<TabsSection {...DEFAULT_MODAL_COMP} isCampaign isViewerIdSource={false} />,
|
|
15
|
+
);
|
|
16
|
+
const jsBtn = getByRole('tab', { name: /javascript/i });
|
|
17
|
+
act(() => {
|
|
18
|
+
fireEvent.click(jsBtn);
|
|
19
|
+
});
|
|
20
|
+
expect(getByText(/data-video-id/i)).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('renders helper text for campaign players', async () => {
|
|
24
|
+
const { getByText } = render(
|
|
25
|
+
<TabsSection {...DEFAULT_MODAL_COMP} isCampaign isViewerIdSource={false} />,
|
|
26
|
+
);
|
|
27
|
+
expect(getByText('tabs.helperTextWarning')).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('renders helper text for viewer id source players', async () => {
|
|
31
|
+
const { getByText } = render(
|
|
32
|
+
<TabsSection {...DEFAULT_MODAL_COMP} isCampaign={false} isViewerIdSource />,
|
|
33
|
+
);
|
|
34
|
+
expect(getByText('tabs.viewerIdTextWarning')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('renders iframe content if it is not campaign or viewer id', async () => {
|
|
38
|
+
const { getByText } = render(
|
|
39
|
+
<TabsSection
|
|
40
|
+
{...DEFAULT_MODAL_COMP}
|
|
41
|
+
isCampaign={false}
|
|
42
|
+
isViewerIdSource={false}
|
|
43
|
+
/>,
|
|
44
|
+
);
|
|
45
|
+
expect(getByText(/allowfullscreen/i)).toBeInTheDocument();
|
|
46
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { TitleWithTooltip } from '../src/js/components';
|
|
4
|
+
import { truncateVideoTitle } from '../src/js/utils/util';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_VIDEO_COMP = {
|
|
7
|
+
videoId: '123',
|
|
8
|
+
videoName:
|
|
9
|
+
'The cat is a domestic species of small carnivorous mammal. It is the only domesticated species in the family Felidae and is often referred to as the domestic cat to distinguish it from the wild members of the family. ',
|
|
10
|
+
accountId: '456',
|
|
11
|
+
duration: 10,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const DEFAULT_PROJECT_COMP = {
|
|
15
|
+
videoId: '456',
|
|
16
|
+
interactivityProjectId: '987',
|
|
17
|
+
interactivityProjectName:
|
|
18
|
+
"The dog is a domesticated descendant of the wolf. Also called the domestic dog, it is derived from the extinct Pleistocene wolf, and the modern wolf is the dog's nearest living relative. ",
|
|
19
|
+
accountId: '456',
|
|
20
|
+
duration: 10,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
test('renders TitleWithTooltip for Video with truncated title if its too long', () => {
|
|
24
|
+
const truncatedTitle = truncateVideoTitle(DEFAULT_VIDEO_COMP.videoName);
|
|
25
|
+
render(
|
|
26
|
+
<TitleWithTooltip
|
|
27
|
+
name={DEFAULT_VIDEO_COMP.videoName}
|
|
28
|
+
id={DEFAULT_VIDEO_COMP.videoId}
|
|
29
|
+
/>,
|
|
30
|
+
);
|
|
31
|
+
expect(screen.getByText(truncatedTitle)).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('renders TitleWithTooltip for Project with truncated title if its too long', () => {
|
|
35
|
+
const truncatedTitle = truncateVideoTitle(
|
|
36
|
+
DEFAULT_PROJECT_COMP.interactivityProjectName,
|
|
37
|
+
);
|
|
38
|
+
render(
|
|
39
|
+
<TitleWithTooltip
|
|
40
|
+
name={DEFAULT_PROJECT_COMP.interactivityProjectName}
|
|
41
|
+
id={DEFAULT_PROJECT_COMP.videoId}
|
|
42
|
+
/>,
|
|
43
|
+
);
|
|
44
|
+
expect(screen.getByText(truncatedTitle)).toBeInTheDocument();
|
|
45
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { QueryClientProvider, QueryClient } from 'react-query';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import { VideoPlayer } from '../src/js/components/VideoPlayer';
|
|
5
|
+
import { EmbedCodeModalTypes } from '../src/js/types/EmbedCodeModalProps';
|
|
6
|
+
import { PLAYER_LIST_FOR_SELECTION, PLAYERS } from '../src/js/constants/player';
|
|
7
|
+
|
|
8
|
+
jest.mock('../src/js/utils/featureSwitches');
|
|
9
|
+
|
|
10
|
+
const wrappedComponent = (children: React.ReactElement) => (
|
|
11
|
+
<QueryClientProvider client={new QueryClient()}>
|
|
12
|
+
{children}
|
|
13
|
+
</QueryClientProvider>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const DEFAULT_MODAL_COMP = {
|
|
17
|
+
videoId: '123',
|
|
18
|
+
videoName: 'test video',
|
|
19
|
+
accountId: '456',
|
|
20
|
+
duration: 10,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
test('renders EmbedCodeModal component with right information', () => {
|
|
24
|
+
render(
|
|
25
|
+
wrappedComponent(
|
|
26
|
+
<VideoPlayer
|
|
27
|
+
video={DEFAULT_MODAL_COMP}
|
|
28
|
+
embedCodeModalType={EmbedCodeModalTypes.VIDEO}
|
|
29
|
+
playerListForSelection={PLAYER_LIST_FOR_SELECTION}
|
|
30
|
+
players={PLAYERS}
|
|
31
|
+
/>,
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
expect(screen.getByText(DEFAULT_MODAL_COMP.videoId)).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText(DEFAULT_MODAL_COMP.videoName)).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByRole('tab', { name: /javascript/i })).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByRole('tab', { name: /IFrame/i })).toBeInTheDocument();
|
|
38
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatEmbedSnippet,
|
|
3
|
+
generateEmbedCode,
|
|
4
|
+
} from '../src/js/utils/embedCodeGenerator';
|
|
5
|
+
import {
|
|
6
|
+
EmbedCodeAspectRatio,
|
|
7
|
+
EmbedCodeProperties,
|
|
8
|
+
EmbedCodeUnits,
|
|
9
|
+
} from '../src/js/types/EmbedCodeModalProps';
|
|
10
|
+
|
|
11
|
+
test('formats iframe snippet with one attribute per line', () => {
|
|
12
|
+
const input =
|
|
13
|
+
'<iframe src="https://players.brightcove.net/x/index.html?videoId=1" allowfullscreen="" allow="encrypted-media" width="960" height="540"></iframe>';
|
|
14
|
+
const expected = `<iframe
|
|
15
|
+
src="https://players.brightcove.net/x/index.html?videoId=1"
|
|
16
|
+
allowfullscreen=""
|
|
17
|
+
allow="encrypted-media"
|
|
18
|
+
width="960"
|
|
19
|
+
height="540"></iframe>`;
|
|
20
|
+
expect(formatEmbedSnippet(input)).toBe(expected);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('formats javascript snippet by breaking video-js attrs and isolating <script>', () => {
|
|
24
|
+
const input =
|
|
25
|
+
'<video-js data-video-id="1" data-account="2" data-player="3" data-embed="default" controls=""></video-js><script src="https://players.brightcove.net/2/3_default/index.min.js"></script>';
|
|
26
|
+
const expected = `<video-js
|
|
27
|
+
data-video-id="1"
|
|
28
|
+
data-account="2"
|
|
29
|
+
data-player="3"
|
|
30
|
+
data-embed="default"
|
|
31
|
+
controls=""></video-js>
|
|
32
|
+
<script
|
|
33
|
+
src="https://players.brightcove.net/2/3_default/index.min.js"></script>`;
|
|
34
|
+
expect(formatEmbedSnippet(input)).toBe(expected);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('preserves spaces inside attribute values', () => {
|
|
38
|
+
const input =
|
|
39
|
+
'<iframe src="https://x?a=foo bar&b=baz qux" allowfullscreen=""></iframe>';
|
|
40
|
+
const expected = `<iframe
|
|
41
|
+
src="https://x?a=foo bar&b=baz qux"
|
|
42
|
+
allowfullscreen=""></iframe>`;
|
|
43
|
+
expect(formatEmbedSnippet(input)).toBe(expected);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('generateEmbedCode', () => {
|
|
47
|
+
const buildEmbedProperties = (
|
|
48
|
+
overrides: Partial<EmbedCodeProperties> = {},
|
|
49
|
+
): EmbedCodeProperties => ({
|
|
50
|
+
width: 540,
|
|
51
|
+
height: 540,
|
|
52
|
+
units: EmbedCodeUnits.PX,
|
|
53
|
+
responsive: false,
|
|
54
|
+
aspectRatio: EmbedCodeAspectRatio.SIXTEEN_NINE,
|
|
55
|
+
...overrides,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('does not throw when aspectRatio is CUSTOM and produces fluid embed code', () => {
|
|
59
|
+
expect(() =>
|
|
60
|
+
generateEmbedCode({
|
|
61
|
+
accountId: 'acc-1',
|
|
62
|
+
playerId: 'player-1',
|
|
63
|
+
videoId: 'video-1',
|
|
64
|
+
embedProperties: buildEmbedProperties({
|
|
65
|
+
aspectRatio: EmbedCodeAspectRatio.CUSTOM,
|
|
66
|
+
}),
|
|
67
|
+
}),
|
|
68
|
+
).not.toThrow();
|
|
69
|
+
|
|
70
|
+
const { embedCode, embedCodeJS } = generateEmbedCode({
|
|
71
|
+
accountId: 'acc-1',
|
|
72
|
+
playerId: 'player-1',
|
|
73
|
+
videoId: 'video-1',
|
|
74
|
+
embedProperties: buildEmbedProperties({
|
|
75
|
+
aspectRatio: EmbedCodeAspectRatio.CUSTOM,
|
|
76
|
+
responsive: true,
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(typeof embedCode).toBe('string');
|
|
81
|
+
expect(typeof embedCodeJS).toBe('string');
|
|
82
|
+
expect(embedCode.length).toBeGreaterThan(0);
|
|
83
|
+
expect(embedCodeJS).toContain('vjs-fluid');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('does not mutate the caller-provided embedProperties', () => {
|
|
87
|
+
const props = buildEmbedProperties({
|
|
88
|
+
aspectRatio: EmbedCodeAspectRatio.CUSTOM,
|
|
89
|
+
});
|
|
90
|
+
generateEmbedCode({
|
|
91
|
+
accountId: 'acc-1',
|
|
92
|
+
playerId: 'player-1',
|
|
93
|
+
videoId: 'video-1',
|
|
94
|
+
embedProperties: props,
|
|
95
|
+
});
|
|
96
|
+
expect(props.aspectRatio).toBe(EmbedCodeAspectRatio.CUSTOM);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('forwards known aspectRatio values unchanged', () => {
|
|
100
|
+
const { embedCodeJS } = generateEmbedCode({
|
|
101
|
+
accountId: 'acc-1',
|
|
102
|
+
playerId: 'player-1',
|
|
103
|
+
videoId: 'video-1',
|
|
104
|
+
embedProperties: buildEmbedProperties({
|
|
105
|
+
aspectRatio: EmbedCodeAspectRatio.SIXTEEN_NINE,
|
|
106
|
+
responsive: true,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
expect(embedCodeJS).toContain('vjs-16-9');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getVideoPreviewLink,
|
|
3
|
+
sortAsc,
|
|
4
|
+
truncateVideoTitle,
|
|
5
|
+
} from '../src/js/utils/util';
|
|
6
|
+
|
|
7
|
+
test('sorting working as expected', () => {
|
|
8
|
+
const data = [
|
|
9
|
+
{ value: '6B9lFzOYe', label: '#1212' },
|
|
10
|
+
{ value: 'BKCEJEm0L', label: 'other 2' },
|
|
11
|
+
{ value: 'WbMYTw0lh', label: '&^qwe' },
|
|
12
|
+
{ value: 'ZLJg8MzKS', label: '123' },
|
|
13
|
+
{ value: 'default', label: 'Brightcove' },
|
|
14
|
+
];
|
|
15
|
+
const expected = [
|
|
16
|
+
{ value: 'WbMYTw0lh', label: '&^qwe' },
|
|
17
|
+
{ value: '6B9lFzOYe', label: '#1212' },
|
|
18
|
+
{ value: 'ZLJg8MzKS', label: '123' },
|
|
19
|
+
{ value: 'default', label: 'Brightcove' },
|
|
20
|
+
{ value: 'BKCEJEm0L', label: 'other 2' },
|
|
21
|
+
];
|
|
22
|
+
expect(sortAsc(data)).toEqual(expected);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('video preview url created correctly', () => {
|
|
26
|
+
const video = {
|
|
27
|
+
videoId: 'test',
|
|
28
|
+
videoName: 'test',
|
|
29
|
+
accountId: 'test',
|
|
30
|
+
posterUrl: 'test',
|
|
31
|
+
duration: 10,
|
|
32
|
+
};
|
|
33
|
+
const expected =
|
|
34
|
+
'https://players.qa.brightcove.net/test/default_default/index.html?videoId=test';
|
|
35
|
+
expect(
|
|
36
|
+
getVideoPreviewLink({
|
|
37
|
+
accountId: video.accountId,
|
|
38
|
+
videoId: video.videoId,
|
|
39
|
+
playerId: 'default',
|
|
40
|
+
}),
|
|
41
|
+
).toBe(expected);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('interactivity project preview url created correctly', () => {
|
|
45
|
+
const video = {
|
|
46
|
+
interactivityProjectId: 'test',
|
|
47
|
+
accountId: 'test',
|
|
48
|
+
posterUrl: 'test',
|
|
49
|
+
duration: 10,
|
|
50
|
+
};
|
|
51
|
+
const expected =
|
|
52
|
+
'https://players.qa.brightcove.net/test/default_default/index.html?interactivityProjectId=test';
|
|
53
|
+
expect(
|
|
54
|
+
getVideoPreviewLink({
|
|
55
|
+
accountId: video.accountId,
|
|
56
|
+
interactivityProjectId: video.interactivityProjectId,
|
|
57
|
+
playerId: 'default',
|
|
58
|
+
}),
|
|
59
|
+
).toBe(expected);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('long video titles are truncated properly', () => {
|
|
63
|
+
const video = {
|
|
64
|
+
videoId: 'test',
|
|
65
|
+
videoName:
|
|
66
|
+
'The cat is a domestic species of small carnivorous mammal. It is the only domesticated species in the family Felidae and is often referred to as the domestic cat to distinguish it from the wild members of the family. ',
|
|
67
|
+
accountId: 'test',
|
|
68
|
+
posterUrl: 'test',
|
|
69
|
+
duration: 10,
|
|
70
|
+
};
|
|
71
|
+
const expected =
|
|
72
|
+
'The cat is a domestic species of small carnivorous mammal. I...';
|
|
73
|
+
const truncatedTitle = truncateVideoTitle(video.videoName);
|
|
74
|
+
|
|
75
|
+
expect(expected).toEqual(truncatedTitle);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('short video titles are truncated properly', () => {
|
|
79
|
+
const video = {
|
|
80
|
+
videoId: 'test',
|
|
81
|
+
videoName: 'This is a normal video title',
|
|
82
|
+
accountId: 'test',
|
|
83
|
+
posterUrl: 'test',
|
|
84
|
+
duration: 10,
|
|
85
|
+
};
|
|
86
|
+
const truncatedTitle = truncateVideoTitle(video.videoName);
|
|
87
|
+
|
|
88
|
+
expect(video.videoName).toEqual(truncatedTitle);
|
|
89
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"presets": [
|
|
3
|
+
[
|
|
4
|
+
"@babel/preset-env",
|
|
5
|
+
{
|
|
6
|
+
"useBuiltIns": "entry",
|
|
7
|
+
"corejs": 3
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"@babel/preset-typescript",
|
|
11
|
+
"@babel/preset-react"
|
|
12
|
+
],
|
|
13
|
+
"plugins": [
|
|
14
|
+
"@babel/proposal-class-properties",
|
|
15
|
+
"@babel/plugin-transform-runtime"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/build/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# studio-components-embed-code-modal
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
### To build
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run build
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Development
|
|
12
|
+
|
|
13
|
+
To run this module for development clone the repo and run
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
npm run demo
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Sign in to Studio with a Studio UI (Marketing Studio) enabled account. If necessary, click the Profile icon and then the Switch to Studio link.
|
|
21
|
+
|
|
22
|
+
Navigate to [https://studio.brightcove.com/products/videocloud/media/dev/sdk:remote](https://studio.brightcove.com/products/videocloud/media/dev/sdk:remote).
|
|
23
|
+
|
|
24
|
+
The App runs at [https://localhost.brightcove.com:12345/js/app.js](https://localhost.brightcove.com:12345/js/app.js) as described in [Creating a Module](https://brightcove.atlassian.net/wiki/spaces/APPS/pages/2287471973/Creating+A+Module#How-does-that-dev%2Fsdk%3Aremote-URL-work%3F)
|
|
25
|
+
|
|
26
|
+
The results of the API call to retrieve players will depend on sign in permissions.
|
|
27
|
+
|
|
28
|
+
## Integrating with modules
|
|
29
|
+
|
|
30
|
+
This component was built for Marketing Studio modules, such as: [studio-media-module-four](https://bithub.brightcove.com/studio/studio-module-media-four).
|
|
31
|
+
|
|
32
|
+
Below you will find instructions on how to use the component inside of these modules.
|
|
33
|
+
|
|
34
|
+
#### Install the package
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm i @brightcove/components-embed-code-modal
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Import the component and required types
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import {
|
|
44
|
+
EmbedCodeModal,
|
|
45
|
+
VideoPayload,
|
|
46
|
+
} from '@brightcove/components-embed-code-modal';
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`VideoPayload` is a TypeScript interface which describes an Object that will be accepted as a prop for your `<EmbedCodeModal>` component.
|
|
50
|
+
|
|
51
|
+
Here is an overview of the `VideoPayload` interface:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
videoId: string; // Video id, required
|
|
55
|
+
videoName: string; // Video title, required
|
|
56
|
+
accountId: string; // BC account id, required
|
|
57
|
+
posterUrl?: string; // Video poster url, not required
|
|
58
|
+
duration: number; // Video duration in seconds, required
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Component Props
|
|
62
|
+
|
|
63
|
+
The component currently takes in two props:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
language?: 'en' | 'es' | 'fr' | 'ko' | 'ja' | 'zh';
|
|
67
|
+
video: VideoPayload;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- The `VideoPayload` interface is exported by the component.
|
|
71
|
+
- The `language` prop is optional, if not passed, the component will get the language from `StudioModule.config.lang`. Currently, we use this for testing in our local sandbox.
|
|
72
|
+
|
|
73
|
+
#### Wiring Up Through the Module
|
|
74
|
+
|
|
75
|
+
The modal will only render once the `video` prop has been passed into the `EmbedCodeModal` component.
|
|
76
|
+
|
|
77
|
+
In order to keep our components fully decoupled, we look to our parent module's for wiring up our components together.
|
|
78
|
+
|
|
79
|
+
Here's an example of how the the Media Module's VideoLibrary is wiring up two separate components in order to open the EmbedCodeModal:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const [embedVideo, setEmbedVideo] = useState<VideoPayload>(null);
|
|
83
|
+
|
|
84
|
+
const handleAction = (event: DataGridAction) => {
|
|
85
|
+
if (event.type === DataGridEvents.GetCode) {
|
|
86
|
+
// build VideoPayload for EmbedCodeModal component here
|
|
87
|
+
// this way we are completely de-coupling the EmbedCodeModal from the module
|
|
88
|
+
const { payload: video } = event;
|
|
89
|
+
setEmbedVideo({
|
|
90
|
+
videoId: video.id,
|
|
91
|
+
videoName: video.name,
|
|
92
|
+
accountId: video.account_id,
|
|
93
|
+
posterUrl: video?.images?.poster?.src,
|
|
94
|
+
duration: video.duration,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
1. The Media Module imports both the `DataGrid` & `EmbedCodeModal` components. Neither component are coded to be aware of the other.
|
|
101
|
+
2. The `DataGrid` component dispatches the `GetCode` action to tell its parent module: _I would like to retrieve some code, go and do that, however your module handles this action_.
|
|
102
|
+
3. The Media Module handles this action by creating a new payload with the video information handed off by the DataGrid. It knows that it wants to open the EmbedCodeModal, so it will look to the `VideoPayload` interface to create what it needs.
|
|
103
|
+
4. This video object is set to the module's local state.
|
|
104
|
+
5. Within our JSX, our EmbedCodeModal should be passing this video object to the component: `<EmbedCodeModal video={embedVideo} />`
|
|
105
|
+
6. Anytime that `embedVideo` updates in the module - it triggers the Embed Code Modal to open.
|
|
106
|
+
|
|
107
|
+
The reasons we have wired things up this way has been to achieve our goals of keeping micro-frontends decoupled. The EmbedCodeModal & the DataGrid are not interacting directly with each other. The DataGrid is providing video data that is being used, but when it triggers a `Get Code` event, it can just send an entire Video Object along with it. It doesn't need to know exactly what information the Embed Code Modal needs in order to successfully operate.
|
|
108
|
+
|
|
109
|
+
Likewise, the Embed Code Modal could be triggered by any other number of interfaces, and this abstraction helps us better prepare for the integrations coming in our future.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brightcove/components-embed-code-modal",
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://bithub.brightcove.com/studio-ui-kit/studio-components-embed-code-modal.git"
|
|
7
|
+
},
|
|
8
|
+
"description": "Embed Code Modal used for publishing videos",
|
|
9
|
+
"main": "./index.js",
|
|
10
|
+
"types": "./src/index.d.ts",
|
|
11
|
+
"author": "Campaign Team",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"demo": "NODE_ENV=development DEMO=1 webpack-dev-server --progress --color",
|
|
14
|
+
"build": "NODE_ENV=production webpack --progress && cp ./README.md ./build && node scripts/create-dist-pkg-prod && tsc",
|
|
15
|
+
"build:watch": "NODE_ENV=production webpack --watch",
|
|
16
|
+
"clean": "rm -r build",
|
|
17
|
+
"lint": "eslint \"{src,__tests__,demo}/**/*.{ts,tsx,js,jsx}\"",
|
|
18
|
+
"type-check": "tsc",
|
|
19
|
+
"notify": "notify-change -m proj-projstudio",
|
|
20
|
+
"release": "release-it",
|
|
21
|
+
"test": "jest",
|
|
22
|
+
"test:coverage": "jest --coverage",
|
|
23
|
+
"test:watch": "jest --watch",
|
|
24
|
+
"pre-commit": "lint-staged && npm test"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@babel/core": "^7.20.7",
|
|
28
|
+
"@babel/plugin-proposal-class-properties": "^7.16.0",
|
|
29
|
+
"@babel/plugin-transform-runtime": "^7.16.4",
|
|
30
|
+
"@babel/preset-env": "^7.16.4",
|
|
31
|
+
"@babel/preset-react": "^7.16.0",
|
|
32
|
+
"@babel/preset-typescript": "^7.16.0",
|
|
33
|
+
"@brightcove/eslint-config-applications": "^0.3.0",
|
|
34
|
+
"@brightcove/kacl": "^0.1.11",
|
|
35
|
+
"@brightcove/notify-change": "^0.1.7",
|
|
36
|
+
"@brightcove/player-embed-code": "^2.0.4",
|
|
37
|
+
"@brightcove/prism-core": "^1.64.0",
|
|
38
|
+
"@brightcove/react-player-loader": "^1.4.2",
|
|
39
|
+
"@brightcove/studio-api-services": "^7.0.0",
|
|
40
|
+
"@brightcove/studio-components": "^7.23.4",
|
|
41
|
+
"@brightcove/studio-design-tokens": "^1.15.0",
|
|
42
|
+
"@brightcove/studio-icons": "^8.14.0",
|
|
43
|
+
"@floating-ui/react": "^0.27.19",
|
|
44
|
+
"@floating-ui/react-dom": "^2.1.8",
|
|
45
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
46
|
+
"@testing-library/react": "^14.3.1",
|
|
47
|
+
"@testing-library/user-event": "^14.4.3",
|
|
48
|
+
"@types/jest": "^27.4.0",
|
|
49
|
+
"@types/react": "^18.3.17",
|
|
50
|
+
"@types/react-dom": "^18.3.5",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
52
|
+
"@typescript-eslint/parser": "^5.4.0",
|
|
53
|
+
"babel-jest": "^27.5.1",
|
|
54
|
+
"babel-loader": "^8.2.3",
|
|
55
|
+
"css-loader": "^6.5.1",
|
|
56
|
+
"eslint": "^8.3.0",
|
|
57
|
+
"eslint-config-prettier": "^8.3.0",
|
|
58
|
+
"eslint-plugin-import": "^2.25.3",
|
|
59
|
+
"eslint-plugin-react": "^7.27.1",
|
|
60
|
+
"eslint-plugin-react-hooks": "^4.3.0",
|
|
61
|
+
"husky": "^7.0.4",
|
|
62
|
+
"i18next": "^21.5.4",
|
|
63
|
+
"jest": "^27.5.1",
|
|
64
|
+
"jest-canvas-mock": "^2.3.1",
|
|
65
|
+
"lint-staged": "^12.1.2",
|
|
66
|
+
"moment-timezone": "^0.6.1",
|
|
67
|
+
"prettier": "^2.5.0",
|
|
68
|
+
"react": "^18.3.1",
|
|
69
|
+
"react-dom": "^18.3.1",
|
|
70
|
+
"react-i18next": "^11.14.3",
|
|
71
|
+
"react-query": "^3.38.0",
|
|
72
|
+
"release-it": "^14.11.8",
|
|
73
|
+
"resize-observer-polyfill": "^1.5.1",
|
|
74
|
+
"sass": "^1.44.0",
|
|
75
|
+
"sass-loader": "^12.3.0",
|
|
76
|
+
"style-loader": "^3.3.1",
|
|
77
|
+
"typescript": "^4.5.2",
|
|
78
|
+
"webpack": "^5.64.4",
|
|
79
|
+
"webpack-cli": "^4.9.1",
|
|
80
|
+
"webpack-dev-server": "^4.5.0"
|
|
81
|
+
},
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"classnames": "^2.5.1"
|
|
84
|
+
},
|
|
85
|
+
"peerDependencies": {
|
|
86
|
+
"@brightcove/player-embed-code": "^2.0.4",
|
|
87
|
+
"@brightcove/prism-core": "^1.25.1",
|
|
88
|
+
"@brightcove/react-player-loader": "^1.4.2",
|
|
89
|
+
"@brightcove/studio-api-services": "^7.0.0",
|
|
90
|
+
"@brightcove/studio-components": "*",
|
|
91
|
+
"@brightcove/studio-design-tokens": "*",
|
|
92
|
+
"@brightcove/studio-icons": "*",
|
|
93
|
+
"i18next": ">=21",
|
|
94
|
+
"react": "^17.0.2 || ^18.0.0",
|
|
95
|
+
"react-dom": "^17.0.2 || ^18.0.0",
|
|
96
|
+
"react-i18next": ">=11",
|
|
97
|
+
"react-query": "^3.38.0"
|
|
98
|
+
},
|
|
99
|
+
"module": "./index.js"
|
|
100
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
MIIEpAIBAAKCAQEAxXmI7sOBKvFm8TFIhKoYCYOaDE+upc6TcPqNlTt8wA8bBpUY
|
|
3
|
+
Je99ofu5CBNsD0uI1XTWy+Bjmo177ND+3apni6KZkOh8kSb/5OAL+eEbqHksL8Z6
|
|
4
|
+
+bAlKtOjjyv3Se/T8sEIo1dszgBFVdPbQZVrYLzGu9g6tLcu1jJ9mjdCLthEdSJH
|
|
5
|
+
tPkTFUYp8Wlup9qMmvG1jo2wqz4pFVtHyZW/fCkQ+MkfeOPnGiSw2oEnHaVmGuPF
|
|
6
|
+
eyxhWBh2q2MAqpyc9qVMkDQowQxtg//zOVlr632XZpI2xhpuINHUztDxEHOB3Hd5
|
|
7
|
+
lT+v3WQttQZ/1gRXaJkFAGKxgbLfuLh92L975QIDAQABAoIBAFKdh/YsAKwQlnqt
|
|
8
|
+
naMy7h982UPxSiXACNspV3ZpjsVjDHFyisnEKhFMmJqSVZEIjtSOrxZYaBNOwdvP
|
|
9
|
+
i/D8y5kVi52eRg8L+96rBRejX8jZ+Ox74xL26HXEWRca07gxB8D1lUGQ38pHPrqr
|
|
10
|
+
iX0kn+m20IXh7p2QTZ37PaT5HU0vHIs6K0wOWelPxjtU93FIsiwfaOOba3FOLEXa
|
|
11
|
+
Sd5GvRu9pCpSPO45zTsMI6w1MlD38KUJDcBf2Tm/gSMgfDvj1gPvynXBedlWDXsL
|
|
12
|
+
TIckV0YO0gmRiWanoXc0lafE3Fb0ctcRrGBBlpjhGxkXxYNY5A6b8CE9eJQWtUg8
|
|
13
|
+
7Xo14kECgYEA9V3uqpE0TuArzNzy8jth0meH/gGmIWknQSCSX2wj6b4yvArOWrsS
|
|
14
|
+
qyq1Wd0JfE8AOZf4uWuiJKRk0uRE+xkpYk4tH+7/0+R315a1SXiQb020R6iMC406
|
|
15
|
+
wrRSz0R+xFF8zyD4AKKxSO8CgMotcU/oH78lGObWwTuxQlptXjcC8/kCgYEAzghL
|
|
16
|
+
EDS6TzM9EFt8rbOi6quoahTsDNoPm8kG1TNKxmM805N7dQS3E72/6Sp2ndiTysgu
|
|
17
|
+
rS8j0JC8yBx6oaQMcvY/dUZ3/ZdR6Y6SDqmaTFmbcpWGQzKW89VP5kIffi80dF3A
|
|
18
|
+
FtXt94mG2vcbxdWxyC8CIrDwevfmczs0C5pPak0CgYBHJHcg6X0bKZBJk/61EVap
|
|
19
|
+
pO8fTOcYZN7G2WTXWgmHqmgXcaKnV/pvurBeX+JyMo3EJTYuvPCEY04Af8MocwE2
|
|
20
|
+
yaf3zFpM27+LuNzTcqueOg99f3crmkVhUtt30UpYLbBcdhiyRnnUxcgaA4Tth9er
|
|
21
|
+
7MYa1EOMP3yD2qg/Wv/2MQKBgQCnRrJzCOxPC0HDuxOiD9vw/cexwSTZVl4f1HoY
|
|
22
|
+
tRk7syyadv5gRqDBhWh/zXsastFjbV4AO+qvFiQ/sGecPw3gdK+W7szS9n2Jy7gn
|
|
23
|
+
8WmWHZaI1H96pWNLut+xCfR5xaen5snjgHNBa8YylzhUSiiaaBgqxE+q9wSCgAnE
|
|
24
|
+
ddeObQKBgQCpy2Vq/aUUNMVNDV3vmEwYRD8qsqe5JWXswyOM+ZyHg3N06auP2RHx
|
|
25
|
+
NqUE9gdDxR1gc6cUhxbR9+L9DMEWiLVqXY51yddMCVuQVTHyH4MhyJcXv1eEbtX2
|
|
26
|
+
T/5dnQPy5ib85HAvAei6bf+uRKjm86984JfYZIwEwbGS+H9irF/3Pw==
|
|
27
|
+
-----END RSA PRIVATE KEY-----
|